GLSL:通过根据片段的世界位置索引到统一的结构数组中,选择要在片段着色器中使用的纹理 我正在研究一个C++程序,它使用GLSL着色器显示地形网格。我希望它能够根据海拔使用不同的材料

GLSL:通过根据片段的世界位置索引到统一的结构数组中,选择要在片段着色器中使用的纹理 我正在研究一个C++程序,它使用GLSL着色器显示地形网格。我希望它能够根据海拔使用不同的材料,c++,opengl,glsl,shader,fragment-shader,C++,Opengl,Glsl,Shader,Fragment Shader,我试图通过在片段着色器中拥有一个统一的材质数组来实现这一点,然后使用当前片段的世界空间位置的y坐标来确定要使用数组中的哪个材质 以下是我的片段着色器的相关部分: #version 430 struct Material { vec3 ambient; vec3 diffuse; vec3 specular; int shininess; sampler2D diffuseTex; bool hasDiffuseTex; float max

我试图通过在片段着色器中拥有一个统一的材质数组来实现这一点,然后使用当前片段的世界空间位置的y坐标来确定要使用数组中的哪个材质

以下是我的片段着色器的相关部分:

#version 430

struct Material
{
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    int shininess;
    sampler2D diffuseTex;
    bool hasDiffuseTex;
    float maxY; //the upper bound of this material's layer in relation to the height of the mesh (in the range 0-1)
};

in vec2 TexCoords;
in vec3 WorldPos;

const int MAX_MATERIALS = 14;

uniform Material materials[MAX_MATERIALS];
uniform int materialCount; //the actual number of materials in the array

uniform float minY; //the minimum world-space y-coordinate in the mesh
uniform float maxY; //the maximum world-space y-coordinate in the mesh

out vec4 fragColor;

void main()
{

    //calculate the y-position of this fragment in relation to the height of the mesh (in the range 0-1)
    float y = (WorldPos.y - minY) / (maxY - minY);

    //calculate the index into the materials array 
    int index = 0;
    for (int i = 0; i < materialCount; ++i)
    {
        index += int(y > materials[i].maxY);
    }

    //calculate the ambient color
    vec3 ambient = ...

    //calculate the diffuse color
    vec3 diffuse = ...
    //sample from the texture
    vec3 texColor = vec3(texture(materials[index].diffuseTex, TexCoords.xy));
    //only multiply diffuse color with texture color if the material has a texture
    diffuse += int(materials[index].hasDiffuseTex) * ((texColor * diffuse) - diffuse);

    //calculate the specular color
    vec3 specular = ...

    fragColor = vec4(ambient + diffuse + specular, 1.0f);
}
它以红色绘制工件:

这告诉我索引是正确的(0),但没有从纹理中采样

此外,如果我将索引硬编码到着色器中,如下所示:

vec3 texColor = vec3(texture(materials[0].diffuseTex, TexCoords.xy));
它渲染正确。所以我猜这与索引有关,但是索引似乎是正确的,纹理在那里,为什么它不采样颜色呢


我还发现,如果我切换材质的顺序,并以某种方式在程序的GUI中移动它们的边框,它将从我完全不理解的点开始正确渲染。我最初怀疑这可能是因为我最初给着色器发送了错误的值,然后在GUI中做了一些改动之后,它得到了正确的值,但是我已经测试了我从C++端发送给着色器的所有统一值,它们从一开始就看起来是正确的,我没有看到任何其他的值。可能的问题,这可能导致这从C++侧。因此,我现在认为问题可能出在着色器中。

我的猜测是,您正在使用的OpenGL实现不喜欢动态采样纹理,因为基于
纹理的第一个参数始终为。即使您的实现确实正确地支持该过程,基于片段数据选择采样器对着色器性能也是非常有害的。我建议您使用动态统一表达式替换
纹理
的第一个参数,最好是常量。特别是,我建议您使用单个纹理一次存储所有材质,或者并排作为缝合的图集,在这种情况下,您可以从统一偏移阵列中查找子纹理采样偏移,或者作为每个材质一层的3D纹理,如果你需要包装材料。我不确定,但我认为你不应该用一个整数乘以一个vec3
int(材料[index].hasDiffuseTex)*((texColor*diffuse)-diffuse)
你想要一个步进函数吗?@Wyck因为
int(boolvar)
如果
boolvar
为真,则计算结果为1,否则为0,惯用法
int(boolvar)*value
boolvar的非分支替代方法?值:0
,可提高不太智能的GLSL编译器的性能。将布尔值强制转换为不同的基元类型是必要的,因为不能直接与布尔值相乘。整数将立即转换为浮点,因此直接将其转换为浮点可能更合适。@Wyck:“硬件将对所有纹理进行采样”不,不会。
vec3 texColor = vec3(texture(materials[0].diffuseTex, TexCoords.xy));