GLSL shadow/normal mapping troubles with tangents and seams

Started by
1 comment, last by Misantes 9 years, 2 months ago

So, I'm attempting to combine shadow mapping and normal mapping together. My tests for each work wonderfully individually, but when I try to combine them I get some odd reflections at the seams of the texture. I'm having difficulty tracking down exactly where I'm going wrong. It seems like the tangent values get...'wonky' around the seams, and have drastically different values from their corresponding edge of the texture. In my head, it ought to work to simply calculate the normal map values, then check that against the shadow mapping for the final draw color, and it sort of works, other than the issues around the seams.

The issue I think is in how I'm calculating the light for the normal map. Again, if I render just with the shadow mapping, it's fine, the issue arises when I change the cosTheta and cosAlpha to adjust for the normal texture that things go wrong, but I'm uncertain how to go about fixing that. Those values work great if I'm not calculating the visibility from the shadow map, however. Also, a bit of testing shows the bigger issue is the diffuse color, though the specular suffers the same problem, it's less noticable since it's...specular. I've tried changing the bias values, and rendering the initial pass of the shadow map with culling GL_FRONT, but the problem remains. On a visual level, it seems the light is being culled for pretty much everything but what's right near the seams.

Edit*

after some combing through the code, it does appear the problem is with how I'm computing the tangents, or rather how the tangents handle seams, where I'm getting rather different values for either side of them. I'm unsure how to go about fixing this though.

edit**

Well, not sure if it's a coding error per se, any longer. If I cut the uvs differently on the sphere, eliminating the lines, so to speak, the rest of the code seemingly works fine. So, it's definitely a problem at the seams, but I'm still not entirely sure what can be done about it. I don't suffer the same problem on different models, or larger angles, just the gradual spherical surfaces, I think.

For reference here is my:

vertex shader, for the final draw of the object:


#version 330 core

layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec2 vertexUV;
layout(location = 2) in vec3 vertexNormal_modelspace;
layout(location = 3) in vec3 vertexTangent_modelspace;
layout(location = 4) in vec3 vertexBitangent_modelspace;

out vec2 UV;
out vec3 Position_worldspace;
out vec3 Normal_cameraspace;
out vec3 EyeDirection_cameraspace;
out vec3 LightDirection_cameraspace;
out vec4 ShadowCoord;
out vec3 LightDirection_tangentspace;
out vec3 EyeDirection_tangentspace;

uniform mat4 MVP;
uniform mat4 V;
uniform mat4 M;
uniform mat3 MV3x3;
uniform vec3 LightPosition_worldspace;
uniform vec3 LightInvDirection_worldspace;
uniform mat4 DepthBiasMVP;


void main(){

	gl_Position =  MVP * vec4(vertexPosition_modelspace,1);

	ShadowCoord = DepthBiasMVP * vec4(vertexPosition_modelspace,1);

	Position_worldspace = (M * vec4(vertexPosition_modelspace,1)).xyz;

	EyeDirection_cameraspace = vec3(0,0,0) - ( V * M * vec4(vertexPosition_modelspace,1)).xyz;

	LightDirection_cameraspace = (V*vec4(LightInvDirection_worldspace,0)).xyz;
	vec3 LightPosition_cameraspace = ( V * vec4(LightPosition_worldspace,1)).xyz;

	Normal_cameraspace = ( V * M * vec4(vertexNormal_modelspace,0)).xyz;

	UV = vertexUV;

	vec3 vertexTangent_cameraspace = MV3x3 * vertexTangent_modelspace;
	vec3 vertexBitangent_cameraspace = MV3x3 * vertexBitangent_modelspace;
	vec3 vertexNormal_cameraspace = MV3x3 * vertexNormal_modelspace;

	mat3 TBN = transpose(mat3(
		vertexTangent_cameraspace,
		vertexBitangent_cameraspace,
		vertexNormal_cameraspace
	));

	LightDirection_tangentspace = TBN * LightDirection_cameraspace;
	EyeDirection_tangentspace =  TBN * EyeDirection_cameraspace;
}

and fragement shader for the final draw:


#version 330 core

in vec2 UV;
in vec3 Position_worldspace;
in vec3 Normal_cameraspace;
in vec3 EyeDirection_cameraspace;
in vec3 LightDirection_cameraspace;
in vec4 ShadowCoord;
in vec3 LightDirection_tangentspace;
in vec3 EyeDirection_tangentspace;

layout(location = 0) out vec3 color;

uniform mat3 MV3x3;
uniform sampler2D myTextureSamplerD;
uniform sampler2D myTextureSamplerN;
uniform sampler2D myTextureSamplerS;
uniform mat4 MV;
uniform vec3 LightPosition_worldspace;
uniform sampler2DShadow shadowMap;

