Very strange GLSL problem. Objects not rendering when accessing shadowMaps

Started by
6 comments, last by SolDirix 9 years, 2 months ago

I have a very strange problem with rendering a scene, even with one point shadow map.

NOTE: This problem has been solved. Apparently I was trying to read my cubeMaps into an array of samplerCubes, but this does not work for me for some reason.

I am rendering a scene with one floor with a shader which recieves a singe shadow cube map, and 9 cubes with a light shader with no shadow map.

Whenever I render the scene without testing for the shadow map depth comparison, it renders just fine (but without the shadows), but if i render the scene WITH shadow map depth testing, the floor just... disappears ohmy.png

It doesn't give me an error message or anything.

Here are pictures of what I am talking about:

Without shadow map depth testing:

shadow_map1_zps44a91e8b.png

With shadow map depth testing:

shadow_map2_zpsa254056f.png

Here is the GLSL code for the floor object (specular code omitted):


#version 400

in vec2 outUV;
in vec3 outNormals;
in vec4 outPosition;
in vec4 outEyePosition;

out vec4 outColor;

uniform vec4 diffuseColor;
uniform vec4 specularColor;
uniform float diffuseAmount;
uniform float specularAmount;
uniform float specularOffset;
uniform float ambientAmount;
uniform float emmisionAmount;
uniform unsigned int specularHardness;

uniform vec3 lightPositions[8];
uniform vec3 lightColors[8];
uniform float lightIntensities[8];
uniform float lightDistances[8];

uniform sampler2D diffuse;
uniform samplerCube shadowCubeMaps[8];

vec3 calcPointLightColor(int index, inout vec3 lightDirection, vec3 viewDirection, vec3 currentNormal, float inShadow)
{
    float lightDistance;
    float lightIntensity;

    vec3 lightColor;
    lightColor = vec3(0.0, 0.0, 0.0);

    if(inShadow == 0.0)
    {
        lightDistance = lightDistances[index];

        lightDirection = outPosition.xyz - lightPositions[index];
        lightDistance = length(lightDirection) / lightDistance;
        lightDistance = clamp(lightDistance, 0.0, 1.0);
        lightDistance = (lightDistance * -1.0) + 1.0;
        lightDirection = normalize(lightDirection);

        lightIntensity = dot(currentNormal, -lightDirection);
        if(lightIntensity < 0.0)
        {
            lightIntensity = 0.0;
        }
        lightIntensity = lightIntensity * lightDistance;

        lightColor = vec3((lightColors[index] * lightIntensities[index]) * lightIntensity);
    }

    return lightColor;
}

float shadowMapComparison(int index)
{
    float lengthToPixel;
    float shadowDistance;
    float inShadow1;

    inShadow1 = 0.0;

    vec3 directionToShadowMap = outPosition.xyz - lightPositions[index];
    shadowDistance = texture(shadowCubeMaps[index], directionToShadowMap).r;

    lengthToPixel = length(directionToShadowMap);

    if(shadowDistance + 0.001 >= lengthToPixel)
    {
        inShadow1 = 1.0;
    }
    else
    {
        inShadow1 = 0.0;
    }
    return inShadow1;
}

void main()
{
    vec3 viewDirection;
    vec3 currentNormal;
    vec3 lightDirections[8];

    vec4 finalColor;
    vec4 diffuseColorFinal;

    float inShadow[8];

    diffuseColorFinal = diffuseColor * diffuseAmount;
    
    currentNormal = normalize(outNormals);

    viewDirection = outPosition.xyz - outEyePosition.xyz;
    
    viewDirection = normalize(viewDirection);
    viewDirection = -viewDirection;
    
    inShadow[0] = shadowMapComparison(0);

    finalColor += vec4(calcPointLightColor(0, lightDirections[0], viewDirection, currentNormal, inShadow[0]), 1.0);
    finalColor.a = 1.0;

    finalColor = finalColor * vec4(texture(diffuse, outUV).rgb, 1.0);

    finalColor = finalColor * diffuseColorFinal;

    outColor = finalColor;
}

