I'm working on a program using GLSL shaders. I coded 2 different ways to compute ADS (Ambient + Diffuse + Specular) shading in 2 different methods. To do the job properly I used subroutines to use one or the other method to compute ADS shading.
Here's a piece of the fragment shader code :
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);
}
And the C++ code :
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);
Until here the display is correct. In this case I've choosen to execute the second subroutine definition (Phong_ADS_Shading call).
But I want to declare another subroutine type in my program to manage textures (the signature is not the same). Here's an other piece of the fragment shader code (in the same shader) :
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));
}
So, finally, my C++ code is the following :
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);
Here's the value for each subroutine index :
std::cout << phong_idx << ", " << blinn_phong_idx << ", " << textured_idx << ", " << untextured_idx << std::endl;
-> 1, 0, 4294967295, 4294967295
The two first values seems to be correct but the two others.
Here's now the whole fragment shader code to have a better understanding of my problem:
#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();
}
The problem is my geometry is render in black. I think there is a conflict between the two uniform subroutines. I'm lost. Does anyone can help me ?