Terrain Simplification | Steam Revolution Game Devlog #5

Поделиться
HTML-код
  • Опубликовано: 20 сен 2024

Комментарии • 8

  • @Ratchetx7
    @Ratchetx7 Год назад

    Very cool! Really liked you walking through all of that. I shouldn't be surprised by the buffer alignment + min size requirements, but I am. Over 20x waste is insane haha. Also the fact that using a custom simple hashmap had the biggest improvement in generation made me laugh. A few questions:
    1. You said you had to switch the positions to be 3 floats instead of 2 16 bits. Was a bit confused as to why this was needed? Are you still reading the Z value from the height maps by the end of the video? Even if so, couldn't you still quantize the post-simplified mesh X + Y coordinates without cracks?
    2. You said you switched to 32 bit indices because the 1 buffer combined mesh had many elements. But can any individual draw call have more than 16 bit indices? If not, you could still keep 16 bit indices right?
    3. I was surprised to see the ocean is it's own mesh that goes through the simplifier. Is it ever not at Z = 0 (or whatever is sea level)?
    4. What are you using for all your UI? I'm adding UI to my little engine right now, so I'm curious :) The window in the top left of the screen kind of looks like ImGUI, but I was unsure about the top middle or the plain windowless text over cities/factories

    • @josiahmanson
      @josiahmanson  Год назад

      Thanks, I'm glad you liked the video. The waste from alignment restrictions each of the patches having potentially a relatively low number of triangles that don't come anywhere close to filling the 64k buffer.
      1. Honestly using floats is a little overkill in terms of precision. And I could scale down to 3 x 16 bits without noticeable drop in quality. My world terrain is 1377 units across, so let's round that up to 2048. 2^16 / 2048 would give me 32 subdivisions per unit grid, so yes, I could quantize after. To clarify, I am reading the height map in the pixel shader at the end of the video, and it is only used to determine the color of the terrain. Before, it was reading the height map in the vertex shader to determine the shape of the mesh.
      2. As it stands, yes, a call could need more than 16-bit indices, because for a given lod, I dump out all the vertices once and vertices on a tile boundary could be referenced by different tiles. A way to work around this would be to duplicate the vertices on the tile boundaries and have the indices be tile-relative, in which case I could be confident of indices fitting in 16 bits. I considered doing this and just didn't want to bother as the memory usage was fairly low already.
      3. The water is also in rivers and lakes, which have higher elevations than the ocean. Even if the elevation was all 0, it would still be beneficial running through a simplifier to reduce overdraw and thus pixel shader work.
      4. I'm using my own custom GUI code. I'm not sure if that is the best idea or not, but so far it is okay, I guess. It is a bit of a pain to write, but customizing other people's GUI libs is also a pain, so I'm not sure it is really much worse in the end.
      In conclusion, I could reduce memory usage by half using your suggestions. I don't have a great reason not to do those things other than it would take a bit more work. The thing is that I am nowhere near ram limits on any modern GPU, and I'm not bandwidth limited so from a performance perspective there is no reason to reduce memory. The one place it might matter is in disk space usage, so maybe that makes it worthwhile? That said, I am compressing the files on disk, so halving memory may not wind-up halving disk space after compression.

    • @Ratchetx7
      @Ratchetx7 Год назад

      @@josiahmanson
      1-2: For the index changes + position quantization, I was thinking more of performance than memory. I've always seen 16 bit indices give a nice little performance boost, even if bandwidth wasn't the limiting factor. And the memory savings are always a nice thing too. Just mention it because it seems like a low hanging fruit for you. Same for quantizing the positions more. Reading less data is usually at least a little bit faster.
      3: That makes sense about the water. I was somewhat wondering if there would be an implicit way to specify water (at least sea level), but I don't actually know what that would look like haha, so nvrmd.
      4: Ah, that makes sense! Just in the last couple weeks I started writing my own game UI code. None of the libraries I found seemed to be really good desktop application UI, but not good for windowless & in-game UI. Maybe that's just my unfamiliarity with the libraries, but I also started writing my own.

    • @Ratchetx7
      @Ratchetx7 Год назад

      @@josiahmanson Also had a couple new questions:
      1. I suppose if your vertices are not tile relative, then I would hazard a guess you are not running them through any library like meshoptimizer after simplification? Also a really easy to use library, giving a nice little perf win usually.
      2. Have you noticed any quality issues with the meshes? The possible issue on my mind specifically-- does the subdivision take into account the mesh contours at all? Like, imagine you have a long ridge from a mountain range. Are you doing anything to make sure you have edges aligned with that ridge, and not cutting through it + making the mountain look like a sawtooth ridge instead of a straight ridge?

    • @josiahmanson
      @josiahmanson  Год назад

      @@Ratchetx7
      I actually tried the vertex position quantization. I wound up rolling back the change though. It turns out that the quantization was taking large enough steps that I was seeing the coastline looking slightly worse, and was seeing more triangles invert, which I wasn't super happy about. A bit annoyingly, I only saw a 4 channel 16 bit layout option, so it wound up taking 2/3 space on GPU rather than 1/2. On disk, the baked data took 66.6 mb vs 68.7 mb, so it wasn't a huge savings anyhow and felt a little dirty to me. I think the 16 bit index holds more promise, as it has no quality cost and the indices actually take more memory than the vertices anyhow. But it would take a bit more effort to implement, so... maybe I will revisit, but I feel like I have spent enough time on terrain rendering, and there are bigger issues in the game that I need to deal with.
      Maybe the video was a bit unclear about this, but I actually have 2 height maps, one for the water, and one for the ground. Getting the seamless mesh involved solving for where those height maps cross.
      Ya, GUI is tough. Games generally want to be able to stylize the UI to fit the mood of the game, so that is generally going to involve effort regardless of how full-featured a lib you might find. Then there is the issue that you might need custom elements anyhow. For example, in my game, I draw a preview of what a train is going to look like, and render to texture to get images of the different cars. I also have a bit of a graphics optimization built into my GUI, which is that I render it opaquely into the depth buffer in front of the game world, before rendering the world, which allows some early z discard.
      Correct, I haven't used a mesh optimization library. That is something worth considering. I'm actually not concerned about the terrain for that, but rendering the buildings and trains is very vertex shader heavy, and I preprocess those meshes offline, so those are a good candidate for optimization.
      No, I'm not doing anything special about ridge lines. I think the terrain mesh is fairly smooth in the first place so I don't really get a sawtooth problem on the input mesh, and then the decimation algorithm will hopefully retain features well enough not to introduce problems like you describe.

    • @Ratchetx7
      @Ratchetx7 Год назад

      ​@@josiahmanson Bummer the simple quantization didn't work out. You could try having the quantization to be relative to the tile/grid position (stored in full precision). That way the spacing between values is much smaller. You could also fetch the positions in the shader yourself with SV_VertexID to avoid the memory padding. Also i imagine for terrain you don't need as many bits for the Z coord, and lend those to the X + Y if they need more.
      Not saying you should bother doing that though, like you said there are more important things haha. Just bouncing ideas to make it work, theoretically.
      Rendering the UI to the depth buffer before the world geo pass is an interesting idea! I've never thought of UI ever being anywhere other than at the very end. Seems very situational to be able to do that though-- lots of UI in other games isn't fully opaque, and often needs to be excluded from any tonemapping/postprocessing effects.
      I've used this mesh optimizer library before: github.com/zeux/meshoptimizer. Thought it was super easy to use and awesome! Was a free like 6% perf improvement for me, and that was with a super simple vertex shader. If your vertex shader is heavy, you could see a lot more improvement potentially with better vertex cache utilization
      That's nice that the terrain is pretty smooth and you haven't noticed issues there. I've certainly seen it before where you get sawtooth ridges before even passing it to the simplifier, so the simplifier is optimizing error for a mesh that isn't very representative of the true surface. Nice if you don't have to worry about it tho :)

  • @josiahmanson
    @josiahmanson  Год назад

    At 42:42 the continue statement serves no purpose and can be removed. Oops.