Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (522)
Games in Android Showcase (127)
games submitted by our members
Games in WIP (589)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Optimisation of continuous terrain engine  (Read 1410 times)
0 Members and 1 Guest are viewing this topic.
Offline StrideColossus
« Posted 2013-05-03 10:55:30 »

I now have a working terrain application which currently consists of a single terrain mesh and I'm thinking through the design for extending this to a continuous terrain engine.

The structure of each terrain 'chunk' is as follows:
- 512 x 512 grid of vertices stored in an interleaved VBO.
- Each vertex consists of a 3-float vertex position (X-Z grid, height in Y direction), 3-float normal and 2-float texture coordinate.
- Index buffer specifying the terrain grid as a single triangle-strip with degenerate triangles on the end of each row.
- Single VAO covering the terrain segment.
- Vertex and fragment shaders for rendering, fog and lighting.
- One-or-more textures used in the fragment shader to render sand, grass, rock, snow, etc. depending on height or slope.

The application loads and creates terrain chunks on the fly on a background thread and adds them to the scene as needed depending on where the camera is in the 'world'.

Now this works fine for the relatively trivial case of a single chunk of terrain, but will clearly not scale up to a terrain extending to the 'horizon' consisting of (perhaps) around a couple of hundred chunks.  The first naive implementation simply uses multiple instances of these chunks, but even with a handful it's clear that rendering performance will be poor.

So I need to start optimising the design and would appreciate any thoughts or ideas from anyone that have tried similar projects before I dive in.

Some obvious optimisations spring to mind:

- Collapse the terrain vertex data into 'compound' VBOs (or maybe even just one VBO).  This would reduce the number of VBO/VAO state changes, at the cost of additional complexity.  But might it also reduce rendering performance?

- Consider using 'smaller' data types for the position, normal, texture coordinates, rather than the default 4-byte float - is this viable?  logical?

- Use smaller terrain chunk sizes?  512 x 512 equates to around 8Mb of data per chunk which I suspect is quite a lot?

- Share the index buffer across all terrain chunks.

- Create lower LOD terrain chunks for more distant terrain (in addition to rendering LOD) and replace these with higher LODs as required (and discard higher LOD chunks as they become redundant).

- Investigate geometry and tesselation shaders as a possible means of generating the X-Z and texture coordinates using the vertex index?

However the biggest bottle-neck seems to me to be the amount of redundant data, namely the X-Z grid positions and texture coordinates.  These are the same for every terrain chunk.  DirectX supports (AFAIK) the idea of vertex streams, i.e. a mesh can be comprised of multiple VBOs, in this case we would have one for the static data that is the same for every chunk, and individual VBOs for the height-data.  Does OpenGL have the same mechanism, because I can't find it if it does?

Any opinions, thoughts, suggestions, etc. on the above is appreciated in advance  Smiley

- stride
Offline StrideColossus
« Reply #1 - Posted 2013-05-03 11:10:00 »

And just for illustration here's a screenshot of a single chunk terrain.

Offline Spasi
« Reply #2 - Posted 2013-05-03 12:05:34 »

I was reading this recently, it might help you a bit. It's written in JS/WebGL, but the techniques used apply equally well to desktop GL.

- Collapse the terrain vertex data into 'compound' VBOs (or maybe even just one VBO).  This would reduce the number of VBO/VAO state changes, at the cost of additional complexity.  But might it also reduce rendering performance?
The reduced state changes will improve rendering performance, but you'll have to deal with a lot of complexity and performance issues when updating the bigger VBO. Mutating a VBO while it's still being used for rendering by the previous frame is tricky (see Riven's streaming VBO updates).

- Consider using 'smaller' data types for the position, normal, texture coordinates, rather than the default 4-byte float - is this viable?  logical?
It's a decent bandwidth win, but you should prioritize other optimizations first.

- Use smaller terrain chunk sizes?  512 x 512 equates to around 8Mb of data per chunk which I suspect is quite a lot?
Yes, sounds a lot, especially without LOD.

- Share the index buffer across all terrain chunks.
Yes.

- Create lower LOD terrain chunks for more distant terrain (in addition to rendering LOD) and replace these with higher LODs as required (and discard higher LOD chunks as they become redundant).
This is a must imho. It should also improve quality, by reducing geometry aliasing artifacts. GPUs don't like sub-pixel sized triangles.

- Investigate geometry and tesselation shaders as a possible means of generating the X-Z and texture coordinates using the vertex index?
This is waste I think, unless you need really fine detail up-close.

However the biggest bottle-neck seems to me to be the amount of redundant data, namely the X-Z grid positions and texture coordinates.  These are the same for every terrain chunk.  DirectX supports (AFAIK) the idea of vertex streams, i.e. a mesh can be comprised of multiple VBOs, in this case we would have one for the static data that is the same for every chunk, and individual VBOs for the height-data.  Does OpenGL have the same mechanism, because I can't find it if it does?
You can do this in OpenGL, yes. Different vertex data can come from different VBOs. It's not as useful as you'd imagine because you can only have a single index stream for all VBOs. You can do more fancy stuff with uniform buffer objects, but then you'd have to increase minimum GPU spec requirements.

Bonus tip: VAOs are shit. It was a bad idea and performance suffers across all vendors and implementations. Create and bind one on init and then forget they even exist.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline pitbuller
« Reply #3 - Posted 2013-05-03 12:36:41 »

Your chunks seems to be just height maps and everything else can be calculated from that.

So you could try this. Create one vbo with 512x512 and texture coordinates(shorts have plenty precision) but nothing else. Reuse this vbo for every chunk. At vertex shader use vertex fetch and get current height. Calculate x and y position by chunk middle pos(uniform) + texture coord * chunk size. Z by height * scale. Calculate normal by fetching couple neighbour height.
This will massively reduce the data bandwith used and total memory requirments. Now chunk is only 256 Kb of data and vbo is 1Mb. It's aslo quite easy to make couple different size LOD vbo's.
Offline quew8

JGO Coder


Medals: 31



« Reply #4 - Posted 2013-05-03 16:52:57 »

Personally I often find height maps and the like are troublesome to develop with unless you're going for quality. You can actually have two static vbos for x/z position and indices (or 1 set for each lod), then you have a third vbo containing only height data. You would need to have 1 vec2 and 1 float in your shader (for x/z then y) and splice them together, but I don't think that's bad performance wise. If you want dynamic terrain (who doesn't these days?) this is probably an easier system to work with than height maps.

Edit:
Probably with terrain you are using normal maps anyway, so likely no harder to use height maps as well? Although perhaps rgb = normal's xyz then a = height? Then you can sample selectively from this based on the lod of your x/z vbo. One texture per chunk.
Offline StrideColossus
« Reply #5 - Posted 2013-05-04 12:23:13 »

Thanks for the responses guys, lots of good suggestions and pointers, exactly what I was hoping for.

Cheers  Smiley

- stride
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xFryIx (62 views)
2014-11-13 12:34:49

digdugdiggy (41 views)
2014-11-12 21:11:50

digdugdiggy (34 views)
2014-11-12 21:10:15

digdugdiggy (30 views)
2014-11-12 21:09:33

kovacsa (52 views)
2014-11-07 19:57:14

TehJavaDev (56 views)
2014-11-03 22:04:50

BurntPizza (55 views)
2014-11-03 18:54:52

moogie (70 views)
2014-11-03 06:22:04

CopyableCougar4 (70 views)
2014-11-01 23:36:41

DarkCart (155 views)
2014-11-01 14:51:03
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!