So yeah. The shadow maps are fine, I debugged them by outputting to a quad, and they look fine. They are point light shadow maps, so they check for distance stored in the red component, instead of a depth component, for spherical distance.

I am guessing this is just a runtime GLSL error, but I cannot figure out what I am doing wrong.

I am following this tutorial: http://ogldev.atspace.co.uk/www/tutorial43/tutorial43.html

View my game dev blog here!

Advertisement

Why are you allowing lights to modify the alpha component of the diffuse value?

Why is specular not affected by shadows?

Why are you lighting via 8 speculars but only 1 diffuse?

Why is your shadowing term the reverse of what it should be? It’s not a boolean, it is a factor. 1.0 means completely not in shadows. 0.0 means totally in shadows.

Your link is not valid so I can’t compare with what they are doing, but there are no worthwhile tutorials that teach using 1 = in shadow and 0 = not in shadow.

Why don’t you see if you are actually drawing the floor when you have shadow maps enabled?

If you are, why not remove code section-by-section until it appears?

If it turns out that it is not rendering because of the alpha value, why are you using alpha testing for opaque objects?

L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

"Why are you allowing lights to modify the alpha component of the diffuse value?"

Well I have to output a vec4 color to the back buffer, in case I ever use alpha blending, so I add an extra 1.0 to the end of the light value when adding it to the final color. I changed the default color back to vec4(0.0, 0.0, 0.0, 1.0), but no change. I'm not using alpha blending, but I plan to with other objects in the future.

"Why is specular not affected by shadows?"

I want to test it with diffuse first before testing it with specular. If the diffuse doesn't work, then the specular wont work either. It would be a wasted effort.

"Why are you lighting via 8 speculars but only 1 diffuse?"

My bad. At the moment I left it in there regardless since i'm only testing the diffuse. I commented it out for now.

"Why is your shadowing term the reverse of what it should be? It’s not a boolean, it is a factor. 1.0 means completely not in shadows. 0.0 means totally in shadows.

Your link is not valid so I can’t compare with what they are doing, but there are no worthwhile tutorials that teach using 1 = in shadow and 0 = not in shadow."

I don't know what is wrong with the link. It's ogldev.atspace.co.uk, the 43 tutorial. I have no excuse for the floating point, other than that i've never used bools in glsl and was more familiar with floats, I changed it to a bool.

"Why don’t you see if you are actually drawing the floor when you have shadow maps enabled?

If you are, why not remove code section-by-section until it appears?

I've tried that multiple times, and the only like of code that makes things work when being commented out is this one:


bool shadowMapComparison(int index)
{
	float lengthToPixel;
	float shadowDistance;
	bool inShadow1;

	inShadow1 = false;

	vec3 directionToShadowMap = outPosition.xyz - lightPositions[index];

        //The culprit
	//shadowDistance = texture(shadowCubeMaps[index], directionToShadowMap).r;

	lengthToPixel = length(directionToShadowMap);

	if(shadowDistance + 0.001 >= lengthToPixel)
	{
		inShadow1 = true;
	}
	else
	{
		inShadow1 = false;
	}
	return(inShadow1);
}

"If it turns out that it is not rendering because of the alpha value, why are you using alpha testing for opaque objects?"

The alpha value isn't doing anything, since i'm just adding 0.0 to 1.0, which gives 1.0 regardless, however I do plan on using this same shader for both alpha and opaque objects.

And I swear I am sending the texture over to it properly. This is the function I use in C++ to send the light data over to the shader for every object:


