7
\$\begingroup\$

I'm using OpenGL (Version 4.4) (and C++ if that matters).

I've created a terrain renderer, the terrain is stored as a 3D scalar field (isosurface/voxels). It uses a slightly modified version of Marching Cubes, to perform polygonization (converting the scalar field to triangles).

Currently I'm texturing the terrain using a horizontal (grass) texture and a vertical (dirt) texture. Then when applying the texture I simply calculate the amount of the horizontal and vertical texture that is required on the current triangle, depending on the normals of the current triangle. Thereby the more a normal is pointing upwards (or downward) the more dominant the horizontal (grass) texture will be.

Terrain Renderer in Action

terrain Fullscreen Image

Now the question is, what would be the best (or a good) way to perform Multi-Texturing on the terrain? I will give all the values in the scalar field a voxel type value as well. So the main question is how should the rendering be handled. I have a couple of ideas of how this could be done, but I'm not sure which of my ideas would be the best one to do or if there's even a better way.

First Idea

  • Bind all the needed textures, thereby call glActiveTexture(...) for each texture there is.
  • Now the mesh can be rendered using a single glDraw*(...) call.
  • This of course only works if the Shader knows when and where to use each texture, or that the info for using each texture, is stored within the buffer, as some sort of value which the Shader uses, to "detect" which texture should be used. As mentioned previously this could be the voxel type value.

Problem: The maximum amount of textures which can be bound simultaneously is very limited, so that could (and probably would) create some problems.

Second Idea

  • Bind a single texture and call glDraw*(...) with a specific first and count value, so that only a part of the mesh is rendered. Which of course is the part which uses the bound texture.
  • Thereby loop the above until the whole mesh is rendered using all the individual textures.

I don't see any real problem with this idea, the only extra thing we need to take in mind, is that all the triangles need to be sorted according to their voxel type value.

Though we wouldn't be able to fade the textures, like in the image above.

Third Idea

  • Split the mesh into individual buffers (VBOs and VAOs), so that each buffer only uses a single (or a couple) texture(s). Basically the same as the Second Idea though here the buffer would physically be split according to the textures.

Fourth Idea?

or is there an even better way?

Side Note

  • Each texture has it's own handle, thereby none of them can be used as a Texture Atlas.
\$\endgroup\$
2
\$\begingroup\$

Instead of glActiveTexture you could bind a texture array and sample as many texture you like... BUT!! That it's expensive, if you have 16 layer, you will read 16 sample and then probably only one or two will be predominant.

You can bind a texture array and then specify the index of the two (or three) most predominants textures and the sampling weight.

Sampling weight and index can be other textures or parameters passed by vertex.

\$\endgroup\$
  • \$\begingroup\$ How do you bind and create a texture array? \$\endgroup\$ – Vallentin Mar 12 '14 at 1:57
  • \$\begingroup\$ A texture array is basically a texture3d without interpolation on the Z. link But I read now that each texture has it's own handle.. :-/ \$\endgroup\$ – ilmale Mar 12 '14 at 10:57
  • \$\begingroup\$ I am using texture arrays for multitexturing a terrain and I saved two most prominent indices for each vertex. i.e. (1,0.7,3,0.3) for a vertex means texture one with 0.7 weight and texture 3 with 0.3. But I can't find a way to use these without artifacts. If we simply use the interpolated values for indices there will be artifacts when indices change between vertices. For example vertex A is fully texture 1 and vertex B is fully texture 2. If we interpolate them in pixel shader there will be pixels where texture index become 2. Have you any suggestions for this problem? \$\endgroup\$ – morteza khosravi Sep 13 '17 at 16:45
1
\$\begingroup\$

If you're creative with what data you pack into your verts, you can build a texture atlas.

Basically, you need 3 sets of UV data, rather than the usual single set. Each represents the mapping for one of the 3 textures used by that triangle. Your color channel will determine how much these will show through.

With a voxel field, you can work out this blend through distance from the vertex.

\$\endgroup\$
0
\$\begingroup\$

From the options you suggested, I would stick with splitting the mesh into sub-meshes sorted by material/texture. This might actually be faster to render if your data set is really huge. OpenGL draw calls might fail due to out-of-memory conditions, though you'd have to push it really hard to make it happen.

That said, if you are really serious about optimizing your terrain renderer, you'll probably want to do some research on Virtual Texture Mapping (sometimes referred to as "Megatextures"). This is probably the most efficient way there is to manage large texture data sets.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.