Procedural terrain and loading other scenery

Thanks for fixing getHeight(), I’m closer to a working demo now with “infinite” terrain and trees/grass.



I still have some other problems, and they’re with how I’m using this, but I wanted to get some advice.



I’m generating and loading my scenery (creating geometry batches) in a thread, which gets terrain heights for tree locations as a bulk array from the OpenGL thread using the task queue (because it causes problems calling getHeight() from outside the main thread).



The problem is that my own gridded paging system for scenery is unable to synchronize with the terrain loading, and is trying to load (procedurally generate) scenery pages without the terrain underneath being loaded (yet). So I still get some patches with no trees or grass because the heights return zero, but it’s because the terrain hasn’t been generated, not because of the previous bug.



Any suggestions for a way to synchronize the two processes, so that my scenery pages can be assured of always loading on top of generated terrain? The scenery grid should be always smaller than the terrain grid, but right now I cannot be guaranteed that a given patch is loaded when my pager decides to load that area’s scenery.



Also, I’m having a problem where getHeight() is returning a height from a low LOD far from the camera, and when the camera approaches, my trees end up floating off the ground when the final LOD is determined. When I was using a single TerrainQuad, I had worked around this and the terrain access from another thread problem by passing a static copy of the TerrainQuad’s heightmap to my scenery loader, and then using the interpolated height from the heightmap, instead of the terrain’s getHeight(). That appeared to be faster, too. But I don’t know how to make it work with TerrainGrid and the procedurally generated heightmaps. Is there a way to get a more accurate height than getHeight(), even for far-off patches?



Thanks for all your time and efforts on such a great terrain system, I can’t wait to see this all work together seamlessly (trees, grass, water, and terrain)!

Maybe this can give you some ideas:

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:multithreading

Actually, that’s exactly how I’m reaching back into the OpenGL thread from my scenery loader thread when I need the terrain height values.



I can probably use a similar method to synchronize the terrain and scenery loading, but I don’t know where the hook is.



Maybe a listener for callbacks from the terrain system that can indicate that a scenery page can now be loaded?

I think I can make something work with TerrainGridListener, maybe build an index of where has been loaded so my scenery page loads can wait until the terrain heights become available in their region (cell).



How do I convert TerrainGridListener cell coordinates into world space coordinates?

hi there,



you can take a look into terrainGrid’s getCellCoords method, it’s calculated as:



[java](x / quadsize) + 0.5f[/java]



where quadsize is the half of the terrain size. If you would like to load the scene parts in a different thread, you can do it, and update only it’s location in the TerrainGridListener :wink: And you’re right, I’ll create a method in listener for LODUpdates too, so you can fine tune the positions of far away objects too.

Thanks.



My far away objects are actually entire optimized batches of trees once I have created them using the individual heights, so I’m not sure how I would adjust their heights with the LOD changes. I’m not sure i’d want to completely readjust the scenery in the page and make a whole new batch for every LOD change, would I?

well you can always call getHeightMapHeight on terrain instead of getHeight, though you will have to scale the value returned yourself, and it returns the height of the closest grid element. you can interpolate between the four sourrounding corner points to get a closer match than with getHeight.

I’ll maybe try my own heightmap interpolation and compare performance. Having to go through the application task queue to avoid conflicting with the LOD thread seems to be a pretty big hit as well, maybe I won’t need to if I can get a heightmap reference (I won’t be doing terrain deformation in my game anytime soon).



I think it’s possible that the bulk of the differences between terrain heights I’m seeing is actually the result of a bug, but I’m not sure.



When I move my character back and forth across a boundary where gridMoved() events occur as I cross (you can actually see the texture seam on the ground if you look down), it looks like the entire terrain shifts laterally by about maybe 0.5 world units. It’s not just the kind of vertex adjustments you’d think of as being due to LOD changing.



If I knew how to use fraps and had time, I’d give you a video. You can definitely see the same behavior in TerrainFractalGridTest off the trunk. At first I just thought it was a frame hiccup as the new terrain loaded, but now that I have objects sitting on the terrain that don’t move, I can definitely see that the terrain is shifting laterally, and my objects are not.



Thanks for all your time supporting this!

Hi !



I’ll look deeper into this problem, as I would like to use this too in my own project, so I’m glad that someone has the time to debug it. :wink: Can’t promise now anything, but I’ll take the time this evening to “upgrade” the grid.



One question: there might be visible artifacts when changing the grid, that will get removed when the LOD update thread does it’s job. You just have to wait and see. Is it the shifting problem you see?

