Strange normal mapping problem

Started by
8 comments, last by pachesantiago 11 years, 7 months ago
Hy guys, having a little problem here, wich i think is self explanatory:
gNPmb.jpg
yuw46.jpg

Im trying to implement a simple normal mapping shader, wich I allready tryed in a program i use to test shaders ( DarkShader) but when i loaded it into my engine, that happend. Got that strange black parts.
This is the shader in DarkShader
WB1Gn.jpg


string Description = "This shader uses preview lights to produce per pixel normal mapped lighting. This shader requires lights.";
string Thumbnail = "Normal Mapping.png";
//The Extra Data map, contains :
// Red : Seams
// Blue : Specular Power
// Green : Specular Ammount
// The seams data is used to multiply the specs inverse, so the seams arent visible
//--------------
//Untweakables
//--------------
float4x4 WorldViewProj : WorldViewProjection;
float4x4 World : World;
float4x4 WorldT : WorldTranspose;
float4x4 WorldIT : WorldInverseTranspose;
float4 LightPos[8] : LIGHTPOSITION;
float3 LightColor[8] : LIGHTCOLOR;
float3 AmbientColor : AMBIENTCOLOR;
float3 eyepos : CameraPosition;
float time : TIME;
int L_Count : LightCount;
//--------------
//Tweakables
//--------------
int TileRes = 512;
float detailScale
<
string UIWidget = "slider";
float UIMax = 16.0;
float UIMin = 0.1;
float UIStep = 0.01;
> = 5.0f;
float SpecularPower1
<
string UIWidget = "slider";
float UIMax = 15;
float UIMin = 0.001;
float UIStep = 0.0001;
> = 3;
float DetailInfluence
<
string UIWidget = "slider";
float UIMax = 1;
float UIMin = 0.001;
float UIStep = 0.0001;
> = 0.24;
/*
float SeamCorrection
<
string UIWidget = "slider";
float UIMax = 10;
float UIMin = 1;
float UIStep = 0.0001;
> = 2;*/
texture ExtraData
<
string ResourceName = "";
>;
sampler ExtraData_smp = sampler_state
{
Texture = <ExtraData>;
MinFilter = Anisotropic;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
texture BaseTex
<
string ResourceName = "";
>;
sampler diffuse_smp = sampler_state
{
Texture = <BaseTex>;
MinFilter = Anisotropic;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
texture NormalMap
<
string ResourceName = "";
>;
sampler normalmap_smp = sampler_state
{
Texture = <NormalMap>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};
texture NormalMapTile
<
string ResourceName = "";
>;
sampler normalmapTile_smp = sampler_state
{
Texture = <NormalMapTile>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
AddressV = Wrap;
};

struct app_in
{
float4 pos : POSITION;
float3 normal : NORMAL0;
float3 tangent : TANGENT0;
float3 binormal : BINORMAL0;
float2 uv : TEXCOORD0;
};
struct vs_out
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float3 tangent : TEXCOORD2;
float3 binormal : TEXCOORD3;
float4 wpos : TEXCOORD4;
float2 uvTile : TEXCOORD5;
};
vs_out VS( app_in IN )
{
vs_out OUT;

float4 pos = mul( IN.pos, WorldViewProj );
OUT.pos = pos;
OUT.wpos = mul( IN.pos, World );
OUT.uv = IN.uv;
OUT.uvTile = IN.uv * detailScale;
float3 normal = normalize(mul(IN.normal.xyz,(float3x3)World ));
float3 tangent = normalize(mul(IN.tangent.xyz,(float3x3)World ));
float3 binormal = normalize(mul(IN.binormal.xyz,(float3x3)World ));

//smooth out the tangents and binormals with the normals
float3 b = normalize(cross( normal,tangent ));
b *= sign(dot(b,binormal));

float3 t = normalize(cross( normal,b ));
t *= sign(dot(t,tangent));

float3 t2 = normalize(cross( normal,binormal ));
t2 *= sign(dot(t2,tangent));

float3 b2 = normalize(cross( normal,t2 ));
b2 *= sign(dot(b2,binormal));

//pass normal, tangent, and binormal to pixel shader
OUT.normal = normal;
OUT.tangent = normalize((t+t2)*0.5);
OUT.binormal = normalize((b+b2)*0.5);

return OUT;
}
float luminance ( float3 rgb )
{
return rgb.r*0.3 + rgb.g*0.59 + rgb.b*0.11;
}
float3 getTexel( float2 p, uniform sampler2D texSamp,uniform int TexRes )
{
TexRes *= 8;

p = p*TexRes + 0.5;
float2 i = floor(p);
float2 f = p - i;
f = f*f*f*(f*(f*6.0-15.0)+10.0);
p = i + f;
p = (p - 0.5)/TexRes;
float3 outValue = tex2D( texSamp, p );
return outValue;
}
float4 PS( vs_out IN, uniform int numLights ) : COLOR
{
float3 color = AmbientColor;

float3 n = normalize(IN.normal);
float3 t = normalize(IN.tangent);
float3 b = normalize(IN.binormal);

//build transpose matrix
float3x3 TangentSpace = {t,b,n};
TangentSpace = transpose(TangentSpace);

n = normalize(tex2D(normalmap_smp, IN.uv)*2 - 1);
//float3 nT = normalize(tex2D(normalmapTile_smp, IN.uvTile)*2 - 1);
float3 nT = normalize(getTexel(IN.uvTile,normalmapTile_smp,TileRes));

float3 e = normalize(eyepos - IN.wpos);
float eyeDist = length(eyepos - IN.wpos);

e = mul(e,TangentSpace);

float4 texColor = tex2D( diffuse_smp, IN.uv );

//cycle through all lights, number depending on technique chosen
for ( int i = 0; i < numLights; i++ )
{
float range = LightPos.w;

if ( range > 0 )
{
float3 l = (LightPos.xyz);// - IN.wpos.xyz);
l = mul(l,TangentSpace);

//calculate attenuation
float dist = length(l);
float att = saturate((range-dist) / range);

//calculate diffuse lighting
l = normalize(l);
float diffuse = dot(n,l)* 0.5 +0.5;

//caculate specular lighting
float3 h = normalize(l+e);
float spec = pow( saturate(dot(n,h)), SpecularPower1 )*(1-pow(1-diffuse,10));

//calculate diffuse lighting
float diffuseTile = saturate(dot(n,l));

//caculate specular lighting
float specTile = pow( saturate(dot(nT,h)), SpecularPower1 )*(1-pow(1-diffuseTile,10));

float finalSpec = (specTile+(spec-DetailInfluence)/2);

// correct seams
//finalSpec *= -(tex2D(ExtraData_smp,IN.uv).r/SeamCorrection-1);

//add to final color
//color += ((diffuse * att * LightColor) + finalSpec * att * LightColor * smoothstep(0.3,0.6,luminance(texColor.xyz)));
color = diffuse;
}
}

return float4(color,1.0);// * texColor;
}
//choose the technique corresponding to the number of lights in your application
technique PerPixelLighting
{
pass p0
{
VertexShader = compile vs_2_0 VS( );
PixelShader = compile ps_3_0 PS( L_Count );
}
}


a lot of parts are commented, because i was trying to find where the error was. Narrowed it to the N dot L i think, but the odd part is that it worked perfect in the other program.
I ran out of ideas, if someone can help me it would be great.
Advertisement
Anyone?
come one, no one? maybe render states?
Have you tried debugging it in PIX?
yes, but i dont find anything strange. i mean, i dont know assembler, but i can see the pixel history, and it says that it exited the pixel shader with that color.
So you see that it exited the pixel shader with the wrong color. Now you can use PIX to step through the shader code for that pixel and figure out why.
I would say your per vertex tangent space vectors are messed up (as this is an input that differs from Darkshader).

But still, in your shader you transform tangent space vectors to world space, and pass them to pixel shader, thus I think you do the dot product with a worldspace normal and a world space light direction vector.

The most effective and generall way is to

Vertex shader:
transform a light direction from world to object space (inverse world), and then from object space to texture space (tangent matrix), and, transform the object normal from Object space to texture Space(tangent matrix), pass those two , tx normal and tx light to pixel shader

Pixel Shader:
just dot the two direction vectors.

Your tangent triple should transform from object space to texture space. (byt it can also transform from texture space to even view space, this is done in deffered rendering techniques). Also, if you have smooth normals on verticies, just compute the tangent and have binormal computed just as the cross product of those two in the vertex shader, you then have smooth tangent space, tghough not perpendicular in all directions (but it does not matter, you just can invert the matrix by transponing only and so on then)

I would say your per vertex tangent space vectors are messed up (as this is an input that differs from Darkshader).

But still, in your shader you transform tangent space vectors to world space, and pass them to pixel shader, thus I think you do the dot product with a worldspace normal and a world space light direction vector.

The most effective and generall way is to

Vertex shader:
transform a light direction from world to object space (inverse world), and then from object space to texture space (tangent matrix), and, transform the object normal from Object space to texture Space(tangent matrix), pass those two , tx normal and tx light to pixel shader

Pixel Shader:
just dot the two direction vectors.

Your tangent triple should transform from object space to texture space. (byt it can also transform from texture space to even view space, this is done in deffered rendering techniques). Also, if you have smooth normals on verticies, just compute the tangent and have binormal computed just as the cross product of those two in the vertex shader, you then have smooth tangent space, tghough not perpendicular in all directions (but it does not matter, you just can invert the matrix by transponing only and so on then)

wow thanks. in the vertex shader, when you say the "object normals" do you mean the normals in the normal map right?
the other thing, about smooth tangent space, I do have the normals smoothed, so i can do as you said. if is not a problem, can you point me to where i can find information on computing tangents? can you also explain a bit or point to documentacion of wath do you mean with "not perpendicular in all directions"?
thanks anyway, that's probably it, if thats it, you just saved me a lot of time


wow thanks. in the vertex shader, when you say the "object normals" do you mean the normals in the normal map right?


no, I have ment the per vertex normal, not the ones in the texture. Vertex normal is one of the bazic vectors for the tangent triple.

So, you have normals on your verticies, and you know how to compute binormal. tangent is a direction vector which exists in object space and points to the direction of texture coordinates x axis. It is actualy the x axis of texture coordinates expressed in 3d space (object space)

this is a great resource for u:
http://answers.unity3d.com/questions/7789/calculating-tangents-vector4.html

it laso calculates the handedness of a tangent that you need to decide with wheather cross product between tangent and normal points+ or -
so tangent data is 4 float vector [x,y,z,handedness].

[quote name='pachesantiago' timestamp='1347242289' post='4978451']
wow thanks. in the vertex shader, when you say the "object normals" do you mean the normals in the normal map right?


no, I have ment the per vertex normal, not the ones in the texture. Vertex normal is one of the bazic vectors for the tangent triple.

So, you have normals on your verticies, and you know how to compute binormal. tangent is a direction vector which exists in object space and points to the direction of texture coordinates x axis. It is actualy the x axis of texture coordinates expressed in 3d space (object space)

this is a great resource for u:
http://answers.unity...ts-vector4.html

it laso calculates the handedness of a tangent that you need to decide with wheather cross product between tangent and normal points+ or -
so tangent data is 4 float vector [x,y,z,handedness].
[/quote]
thanks, gonna research a bit and try it

This topic is closed to new replies.

Advertisement