void RenderingEngine::UpdateRenderQueueNodeLightData(RenderQueueNode& renderQueueNode,
GLuint& currentShader)
{
	GLuint location;

	glm::vec3 lightPosition;
	glm::vec3 lightColor;

	float lightIntensity;
	float lightDistance;

	for(unsigned int i = 0; i < 8; i++)
	{
		lightPosition =
				renderQueueNode.renderingComponent->GetLight(i).lightPosition;

		location = glGetUniformLocation(currentShader, lightPosStr[i].c_str());
		glUniform3fv(location, 1, (GLfloat*)&lightPosition);
	}

	for(unsigned int i = 0; i < 8; i++)
	{
		lightColor =
				renderQueueNode.renderingComponent->GetLight(i).lightColor;

		location = glGetUniformLocation(currentShader, lightColStr[i].c_str());
		glUniform3fv(location, 1, (GLfloat*)&lightColor);
	}

	for(unsigned int i = 0; i < 8; i++)
	{
		lightIntensity =
				renderQueueNode.renderingComponent->GetLight(i).lightIntensity;

		location = glGetUniformLocation(currentShader, lightIntStr[i].c_str());
		glUniform1f(location, lightIntensity);
	}

	for(unsigned int i = 0; i < 8; i++)
	{
		lightDistance =
				renderQueueNode.renderingComponent->GetLight(i).lightDistance;

		location = glGetUniformLocation(currentShader, lightDisStr[i].c_str());
		glUniform1f(location, lightDistance);
	}

	switch(renderQueueNode.shaderIndex)
	{
	case LIGHT_SHAD_1D :
	case LIGHT_SHAD_1D_1N_1S :
	case LIGHT_SHAD_1D_ALPHA_CLIP :
	case LIGHT_SHAD_1D_1N_1S_ALPHA_CLIP :
	case LIGHT_SHAD_INST_1D :
	case LIGHT_SHAD_INST_1D_1N_1S :
	case LIGHT_SHAD_REFL_1D :
	case LIGHT_SHAD_REFL_1D_1N_1S :
	case LIGHT_SHAD_BONE_ANIM_1D :
	case LIGHT_SHAD_BONE_ANIM_1D_1N_1S :
	case LIGHT_SHAD_BONE_ANIM_REFL_1D :
	case LIGHT_SHAD_BONE_ANIM_REFL_1D_1N_1S :
	case VLIGHT_SHAD_1D :
		location = glGetUniformLocation(currentShader, "shadowCubeMaps[0]");
					glUniform1i(location, 12);

					glActiveTexture(GL_TEXTURE0 + 12);
					glBindTexture(GL_TEXTURE_2D, renderQueueNode.renderingComponent->GetLight(0).shadowMap);

		break;
	default:
		break;
	}
}

View my game dev blog here!

I don't know what is wrong with the link. It's ogldev.atspace.co.uk, the 43 tutorial. I have no excuse for the floating point, other than that i've never used bools in glsl and was more familiar with floats, I changed it to a bool.

That is exactly the opposite of what I said. Shadowing is not a boolean.


The alpha value isn't doing anything, since i'm just adding 0.0 to 1.0, which gives 1.0 regardless

That’s only true (partially) because your lighting is wrong.
finalColor = finalColor + calcPointLightColor(0, lightDirections[0], viewDirection, currentNormal, inShadow[0]);
should be:
finalColor *= calcPointLightColor(0, lightDirections[0], viewDirection, currentNormal, inShadow[0]);

But it’s not really true.
calcPointLightColor() returns [X, X, X, 1] if inShadow is not 0.0, and [X, X, X, 0] otherwise. Whether you add (wrong) or multiply (correct), light is modifying your diffuse alpha in one condition or the other.

I've tried that multiple times, and the only like of code that makes things work when being commented out is this one:

You failed to normalize shadowDistance.



Is this shader only being run on the ground?
If so, then you may have a compiler or linker error on that shader. You should be checking all OpenGL ES errors and compilation success religiously.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

"That is exactly the opposite of what I said. Shadowing is not a boolean."

Ah, ok. For some reason I misunderstood what you said earlier. Will change back to float.



"That’s only true (partially) because your lighting is wrong.
finalColor = finalColor + calcPointLightColor(0, lightDirections[0], viewDirection, currentNormal, inShadow[0]);
should be:
finalColor *= calcPointLightColor(0, lightDirections[0], viewDirection, currentNormal, inShadow[0]);

