2

I have a question regarding glDraw(arrays)(elements). The thing is, most people say elements is more efficient due to vertex reuse and caching, but I try to render a terrain, each vertex with same position a different texture coordinate. THat makes each vertex unique right? So if I do not have any vertex reuse, should I prefer arrays because its much easier to implement and renders the buffer in one go compared to elements which I need to supply not only with vertex data but also an index buffer? And is there a way to render terrains which makes it able to use elements? I just dont get how to texture the terrain properly, maybe that is the problem.

I could imagine rendering models of persons would be nice with elements, since I can supply one texture file and not need more tex coords per position of vertex. But the terrain should be rendered with arrays?

When should I choose arrays and when elements?

1 Answer 1

3

For terrain glDrawElements is the way to go, assuming you have a simple 2d grid, and you displace it on the vertex shader or send heights as vertex attribs. It's much faster than glDrawArrays for this kind of mesh.

For the textures: I don't know if you want to texture the terrain with one big texture, or more textures blended together, for example a simple grass pattern, or grass blended to snow with increasing height.

The first one is pretty easy: lets say your terrain's width is W and its height is H. You use one big texture over the whole map. Then the texture coord for one vertex is:

vec2 TexCoord = vec2(VertexPos.x/W,VertexPos.z/H);

For the second it changes a bit:

If your texture is a simple grass tile, or anything that you want to cover the whole terrain with, then texture coord of a vertex is:

vec2 TexCoord = vec2(VertexPos.x/XdirectionTileSize,VertexPos.z/ZdirectionTileSize);

XdirectionTileSize and ZdirectionTileSize are the dimensions of one pattern. For example you want to fetch a grass texture over the terrain with 1 meters * 1 meters resolution, and your vertices are each 2 meters away from each other, then set them to 0.5 (1/2).

For more textures you can define more tile-sizes, and one big texture map with each color defining one material. Example: red is grass, blue is snow, green is sand, and alpha is rock. Then you blend the textures like this: (You can fetch this big material map just like the one big texture)

color = materialmap.r*grass + materialmap.b*snow + materialmap.g*sand + materialmap.a*rock;

And finally my favorite method for terrain texturing is procedural shader splatting. I won't write it here. For example the Frostbite Engine (Battlefields) uses this. Here's a link to a very good presentation: Terrain Rendering in Frostbite Using Procedural Shader Splatting. In short it's like masking. Rendering the heights, normals, slopes into an FBO texture, and using it like in deferred rendering/shading.

For quality: if your texcoords are calculated in a shader with vertex positions on a plane (.xy, .xz), it can distort textures with increasing slope. The solution for this problem is triplanar texturing. Bottom of the page: Generating Complex Procedural Terrains Using the GPU. In short: it projects the texture to the terrain from 3 planes (xz, xy, yz) and mixes/blends them with normals.

Of course you can mix these texturing methods. I know it doesn't directly answer your question, but I don't think you should pass texture coordinates as vertex attribs. It's much easier defining them with big textures, tiles, or splatting. Oh, and I hope you use shaders;).

Sign up to request clarification or add additional context in comments.

1 Comment

This is very helpful! You indirectly answered a big issue of mine, how to render terrains efficiently with elements or arrays. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.