Snapping Atlas Geometry Morphs
by Jeff Faust · in Torque Game Engine Advanced · 08/30/2007 (10:33 am) · 6 replies
As Atlas transitions between different terrain detail levels, it morphs the geometry into place over several frames. Generally this is a good thing, especially at a distance. However, after a discontinuous camera change, such that might happen with a player teleportation, the morphing produces a rather unrealistic behavior at the new location. It looks especially bad with a camera at player level. The terrain looks like it's inflating into place below the player.
Is there a way to tell atlas to go ahead and snap to its final geometry state rather than gradually transition over several frames? In cases where the camera change is essentially a discontinuous cut, an instantaneous change is preferable.
If this is not possible, is it at least a feasible customization, or is it a technical requirement that atlas always morphs?
Is there a way to tell atlas to go ahead and snap to its final geometry state rather than gradually transition over several frames? In cases where the camera change is essentially a discontinuous cut, an instantaneous change is preferable.
If this is not possible, is it at least a feasible customization, or is it a technical requirement that atlas always morphs?
About the author
Jeff Faust creates special effects indie middleware and games for Faust Logic. --- Blog: Effectronica.com --- Twitter: @FaustLogic
#2
AtlasInstanceGeomTOC::batchGeometry
Basically, you'd set some sort of flag, or "figure out" that you want to just snap everything into place and change the morph calculations here. For example, I think you can just set mLastMorph to 0 and it should snap everything fine. (Note use of should, I haven't looked at this very closely ;) ).
Thinking about it a bit more, this assumes that the correct geometry is ready to go. That might not be the case, and that would require more changes in AtlasInstanceGeomTOC::processLOD which figures out when to load different LOD of chunks.
Hope this helps out a little bit.
08/30/2007 (11:24 am)
I think that'd be doable. First place to look would be:AtlasInstanceGeomTOC::batchGeometry
// Draw ourselves. :)
if(getResourceStub(s)->mChunk && !s->isSplit())
{
PROFILE_START(AIGTC_renderGeometry_GFXcalls);
// Figure the target morph value...
const F32 targetMorph = 1.f - (F32(s->mLod & 0xFF) / F32(0xFF));
// Update mLastMorph to match...
if(targetMorph > s->mLastMorph)
s->mLastMorph = targetMorph;
else
s->mLastMorph -= getMin(F32(0.05), F32(s->mLastMorph - targetMorph));
cmb->queue(mCuller.mCamPos, getResourceStub(s), s->mLastMorph);
PROFILE_END();
}Basically, you'd set some sort of flag, or "figure out" that you want to just snap everything into place and change the morph calculations here. For example, I think you can just set mLastMorph to 0 and it should snap everything fine. (Note use of should, I haven't looked at this very closely ;) ).
Thinking about it a bit more, this assumes that the correct geometry is ready to go. That might not be the case, and that would require more changes in AtlasInstanceGeomTOC::processLOD which figures out when to load different LOD of chunks.
Hope this helps out a little bit.
#3
@ Stephen -- I was afraid that the morphing was connected to data paging issues. Good old magician's misdirection will probably be acceptable for effects based transitions, like teleporting, but it doesn't bode well for cinematic camera cuts. I think there, I would want to do something equivalent to starting up a second viewpoint, and then switching to it after a small delay.
Thanks for the quick feedback.
08/30/2007 (11:49 am)
@ Brian -- I already played with that exact piece of code a bit without getting any meaningful results, but I may not have been doing the right thing. I was forcing mLastMorph to equal targetMorph. Perhaps forcing it to zero will do something better, I'll give it a try.@ Stephen -- I was afraid that the morphing was connected to data paging issues. Good old magician's misdirection will probably be acceptable for effects based transitions, like teleporting, but it doesn't bode well for cinematic camera cuts. I think there, I would want to do something equivalent to starting up a second viewpoint, and then switching to it after a small delay.
Thanks for the quick feedback.
#4
Very similar in theory by the way to the issues with teleporting your control object and how that affects the network scoping system--in theory, you have to newly scope X number of new objects, and all the network traffic that entails, and you'd have to do something similar here ("scoping" the new terrain chunk sub-tree, and pre-loading the chunks for rapid transition).
08/30/2007 (11:57 am)
This is an area where I quickly become unfamiliar, but I'm decently sure that the server has all "leaf" chunk levels of detail loaded at all times (for collision purposes), while the client is only loading a sub-tree of chunks. You may be able to implement a "second focus object" and load a secondary sub-tree based on the location of that focus object for immediate transition, but that will probably require some extensive work within the Atlas chunk tracking system.Very similar in theory by the way to the issues with teleporting your control object and how that affects the network scoping system--in theory, you have to newly scope X number of new objects, and all the network traffic that entails, and you'd have to do something similar here ("scoping" the new terrain chunk sub-tree, and pre-loading the chunks for rapid transition).
#5
Actually, you can "prime the pump" with some code like this:
I think if you change the "reason" parameter of toc->immediateLoad, you'll get different types of loading behavior. Then, you just need to make sure the chunk doesn't get kicked out of memory. Which I'm not too familiar with, but shouldn't be hard to track down.
08/30/2007 (12:01 pm)
Jeff,Actually, you can "prime the pump" with some code like this:
AtlasResourceGeomTOC *toc = mAtlas->getGeomTOC()->getResourceTOC();
U32 treeDepth = toc->getTreeDepth();
// x&y below are chunk x&y, you'll have to calc this, or search through the stubs to
// see if the stub->mBounds is interesting to you
AtlasResourceGeomStub* stub = toc->getStub(treeDepth-1, Point2I(x, y));
toc->immediateLoad(stub, AtlasTOC::RootLoad);I think if you change the "reason" parameter of toc->immediateLoad, you'll get different types of loading behavior. Then, you just need to make sure the chunk doesn't get kicked out of memory. Which I'm not too familiar with, but shouldn't be hard to track down.
#6
08/30/2007 (12:25 pm)
@ Brian -- Setting mLastMorph to zero in that bit of code works quite well in my test cases. The trick was to realize that the zero-snapping had to occur over a series of frames to get any noticable change. Right now I'm just doing a serious hack of 30 frames, but it looks nice. I'm guessing we'll see some kind of start-and-stop glitchy-ness in cases where any nasty paging kicks in with the change. I'll attempt to reproduce that case somehow and get a worst-case feel for the downside of snapping the morph. Your other code clip might offer some possibilities in that situation.
Torque 3D Owner Stephen Zepp
--an aggressive modification of the clipmap (negating the primary advantage of the clipmap, which is being able to make very small incremental changes to the total texture aggregate)
--loading off the hard drive the entire new sub-section of the geometry tree, based on how far the change was.
The first is a relatively small impact in the big picture, but the second is why the terrain morphs--as new geometry is made available (in memory) by the background chunk loader, it's factored in to the composite geometry displayed.
A decent to good "smoke and mirrors" method to handle this loading time issue would be to "flash" the screen with player distracting graphics while the threaded loader executes, and once all geometry is available, fade out your distraction flash and use the fully loaded geometry set for your new location.
I'm reasonably sure Atlas provides metrics for requested loads and available loads, but you would probably need to implement a small system around it to notify your distractor when the total resource loading phase is complete.