296 lines
8.5 KiB
Plaintext
296 lines
8.5 KiB
Plaintext
|
|
#[set(everything)]
|
|
const constants: {
|
|
invVP: float4x4;
|
|
eye: float3;
|
|
envmap_data: float4; // angle, sin(angle), cos(angle), strength
|
|
envmap_num_mipmaps: int;
|
|
camera_proj: float2;
|
|
eye_look: float3;
|
|
shirr0: float4;
|
|
shirr1: float4;
|
|
shirr2: float4;
|
|
shirr3: float4;
|
|
shirr4: float4;
|
|
shirr5: float4;
|
|
shirr6: float4;
|
|
};
|
|
|
|
#[set(everything)]
|
|
const sampler_linear: sampler;
|
|
|
|
#[set(everything)]
|
|
const gbufferD: tex2d;
|
|
|
|
#[set(everything)]
|
|
const gbuffer0: tex2d;
|
|
|
|
#[set(everything)]
|
|
const gbuffer1: tex2d;
|
|
|
|
#[set(everything)]
|
|
const senvmap_brdf: tex2d;
|
|
|
|
#[set(everything)]
|
|
const senvmap_radiance: tex2d;
|
|
|
|
#[set(everything)]
|
|
const senvmap_radiance0: tex2d;
|
|
|
|
#[set(everything)]
|
|
const senvmap_radiance1: tex2d;
|
|
|
|
#[set(everything)]
|
|
const senvmap_radiance2: tex2d;
|
|
|
|
#[set(everything)]
|
|
const senvmap_radiance3: tex2d;
|
|
|
|
#[set(everything)]
|
|
const senvmap_radiance4: tex2d;
|
|
|
|
#[set(everything)]
|
|
const ssaotex: tex2d;
|
|
|
|
const PI: float = 3.14159265358979;
|
|
const PI2: float = 6.28318530718;
|
|
|
|
struct vert_in {
|
|
pos: float2;
|
|
}
|
|
|
|
struct vert_out {
|
|
pos: float4;
|
|
tex: float2;
|
|
view_ray: float3;
|
|
}
|
|
|
|
fun deferred_light_vert(input: vert_in): vert_out {
|
|
var output: vert_out;
|
|
output.tex = input.pos.xy * 0.5 + 0.5;
|
|
output.tex.y = 1.0 - output.tex.y;
|
|
output.pos = float4(input.pos.xy, 0.0, 1.0);
|
|
|
|
// NDC (at the back of cube)
|
|
var v: float4 = float4(input.pos.xy, 1.0, 1.0);
|
|
v = constants.invVP * v;
|
|
v.xyz = v.xyz / v.w;
|
|
output.view_ray = v.xyz - constants.eye;
|
|
|
|
return output;
|
|
}
|
|
|
|
fun octahedron_wrap(v: float2): float2 {
|
|
var a: float2;
|
|
if (v.x >= 0.0) {
|
|
a.x = 1.0;
|
|
}
|
|
else {
|
|
a.x = -1.0;
|
|
}
|
|
|
|
if (v.y >= 0.0) {
|
|
a.y = 1.0;
|
|
}
|
|
else {
|
|
a.y = -1.0;
|
|
}
|
|
|
|
var r: float2;
|
|
r.x = abs(v.y);
|
|
r.y = abs(v.x);
|
|
r.x = 1.0 - r.x;
|
|
r.y = 1.0 - r.y;
|
|
return r * a;
|
|
|
|
// return (1.0 - abs(v.yx)) * (float2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0));
|
|
}
|
|
|
|
// fun unpack_f32_i16(val: float, out f: float, out i: uint) {
|
|
// // Constant optimize by compiler
|
|
// const num_bit_target: int = 16;
|
|
// const num_bit_i: int = 4;
|
|
// const prec: float = float(1 << num_bit_target);
|
|
// const maxi: float = float(1 << num_bit_i);
|
|
// const prec_minus_one: float = prec - 1.0;
|
|
// const t1: float = ((prec / maxi) - 1.0) / prec_minus_one;
|
|
// const t2: float = (prec / maxi) / prec_minus_one;
|
|
// // Code
|
|
// // extract integer part
|
|
// // + rcp(prec_minus_one) to deal with precision issue
|
|
// i = uint((val / t2) + (1.0 / prec_minus_one));
|
|
// // Now that we have i, solve formula in pack_f32_i16 for f
|
|
// //f = (val - t2 * float(i)) / t1 => convert in mads form
|
|
// f = clamp((-t2 * float(i) + val) / t1, 0.0, 1.0); // Saturate in case of precision issue
|
|
// }
|
|
|
|
fun surface_albedo(base_color: float3, metalness: float): float3 {
|
|
return lerp3(base_color, float3(0.0, 0.0, 0.0), metalness);
|
|
}
|
|
|
|
fun surface_f0(base_color: float3, metalness: float): float3 {
|
|
return lerp3(float3(0.04, 0.04, 0.04), base_color, metalness);
|
|
}
|
|
|
|
fun get_pos(eye: float3, eye_look: float3, view_ray: float3, depth: float, camera_proj: float2): float3 {
|
|
// eye_look, view_ray should be normalized
|
|
var linear_depth: float = camera_proj.y / (depth - camera_proj.x);
|
|
var view_z_dist: float = dot(eye_look, view_ray);
|
|
var wposition: float3 = eye + view_ray * (linear_depth / view_z_dist);
|
|
return wposition;
|
|
}
|
|
|
|
const c1: float = 0.429043;
|
|
const c2: float = 0.511664;
|
|
const c3: float = 0.743125;
|
|
const c4: float = 0.886227;
|
|
const c5: float = 0.247708;
|
|
|
|
fun sh_irradiance(nor: float3): float3 {
|
|
// TODO: Use padding for 4th component and pass shirr[].xyz directly
|
|
var cl00: float3 = float3(constants.shirr0.x, constants.shirr0.y, constants.shirr0.z);
|
|
var cl1m1: float3 = float3(constants.shirr0.w, constants.shirr1.x, constants.shirr1.y);
|
|
var cl10: float3 = float3(constants.shirr1.z, constants.shirr1.w, constants.shirr2.x);
|
|
var cl11: float3 = float3(constants.shirr2.y, constants.shirr2.z, constants.shirr2.w);
|
|
var cl2m2: float3 = float3(constants.shirr3.x, constants.shirr3.y, constants.shirr3.z);
|
|
var cl2m1: float3 = float3(constants.shirr3.w, constants.shirr4.x, constants.shirr4.y);
|
|
var cl20: float3 = float3(constants.shirr4.z, constants.shirr4.w, constants.shirr5.x);
|
|
var cl21: float3 = float3(constants.shirr5.y, constants.shirr5.z, constants.shirr5.w);
|
|
var cl22: float3 = float3(constants.shirr6.x, constants.shirr6.y, constants.shirr6.z);
|
|
return (
|
|
cl22 * c1 * (nor.y * nor.y - (-nor.z) * (-nor.z)) +
|
|
cl20 * c3 * nor.x * nor.x +
|
|
cl00 * c4 -
|
|
cl20 * c5 +
|
|
cl2m2 * 2.0 * c1 * nor.y * (-nor.z) +
|
|
cl21 * 2.0 * c1 * nor.y * nor.x +
|
|
cl2m1 * 2.0 * c1 * (-nor.z) * nor.x +
|
|
cl11 * 2.0 * c2 * nor.y +
|
|
cl1m1 * 2.0 * c2 * (-nor.z) +
|
|
cl10 * 2.0 * c2 * nor.x
|
|
);
|
|
}
|
|
|
|
fun mip_from_roughness(roughness: float, num_mipmaps: float): float {
|
|
// First mipmap level = roughness 0, last = roughness = 1
|
|
return roughness * num_mipmaps;
|
|
}
|
|
|
|
fun envmap_equirect(normal: float3, angle: float): float2 {
|
|
var phi: float = acos(normal.z);
|
|
var theta: float = atan2(normal.x, -normal.y) + PI + angle;
|
|
return float2(theta / PI2, phi / PI);
|
|
}
|
|
|
|
fun envmap_sample(lod: float, coord: float2): float3 {
|
|
if (lod == 0.0) {
|
|
return sample_lod(senvmap_radiance, sampler_linear, coord, 0.0).rgb;
|
|
}
|
|
if (lod == 1.0) {
|
|
return sample_lod(senvmap_radiance0, sampler_linear, coord, 0.0).rgb;
|
|
}
|
|
if (lod == 2.0) {
|
|
return sample_lod(senvmap_radiance1, sampler_linear, coord, 0.0).rgb;
|
|
}
|
|
if (lod == 3.0) {
|
|
return sample_lod(senvmap_radiance2, sampler_linear, coord, 0.0).rgb;
|
|
}
|
|
if (lod == 4.0) {
|
|
return sample_lod(senvmap_radiance3, sampler_linear, coord, 0.0).rgb;
|
|
}
|
|
return sample_lod(senvmap_radiance4, sampler_linear, coord, 0.0).rgb;
|
|
}
|
|
|
|
fun deferred_light_frag(input: vert_out): float4 {
|
|
// normal.xy, roughness, metallic/matid
|
|
var g0: float4 = sample_lod(gbuffer0, sampler_linear, input.tex, 0.0);
|
|
|
|
var n: float3;
|
|
n.z = 1.0 - abs(g0.x) - abs(g0.y);
|
|
if (n.z >= 0.0) {
|
|
//n.xy = g0.xy;
|
|
n.x = g0.x;
|
|
n.y = g0.y;
|
|
}
|
|
else {
|
|
//n.xy = octahedron_wrap(g0.xy);
|
|
var f2: float2 = octahedron_wrap(g0.xy);
|
|
n.x = f2.x;
|
|
n.y = f2.y;
|
|
}
|
|
n = normalize(n);
|
|
|
|
var roughness: float = g0.b;
|
|
var metallic: float;
|
|
var matid: uint;
|
|
// unpack_f32_i16(g0.a, metallic, matid);
|
|
matid = uint((g0.a / 0.06250047610269868710814625956118106842041015625) + (1.0 / 65535.0));
|
|
metallic = clamp((-0.06250047610269868710814625956118106842041015625 * float(matid) + g0.a) / 0.062485207147583624058737396240234375, 0.0, 1.0);
|
|
|
|
var g1: float4 = sample_lod(gbuffer1, sampler_linear, input.tex, 0.0); // basecolor.rgb, occ
|
|
var occ: float = g1.a;
|
|
var albedo: float3 = surface_albedo(g1.rgb, metallic);
|
|
var f0: float3 = surface_f0(g1.rgb, metallic);
|
|
|
|
var depth: float = sample_lod(gbufferD, sampler_linear, input.tex, 0.0).r;
|
|
var p: float3 = get_pos(constants.eye, constants.eye_look, normalize(input.view_ray), depth, constants.camera_proj);
|
|
var v: float3 = normalize(constants.eye - p);
|
|
var dotnv: float = max(0.0, dot(n, v));
|
|
|
|
occ = lerp(1.0, occ, dotnv); // ao fresnel
|
|
|
|
// Envmap
|
|
var envl: float3 = sh_irradiance(
|
|
float3(
|
|
n.x * constants.envmap_data.z - n.y * constants.envmap_data.y,
|
|
n.x * constants.envmap_data.y + n.y * constants.envmap_data.z,
|
|
n.z
|
|
)
|
|
);
|
|
// envl /= PI;
|
|
envl = envl / PI;
|
|
|
|
var reflection_world: float3 = reflect(-v, n);
|
|
|
|
// var lod: float = mip_from_roughness(roughness, float(constants.envmap_num_mipmaps));
|
|
// var prefiltered_color: float3 = sample_lod(senvmap_radiance, sampler_linear, envmap_equirect(reflection_world, constants.envmap_data.x), lod).rgb;
|
|
|
|
var lod: float = mip_from_roughness(roughness, 5.0);
|
|
var lod0: float = floor(lod);
|
|
var lod1: float = ceil(lod);
|
|
var lodf: float = lod - lod0;
|
|
var envmap_coord: float2 = envmap_equirect(reflection_world, constants.envmap_data.x);
|
|
var lodc0: float3 = envmap_sample(lod0, envmap_coord);
|
|
var lodc1: float3 = envmap_sample(lod1, envmap_coord);
|
|
var prefiltered_color: float3 = lerp3(lodc0, lodc1, lodf);
|
|
|
|
envl.rgb = envl.rgb * albedo;
|
|
// Indirect specular
|
|
// var env_brdf: float2 = senvmap_brdf[uint2(roughness * 255.0, (1.0 - dotnv) * 255.0)].xy;
|
|
var env_brdf: float4 = senvmap_brdf[uint2(uint(roughness * 255.0), uint((1.0 - dotnv) * 255.0))];
|
|
|
|
//envl.rgb += prefiltered_color * (f0 * env_brdf.x + env_brdf.y) * 1.5;
|
|
envl.rgb = envl.rgb + (prefiltered_color * (f0 * env_brdf.x + env_brdf.y) * 1.5);
|
|
envl.rgb = envl.rgb * constants.envmap_data.w * occ;
|
|
|
|
var color: float4;
|
|
color.rgb = envl.rgb;
|
|
color.rgb = color.rgb * sample_lod(ssaotex, sampler_linear, input.tex, 0.0).r;
|
|
|
|
// if (matid == uint(1)) { // Emission
|
|
if (matid == uint(1.0)) { // Emission
|
|
color.rgb = color.rgb + g1.rgb; // materialid
|
|
albedo = float3(0.0, 0.0, 0.0);
|
|
}
|
|
|
|
color.a = 1.0; // Mark as opaque
|
|
|
|
return color;
|
|
}
|
|
|
|
#[pipe]
|
|
struct pipe {
|
|
vertex = deferred_light_vert;
|
|
fragment = deferred_light_frag;
|
|
}
|