DX 9 deferred shading help,

Started by
13 comments, last by david w 15 years, 4 months ago
I have been using the deferred shader from codesource written by: Nikita Kindt. I have everything running and the render targets are getting the correct information. What I need help on is a way to calculate the lights. He has a section in the LightPass technique, but the dx/C++ code dont show how to actually get lights onto the scene. And it seems like his lighting section is just a sample of lighting. So I would like any advice/ideas that anyone might have, that would add lighting into the scene. here is the shader:


//-------------------------------------------------------------------------------
//           Name: deferred.fx
//         Author: Nikita Kindt (nk47@bk.ru)
//  Last Modified: 17/06/06
//-------------------------------------------------------------------------------

matrix c_mWorld;
matrix c_mView;
matrix c_mViewInverse;
matrix c_mProjection;
matrix c_mViewProjection;
matrix WorldVP:WorldViewProjection; 

// light parameters
float3 c_vLightDir;
float4 c_vLightPos;
float4 c_vLightDiffuse;
float4 c_vLightSpecular;


// material parameters
float4 c_vMaterialDiffuse;
float4 c_vMaterialSpecular;
float c_fSpecularPower;

// textures
texture2D c_tDiffuseMap;
texture2D c_tNormalMap;

texture2D c_tSceneMaterialMap;
texture2D c_tSceneNormalMap;
texture2D c_tScenePositionXYMap;
texture2D c_tScenePositionZMap;
texture2D c_tLightMap;


sampler DiffuseSampler = sampler_state
{
	Texture = <c_tDiffuseMap>;
	
	AddressU = Wrap;
	AddressV = Wrap;
	
	MagFilter = Linear;
	MinFilter = Linear;
	MipFilter = Linear;
};

sampler NormalSampler = sampler_state
{
	Texture = <c_tNormalMap>;
	
	AddressU = Wrap;
	AddressV = Wrap;
	
	MagFilter = Linear;
	MinFilter = Linear;
	MipFilter = Linear;
};

sampler LightSampler = sampler_state
{
	Texture = <c_tLightMap>;
	
	AddressU = Wrap;
	AddressV = Wrap;
	
	MagFilter = Linear;
	MinFilter = Linear;
	MipFilter = Linear;
};








// rendertargets
sampler SceneMaterialSampler = sampler_state
{
	Texture = <c_tSceneMaterialMap>;
	MagFilter = Point;
	MinFilter = Point;
};

sampler SceneNormalSampler = sampler_state
{
	Texture = <c_tSceneNormalMap>;
	MagFilter = Point;
	MinFilter = Point;
};

sampler ScenePositionXYSampler = sampler_state
{
	Texture = <c_tScenePositionXYMap>;
	MagFilter = Point;
	MinFilter = Point;
};

sampler ScenePositionZSampler = sampler_state
{
	Texture = <c_tScenePositionZMap>;
	MagFilter = Point;
	MinFilter = Point;
};



struct VS_INPUT_BUILD
{
    float3  vPos            : POSITION0;
    float2  vTex0           : TEXCOORD0;
    float3  vNrm            : NORMAL0;
    float3  vTan            : TANGENT0;
    float3  vBin            : BINORMAL0;
};

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

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

VS_OUTPUT_BUILD vsBuild(VS_INPUT_BUILD i)
{
	VS_OUTPUT_BUILD o;

	o.vWorldPos = mul(float4(i.vPos, 1), c_mWorld);
	o.vPos = mul(float4(o.vWorldPos, 1), c_mViewProjection);	
	o.vTex0 = i.vTex0;	
	o.vWorldNrm = normalize(mul(float4(i.vNrm, 0), c_mWorld));
	
	return o;
};

// psBuild()
// put geometry data into render targets
PS_OUTPUT_BUILD psBuild(VS_OUTPUT_BUILD i) : COLOR0
{
	PS_OUTPUT_BUILD o;

	// material
	float4 vDiffuseMaterial = tex2D(DiffuseSampler, i.vTex0);

	o.vMaterial.rgb = vDiffuseMaterial;
	o.vMaterial.a = 1.0;
	
  	
	// convert normal to texture space [-1;+1] -> [0;1]
	float4 vNormalMaterial = tex2D(NormalSampler, i.vTex0);
	o.vWorldNrm.xyz = i.vWorldNrm * 0.5 + 0.5;
	o.vWorldNrm.rgb = i.vWorldNrm + vNormalMaterial;
	o.vWorldNrm.w = 0.0;
	
	// position
	o.vWorldPosXY = float4(i.vWorldPos.xy, 0, 0);
	o.vWorldPosZ = float4(i.vWorldPos.z, 0, 0, 0);
	
	

	return o;
};


struct PS_INPUT_LIGHT
{
	float2 vTex0		: TEXCOORD0;
};

