![]() |
|
[HLSL] Point Light and 2D Normal Mapping |
CursedTyrant
Member #7,080
April 2006
![]() |
Here's my (well, mostly borrowed) shader code: 1float4x4 World;
2float4x4 View;
3float4x4 Projection;
4
5texture DiffuseTexture;
6texture BumpTexture;
7texture NormalTexture;
8float3 CameraPos;
9float3 LightPosition;
10float3 LightDiffuseColor; // intensity multiplier
11float3 LightSpecularColor; // intensity multiplier
12float LightDistanceSquared;
13float3 DiffuseColor;
14float3 AmbientLightColor;
15float3 EmissiveColor;
16float3 SpecularColor;
17float SpecularPower;
18bool BumpMapping = true;
19
20sampler texsampler = sampler_state
21{
22 Texture = <DiffuseTexture>;
23};
24
25sampler bumpsampler = sampler_state
26{
27 Texture = <BumpTexture>;
28};
29
30sampler normalsampler = sampler_state
31{
32 Texture = <NormalTexture>;
33};
34
35struct VertexShaderInput
36{
37 float4 Position : POSITION0;
38 float2 TexCoords : TEXCOORD0;
39};
40
41struct VertexShaderOutput
42{
43 float4 Position : POSITION0;
44 float2 TexCoords : TEXCOORD0;
45 float3 WorldPos : TEXCOORD1;
46};
47
48VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
49{
50 VertexShaderOutput output;
51
52 // "Multiplication will be done in the pre-shader - so no cost per vertex"
53 float4x4 viewprojection = mul(View, Projection);
54 float4 posWorld = mul(input.Position, World);
55 output.Position = mul(posWorld, viewprojection);
56 output.TexCoords = input.TexCoords;
57
58 // Passing information on to do both specular AND diffuse calculation in pixel shader
59 output.WorldPos = posWorld;
60
61 return output;
62}
63
64float4 PixelShaderFunctionWithTex(VertexShaderOutput input) : COLOR0
65{
66 // Get light direction for this fragment
67 float3 lightDir = normalize(input.WorldPos - LightPosition); // per pixel diffuse lighting
68 float3 Normal = tex2D(normalsampler, input.TexCoords);
69
70 // Note: Non-uniform scaling not supported
71 float diffuseLighting = saturate(dot(Normal, -lightDir));
72
73 // Introduce fall-off of light intensity
74 diffuseLighting *= (LightDistanceSquared / dot(LightPosition - input.WorldPos, LightPosition - input.WorldPos));
75
76 // Using Blinn half angle modification for perofrmance over correctness
77 float3 h = normalize(normalize(CameraPos - input.WorldPos) - lightDir);
78 float specLighting = pow(saturate(dot(h, Normal)), SpecularPower);
79 float4 texel = tex2D(texsampler, input.TexCoords);
80 float4 bump = tex2D(bumpsampler, input.TexCoords);
81
82 if (!BumpMapping)
83 {
84 bump = float4(1, 1, 1, 1);
85 }
86
87 return float4(saturate(
88 AmbientLightColor +
89 (texel.xyz * DiffuseColor * LightDiffuseColor * diffuseLighting * 0.6 * bump) + // Use light diffuse vector as intensity multiplier
90 (SpecularColor * LightSpecularColor * specLighting * 0.5 * bump) // Use light specular vector as intensity multiplier
91 ), texel.w);
92 }
93
94technique TechniqueWithTexture
95{
96 pass Pass1
97 {
98 VertexShader = compile vs_2_0 VertexShaderFunction();
99 PixelShader = compile ps_2_0 PixelShaderFunctionWithTex();
100 }
101}
I'm using a point light (its center is more or less in the middle of the image). Here's what happens: So, everything seems to be working perfectly for the top left part of the screen, but the other side of the light is completely black. I isolated the fault to the float diffuseLighting = saturate(dot(Normal, -lightDir)); line, but I don't know why it doesn't work and how to fix it. Any help in making it work like it's supposed to would be appreciated. It would be fairly easy if I were to use directional lights, but I need point lights for this. Heck, directional lights wouldn't even require a vertex shader, because it's 2D anyway. --------- |
Billybob
Member #3,136
January 2003
|
Is the light on the same plane, or is it floating above the plane? I'm not sure if it being on the plane would cause that error, but it might.
|
CursedTyrant
Member #7,080
April 2006
![]() |
The light is positioned at +50 Z. The camera is at +20 Z (ortographic). The plane is at 0 Z. What is strange is that when I change that faulty line from -lightDir to +lightDir, the normal map is inverted, and the bottom right side works, while the top left one is black. Something really weird is going on here. EDIT: Praised be examples on the internet. Modifying that single line to float3 Normal = normalize((2 * tex2D(normalsampler, input.TexCoords)) - 1.0); fixed the issue. Still, thanks for trying to help. EDIT 2: --------- |
Billybob
Member #3,136
January 2003
|
So puurty!
|
CursedTyrant
Member #7,080
April 2006
![]() |
Thanks! Who said 2D games can't be pretty? --------- |
|