Search code examples
c++openglglsltexturesblending

C++/OpenGL/GLSL Blending two textures edges


Firstly here is the screenshot:

enter image description here

I am trying to blend in multiple textures on the mesh based on the height of the point on mesh.

Now what i want to achieve is a smooth blend at the borders(unlike what is currently a sharp line).

Also i would like the border to be slightly random and have a factor to control the randomness.

Here is my current code :

#version 430 core
out vec4 FragColor;

#define NUM_TEXTURE_LAYERS 8

uniform vec3 _LightPosition;
uniform vec3 _LightColor;

in float height;
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoord;

uniform sampler2D  _DiffuseTextures[NUM_TEXTURE_LAYERS];
uniform vec3  _DiffuseTexturesHeights[NUM_TEXTURE_LAYERS];

vec4 GetTextureColorBasedOnHeight(vec2 coord){
    for(int i=0;i<NUM_TEXTURE_LAYERS;i++){
        if(height > _DiffuseTexturesHeights[i].x && height < _DiffuseTexturesHeights[i].y){
            return texture(_DiffuseTextures[i], coord*_DiffuseTexturesHeights[i].z);
        }
    }
    return vec4(0.0f);
}

void main()
{   
    vec3 objectColor = vec3(1, 1, 1);
    objectColor = GetTextureColorBasedOnHeight(TexCoord).xyz;
    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(_LightPosition - FragPos);
    float diff = max(dot(norm, lightDir), 0.0f);
    vec3 diffuse = diff * _LightColor;
    vec3 result = (vec3(0.2, 0.2, 0.2) + diffuse) * objectColor;
    FragColor = vec4(result, 1.0);
} 

I did try the random boundaries but that was not very good and still blending is the issue!

Here is the code with randomness:

vec2 hash( vec2 p ) // replace this by something better
{
    p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) );
    return -1.0 + 2.0*fract(sin(p)*43758.5453123);
}

float noise( in vec2 p )
{
    const float K1 = 0.366025404; // (sqrt(3)-1)/2;
    const float K2 = 0.211324865; // (3-sqrt(3))/6;

    vec2  i = floor( p + (p.x+p.y)*K1 );
    vec2  a = p - i + (i.x+i.y)*K2;
    float m = step(a.y,a.x); 
    vec2  o = vec2(m,1.0-m);
    vec2  b = a - o + K2;
    vec2  c = a - 1.0 + 2.0*K2;
    vec3  h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
    vec3  n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
    return dot( n, vec3(70.0) );
}


vec4 GetTextureColorBasedOnHeight(vec2 coord){
    for(int i=0;i<NUM_TEXTURE_LAYERS;i++){
        float nv=noise(coord*0.01f);
        if(height+nv > _DiffuseTexturesHeights[i].x && height+nv < _DiffuseTexturesHeights[i].y){
            return texture(_DiffuseTextures[i], coord*_DiffuseTexturesHeights[i].z);
        }
    }
    return vec4(0.0f);
}

Solution

  • Thanks to Frank's answer, I am able to finally have something i like,

    Here is the result: https://youtu.be/DSkJqPhdRYI

    The Code :

    #version 430 core
    out vec4 FragColor;
    
    #define NUM_TEXTURE_LAYERS 8
    
    uniform vec3 _LightPosition;
    uniform vec3 _LightColor;
    
    in float height;
    in vec3 FragPos;
    in vec3 Normal;
    in vec2 TexCoord;
    
    uniform sampler2D  _DiffuseTextures[NUM_TEXTURE_LAYERS];
    uniform vec3  _DiffuseTexturesHeights[NUM_TEXTURE_LAYERS];
    
    
    vec2 hash( vec2 p ) // replace this by something better
    {
        p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) );
        return -1.0 + 2.0*fract(sin(p)*43758.5453123);
    }
    
    float noise( in vec2 p )
    {
        const float K1 = 0.366025404; // (sqrt(3)-1)/2;
        const float K2 = 0.211324865; // (3-sqrt(3))/6;
    
        vec2  i = floor( p + (p.x+p.y)*K1 );
        vec2  a = p - i + (i.x+i.y)*K2;
        float m = step(a.y,a.x); 
        vec2  o = vec2(m,1.0-m);
        vec2  b = a - o + K2;
        vec2  c = a - 1.0 + 2.0*K2;
        vec3  h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
        vec3  n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
        return dot( n, vec3(70.0) );
    }
    
    
    float getTextureInfluence(int i, vec2 coord) {
    float h = height + noise(coord*5)*2;
      float midVal = (_DiffuseTexturesHeights[i].x + _DiffuseTexturesHeights[i].y)/2;
      float p = 0;
      if(height < midVal)
        p = _DiffuseTexturesHeights[i].x - height;
      if(height >= midVal)
        p =height -  _DiffuseTexturesHeights[i].y;
      
      return pow(2.713, -1.0*p);
    }
    
    vec4 GetTextureColorBasedOnHeight(vec2 coord){
        vec4 accum = vec4(0.0);
        float total_influence = 0.0;
        
        for(int i=0; i < NUM_TEXTURE_LAYERS ; i++){
            float texture_influence = getTextureInfluence(i, coord*_DiffuseTexturesHeights[i].z);
    
            total_influence += texture_influence;
            accum += texture(_DiffuseTextures[i],  coord*_DiffuseTexturesHeights[i].z) * texture_influence;
        }
    
        if(total_influence > 0) {
          accum /= total_influence ;
        }
        return accum;
    }
    
    
    void main()
    {   
        vec3 objectColor = vec3(1, 1, 1);
        objectColor = GetTextureColorBasedOnHeight(TexCoord).xyz;
        vec3 norm = normalize(Normal);
        vec3 lightDir = normalize(_LightPosition - FragPos);
        float diff = max(dot(norm, lightDir), 0.0f);
        vec3 diffuse = diff * _LightColor;
        vec3 result = (vec3(0.2, 0.2, 0.2) + diffuse) * objectColor;
        FragColor = vec4(result, 1.0);
    } 
    

    If you are interested in the full source : https://github.com/Jaysmito101/TerraGen3D