I am facing a really weird bug.
On an old copy of my engine, i was doing a loop to render all the lights in my scene:
for(int i = 0; i < numLights; i++){
finalColor += ApplyLight(lights[i], diffuseColor.rgb, normal, fragPosition, surfaceToCamera,specularColor,shininess);
}
Which was working just fine (i had 3 lights and they were all rendering).
But now, in a newer version that includes shadows for my lights, im trying to achieve the same thing:
for(int i = 0; i < numLights; i++){
color += ApplyLighting(lights[i], frag, normal, tex);
}
But this does not work!
I will explain:
Doing 1 index at a time works just fine (i = 0; i < 1; i++) will only execute one loop and therefore, will render the single light correctly.
But as soon as there is more than 1 light to be rendered, everything is black (compiler crash i guess).
I've heard about "constant array indexing" restriction but why in the world is it working in my other shader but not on my new one?
Here are both the shaders:
OLD
#version 430
#define MAX_LIGHTS 15
uniform int numLights;
uniform struct Light{
vec4 position;
vec3 intensities;
float ambientCoefficient;
float attenuation;
float coneAngle;
vec3 coneDirection;
} lights[MAX_LIGHTS];
uniform float materialShininess;
uniform vec3 materialSpecularColor;
uniform vec3 cameraPosition;
uniform mat4 model;
uniform bool specularMapping;
uniform bool normalMapping;
uniform bool glossMapping;
uniform bool ambientOcclusionMapping;
uniform sampler2D diffuseTexture;
uniform sampler2D specularTexture;
uniform sampler2D normalTexture;
uniform sampler2D glossTexture;
uniform sampler2D aoTexture;
in vec2 fragTexcord;
in vec3 fragNormal;
in vec3 fragVert;
out vec4 color;
vec3 ApplyLight(Light light, vec3 diffuseColor, vec3 normal, vec3 fragPosition, vec3 surfaceToCamera, vec4 specularColor, float shininess){
vec3 surfaceToLight;
float attenuation = 1.0;
float pointAttenuation = 1.0f;
if(light.position.w == 0.0) {
//directional light
surfaceToLight = normalize(light.position.xyz);
attenuation = 1.0; //no attenuation for directional lights
} else {
//point light
surfaceToLight = normalize(light.position.xyz - fragPosition);
float distanceToLight = length(light.position.xyz - fragPosition);
attenuation = 1.0 / (1.0 + light.attenuation * pow(distanceToLight, 2));
//cone restrictions (affects attenuation)
float lightToSurfaceAngle = degrees(acos(dot(-surfaceToLight, normalize(light.coneDirection))));
if(lightToSurfaceAngle > light.coneAngle){
if(lightToSurfaceAngle - light.coneAngle < 2.5f){ //Smooth around the spotlight by 2.5 degree
pointAttenuation = 1 / lightToSurfaceAngle;
pointAttenuation = clamp(pointAttenuation, 0, 1);
}else{
attenuation = 0.0;
}
}else{
pointAttenuation = (1 + 15) / lightToSurfaceAngle; //Smooth color from center
pointAttenuation = clamp(pointAttenuation, 0, 1);
}
}
//Ambient
vec3 ambient = diffuseColor.rgb * light.ambientCoefficient * light.intensities * pointAttenuation;
//Diffuse
float brightness = max(0,dot(normal, surfaceToLight));
vec3 diffuse = brightness * light.intensities * diffuseColor.rgb;
//specular
float specularCoefficient = 0.0f;
float cosAngle = dot(surfaceToCamera, reflect(-surfaceToLight, normal));
if(shininess < 255){
if(brightness > 0.0)
specularCoefficient = pow(max(0.0, cosAngle), shininess);
}
vec3 specular = specularCoefficient * materialSpecularColor * light.intensities * specularColor.rgb;
//Attenuation relative to distance
float distanceToLight = length(vec3(light.position.xyz) - fragPosition);
return ambient + attenuation * (diffuse + specular);
}
void main(){
float shininess = materialShininess;
vec4 diffuseColor = vec4(1);
vec4 specularColor = vec4(1);
vec4 normalColor = vec4(1);
diffuseColor = texture(diffuseTexture,fragTexcord); //Color on the diffuse texture
if(ambientOcclusionMapping)
diffuseColor *= texture(aoTexture, fragTexcord) * 1.2;
if(specularMapping)
specularColor = texture(specularTexture,fragTexcord); //Color on the specular texture
if(glossMapping)
shininess = texture(glossTexture, fragTexcord).r;
mat3 normalMatrix = transpose(inverse(mat3(model)));
vec3 normal = normalize(normalMatrix * fragNormal);
vec3 fragPosition = vec3(model * vec4(fragVert,1));
vec3 surfaceToCamera = normalize(cameraPosition - fragPosition);
if(normalMapping){
normal = normalize(normalMatrix * fragNormal);
}
//Calculate all the lights
vec3 finalColor = vec3(0);
for(int i = 0; i < numLights; i++){
finalColor += ApplyLight(lights[i], diffuseColor.rgb, normal, fragPosition, surfaceToCamera,specularColor,shininess);
}
//HDR (high dynamic range)
finalColor = vec3(1.0) - exp(-finalColor * 0.8);
//Gamma correction
vec3 gamma = vec3(1.0/2.2);
//Final color calculation
//Gamma calculation : color = vec4(pow(linearColor,gamma),diffuseColor.a);
color = vec4(finalColor,diffuseColor.a);
if(color.a<0.1)
{
discard;
}
}
NEW
#version 430
out vec4 FragColor;
#define MAX_LIGHTS 15
uniform int numLights;
in VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
} fs_in;
uniform sampler2D diffuseTexture;
uniform struct Light{
int lightType;
vec4 position;
vec3 intensities;
float ambientCoefficient;
float attenuation;
float coneAngle;
vec3 coneDirection;
float far_plane;
sampler2D shadowMap;
samplerCube depthMap;
mat4 lightMatrix;
} lights[MAX_LIGHTS];
uniform vec3 viewPos;
float ShadowCalculation(Light light, vec3 fragPos)
{
// Get vector between fragment position and light position
vec3 fragToLight = fragPos - light.position.xyz;
// Use the light to fragment vector to sample from the depth map
float closestDepth = texture(light.depthMap, fragToLight).r;
// It is currently in linear range between [0,1]. Re-transform back to original value
closestDepth *= light.far_plane;
// Now get current linear depth as the length between the fragment and light position
float currentDepth = length(fragToLight);
// Now test for shadows
float bias = 0.15;
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
return shadow;
}
vec3 ApplyLighting(Light light, vec3 FragPosition, vec3 norm, vec2 texCoords){
vec3 color = texture(diffuseTexture, texCoords).rgb;
vec3 normal = normalize(norm);
vec3 lightColor = vec3(1.0);
// Ambient
vec3 ambient = 0.1 * color;
// Diffuse
vec3 lightDir = normalize(vec3(light.position) - FragPosition);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = diff * lightColor;
// Specular
vec3 viewDir = normalize(viewPos - FragPosition);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = 0.0;
vec3 halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
vec3 specular = spec * lightColor;
// Calculate shadow
float shadow = ShadowCalculation(light, FragPosition);
//shadow = 0;
vec3 lighting = (ambient + (1.0 - shadow ) * (diffuse + specular)) * color;
return lighting;
}
void main()
{
vec3 color = vec3(0);
vec3 frag = fs_in.FragPos;
vec3 normal = fs_in.Normal;
vec2 tex = fs_in.TexCoords;
for(int i = 0; i < numLights; i++){
color += ApplyLighting(lights[i], frag, normal, tex);
}
//color = ApplyLighting(lights[0], fs_in.FragPos, fs_in.Normal, fs_in.TexCoords);
//color += ApplyLighting(lights[1], fs_in.FragPos, fs_in.Normal, fs_in.TexCoords);
//FragColor = vec4(numLights*0,numLights*255,0,1);
//else
FragColor = vec4(color, 1.0f);
}
As i said, the old one works perfectly fine (dont know why!).
I also noticed that if i set my MAX_LIGHTS define (on the new shader) to exactly the amount of light being used (2 in this case), it works!
But as soon as i set the size of define to (numLights+1), it doesnt work!
Any idea?
NUM_LIGHTS
is not used in the new shader andcount
is not defined. \$\endgroup\$