use*_*743 2 opengl shader glsl fragment-shader
我正在使用GLSL着色器开发一个程序.我用2种不同的方法编写了两种不同的方法来计算ADS(环境+漫反射+镜面反射)着色.为了正确地完成工作,我使用子程序来使用一种或另一种方法来计算ADS着色.
这是一段片段着色器代码:
subroutine vec3 LightShadingEffectType(int idx, vec3 normal, vec3 lightDir);
subroutine uniform LightShadingEffectType LightShadingEffect;
subroutine (LightShadingEffectType)
vec3 Basic_ADS_Shading(int idx, vec3 normal, vec3 lightDir)
{
vec3 reflectDir = reflect(-lightDir, normal);
vec3 viewDir = normalize(-Position.xyz);
vec3 Ambient = LightInfos[idx].La * MaterialInfos.Ka;
vec3 Diffuse = LightInfos[idx].Ld * MaterialInfos.Kd * max(dot(lightDir, normal), 0.0f);
vec3 Specular = LightInfos[idx].Ls * MaterialInfos.Ks * pow(max(dot(reflectDir, viewDir), 0.0f), MaterialInfos.Shininess);
vec3 Emissive = MaterialInfos.Ke;
return (Ambient + Diffuse + Specular + Emissive);
}
subroutine (LightShadingEffectType)
vec3 Phong_ADS_Shading(int idx, vec3 normal, vec3 lightDir)
{
vec3 v = normalize(vec3(-Position));
vec3 h = normalize(v + lightDir);
vec3 Ambient = LightInfos[idx].La * MaterialInfos.Ka;
vec3 Diffuse = LightInfos[idx].Ld * MaterialInfos.Kd * max(dot(lightDir, normal), 0.0f);
vec3 Specular = LightInfos[idx].Ls * MaterialInfos.Ks * pow(max(dot(h, normal), 0.0f), MaterialInfos.Shininess);
vec3 Emissive = MaterialInfos.Ke;
return (Ambient + Diffuse + Specular + Emissive);
}
Run Code Online (Sandbox Code Playgroud)
和C++代码:
type::uint32 basic_ads_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Basic_ADS_Shading");
type::uint32 phong_ads_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Phong_ADS_Shading");
glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &phong_ads_idx);
Run Code Online (Sandbox Code Playgroud)
直到这里显示是正确的.在这种情况下,我选择执行第二个子程序定义(Phong_ADS_Shading调用).
但我想在我的程序中声明另一个子程序类型来管理纹理(签名不一样).这是片段着色器代码的另一部分(在同一着色器中):
subroutine vec4 TexturedShadingType();
subroutine uniform TexturedShadingType TexturedShading;
subroutine (TexturedShadingType)
vec4 Textured_Shading(void)
{
vec4 TexColor = texture(Tex1, TexCoords);
return (vec4(getLightIntensity(), 1.0f) * TexColor);
}
subroutine (TexturedShadingType)
vec4 Untextured_Shading(void)
{
return (vec4(getLightIntensity(), 1.0f));
}
Run Code Online (Sandbox Code Playgroud)
最后,我的C++代码如下:
type::uint32 basic_ads_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Basic_ADS_Shading");
type::uint32 phong_ads_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Phong_ADS_Shading");
glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &phong_ads_idx);
type::uint32 textured_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Textured_Shading");
type::uint32 untextured_idx = glGetSubroutineIndex(program->getHandle(), GL_FRAGMENT_SHADER, "Untextured_Shading");
glUniformSubroutinesuiv(GL_FRAGMENT_SHADER, 1, &untextured_idx);
Run Code Online (Sandbox Code Playgroud)
这是每个子程序索引的值:
std::cout << phong_idx << ", " << blinn_phong_idx << ", " << textured_idx << ", " << untextured_idx << std::endl;
-> 1, 0, 4294967295, 4294967295
Run Code Online (Sandbox Code Playgroud)
两个第一个值似乎是正确的,但另外两个.
现在,整个片段着色器代码可以更好地理解我的问题:
#version 400
in vec3 Position;
in vec3 Normal;
in vec2 TexCoords;
layout (location = 0) out vec4 FragColor;
uniform sampler2D Tex1;
uniform int lightCount;
struct PointLight
{
vec4 Position;
vec3 La, Ld, Ls;
float Kc, Kl, Kq;
vec3 direction;
float exponent;
float cutoff;
int type;
};
struct Material
{
vec3 Ka, Kd, Ks, Ke;
float Shininess;
};
uniform PointLight LightInfos[10];
uniform Material MaterialInfos;
subroutine vec3 LightShadingEffectType(int idx, vec3 normal, vec3 lightDir);
subroutine uniform LightShadingEffectType LightShadingEffect;
subroutine (LightShadingEffectType)
vec3 Phong_Shading(int idx, vec3 normal, vec3 lightDir)
{
vec3 reflectDir = reflect(-lightDir, normal);
vec3 viewDir = normalize(-Position.xyz);
vec3 Ambient = LightInfos[idx].La * MaterialInfos.Ka;
vec3 Diffuse = LightInfos[idx].Ld * MaterialInfos.Kd * max(dot(lightDir, normal), 0.0f);
vec3 Specular = LightInfos[idx].Ls * MaterialInfos.Ks * pow(max(dot(reflectDir, viewDir), 0.0f), MaterialInfos.Shininess);
vec3 Emissive = MaterialInfos.Ke;
return (Ambient + Diffuse + Specular + Emissive);
}
subroutine (LightShadingEffectType)
vec3 Blinn_Phong_Shading(int idx, vec3 normal, vec3 lightDir)
{
vec3 v = normalize(vec3(-Position));
vec3 h = normalize(v + lightDir);
vec3 Ambient = LightInfos[idx].La * MaterialInfos.Ka;
vec3 Diffuse = LightInfos[idx].Ld * MaterialInfos.Kd * max(dot(lightDir, normal), 0.0f);
vec3 Specular = LightInfos[idx].Ls * MaterialInfos.Ks * pow(max(dot(h, normal), 0.0f), MaterialInfos.Shininess);
vec3 Emissive = MaterialInfos.Ke;
return (Ambient + Diffuse + Specular + Emissive);
}
float getLightAttenuation(vec3 lightDir, PointLight light)
{
float lightAtt = 0.0f;
float dist = 0.0f;
dist = length(lightDir);
lightAtt = 1.0f / (light.Kc + (light.Kl * dist) + (light.Kq * pow(dist, 2)));
return (lightAtt);
}
float getSpotFactor(vec3 lightDir, vec3 spotDir, PointLight light)
{
return (pow(dot(-lightDir, spotDir), light.exponent));
}
vec3 Spot_ADS_Shading(float lightAtt, vec3 tnorm, vec3 lightDirNorm, int idx)
{
vec3 LightIntensity = vec3(0.0f);
vec3 spotDirNorm = normalize(LightInfos[idx].direction);
float angle = acos(dot(-lightDirNorm, spotDirNorm));
float cutoff = radians(clamp(LightInfos[idx].cutoff, 0.0f, 90.0f));
if (angle < cutoff)
{
float spotFactor = getSpotFactor(lightDirNorm, spotDirNorm, LightInfos[idx]);
LightIntensity = lightAtt * spotFactor * LightShadingEffect(idx, -tnorm, lightDirNorm);
}
else
{
LightIntensity = LightShadingEffect(idx, -tnorm, lightDirNorm) * MaterialInfos.Ka;
}
return (LightIntensity);
}
vec3 Point_ADS_Shading(float lightAtt, vec3 tnorm, vec3 lightDirNorm, int idx)
{
return (lightAtt * LightShadingEffect(idx, tnorm, lightDirNorm));
}
vec3 getLightIntensity(void)
{
vec3 LightIntensity = vec3(0.0f);
for (int idx = 0; idx < lightCount; idx++)
{
vec3 tnorm = (gl_FrontFacing ? -normalize(Normal) : normalize(Normal));
vec3 lightDir = vec3(LightInfos[idx].Position) - Position;
vec3 lightDirNorm = normalize(lightDir);
float lightAtt = getLightAttenuation(lightDir, LightInfos[idx]);
if (LightInfos[idx].type == 1)
{
LightIntensity += Spot_ADS_Shading(lightAtt, tnorm, lightDirNorm, idx);
}
else
{
LightIntensity += Point_ADS_Shading(lightAtt, -tnorm, lightDirNorm, idx);
}
}
return (LightIntensity);
}
subroutine vec4 TexturedShadingType();
subroutine uniform TexturedShadingType TexturedShading;
subroutine (TexturedShadingType)
vec4 Textured_Shading(void)
{
vec4 TexColor = texture(Tex1, TexCoords);
return (vec4(getLightIntensity(), 1.0f) * TexColor);
}
subroutine (TexturedShadingType)
vec4 Untextured_Shading(void)
{
return (vec4(getLightIntensity(), 1.0f));
}
void main(void)
{
FragColor = TexturedShading();
}
Run Code Online (Sandbox Code Playgroud)
问题是我的几何体是黑色渲染.我认为两个统一子程序之间存在冲突.我迷路了.有人能帮帮我吗?
glUniformSubroutines
设置着色器阶段的所有子例程,而不仅仅是其中一个子例程.
看,当OpenGL链接你的程序时,它需要所有的子程序制服并从中构建一个数组.每个制服都有一个索引到这个数组.如果要弄清楚数组中特定子例程统一的索引是什么,则需要调用glGetSubroutineIndex
.另外,假设你有4.3/ARB_explicit_uniform_locations(这固然AMD是相当缓慢的),你可以使用这个设置直接的layout(location = #)
布局预选赛.这样,您不必查询它.
一旦你知道每个子程序统一指的是什么指数,然后你可以设置所有的子程序制服用过程中的阶段单次调用来glUniformSubroutines
.您构建一个短数组,其中数组中的每个索引都包含您要使用的子例程函数的索引.
但我想在四个子程序中每次只选择2个子程序.
您可能有4个子例程,但只有两个子例程统一变量.这些制服表示用户在要调用的着色器中设置特定功能.
此外,两个制服都使用不同的类型,因此他们无法从4个子程序中进行选择.每个子例程统一只能从该特定类型使用的特定子例程中进行选择.这是在声明子例程函数时定义的subroutine(SubroutineType)
.每种类型都有自己的一组功能,可以使用它们.因此,每个制服只能从为该制服声明的子程序类型中设置的那些特定函数中进行选择.
所以你不能在4个子程序中选择; 每个制服只能在为每个子程序类型设置的功能中进行选择.每个制服只能在您声明子例程类型的两个函数之间进行选择.
如果我只有一次调用glUniformSubroutinesuiv我该怎么选择它们?
通过传递一个数组.第三个参数是指针的原因是什么,以及为什么第二个参数是数组中的条目数.
片段着色器有两个子例程统一值.因此,数组中有2个元素,每个元素代表特定子程序统一的子程序索引.您可以通过创建数组,将两个子例程索引设置到其中,并将该数组传递给函数来选择它们.
我认为两个统一子程序之间存在冲突.
不,问题(除了前面提到的阵列问题)是你没有使用其他子程序.虽然子程序制服在大多数方面与常规制服不同,但它们就像这样的常规制服.如果您不使用它们,驱动程序可以优化它们(以及它们依赖的任何东西).
您的片段着色器可能无法TexturedShading
在任何地方使用.由于没有其他子例程统一声明TexturedShadingType
统一,编译器意识到这两个函数从未用作子例程.所以它优化了它们.因此,您获得的指数是GL_INVALID_INDEX
.