Multi-Shader

Started by
2 comments, last by MJP 15 years, 10 months ago
I've got two seperate shader files, an ambient light shader and a point light shader. I'd like to use both of them in a scene together so I've decided to combine them into one file using multiple passes (not sure if this is possible) but all it seems to do is render the second pass without taking into account the first pass. How would I go about doing this? Shader:

float4x4 matWorldViewProj;	//World*View*Projection Matrix
float4x4 matWorld;		//World Space Matrix
texture modelTexture;		//Texture of models in scene

float4 lightPosition = {0.0f, 0.0f, 0.0f, 0.0f};	//Position of the Light
float4 lightColor = {1.0f, 1.0f, 1.0f, 1.0f};		//Color of the Light
float4 matColor = {1.0f, 1.0f, 1.0f, 1.0f};		//Material Color
float falloff = 10.0f;		//Light Falloff
float brightness = 1.0f;	//Brightness of Ambient Light


float4 ambientColor = {1.0f, 1.0f, 1.0f, 1.0f};		//Color of Ambient Light
float ambientbrightness = 1.0f;	//Brightness of Ambient Light

sampler TextureSampler = sampler_state
{
	Texture = (modelTexture);
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
};

struct ambientA2V
{
	float4 Pos: POSITION;
	float2 TexCoord: TEXCOORD0;
};

struct ambientV2P
{
	float4 Pos: POSITION;
	float2 TexCoord: TEXCOORD0;
};

struct A2V
{
	float4 Pos: POSITION;
	float3 Normal : NORMAL;
	float2 TexCoord: TEXCOORD0;
};

struct V2P
{
	float4 Pos : POSITION;
	float4 WorldPos : TEXCOORD0;
	float3 WorldNormal : TEXCOORD1;
	float2 TexCoord : TEXCOORD2;
	float4 Diffuse : TEXCOORD3;
	float3 LightDir : TEXCOORD4;
};

void VS(in A2V IN, out V2P OUT)
{
	//Transform from view space to projection space
	OUT.Pos = mul(IN.Pos, matWorldViewProj);
	
	//Find World Position
	OUT.WorldPos = mul(IN.Pos, matWorld);
	
	//Calculate Light Direction
	OUT.LightDir = lightPosition - OUT.WorldPos;
	
	//Calculate world normal
	OUT.WorldNormal = normalize( mul(IN.Normal, (float3x3)matWorld));
	
	//Obtain Diffuse of Material
	OUT.Diffuse = matColor * lightColor;
	
	//Texture coordinates
	OUT.TexCoord = IN.TexCoord;
}

float4 PS(in V2P IN) : COLOR0
{
	//Pixel to light
	float LenSq = dot(IN.LightDir, IN.LightDir);
	IN.LightDir = normalize(IN.LightDir);

	//Determine Attenuation of light
	float Attn = min((falloff*falloff) / LenSq, 1.0f);
	
	//Calculate lighting amount
	float4 I = saturate(dot(normalize(IN.WorldNormal), IN.LightDir)) * IN.Diffuse * Attn;
	
	//Get Texture	
	float4 Color = tex2D(TextureSampler, IN.TexCoord);
	
	return Color * (I * brightness);
}

void ambientVS(in ambientA2V IN, out ambientV2P OUT)
{
	//Transform from view space to projection Space
	OUT.Pos = mul(IN.Pos, matWorldViewProj);
	
	//Grab texture coordinates
	OUT.TexCoord = IN.TexCoord;
}

float4 ambientPS(in ambientV2P IN) : COLOR
{
	//Get texture
	float4 Color = tex2D(TextureSampler, IN.TexCoord);
	
	//Return texture * color * ambientbrightness
	return Color * (ambientColor * ambientbrightness);
}

technique PointLight
{
	pass P0
	{
		vertexshader = compile vs_2_0 VS();
		pixelshader = compile ps_2_0 PS();
	}
	
	pass P1
	{
		vertexshader = compile vs_2_0 ambientVS();
		pixelshader = compile ps_2_0 ambientPS();
	}
}

=============================RhinoXNA - Easily start building 2D games in XNA!Projects

Advertisement
Don't forget that you need to also set blending states for this to work. If you leave everything at default, alpha blending will be disabled and the results of the second pass will wipe out and replace the results of the first pass. For multi-pass lighting, you'll want to use additive blending as this sums the result of the second pass with the result of the first (you always sum the contributions from different light sources). Setting the appropriate effect states would look like this:

technique PointLight{	pass P0	{		AlphaBlendEnable = FALSE;			ZEnable = TRUE;		ZWriteEnable = TRUE;		vertexshader = compile vs_2_0 VS();		pixelshader = compile ps_2_0 PS();	}		pass P1	{		AlphaBlendEnable = TRUE;		SrcBlend = ONE;		DestBlend = ONE;		BlendOp = ADD;		ZEnable = TRUE;		ZWriteEnable = FALSE;		vertexshader = compile vs_2_0 ambientVS();		pixelshader = compile ps_2_0 ambientPS();	}}


Also note that this will disable z-writes on the second pass...there's no need to do z-writes since you're be rendering to the exact same spot as the first pass.

[Edited by - MJP on June 23, 2008 8:39:47 PM]
Thanks! For anyone reading though, make sure you have semi-colons after those lines. I've read a bunch on shaders but never found anything about that stuff, do you happen to know of any sites that talk about that? If not, thats cool.

=============================RhinoXNA - Easily start building 2D games in XNA!Projects

Quote:Original post by programmermattc
Thanks! For anyone reading though, make sure you have semi-colons after those lines. I've read a bunch on shaders but never found anything about that stuff, do you happen to know of any sites that talk about that? If not, thats cool.


Err...the missing semi-colons were a test of how observant you are. [grin]

Anyway as far as setting effect states, you can check out the documentation for those right here. Not sure where I first learned about blending with multiple passes, it might have been just something I figured out. Or I may have just learned it from hanging out here!




This topic is closed to new replies.

Advertisement