2

I'm trying to achieve terrain texturing using 3D texture that consists of several layers of material and to make smooth blending between materials.

Maybe my illustration will explain it better:
Pretty picture

Just imagine that each color is a cool terrain texture, like grass, stone, etc.
I want to get them properly blended, but with current approach I get all textures between requested besides textures which I want to appear (it seems logical because, as I've read, 3D texture is treated as three-dimensional array instead of texture pillars).
Current (and foolish, obviously) approach is simple as a pie ('current' result is rendered using point interpolation, desired result is hand-painted):

Vertexes:
Vertex 1: Position = Vector3.Zero, UVW = Vector3.Zero
Vertex 2: Position = Vector3(0, 1, 0), UVW = Vector3(0, 1, 0.75f)
Vertex 3: Position = Vector3(0, 0, 1), UVW = Vector3(1, 0, 1)
As you can see, first vertex of the triangle uses first material (the red one), second vertex uses third material (the blue one) and third vertex uses last fourth material (the yellow one).

This is how it's done in pixel shader (UVW is directly passed without changes):
float3 texColor = tex3D(ColorTextureSampler, input.UVW);
return float4(texColor, 1);
The reason about my choice is my terrain structure. The terrain is being generated from voxels (each voxel holds material ID) using marching cubes. Each vertex is 'welded' because meshes is pretty big and I don't want to make every triangle individual (but I can still do it if there is no way to solve my question using connected vertices).
I recently came to an idea about storing material IDs of other two vertices of the triangle and their blend factors (I would have an float2 UV pair, float3 for material IDs and float3 for blend factor of each material id) in each vertex, but I don't see any way to accomplish this without breaking my mesh into individual triangles.
Any help would be greatly appreciated. I'm targeting for SlimDX with C# and Direct3D 9 API. Thanks for reading.
P.S.: I'm sorry if I made some mistakes in this text, English is not my native language.

RaZeR RawByte
  • 238
  • 1
  • 10

1 Answers1

1

Probably, your ColorTextureSampler using point filtering (D3DTEXF_POINT). Use either D3DTEXF_LINEAR or D3DTEXF_ANISOTROPIC to acheve desired interpolation effect. I'm not very familiar with SlimDX 9, but you've got the idea.

BTW, nice illustration =)

Update 1 Result in your comment below seems appropriate to your code. Looks like to get desired effect you must change overall approach. It is not complete solution for you, but there is how we make it in plain 3D terrains:

  • Every vertex has 1 pair (u, v) of texure coodrinates
  • You have n textures to sample into (T1, T2, T3, ..., Tn) that represents different layers of terrain: sand, grass, rock, etc.
  • You have mask texture(s) n channels in total, that stores blending coefficients for each texture T in its channels: R channel holds alpha for T1, G channel for T2, B for T3, ... etc.
  • In pixel shader you sampling your layer textures as usual, and get color values float4 val1, val2, val3, ...
  • Then you sampling masks texture(s) for corresponding blend coefficients and get float blend1, blend2, blend3, ...
  • Then you applying some kind of blending algorith, for example simple linear interpolation:
float4 terrainColor = lerp( val1, val2, blend1 );
terrainColor = lerp( terrainColor, val3, blend2);
terrainColor = lerp( terrainColor, ..., blendN );

For example if your T1 is a grass, and you have a big grass field in a middle of your map, you will wave a big red field in the middle.

This algorithm is a bit slow, because of much texture sampling, but simple to implement, gives good visual results and most flexible. You can use not only mask as blend coefficients, but any values: for example height (sample more snow in mountain peaks, rock in mountains, dirt in low ground), slope (rock on steep, grass on flat), even fixed values, etc. Or mix up all of that. Also, you can vary a blending: use built-in lerp or something more complicated (warning! this example is stupid):

float4 terrainColor = val1 * val2 * blend1 + val2 * val3 * blend2;
terrainColor = saturate(terrainColor);

Playing with blend algo is the most interesting part of this aproach. And you can find many-many techniques in google.

Not sure, but hope it helps! Happy coding! =)

Ivan Aksamentov - Drop
  • 12,860
  • 3
  • 34
  • 61
  • Thanks for your answer :) Unfortunately, almost nothing changed - I just got the same image, but smoothed, as you can see from [this screenshot](http://i.imgur.com/kdVUswN.png). – RaZeR RawByte May 13 '13 at 18:51
  • Wow, great update. Seems like I've not clearly stated that my terrain consists of "blocks" (voxel), and height-based approach cannot be used since I want the user to edit the terrain by adding other materials. But texture masking seems interesting, maybe I'll try it to achieve splating effect. I hope there is enough texture samplers in ps_3_0, I will look into it. Thanks, it gets a bit clearer, I'll keep you informed on my progress :) – RaZeR RawByte May 13 '13 at 19:51
  • I made it by mixing your and my approaches. Instead of using different samplers I packed my textures into one 3D texture (as I did it before), and blended them by factors I described in my question. It gave me a simple smoothed texture, I'm looking forward to use the 'texture masking' you described to make transitions between materials be more attractive :) – RaZeR RawByte May 18 '13 at 15:34