Sign in to follow this  

Normals and light in View Space

This topic is 2663 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,
Ok, in course of my game development I realized that I have to switch myself to deferred rendering. Everything was working fine when all my position, normals and light were in world space. But when I set then in view space the normals changed depending upon the camera's orientation. So my light should also behave the same way to properly lit the model. I multiplied the light direction with the worldView Matrix. But still when I change my camera orientation the model goes from bright to dark color. Here is my deferred lighting code:



struct Mtrl
{
float4 ambient;
float4 diffuse;
float4 spec;
float specPower;
};

struct DirLight
{
float4 ambient;
float4 diffuse;
float4 spec;
float3 dirW;
};

uniform extern float4x4 gWorld;
uniform extern float4x4 gWorldInv;
uniform extern float4x4 gWVP;
uniform extern Mtrl gMtrl;
uniform extern DirLight gLight;
uniform extern float3 gEyePosW;
uniform extern texture gTex;
uniform extern texture gNormalMap;
uniform extern float4x4 gView;
uniform extern float4x4 worldView;

uniform extern texture sceneMaterialMap, sceneNormalMap, scenePositionXYMap, scenePositionZMap, gEnvMap;

sampler EnvMapS = sampler_state
{
Texture = <gEnvMap>;
MinFilter = Anisotropic;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler textureSampler = sampler_state
{
Texture = <sceneMaterialMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler normalSampler = sampler_state
{
Texture = <sceneNormalMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler positionXYSampler = sampler_state
{
Texture = <scenePositionXYMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler positionZSampler = sampler_state
{
Texture = <scenePositionZMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler TexS = sampler_state
{
Texture = <gTex>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler NormalMapS = sampler_state
{
Texture = <gNormalMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
//AddressU = WRAP;
//AddressV = WRAP;
};

struct OutputVS
{
float4 vPos : POSITION0;
float2 vTex0 : TEXCOORD0;
float3 vWorldPos : TEXCOORD1;
float3 vWorldNrm : TEXCOORD2;

};


struct OutputPS
{
float4 vMaterial : COLOR0;
float4 vWorldNrm : COLOR1;
float4 vWorldPosXY : COLOR2;
float4 vWorldPosZ : COLOR3;
};



OutputVS NormalMapVS(float3 posL : POSITION0,
float3 tangentL : TANGENT0,
float3 binormalL : BINORMAL0,
float3 normalL : NORMAL0,
float2 tex0 : TEXCOORD0)
{

OutputVS outVS = (OutputVS)0;
//worldView = mul(gWorld, gView);
outVS.vWorldPos = mul(float4(posL, 1), gWorld);
outVS.vPos = mul(float4(outVS.vWorldPos, 1), gWVP);
outVS.vTex0 = tex0;
outVS.vWorldNrm = normalize(mul(float4(normalL, 0), worldView));

return outVS;
}

OutputPS NormalMapPS(OutputVS i) : COLOR
{
OutputPS o;
float4 vDiffuseMaterial = tex2D(TexS, i.vTex0);
clip(vDiffuseMaterial.a - 0.2f);

o.vMaterial.rgb = vDiffuseMaterial;
o.vMaterial.a = 1.0;

o.vWorldNrm.xyz = 0.5f * i.vWorldNrm + 1.0;
o.vWorldNrm.w = 0.0;

o.vWorldPosXY = float4(i.vWorldPos.xy, 0, 0);
o.vWorldPosZ = float4(i.vWorldPos.z, 0, 0, 0);

return o;
}


float4 deferredLighting(float2 tex0:TEXCOORD0):COLOR
{
float3 diffuseMaterial = tex2D(textureSampler, tex0);
float3 worldNormal = 2*tex2D(normalSampler, tex0) - 1;

float3 worldPos;
worldPos.xy = tex2D(positionXYSampler, tex0).xy;
worldPos.z = tex2D(positionZSampler, tex0).z;
float3 lightDir = normalize(mul(gLight.dirW, worldView));
//float3 lightDir = normalize(gLight.dirW);
float4 color;
color.rgb = dot(lightDir, worldNormal) * gLight.diffuse * diffuseMaterial +
gLight.ambient * diffuseMaterial;
color.a = 1.0f;

return color;

}

technique NormalMapTech
{
pass P0
{

vertexShader = compile vs_3_0 NormalMapVS();
pixelShader = compile ps_3_0 NormalMapPS();
}
}
technique DeferredLightTechnique
{
pass p0
{
VertexShader = NULL;
PixelShader = compile ps_2_0 deferredLighting();

CullMode = none;
FillMode = solid;
Zenable = false;
StencilEnable = false;
/*AlphaBlendEnable = true;
Srcblend = One;
Destblend = One;
AlphaTestEnable = false;
ColorWriteEnable = red | green | blue;*/

}
};



Also note the light is a single directional light.
Please help. Thanks.

Share this post


Link to post
Share on other sites
Ok, I subtracted camera Position from the resulting light vector and normalized it as:

//vertex shader: In build pass
outVS.vWorldNrm = normalize(mul(float4(normalL, 0), (float3x3) view));

---------

//Pixel shader: In light pass
float3 lightDir = mul(gLight.dirW , viewMatrix);
lightDir = normalize(gEyePosW - lightDir);
color.rgb = dot(lightDir, worldNormal) * gLight.diffuse * diffuseMaterial +
float3(0.2f, 0.2f, 0.2f) * diffuseMaterial;



The variation of light when I move my camera has decreased a lot. But still there is a very little variation. Any ideas?

Share this post


Link to post
Share on other sites
There're some mistakes I've seen in your code:

//in NormalMapVS
outVS.vWorldNrm = normalize(mul(float4(normalL, 0), worldView));

I recommend you to multiply your local-space normal vector with Inverse-Transpose of WorldView matrix instead of pure worldView.



//in NormalMapPS
o.vWorldNrm.xyz = 0.5f * i.vWorldNrm + 1.0;
o.vWorldNrm.w = 0.0;

When you store your normal into a texture, you must multiply your view-space normal with 0.5 then add 0.5f, instead of 1.0f. With this, you can reconstruct it in pixel shader via 2*NMap - 1 formula.


//again in deferredLighting
float3 lightDir = normalize(mul(gLight.dirW, worldView));

Light direction vector is already in world space (if you don't touch it in your software code). Why are you multiplying it with worldView matrix? Just multiply with view matrix, then normalize in pixel shader.


//and again in deferredLighting
color.rgb = dot(lightDir, worldNormal) * gLight.diffuse * diffuseMaterial +
gLight.ambient * diffuseMaterial;

Don't forget to saturate (or clamp to [0, 1]) your NdotL value (I mean, dot(lightDir, worldNormal) value).


hth.
-R

Share this post


Link to post
Share on other sites
Finally I got it working and the full credit goes to programci_84.

Here is the full shader code:

struct Mtrl
{
float4 ambient;
float4 diffuse;
float4 spec;
float specPower;
};

struct DirLight
{
float4 ambient;
float4 diffuse;
float4 spec;
float3 dirW;
};

uniform extern float4x4 gView;
uniform extern float4x4 gWorld;
uniform extern float4x4 gWorldInv;
uniform extern float4x4 gWVP;
uniform extern Mtrl gMtrl;
uniform extern DirLight gLight;
uniform extern float3 gEyePosW;
uniform extern texture gTex;
uniform extern texture gNormalMap;
uniform extern float4x4 gView;
uniform extern float4x4 worldView;
uniform extern float4x4 worldViewInverseTranspose;

uniform extern texture sceneMaterialMap, sceneNormalMap, scenePositionXYMap, scenePositionZMap, gEnvMap;

sampler EnvMapS = sampler_state
{
Texture = <gEnvMap>;
MinFilter = Anisotropic;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler textureSampler = sampler_state
{
Texture = <sceneMaterialMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler normalSampler = sampler_state
{
Texture = <sceneNormalMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler positionXYSampler = sampler_state
{
Texture = <scenePositionXYMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler positionZSampler = sampler_state
{
Texture = <scenePositionZMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler TexS = sampler_state
{
Texture = <gTex>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

sampler NormalMapS = sampler_state
{
Texture = <gNormalMap>;
MinFilter = ANISOTROPIC;
MaxAnisotropy = 16;
MagFilter = LINEAR;
MipFilter = LINEAR;
//AddressU = WRAP;
//AddressV = WRAP;
};

struct OutputVS
{
float4 vPos : POSITION0;
float2 vTex0 : TEXCOORD0;
float3 vWorldPos : TEXCOORD1;
float3 vWorldNrm : TEXCOORD2;

};


struct OutputPS
{
float4 vMaterial : COLOR0;
float4 vWorldNrm : COLOR1;
float4 vWorldPosXY : COLOR2;
float4 vWorldPosZ : COLOR3;
};



OutputVS NormalMapVS(float3 posL : POSITION0,
float3 tangentL : TANGENT0,
float3 binormalL : BINORMAL0,
float3 normalL : NORMAL0,
float2 tex0 : TEXCOORD0)
{

OutputVS outVS = (OutputVS)0;

outVS.vWorldPos = mul(float4(posL, 1), gWorld);
outVS.vPos = mul(float4(outVS.vWorldPos, 1), gWVP);
outVS.vTex0 = tex0;
outVS.vWorldNrm = normalize(mul(float4(normalL, 0), worldViewInverseTranspose));

return outVS;
}

OutputPS NormalMapPS(OutputVS i) : COLOR
{
OutputPS o;
float4 vDiffuseMaterial = tex2D(TexS, i.vTex0);
clip(vDiffuseMaterial.a - 0.2f);

o.vMaterial.rgb = vDiffuseMaterial;
o.vMaterial.a = 1.0;

o.vWorldNrm.xyz = 0.5f * (i.vWorldNrm + 1.0);
o.vWorldNrm.w = 0.0;

o.vWorldPosXY = float4(i.vWorldPos.xy, 0, 0);
o.vWorldPosZ = float4(i.vWorldPos.z, 0, 0, 0);

return o;
}

float4 deferredLighting(float2 tex0:TEXCOORD0):COLOR
{
float3 diffuseMaterial = tex2D(textureSampler, tex0);
float3 worldNormal = 2*tex2D(normalSampler, tex0) - 1;

float3 worldPos;
worldPos.xy = tex2D(positionXYSampler, tex0).xy;
worldPos.z = tex2D(positionZSampler, tex0).z;

float3 lightDir = mul(gLight.dirW , gView);
lightDir = normalize(lightDir);

float4 color;
color.rgb = saturate(dot(lightDir, worldNormal)) * gLight.diffuse * diffuseMaterial
+ gLight.ambient * diffuseMaterial;

color.a = 1.0f;

return color;

}



In my previous code as world was always an identity matrix so I just wrote worldView instead of only viewMatrix. And also I forgot to put bracket in storing my normals as:

o.vWorldNrm.xyz = 0.5f * (i.vWorldNrm + 1.0);
equivalent to
o.vWorldNrm.xyz = 0.5f * i.vWorldNrm + 0.5;


Also now I want my position to be in view space so should I multiply it wih worldViewMatrix instead of worldInverseTransposeMatrix??

Share this post


Link to post
Share on other sites
First, thank you for your positively rating ;)

BTW,
Quote:
Also now I want my position to be in view space so should I multiply it wih worldViewMatrix instead of worldInverseTransposeMatrix??

The answer is: Multiplying your local-space pos. vector with pure worldView matrix is ideal.

-R

Share this post


Link to post
Share on other sites

This topic is 2663 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this