Point light question

Started by
7 comments, last by pindrought 5 years, 3 months ago

Hi Guys,

I have been looking in to point light shaders and have created one which seems to work ok.

But, if I rotate the object that is being lit, the rotates around with it, keeping the same face lit all of the time.

This is what I have so far;


cbuffer WVPCB : register(b0)
{
	float4x4 matWorld;
	float4x4 matView;
	float4x4 matProjection;
}

cbuffer LIGHT : register(b1)
{
	float4 lightPosition;
	float4 lightAmbient;
}

struct VS_INPUT
{
	float4 position : POSITION;
	float3 normal : NORMAL;
	float2 textureCoord : TEXCOORD0;
};

struct VS_OUTPUT
{
	float4 position : SV_POSITION;
	float3 normal : NORMAL;
	float2 textureCoord : TEXCOORD0;

	float4 lightPosition : COLOR1;
	float4 lightAmbient : COLOR2;
	float3 fragmentPosition : COLOR3;
};

VS_OUTPUT vs_main(VS_INPUT input)
{
	VS_OUTPUT output;
	output.position = mul(input.position, matWorld);
	output.position = mul(output.position, matView);		// WV position of the model
	output.fragmentPosition = output.position;				// Put light in correct place?
	output.position = mul(output.position, matProjection);

	// Pass paramters to the pixel shader
	output.normal = input.normal;
	output.textureCoord = input.textureCoord;
	output.lightPosition = lightPosition;
	output.lightAmbient = lightAmbient;

	return output;
}

float4 ps_main(VS_OUTPUT input) : SV_TARGET
{
	float3 lightColor = input.lightAmbient;
	float ambientStrength = input.lightAmbient.w;
	float3 ambient = ambientStrength * lightColor;

	float3 norm = normalize(input.normal);
	float3 lightDir = normalize(input.lightPosition - input.fragmentPosition);

	float diff = max(dot(norm, lightDir), 0.0f);
	float3 diffuse = diff * lightColor;
	float3 result = (ambient + diffuse);

	return squareMap.Sample(samLinear, input.textureCoord) * float4(result, 1.0f);
}

From my understanding, the fifth last line in the PS should put the light back into the correct place (shouldn't it?).

Or do I need to send the light position as a float4x4 matrix, similar to how you'd position the model itself?

Any help would be greatly appreciated. I'm almost there - LOL.

Thanks in advance.

Advertisement

You're computing your fragment position in view space, but your light is presumably defined in world space and that's where you leave it. Personally I find it much easier and more intuitive to do all my lighting in world space rather than the old school view space tradition. Just output position times world into the shader, and then everything else will generally already be in world space.

SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.

Thanks for your advice Promit.

Do you mean like this?


	VS_OUTPUT output;
	output.position = mul(input.position, matWorld);
	output.fragmentPosition = output.position;				// Put light in correct place?

	output.position = mul(output.position, matView);		// WV position of the model
	output.position = mul(output.position, matProjection);

As this gives the same result.

Or do you mean to send the light to the shader in a 4x4 matrix like you would with any other model?

Thanks for your patience. I am new to this side of things and still getting my head around it.

Even tried sending the lights own world matrix and it still spins with the rotation of the first object.

I'm officially confused.


cbuffer WVPCB : register(b0)
{
	float4x4 matWorld;
	float4x4 matView;
	float4x4 matProjection;
}

cbuffer LIGHT : register(b1)
{
	float4x4 matLightWorld;
	float4 lightPosition;
	float4 lightAmbient;
}

struct VS_INPUT
{
	float4 position : POSITION;
	float3 normal : NORMAL;
	float2 textureCoord : TEXCOORD0;
};

struct VS_OUTPUT
{
	float4 position : SV_POSITION;
	float3 normal : NORMAL;
	float2 textureCoord : TEXCOORD0;

	float4 lightPosition : COLOR1;
	float4 lightAmbient : COLOR2;
	float3 fragmentPosition : COLOR3;
};

VS_OUTPUT vs_main(VS_INPUT input)
{
	VS_OUTPUT output;
	output.position = mul(input.position, matWorld);
	output.position = mul(output.position, matView);		// WV position of the model
	output.position = mul(output.position, matProjection);

	// Pass paramters to the pixel shader
	output.normal = input.normal;
	output.textureCoord = input.textureCoord;
	output.lightPosition = lightPosition;
	output.lightAmbient = lightAmbient;

	output.fragmentPosition = mul(lightPosition, matLightWorld);

	return output;
}

 

You don't multiply normal by world matrix of the object (the rotation and translation) this is why it fails

 


output.position = mul(input.position, matWorld);
	

you do exactly the same for output.normal

then you calculate normal direction from light to this position, then you can do max(dot(lightdir, output.normal), 0.0);

Thanks @_WeirdCat_

I have changed the VS to this;


VS_OUTPUT vs_main(VS_INPUT input)
{
	VS_OUTPUT output;

	output.fragmentPosition = input.position;

	output.position = mul(input.position, matWorld);
	output.position = mul(output.position, matView);
	output.position = mul(output.position, matProjection);

	output.fragmentPosition = mul(input.position, matWorld);
	output.normal = mul(input.normal, matWorld);

	// Pass paramters to the pixel shader
	//output.normal = input.normal;
	output.textureCoord = input.textureCoord;
	output.lightPosition = lightPosition;
	output.lightAmbient = lightAmbient;

	return output;
}

And the PS to this


float4 ps_main(VS_OUTPUT input) : SV_TARGET
{
	float3 lightColor = input.lightAmbient;
	float ambientStrength = input.lightAmbient.w;
	float3 ambient = ambientStrength * lightColor;

	float3 norm = normalize(input.normal);
	float3 lightDir = normalize(input.lightPosition - input.fragmentPosition);

	//float diff = max(dot(norm, lightDir), 0.0f);
	
	float diff = max(dot(lightDir, norm), 0.0);

	float3 diffuse = diff * lightColor;
	float3 result = (ambient + diffuse);

	return squareMap.Sample(samLinear, input.textureCoord) * float4(result, 1.0f);
}

The light is now fixed in position as the object, which is great.

But, the light can't be positioned now, the lightPosition co-ordinates don't respond to what I am putting in. It is locked in the same place regardless of its values.

Thanks again for your help

 

 

Sorry, I had a double up in my constant buffer code. Had it in my render cycle twice and of course I was adjusting the first call, which was getting over written. So, I have removed that.

Things are looking better now.  :D

Thanks again for your help. I'll have a play and see if I run into any problems.

One thing to note...

 


output.normal = mul(input.normal, matWorld);

Be careful about this. You want to exclude the translation component of your matWorld matrix. You can do this by converting it to a matrix that omits the translation component, or alternatively, you can cast the normal as a float4 with a 0 for the w component.

Ex.


output.normal = mul(float4(input.normal,0.0f), matWorld);

 

This topic is closed to new replies.

Advertisement