You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++/OpenGL/GLSL多层高度纹理融合的边缘平滑与随机控制问题

多层高度纹理平滑混合问题

效果截图

效果截图

问题描述

我需要基于网格顶点的高度值,在网格上混合多层纹理。当前实现的纹理过渡边缘为硬切边,我想要实现边缘的平滑融合效果,同时希望边缘带有一定随机性,且可以调整随机度参数。

原始实现代码

#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);
}
解决方案

你之前的代码核心问题是用了硬分支判断纹理选择,就算加了噪声偏移高度,本质还是二选一的切边,没有真正的混合过程。下面是修改后的实现,支持平滑过渡、随机边界扰动,还有参数可调:
首先新增两个可调参数的uniform声明,放在代码头部的uniform定义区域即可:

uniform float _TransitionWidth; // 过渡带宽度,数值越大融合范围越宽
uniform float _RandomStrength; // 边界随机强度,0为完全平滑无随机,数值越大随机扭曲越明显

修改GetTextureColorBasedOnHeight函数,改用权重混合逻辑:

vec4 GetTextureColorBasedOnHeight(vec2 coord){
    // 计算噪声扰动,叠加到高度值上实现随机边界
    float nv = noise(coord * 0.01f) * _RandomStrength;
    float adjustedHeight = height + nv;
    
    vec4 finalColor = vec4(0.0);
    float totalWeight = 0.0;
    
    for(int i=0;i<NUM_TEXTURE_LAYERS;i++){
        float layerMin = _DiffuseTexturesHeights[i].x;
        float layerMax = _DiffuseTexturesHeights[i].y;
        float texScale = _DiffuseTexturesHeights[i].z;
        
        // 用smoothstep计算当前层的权重,实现上下边界的平滑过渡
        float lowerWeight = smoothstep(layerMin - _TransitionWidth, layerMin + _TransitionWidth, adjustedHeight);
        float upperWeight = smoothstep(layerMax + _TransitionWidth, layerMax - _TransitionWidth, adjustedHeight);
        float weight = lowerWeight * upperWeight;
        
        // 累加当前层的颜色贡献和总权重
        finalColor += texture(_DiffuseTextures[i], coord * texScale) * weight;
        totalWeight += weight;
    }
    
    // 权重归一化,避免过渡区域颜色变暗
    if(totalWeight > 0.0){
        finalColor /= totalWeight;
    }
    return finalColor;
}

参数调整说明

  • 调整_TransitionWidth参数控制过渡区域的宽度,可根据你的高度值范围设置,比如高度范围是0100的话,可以先试0.55的数值
  • 调整_RandomStrength控制边界的随机扭曲程度,不需要随机就设为0即可
  • 如果觉得噪声的颗粒度不符合需求,可以修改noise(coord * 0.01f)里的缩放系数,数值越小噪声越平缓,越大噪声越细碎

内容的提问来源于stack exchange,提问作者Jaysmito Mukherjee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 06:36:01