vec2 poissonDisk[16] = vec2[](
   vec2( -0.94201624, -0.39906216 ),
   vec2( 0.94558609, -0.76890725 ),
   vec2( -0.094184101, -0.92938870 ),
   vec2( 0.34495938, 0.29387760 ),
   vec2( -0.91588581, 0.45771432 ),
   vec2( -0.81544232, -0.87912464 ),
   vec2( -0.38277543, 0.27676845 ),
   vec2( 0.97484398, 0.75648379 ),
   vec2( 0.44323325, -0.97511554 ),
   vec2( 0.53742981, -0.47373420 ),
   vec2( -0.26496911, -0.41893023 ),
   vec2( 0.79197514, 0.19090188 ),
   vec2( -0.24188840, 0.99706507 ),
   vec2( -0.81409955, 0.91437590 ),
   vec2( 0.19984126, 0.78641367 ),
   vec2( 0.14383161, -0.14100790 )
);
float random(vec3 seed, int i){
	vec4 seed4 = vec4(seed,i);
	float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
	return fract(sin(dot_product) * 43758.5453);
}

void main(){
	vec3 LightColor = vec3(1,1,1);
	float LightPower = 10.0f;

	vec3 MaterialDiffuseColor = texture2D( myTextureSamplerD, UV ).rgb;
	vec3 MaterialAmbientColor = vec3(0.1,0.1,0.1) * MaterialDiffuseColor;
	vec3 MaterialSpecularColor = vec3(0.01,.01,.01);//texture2D( myTextureSamplerS, UV ).rgb * .01;

	vec3 TextureNormal_tangentspace = normalize(texture( myTextureSamplerN, UV ).rgb*2.0 - 1.0);

	float distance = length( LightPosition_worldspace - Position_worldspace );

	//diffuse calcs//
	vec3 n = TextureNormal_tangentspace;
	vec3 l = normalize(LightDirection_tangentspace);
	float cosTheta = clamp( dot( n,l ), 0,1 );

	//specular cals////
	vec3 E = normalize(EyeDirection_tangentspace);
	vec3 R = reflect(-l,n);
	float cosAlpha = clamp( dot( E,R ), 0,1);

	float visibility=1.0;

	//float bias = 0.005;
	// variable bias:
	 float bias = 0.005*tan(acos(cosTheta));
	 bias = clamp(bias, 0,1);

	//subtract light against shadowmap////
	for (int i=0;i<4;i++){
		 int index = int(16.0*random(floor(Position_worldspace.xyz*1000.0), i))%16;
		visibility -= 0.2*(1.0-texture( shadowMap, vec3(ShadowCoord.xy + poissonDisk[index]/700.0,  (ShadowCoord.z-bias)/ShadowCoord.w) ));
	}

	color =
		MaterialAmbientColor +
		visibility * MaterialDiffuseColor * LightColor * LightPower * cosTheta+
		visibility * MaterialSpecularColor * LightColor * LightPower * pow(cosAlpha,5);
}

I've debugged in several ways, and the shaders have undergone a lot of changes trying to get this to work, but this is roughly how they look now, minus some changes to the bias values and cosAlpha/cosTheta vaules.

I thought perhaps the problem was due to poor normal map creation on my part, but a blank normal map image results in the same issue, seen below.

Additionally, I'm not 100% certain this is the ideal way to to about implementing both normal and shadowmaps, though I'm having trouble tracking down the best method, as any searches tend to turn up information on one or the other, but not the combination of them. If I'm going about this in entirely the wrong way, please let me know. Also, if you'd like any additional code, I'd be happy to add it, i limited it to the shaders as it appears to me the issue is there.

Any insights are deeply appreciated smile.png

Here are a couple of images illustrating the problem, the last two images are with just a completely solid color for the diffuse, normal, and specular textures (though, I'm currently just manually setting the specular), to rule out a texture issue.

Beginner here <- please take any opinions with grain of salt

Advertisement

after some combing through the code, it does appear the problem is with how I'm computing the tangents, or rather how the tangents handle seams, where I'm getting rather different values for either side of them. I'm unsure how to go about fixing this though.

Tangent space handling is sometimes tricky. Indead, at seems it could happend that you get different tangent spaces, where the normals point in different directions (eg when using mirrored textures ). In this case you need to split the vertices like splitting vertices when you encounter different normals or uv coords.


after some combing through the code, it does appear the problem is with how I'm computing the tangents, or rather how the tangents handle seams, where I'm getting rather different values for either side of them. I'm unsure how to go about fixing this though.

Tangent space handling is sometimes tricky. Indead, at seems it could happend that you get different tangent spaces, where the normals point in different directions (eg when using mirrored textures ). In this case you need to split the vertices like splitting vertices when you encounter different normals or uv coords.

Ah, thank you.

I ended up blending the color output by multiplying the tangent space reflections by the camera space/shadow map calculation, rather than try to force them into one value. It seems to have cleared things up remarkably. I'll look into your suggestion as well. Thanks again :)

Beginner here <- please take any opinions with grain of salt

This topic is closed to new replies.

Advertisement