#include "Macros.fxh" //from FNA // Effect applies normalmapped lighting to a 2D sprite. DECLARE_TEXTURE(Texture, 0); DECLARE_TEXTURE(Normal, 1); BEGIN_CONSTANTS float3 AmbientColor _ps(c0) _cb(c0); float3 PointLightPositions[8] _ps(c1) _cb(c1); float3 PointLightColors[8] _ps(c9) _cb(c9); float3 DirectionalLightDirection _ps(c17) _cb(c17); float3 DirectionalLightColor _ps(c18) _cb(c18); MATRIX_CONSTANTS float4x4 WorldInverseTranspose _ps(c19) _cb(c19); float4x4 World _vs(c0) _cb(c23); float4x4 WorldViewProjection _vs(c4) _cb(c27); END_CONSTANTS struct VertexShaderInput { float4 Position : POSITION; float3 Normal : NORMAL; float2 TexCoord : TEXCOORD0; }; struct PixelShaderInput { float4 Position : SV_Position; float2 TexCoord : TEXCOORD0; float3 NormalWS : TEXCOORD1; float3 PositionWS : TEXCOORD2; }; PixelShaderInput main_vs(VertexShaderInput input) { PixelShaderInput output; output.Position = mul(input.Position, WorldViewProjection); output.TexCoord = input.TexCoord; output.NormalWS = mul(input.Normal, (float3x3)WorldInverseTranspose).xyz; output.PositionWS = mul(input.Position, World).xyz; return output; } // Easy trick to get tangent-normals to world-space to keep PBR code simplified. float3 GetNormalFromMap(float3 worldPos, float2 texCoords, float3 normal) { float3 tangentNormal = SAMPLE_TEXTURE(Normal, texCoords).xyz * 2.0 - 1.0; float3 Q1 = ddx(worldPos); float3 Q2 = ddy(worldPos); float2 st1 = ddx(texCoords); float2 st2 = ddy(texCoords); float3 N = normalize(normal); float3 T = normalize(Q1*st2.y - Q2*st1.y); float3 B = -normalize(cross(N, T)); float3x3 TBN = float3x3(T, B, N); return normalize(mul(tangentNormal, TBN)); } float4 LightColor(float3 worldPosition, float3 worldNormal) { float3 lightColor = float3(0.0, 0.0, 0.0); // point lights for (int i = 0; i < 8; i++) { float3 lightVec = PointLightPositions[i] - worldPosition; float distance = length(lightVec); float3 lightDir = normalize(lightVec); float diffuse = max(dot(worldNormal, lightDir), 0.0); float3 attenuation = 1.0 / (distance * distance); lightColor += diffuse * attenuation * PointLightColors[i]; } // directional light float directionalDiffuse = max(dot(worldNormal, DirectionalLightDirection), 0.0); lightColor += directionalDiffuse * DirectionalLightColor; // ambient light lightColor += AmbientColor; return float4(lightColor, 1.0); } float4 WithoutNormalMap(PixelShaderInput input) : COLOR0 { float4 tex = SAMPLE_TEXTURE(Texture, input.TexCoord); float3 normalWS = normalize(input.NormalWS); return tex * LightColor(input.PositionWS, normalWS); } float4 WithNormalMap(PixelShaderInput input) : COLOR0 { float4 tex = SAMPLE_TEXTURE(Texture, input.TexCoord); float3 normalWS = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); return tex * LightColor(input.PositionWS, normalWS); } PixelShader PSArray[2] = { compile ps_3_0 WithoutNormalMap(), compile ps_3_0 WithNormalMap() }; int PSIndices[2] = { 0, 1 }; int ShaderIndex = 0; Technique DiffuseLitSprite { pass { VertexShader = compile vs_3_0 main_vs(); PixelShader = (PSArray[PSIndices[ShaderIndex]]); } }