繁体   English   中英

C++/OpenGL/GLSL 混合两个纹理边缘

[英]C++/OpenGL/GLSL Blending two textures edges

首先这里是截图:

在此处输入图片说明

我试图根据网格上点的高度在网格上混合多个纹理。

现在我想要实现的是边界处的平滑混合(与目前的锐线不同)。

另外我希望边界稍微随机并且有一个控制随机性的因素。

这是我当前的代码:

#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);
} 

我确实尝试了随机边界,但这不是很好,仍然混合是问题!

这是具有随机性的代码:

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);
}

一般来说,您需要进行多次纹理查找并将结果组合在一起,很可能通过加权平均。

一种直接的方法是始终对所有可用纹理进行采样(可以选择提前退出影响为 0 的纹理)。 这样,“组合”逻辑和“影响确定”逻辑就保持了干净的分离。 这非常灵活,因为它不会限制您创建平滑的边缘。 您可以使用任何您想要的组合逻辑,例如使用影响图。

float getTextureInfluence(int tex_id, vec2 coord) {
  // have fun!
}

vec4 GetTextureColor(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);

      // This if is optional. 
      // It may help or hurt performance depending on what 
      // percentage of samplers are used on average per sample.
      if(texture_influence > INFLUENCE_MIN) {
        total_influence += texture_influence;
        accum += texture(_DiffuseTextures[i], coord) * texture_influence;
      }
    }

    if(total_influence > 0.0) {
      accum /= total_influence ;
    }
    return accum;
}

后续:至于使用它来创建模糊边缘:

您当前的代码实际上与以下配置文件相同:在每一点上,一个纹理得到完全影响,而所有其他纹理都没有。 这将创建一个方形步骤,如下所示:


influence
^
|           Sharp edge
|                |
|                v
| |--------------||--------------|
| |              ||              |
| |     Tex[0]   ||   Tex[1]     |
| |              ||              |
+-----------------------------------> Height

相反,像以下图案一样重叠纹理的影响将使您从一个纹理平滑过渡到下一个。

influence
^
|           Blurred edge
|                |
|                v
|      ---------    -----------
|     /         \  /           \
|   /   Tex[0]   /\    Tex[1]    \
| /            /    \              \
+-----------------------------------> Height

使用多项式或指数衰减而不是线性也会给出不同的结果,找到将导致您喜欢的结果的精确数学将进行实验。

感谢弗兰克的回答,我终于能够拥有我喜欢的东西,

结果如下: https : //youtu.be/DSkJqPhdRYI

编码 :

#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);
} 

如果您对完整源代码感兴趣: https : //github.com/Jaysmito101/TerraGen3D

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM