Created
January 21, 2020 22:54
-
-
Save slembcke/40544dc6ec2256701e9e4c5927318d22 to your computer and use it in GitHub Desktop.
Fourier lighting code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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