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.)
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:
- 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.
- 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.
- 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.
- 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...
[attachment=35831:Screenshot from 2017-05-07 13-33-31.png]