I’m happy to help debug - I’m super excited to be able to use this and not have to build it myself! In fact, once the scenery paging system matures a bit, I am strongly considering contributing it to the project. I think other folks with shader and render to texture experience could really help with completing details like billboard impostors, wind animations, etc. that I would be pretty lost trying to get into but really would love to have. I have years of enterprise Java experience, but minimal 3D/OpenGL background, and with a day job and two kids don’t have a ton of time for this.



The shifting I’m talking about does not get resolved by the LOD updates. I can see those happen too, they generally affect items that are far in the distance (minor cracks getting welded, etc), whereas the shifting appears to affect the entire terrain underneath me when I cross the grid boundary, and if you stop and move back and forth across the boundary it gets really obvious (to me).



If it matters, I’m using a Q6600@3.1, Vista, and a 8800GT with the latest Nvidia drivers.

Yea the getHeight is a bit of a tradeoff between real height and visual height. They both have their uses.

As anthyon said, you could use getHeightmapHeight instead, but you will have to scale it by the terrain’s scale, and it will only get the fixed heightmap point rounded to the nearest integer.

If you come up with any utility methods to get around this, as I’m sure other people will need it too, I would be glad to include them.

For trees, rocks, etc. it’s not such a big issue because you can just “plant them deeper”. But grass seems to be pretty sensitive to slope and LOD offset issues (though it’s mitigated by the fact that you generally only want grass in a short radius around the player where LOD is highest).



I’ll let you know what I find.

After some thought, I have some ideas and a suggestion:



Instead of having the scenery grid scrolling trigger scenery data creation and loading independently from the terrain, I think I want to trigger it from the terrain loading. My scenery page loading would then just have to handle the creation of visual artifacts (the geometry batches, impostors, etc) when areas move into the visibility radius around the player.



So I’m going to implement a TerrainGridListener that can schedule an async task to load the scenery once the terrain has loaded.

I’ll have to make a WorldManager class that can index the loaded scenery entities, and make it a ScenerySource implementation for my threaded scenery page loader. I’ll also have to make the page loader capable of detecting when the underlying scenery hasn’t been loaded yet and deferring scenery page loading.



What occurs to me is that the TerrainGridListener doesn’t have a way to notify me when a tile is unloaded. Can we have a tileUnloaded() callback, so that my WorldManager can persist state and release the memory associated with scenery and other entities in that area as the player moves away?



Any ideas or return suggestions?

well, the listener notifies you of the gridMoved event, which implies both new loads and unloads as well. It provides you with the cell id of the topleft tile of the new view. At least this was my intention. :slight_smile:

Hey, even though I’ve been fighting serious troubles with that TempVars problem, since I have updated to the trunk the “shifting” problem I noted above seems to be fixed by your change with the commit message “Fix: calculating localTranslation after gridChange”. For as long as I can run around before the main thread gets killed by the TempVars issue, I have not been able to see any trees or grass that are out of place (more than I would expect).



Now I just have to implement a way to sync the terrain loading so that my scenery pages get loaded after the terrain they go on.



What is the “origin” of the grid cells? is cell (0,0,0) centered on (0,0,0) and extending from -patchSize/2 to patchSize/2 in the x and z directions? I think I need to be sure I understand this detail if I’m going to be able to evict the loaded entities from my cache as the center moves.

as I said before :wink: :


anthyon said:
hi there,

you can take a look into terrainGrid's getCellCoords method, it's calculated as:

[java](x / quadsize) + 0.5f[/java]

where quadsize is the half of the terrain size. If you would like to load the scene parts in a different thread, you can do it, and update only it's location in the TerrainGridListener ;) And you're right, I'll create a method in listener for LODUpdates too, so you can fine tune the positions of far away objects too.

Heh. I’ve got too much going on. Thanks for the reminder.



In the meantime, I figured out a way to check to see if i’m getting any nonzero heights at all, and signal my batch loader to retry if there are no heights loaded, and when I can get it to run past the TempVars problem, I now have smoothly loading “infiniite” trees, grass, and terrain using my random scenery source. So I may not need to implement a TerrainGridListener based solution at all (at least not yet).



It might be nice if I had a better value to check for no height (e.g. Float.NaN) instead of 0.0f - there exists a degenerate case where I have only one tree in a grid and it happens to spawn somewhere the terrain is actually 0 height, and my loader will infinitely retry the loading of that page (though it will just add a minor task to the executor’s queue that never goes away rather than causing an infinite loop).