GLSL:通过根据片段的世界位置索引到统一的结构数组中,选择要在片段着色器中使用的纹理 我正在研究一个C++程序,它使用GLSL着色器显示地形网格。我希望它能够根据海拔使用不同的材料
我试图通过在片段着色器中拥有一个统一的材质数组来实现这一点,然后使用当前片段的世界空间位置的y坐标来确定要使用数组中的哪个材质 以下是我的片段着色器的相关部分: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
#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纹理,如果你需要包装材料。我不确定,但我认为你不应该用一个整数乘以一个vec3int(材料[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));