Skip to content

Instantly share code, notes, and snippets.

@slembcke
Created January 21, 2020 22:54
Show Gist options
  • Save slembcke/40544dc6ec2256701e9e4c5927318d22 to your computer and use it in GitHub Desktop.
Save slembcke/40544dc6ec2256701e9e4c5927318d22 to your computer and use it in GitHub Desktop.
Fourier lighting code
struct FragOutput {
half4 a0 : SV_TARGET0;
half4 a1 : SV_TARGET1;
half4 b1 : SV_TARGET2;
half4 a2 : SV_TARGET3;
half4 b2 : SV_TARGET4;
};
// Double angle formula derived from the trig identity.
float2 DoubleAngle(float2 n){
return float2(n.x*n.x - n.y*n.y, 2.0*n.x*n.y);
}
// Rotate direction based on the UVs to avoid the need for vertex tangents.
float2 RotateWithUVs(float2 direction, float2 uv){
return mul(float2x2(normalize(ddx(uv)), normalize(ddy(uv))), direction);
}
// Fragment shader for compositing lights together, used with additive blending.
void FShader(in FragInput FRAG, out FragOutput OUT){
float4 intensity = FRAG.color*max(0, 1 - length(FRAG.uv));
// TODO pseudo-z is hard-coded
float3 direction = normalize(float3(FRAG.uv, 0.025));
direction.xy = RotateWithUVs(direction.xy, FRAG.uv);
// Kinda mostly workable hack to approximate a light not on the xy plane.
// Should figure out a more accurate curve for this.
const float C0 = 0.318309886184; // 1/pi
OUT.a0 = lerp(C0, 1.0, direction.z)*intensity;
const float C1 = 0.5;
float2 g1 = -C1*direction.xy;
OUT.a1 = g1.x*intensity;
OUT.b1 = g1.y*intensity;
const float C2 = 0.212206590789; // 2/(3*pi)
float2 g2 = C2*DoubleAngle(-direction.xy);
OUT.a2 = g2.x*intensity;
OUT.b2 = g2.y*intensity;
}
// ---
// Sample the light-field for a given screen space position and normal direction.
float3 SampleLightField(float z_ish, float3 normal, SamplerState samp, Texture2DArray lightfield, float2 ssuv){
float4 a0 = lightfield.Sample(samp, float3(ssuv, 0));
float4 a1 = lightfield.Sample(samp, float3(ssuv, 1));
float4 b1 = lightfield.Sample(samp, float3(ssuv, 2));
float4 a2 = lightfield.Sample(samp, float3(ssuv, 3));
float4 b2 = lightfield.Sample(samp, float3(ssuv, 4));
float zfactor = 1 - (1 - z_ish)*normal.z;
float2 g1 = normal.xy/sqrt(zfactor);
float2 g2 = DoubleAngle(g1);
return zfactor*max(0, a0 + a1*g1.xxx + b1*g1.yyy + a2[2]*g2.xxx + b2[3]*g2.yyy);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment