141 lines
3.4 KiB
HLSL
141 lines
3.4 KiB
HLSL
#include "Macros.fxh" //from FNA
|
|
|
|
// Effect applies normalmapped lighting to a 2D sprite.
|
|
|
|
DECLARE_TEXTURE(Texture, 0);
|
|
DECLARE_TEXTURE(Normal, 1);
|
|
|
|
float3 AmbientColor;
|
|
|
|
float3 PointLightPositions[8];
|
|
float3 PointLightColors[8];
|
|
|
|
float3 DirectionalLightDirection;
|
|
float3 DirectionalLightColor;
|
|
|
|
float4 UVOffsetAndDimensions;
|
|
|
|
float4x4 WorldInverseTranspose;
|
|
float4x4 World;
|
|
float4x4 WorldViewProjection;
|
|
|
|
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.NormalWS = normalize(mul(input.Normal, (float3x3)WorldInverseTranspose));
|
|
output.PositionWS = mul(input.Position, World).xyz;
|
|
|
|
float2 texCoord;
|
|
texCoord.x = (input.TexCoord.x * UVOffsetAndDimensions.z) + UVOffsetAndDimensions.x;
|
|
texCoord.y = (input.TexCoord.y * UVOffsetAndDimensions.w) + UVOffsetAndDimensions.y;
|
|
output.TexCoord = texCoord;
|
|
|
|
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);
|
|
|
|
if (tex.a == 0.0) { discard; }
|
|
|
|
float3 normalWS = normalize(input.NormalWS);
|
|
|
|
return tex * LightColor(input.PositionWS, normalWS);
|
|
}
|
|
|
|
float4 WithNormalMap(PixelShaderInput input) : COLOR0
|
|
{
|
|
float4 tex = SAMPLE_TEXTURE(Texture, input.TexCoord);
|
|
|
|
if (tex.a == 0.0) { discard; }
|
|
|
|
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]]);
|
|
}
|
|
}
|