Normals and light in View Space

Started by
5 comments, last by programci_84 13 years, 7 months ago
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.
Advertisement
Man I have exactly the same problem. Sorry I am no help at the moment but when I find what's going wrong I'll let you know!
could you post a screen shot of the problem
:)
Ok, I subtracted camera Position from the resulting light vector and normalized it as:
//vertex shader: In build passoutVS.vWorldNrm = normalize(mul(float4(normalL, 0), (float3x3) view));---------//Pixel shader: In light passfloat3 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?
There're some mistakes I've seen in your code:

//in NormalMapVSoutVS.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 NormalMapPSo.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 deferredLightingfloat3 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 deferredLightingcolor.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
There's no "hard", and "the impossible" takes just a little time.
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??
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
There's no "hard", and "the impossible" takes just a little time.

This topic is closed to new replies.

Advertisement