[HLSL] Point Light and 2D Normal Mapping
CursedTyrant

Here's my (well, mostly borrowed) shader code:

#SelectExpand
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:
{"name":"603774","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/7\/a762dc61dd86ec552182359a45e849ac.png","w":712,"h":714,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/7\/a762dc61dd86ec552182359a45e849ac"}603774

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

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

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:

video

Billybob

So puurty! :D

CursedTyrant

Thanks! Who said 2D games can't be pretty? ;D

Thread #606857. Printed from Allegro.cc