// psLighting()
// uses data from textures (previous render targets)
float4 psLighting(PS_INPUT_LIGHT i) : COLOR0
{
	float3 vDiffuseMaterial = tex2D(SceneMaterialSampler, i.vTex0).rgb;
	float3 vSpecularMaterial = tex2D(SceneMaterialSampler, i.vTex0).a;
	
	// normals are stored in texture space [0,1] -> convert them back to [-1,+1] range
	float3 vWorldNrm = (tex2D(SceneNormalSampler, i.vTex0) - 0.5) * 2;

	float3 vWorldPos;
	vWorldPos.xy = tex2D(ScenePositionXYSampler, i.vTex0).xy;
	vWorldPos.z = tex2D(ScenePositionZSampler, i.vTex0).x;
	
	float3 vLightDir = normalize(c_vLightPos - vWorldPos);
	float3 vEyeVec = normalize(c_mViewInverse[3].xyz - vWorldPos);	
	float3 vDiffuseIntensity = dot(vLightDir, vWorldNrm);
	float3 vSpecularIntensity = pow(max(0, dot(vEyeVec, reflect(-vLightDir, vWorldNrm))), c_fSpecularPower);

	float4 color;
	color.rgb = vDiffuseIntensity * c_vLightDiffuse.xyz * vDiffuseMaterial + 
				vSpecularIntensity * c_vLightSpecular.xyz * vSpecularMaterial;
	color.a = 1.0;
	
	// here we add color to show how lighting pass affects the scene
	color.rgb += i.vTex0.rgr * 0.5;
	
	
	
	return color;
};



technique buildPass
{
	pass p0
	{
		VertexShader = compile vs_1_1 vsBuild();
		PixelShader = compile ps_2_0 psBuild();
		
		CullMode = ccw;
		FillMode = solid;
		Zenable = true;
		ZWriteEnable = true;
		ZFunc = less;
		StencilEnable = false;
		AlphaBlendEnable = false;
		AlphaTestEnable = false;		
		ColorWriteEnable = red | green | blue;
	}
}

technique lightPass
{
    pass p0
	{
		VertexShader = NULL;
		PixelShader = compile ps_2_0 psLighting();
		
		CullMode = none;
		FillMode = solid;
		Zenable = false;
		StencilEnable = false;		
		AlphaBlendEnable = true;
		Srcblend = One;
		Destblend = One;
		AlphaTestEnable = false;		
		ColorWriteEnable = red | green | blue;
	}
};













Thanks.
Advertisement
It looks like the psLighting pixel shader does actually compute the contribution from a single point light source (without proper attenuation) and then adds in some strange amount at the end to demonstrate...something. I would just take out that "color.rgb += i.vTex0.rgr * 0.5;" line and that should give you a good place to start. When you've got that working, try making new versions of that shader to calculate the contribution from a spot light, or a directional light.
Thanks for the reply. I have the scene up and running properly. I will be uploading a screen of each render target and final output. Everything looks good for the single light source that does get created. The problem is that I want to support many lights. I am not sure how to use the information in the render targets to make a light. I'm going to be googling for information about deferred shading and how to use this information. I have some ideas. But I really do need some help/explination as to how to make the final lights happen. Also my msn is dwestfall10070@hotmail.com and my yahoo is dwestfall10070@yahoo.com I have both messenger apps and if anyone can help me, could you add me, and help just explain the steps that need to happen. its alot faster than forum posts, thank you.
Typically what you'll do with a deferred shader is you'll render a "shape" for each light source. So for a directional light source you'll render a full-screen quad, for a point light a sphere, and for a spot light a cone. Each one of these "shapes" represents the area of the scene that the light can affect. Then each time your render a shape, you set the appropriate shader (for directional, point, or spot light) and then draw it with additive blending enabled. Once you've rendered everything, you end up with a buffer containing the sum of all of the lighting contributions.

There's a lot of optimizations you can apply...you might want to check out some of these references:

link
link
link
link
Thanks for the links I've been reading them for awhile now trying to get a grip on things. I think I understand what has to happen. I've been experimenting around to see what will work and what wont work. I have a question though. If I build a simple app and post it up here, would you be willing to help walk me through what I need to get done in order to get the "many" lights that I want? If not thanks for the help so far.
Sure. Just try to come up with some specific points or questions you'd like to go over, and I'll try to help you out.
Thanks, Im getting busy right now. I'll try to use very little media. I will just keep it basic and I'll heavily comment the sections with what I "think" is supposed to happen. Ok, getting busy now. I'll have something soon. Thank you.
deferred shading can be a real win if you want lots of lights in one scene. But it gets more and more tricky once shadowing and specific material stuff comes in, like object specific settings and stuff like alpha.

just my share of knowledge
LOL your telling me, I've already been killing myself over this for weeks and I'm just now getting close to finally "getting it." LOL, gotta love pc's.

ok I have the project done. I have everything up and running. Once you have a look over it and read my note in the render section maybe you can put me on the right path. Thanks for the help. ok I have it upload I just got to figure out how to put the link up.


ok thats the link I uploaded it to

link to my test program

copy and paste link in case the other link dont work correctly.

http://forumfiles.thegamecreators.com/download/1593784
there's a specific XNA tutorial which gave me a great impresion of how deferred shading works. It explains in simple language how the lighting is handled and it is easily converted to DX calls. There tutorial:

http://www.ziggyware.com/readarticle.php?article_id=155

This topic is closed to new replies.

Advertisement