Sign in to follow this  
tebriel

Large terrain rendering - reducing popping and calculating normals

Recommended Posts

I'm trying to decide what approach to try next to reduce popping and improve visual quality for a project rendering large spherical terrain which pulls terrain detail from heightmaps. 
 
I'm using a quadtree for LOD with skirting to fill gaps. I'm considering using geomorphing to address popping when LOD changes, but early experimentation made me realize that I'm going to need to interpolate more than just the terrain vertex positions. I believe normals will also need to be interpolated between different LODs, otherwise the lighting changes will be so drastic that morphing the geometry won't do much good. The same needs to be done for all the skirting too, otherwise I'll still see gaps and bad lighting. (Not hard, but a little more work.) 

I'm calculating vertex normals by simply taking the average of the 6 neighboring triangle's surface normals. (As-is now, every vertex is part of 6 triangles. Meshes are just evenly spaced 32x32 grids.) 
 
What I'm not certain about is, will this approach of interpolating between different LOD normals (in addition to vertex position) be enough to get the job done?  Or will I just end up with some other issue after I've done all the work implementing this? 

Another problem I'm seeing (which the above approach should at least mitigate, but maybe not resolve) is that normals at different LODs don't always agree. Skirting does well enough for dealing with the geometry gaps, but that does nothing to address normal disparities. I'm attaching a zoomed-in pic which shows this problem.  You'll have to look closely but you can see that around where the lighting issues are in this picture, the normals are pointing in slightly different directions for bordering meshes at different LOD.  This vanishes entirely once the LODs are all the same, of course.  I'm "padding" my meshes on the edges for purposes of calculating normals, so I don't think that's the reason they're off.  (Actually if that were the problem, it'd still look bad even when LOD matches.)  

Ideas to address this that I can think of so far: 
  1. Try a new LOD level calculation scheme which attempts to calculate LOD error level and boost the level of detail for areas where error is high. Not sure if this would work well for all types of terrain, though. 
  2. Use some other method of calculating normals which isn't so dependent on LOD. I've experimented with pre-calculating normals and using the same for all LODs (essentially, using the normals in play when at the highest level of detail), but that looks like crap. You can have situations where a very small (but steep) slope gives you a lousy vertex normal, totally throwing off the shading for large triangle regions when at low LOD. 
  3. Throw out the idea of using uniformly spaced 32x32 grids and try to generate meshes with higher detail where terrain is more complex. This makes skirting more challenging, and I think it'll be much more CPU intensive generating these non-uniform meshes. Also it may cause my physics engine to choke if I end up with odd geometry. 
  4. The above gradual geomorphing-style interpolation between LODs... and hope that's good enough. I'd provide my vertex shader with two values for vertex positions, the "actual" position, and an alternate position for every other vertex which moves it towards the center point of its neighbors. Same would apply for normals...
I'm leaning towards trying a combination of 1 and 4-- mostly 4.

[attachment=35831:Screenshot from 2017-05-07 13-33-31.png]
 

Share this post


Link to post
Share on other sites

#4 should work well, easy way to tell if this will work well for you, is if the vertex morphing is at all noticeable..

Share this post


Link to post
Share on other sites

I think what I'm finding is that the normals are really the main (almost the only) issue.  When I don't use normals, I don't notice any popping at all. 

The difficulty I'm experiencing with #4 is calculating the dang "tweening" level. I haven't managed to find a way to properly interpolate the normals (or geometry) smoothly from one level to another in the vertex shader without any popping. 

Share this post


Link to post
Share on other sites

I've thought about how you would do this from your approach and I think your issue is also the associated vertex and the seaming along the edge as well as the normal.

I work in Directx 11 (so probably not going to help here), the way I have tackled the popping issue is probably a little different to you. Basically Im using very sparse uniform grid (large chunks) and then using tessellation to add detail.  Using a height and normal map generated and stored in a resource to reference at points.

Upon tessellating, the progression between high detail and low detail is fairly clean.  That's my approach.  

But getting back to it, I can't see a way to fix the normal and seam issue unless you reference something that both the Low and High detail meshes can use to align the edge and normal.  The only thing I can see here, is on the closer, more lower detail mesh you average the normal on the vertex which doesn't have a corresponding neighbour, that is in terms of height and normal.  

Eg.

Low detail Edge    -                    4                       5
High Detail Edge -                      1           2           3  

The interpolation of the normal between 4 -> 5 is different to the interpolation of the normal between 1 -> 2 -> 5.

Thoughts?  well you average vertex/normal of point 2 between 1 and 3 so that the interpolation matches that of between 4 and 5.

MIght not help, but I have had a swing.  This is as close to option 4 of yours as I can think, what you might be missing is pushing the mid vertex (2 in my example) to use the alternate coordinates earlier in your LOD calculation.  In fact thinking about it, early as one level of detail earlier.

Edited by ErnieDingo

Share this post


Link to post
Share on other sites
If your source data is a heightmap, preconvert it into a normal map too. Then discard all per-vertex normal data and instead sample this texture per-pixel to get a normal. The lighting will then always be highly detailed regardless of polygon LOD, and will be stable during LOD transitions.

Share this post


Link to post
Share on other sites

@[member='ErnieDingo'] Yeah, the seam issue pictured is close to that, and in both dimensions.  The normals I'm sampling at lower LOD are also biased towards the flat ground normals farther away, since the triangles themselves are larger.  Actually doing it the way you describe sounds like a #5 option that I've been pondering, but I'm hesitating tossing out much of the work I've done so far.  

The concept seems awesome though, so is most of the rendering work being done by the GPU in your case?  What I have performs fine, but I think my bottleneck is probably the vertex and normal buffers I'm passing to the GPU.  What I'd really like to do, if I can get the nerve to break away from my current methods, is try calculating everything in shaders and just sample my height maps to offset heights. But I feel like I'll run into issues like gaps that I'm not sure how to resolve. Also not sure if the fact that I'm doing huge spherical terrain (rather than flat "endless" terrain) will make that more difficult.  

Did you go off of any good online resources as references?  So you're not relying on a quadtree at all?  The idea of throwing out that nasty recursion is also appealing.  
 

@[member='Hodgman'], I've tried using normal maps (it's a very common recommendation), and I think I was doing it wrong now! I was loading normal data in the vertex shader instead of the fragment shader......  :wacko:  So, if I understand that correctly now, I should probably try that again and see how it looks when done correctly... 

I wonder how it'll scale for very large data sets though?  I'm currently using 4096 x 4096 and I'm considering putting even more data in there...

Share this post


Link to post
Share on other sites

@Tebriel I dont think you will need to wipe out your work.  You've done most of the leg work on your method.  I think the only adjustment you need to do is have your higher detail level start moving toward the next level of detail earlier.  That is, you need to have at each level of detail, 2 stages, 1 full detail, 1 for transition to the next level of detail.  Or, you can to do this GPU.  In each vertex you pass to the GPU, pass current vertex, and where it should be for the next level of detail (Ie, if its one to be removed, it should exist on the same plane).  You would need to pass the position and the normal for each version.

You should be able to lerp between the 2 depending on distance from camera.  produce a smooth transition.  I think this is what you have been looking into, and there are some more tweaks you can do but this should be it for your method of attack.

Share this post


Link to post
Share on other sites

I corrected my incorrect normal map implementation and... it seems to be working pretty well.  Maybe I'll still try another technique later on.  

For some reason, even though I had read about doing this a number of times, the specific wording Hodgman used above was what made it click properly. Thanks! 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this