Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GLSL shader: Interpolate between more than two textures

I've implemented a heightmap in OpenGL. For now it is just a sine/cosine curved terrain. At the moment I am interpolating between the white "ice" and the darker "stone" texture. This is done like this:

color = mix(texture2D(ice_layer_tex, texcoord), texture2D(stone_layer_tex, texcoord), (vertex.y + amplitude) / (amplitude * 2))

The result:

from top

from bottom

It works fine, but what could I do if I want to add more textures, for example a grass texture, so that the interpolation order is "ice, stone, grass"? I think, there isn't a function like mix(sampler2D[], percentages[])? How could I write a GLSL method following this logic?

like image 472
T_01 Avatar asked Jun 22 '14 21:06

T_01


2 Answers

mix() is really just a convenience function for something you can easily write yourself. The definition is:

mix(v1, v2, a) = v1 * (1 - a) + v2 * a

Or putting it differently, it calculates a weighted average of v1 and v2, with two weights w1 and w2 that are float values between 0.0 and 1.0 meeting the constraint w1 + w2 = 1.0:

v1 * w1 + v2 * w2

You can directly generalize this to calculate a weighted average of more than 2 inputs. For example, for 3 inputs v1, v2 and v3, you would use 3 weights w1, w2 and v3 meeting the constraint w1 + w2 + w3 = 1.0, and calculate the weighted average as:

v1 * w1 + v2 * w2 + v3 * w3

For your example, determine the weights you want to use for each of the 3 textures, and then use something like:

weightIce = ...;
weightStone = ...;
weightGrass = 1.0 - weightIce - weightStone;
color = texture2D(ice_layer_tex, texcoord) * weightIce +
        texture2D(stone_layer_tex, texcoord) * weightStone +
        texture2D(grass_layer_tex, texcoord) * weightGrass;
like image 159
Reto Koradi Avatar answered Nov 07 '22 04:11

Reto Koradi


No, according to the GLSL documentation for mix() there are only overloads for interpolation between two parameters.

Would it be acceptable to you to just interpolate "ice" and "stone" then mix the result with the "grass" texture?

vec4 ice_color   = texture2D(ice_layer_tex,   texcoord);
vec4 stone_color = texture2D(stone_layer_tex, texcoord);
vec4 grass_color = texture2D(grass_layer_tex, texcoord);

vec4 tmp = mix(ice_color, stone_color, pct);
vec4 final_color = mix(tmp, grass_color, pct);
like image 2
glampert Avatar answered Nov 07 '22 06:11

glampert