But it’s not really true.
calcPointLightColor() returns [X, X, X, 1] if inShadow is not 0.0, and [X, X, X, 0] otherwise. Whether you add (wrong) or multiply (correct), light is modifying your diffuse alpha in one condition or the other."

Ah, I see now. I'm gonna just use vec3's instead just cuz I won't really need the alpha for the lights. Though I'm a bit confused. Aren't lights supposed to be added together? If I multiply a red light(vec3(1.0, 0.0, 0.0)) with a blue light(vec3(0.0, 1.0, 0.0)), the lights should cancel out. First, I add all the colored lights together, then I multiply it against the diffuse. I try this and I get no artifacts.

"You failed to normalize shadowDistance."

I'm confused. Why would I need to normalize it? if a distance value in the r component of the shadowMap is 5.0 and is sent to shadowDistance, and the distance between the pixel and light is calculated to be 4.9 and is sent to lengthToPixel, I want to check that the distance value is greater than the shadow map value for it to be in shadow. This is exactly the way it is done in the tutorial. What is it that normalizing would do to change this? As far as I know only vectors can be normalized, not floats. I'm not quite sure what you mean.

"Is this shader only being run on the ground?"

Yes. Only the ground.

"If so, then you may have a compiler or linker error on that shader. You should be checking all OpenGL ES errors and compilation success religiously."

I check for errors using glGetShaderIV and glGetShaderInfoLog. I don't get any unless I have a typo or a missing semicolon. I've been error checking the shiznitz out of this thing, and I got nothing.

View my game dev blog here!

UPDATE: Ok, apparently the shadow map ISN'T being sent to the shader for some reason -.- (even though the light data is, which is odd since it's in the same struct as the shadow map). I don't know why, but I tried projecting the shadow map onto the floor using:


    vec3 directionToShadowMap = outPosition.xyz - lightPositions[0];
    finalColor = finalColor * vec4(texture(shadowCubeMaps[0], directionToShadowMap).r, 0.0, 0.0, 1.0);

but I get nothing but black.

It's very strange, because it was working previously. I will get back to you guys once I manage to even get the shadow map into the shader in the first place.

View my game dev blog here!

Aren't lights supposed to be added together?

Yes but your variable names are confusing me (so yes your code was correct).
Why don’t you add them into a variable called “diffuseGather” and “specularGather”?
Then those get multiplied by the diffuse and specular, and then they are added together.
It is not against the law to make your code clear by using totally separate values to gather all your diffuse, and another value to gather all your specular, etc. When your variables are named, “finalColor” and “diffuseColorFinal”, it is pretty hard to follow the flow and to see what part of code is meant to do what.
In any case, you didn’t initialize finalColor and diffuseColorFinal to 0.


I'm confused. Why would I need to normalize it?

Because you are sampling a cube texture with it.
But I am going out of my mind all over the place in this topic for some reason. You don’t need to normalize to sample a cube texture. I am being retarded.


Ah, ok. For some reason I misunderstood what you said earlier. Will change back to float.

But you are still using it as a boolean. As I said. It is a factor. 1 = not in shadow.
Why?

fShadowFactor[0] = getShadow( 0 );
fShadowFactor[1] = getShadow( 1 );
vec3 diffuseLightGather = vec3( 0.0, 0.0, 0.0 );
diffuseLightGather += calcLight( 0 ) * fShadowFactor[0];
diffuseLightGather += calcLight( 1 ) * fShadowFactor[1];
It’s a factor. You don’t if/else it like a boolean, you multiply it (hence 0 = shadowed, 1 = no shadow).


Yes. Only the ground.

Replace the “offensive” line with a hard-coded value such as 1.0.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Replace the “offensive” line with a hard-coded value such as 1.0.

Ah, It seems to work this way.

When replacing the line with shadowDistance = 5.0, I end up with this result:

shadow_map3_zpsa8692179.png

I guess this means that the algorithm is correct, just that the shadow map really isn't getting sent in properly. I will also change my variables like you suggested. And thank you for all your help ^^.

View my game dev blog here!

This topic is closed to new replies.

Advertisement