285 lines
7.2 KiB
GLSL
285 lines
7.2 KiB
GLSL
|
|
uniform sampler2D gbufferD;
|
|
uniform sampler2D gbuffer0;
|
|
uniform sampler2D gbuffer1;
|
|
#ifdef _Voxel
|
|
uniform sampler3D voxels;
|
|
#endif
|
|
uniform vec4 envmap_data; // angle, sin(angle), cos(angle), strength
|
|
uniform vec4 shirr[7];
|
|
uniform sampler2D senvmap_brdf;
|
|
uniform sampler2D senvmap_radiance;
|
|
#ifdef SPIRV
|
|
uniform float envmap_num_mipmaps;
|
|
#else
|
|
uniform int envmap_num_mipmaps;
|
|
#endif
|
|
uniform sampler2D ssaotex;
|
|
uniform vec2 camera_proj;
|
|
uniform vec3 eye;
|
|
uniform vec3 eye_look;
|
|
uniform vec3 point_pos;
|
|
uniform vec3 point_col;
|
|
#ifdef _Voxel
|
|
uniform float cone_offset;
|
|
uniform float cone_aperture;
|
|
#endif
|
|
uniform vec3 light_area0;
|
|
uniform vec3 light_area1;
|
|
uniform vec3 light_area2;
|
|
uniform vec3 light_area3;
|
|
uniform sampler2D sltc_mat;
|
|
uniform sampler2D sltc_mag;
|
|
|
|
#include "gbuffer.glsl"
|
|
#include "brdf.glsl"
|
|
#include "math.glsl"
|
|
#include "shirr.glsl"
|
|
#ifdef _Voxel
|
|
#include "conetrace.glsl"
|
|
#endif
|
|
|
|
in vec2 tex_coord;
|
|
in vec3 view_ray;
|
|
out vec4 frag_color;
|
|
|
|
const float LUT_SIZE = 64.0;
|
|
const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;
|
|
const float LUT_BIAS = 0.5 / LUT_SIZE;
|
|
|
|
float integrate_edge(vec3 v1, vec3 v2) {
|
|
float cos_theta = dot(v1, v2);
|
|
float theta = acos(cos_theta);
|
|
float res = cross(v1, v2).z * ((theta > 0.001) ? theta / sin(theta) : 1.0);
|
|
return res;
|
|
}
|
|
|
|
float ltc_evaluate(vec3 N, vec3 V, float dotnv, vec3 P, mat3 Minv, vec3 points0, vec3 points1, vec3 points2, vec3 points3) {
|
|
// Construct orthonormal basis around N
|
|
vec3 T1, T2;
|
|
T1 = normalize(V - N * dotnv);
|
|
T2 = cross(N, T1);
|
|
|
|
// Rotate area light in (T1, T2, R) basis
|
|
Minv = mul(transpose(mat3(T1, T2, N)), Minv);
|
|
|
|
// Polygon (allocate 5 vertices for clipping)
|
|
vec3 L0 = mul((points0 - P), Minv);
|
|
vec3 L1 = mul((points1 - P), Minv);
|
|
vec3 L2 = mul((points2 - P), Minv);
|
|
vec3 L3 = mul((points3 - P), Minv);
|
|
vec3 L4 = vec3(0.0, 0.0, 0.0);
|
|
|
|
int n = 0;
|
|
// Detect clipping config
|
|
int config = 0;
|
|
if (L0.z > 0.0) config += 1;
|
|
if (L1.z > 0.0) config += 2;
|
|
if (L2.z > 0.0) config += 4;
|
|
if (L3.z > 0.0) config += 8;
|
|
|
|
// Clip
|
|
if (config == 0) {
|
|
// Clip all
|
|
}
|
|
else if (config == 1) { // V1 clip V2 V3 V4
|
|
n = 3;
|
|
L1 = -L1.z * L0 + L0.z * L1;
|
|
L2 = -L3.z * L0 + L0.z * L3;
|
|
}
|
|
else if (config == 2) { // V2 clip V1 V3 V4
|
|
n = 3;
|
|
L0 = -L0.z * L1 + L1.z * L0;
|
|
L2 = -L2.z * L1 + L1.z * L2;
|
|
}
|
|
else if (config == 3) { // V1 V2 clip V3 V4
|
|
n = 4;
|
|
L2 = -L2.z * L1 + L1.z * L2;
|
|
L3 = -L3.z * L0 + L0.z * L3;
|
|
}
|
|
else if (config == 4) { // V3 clip V1 V2 V4
|
|
n = 3;
|
|
L0 = -L3.z * L2 + L2.z * L3;
|
|
L1 = -L1.z * L2 + L2.z * L1;
|
|
}
|
|
else if (config == 5) { // V1 V3 clip V2 V4) impossible
|
|
n = 0;
|
|
}
|
|
else if (config == 6) { // V2 V3 clip V1 V4
|
|
n = 4;
|
|
L0 = -L0.z * L1 + L1.z * L0;
|
|
L3 = -L3.z * L2 + L2.z * L3;
|
|
}
|
|
else if (config == 7) { // V1 V2 V3 clip V4
|
|
n = 5;
|
|
L4 = -L3.z * L0 + L0.z * L3;
|
|
L3 = -L3.z * L2 + L2.z * L3;
|
|
}
|
|
else if (config == 8) { // V4 clip V1 V2 V3
|
|
n = 3;
|
|
L0 = -L0.z * L3 + L3.z * L0;
|
|
L1 = -L2.z * L3 + L3.z * L2;
|
|
L2 = L3;
|
|
}
|
|
else if (config == 9) { // V1 V4 clip V2 V3
|
|
n = 4;
|
|
L1 = -L1.z * L0 + L0.z * L1;
|
|
L2 = -L2.z * L3 + L3.z * L2;
|
|
}
|
|
else if (config == 10) { // V2 V4 clip V1 V3) impossible
|
|
n = 0;
|
|
}
|
|
else if (config == 11) { // V1 V2 V4 clip V3
|
|
n = 5;
|
|
L4 = L3;
|
|
L3 = -L2.z * L3 + L3.z * L2;
|
|
L2 = -L2.z * L1 + L1.z * L2;
|
|
}
|
|
else if (config == 12) { // V3 V4 clip V1 V2
|
|
n = 4;
|
|
L1 = -L1.z * L2 + L2.z * L1;
|
|
L0 = -L0.z * L3 + L3.z * L0;
|
|
}
|
|
else if (config == 13) { // V1 V3 V4 clip V2
|
|
n = 5;
|
|
L4 = L3;
|
|
L3 = L2;
|
|
L2 = -L1.z * L2 + L2.z * L1;
|
|
L1 = -L1.z * L0 + L0.z * L1;
|
|
}
|
|
else if (config == 14) { // V2 V3 V4 clip V1
|
|
n = 5;
|
|
L4 = -L0.z * L3 + L3.z * L0;
|
|
L0 = -L0.z * L1 + L1.z * L0;
|
|
}
|
|
else if (config == 15) { // V1 V2 V3 V4
|
|
n = 4;
|
|
}
|
|
|
|
if (n == 0) return 0.0;
|
|
if (n == 3) L3 = L0;
|
|
if (n == 4) L4 = L0;
|
|
|
|
// Project onto sphere
|
|
L0 = normalize(L0);
|
|
L1 = normalize(L1);
|
|
L2 = normalize(L2);
|
|
L3 = normalize(L3);
|
|
L4 = normalize(L4);
|
|
|
|
// Integrate
|
|
float sum = 0.0;
|
|
|
|
sum += integrate_edge(L0, L1);
|
|
sum += integrate_edge(L1, L2);
|
|
sum += integrate_edge(L2, L3);
|
|
|
|
if (n >= 4) sum += integrate_edge(L3, L4);
|
|
if (n == 5) sum += integrate_edge(L4, L0);
|
|
|
|
return max(0.0, -sum);
|
|
}
|
|
|
|
vec3 sample_light(const vec3 p, const vec3 n, const vec3 v, const float dotnv, const vec3 lp, const vec3 light_col,
|
|
const vec3 albedo, const float rough, const vec3 f0, const float occ
|
|
#ifdef _Voxel
|
|
, sampler3D voxels, vec3 voxpos
|
|
#endif
|
|
) {
|
|
vec3 ld = lp - p;
|
|
vec3 l = normalize(ld);
|
|
float dotnl = max(0.0, dot(n, l));
|
|
|
|
float theta = acos(dotnv);
|
|
vec2 tuv = vec2(rough, theta / (0.5 * PI));
|
|
tuv = tuv * LUT_SCALE + LUT_BIAS;
|
|
vec4 t = textureLod(sltc_mat, tuv, 0.0);
|
|
mat3 inv = mat3(
|
|
vec3(1.0, 0.0, t.y),
|
|
vec3(0.0, t.z, 0.0),
|
|
vec3(t.w, 0.0, t.x));
|
|
float ltcspec = ltc_evaluate(n, v, dotnv, p, inv, light_area0, light_area1, light_area2, light_area3);
|
|
ltcspec *= textureLod(sltc_mag, tuv, 0.0).a;
|
|
|
|
mat3 m1 = mat3(
|
|
vec3(1.0, 0.0, 0.0),
|
|
vec3(0.0, 1.0, 0.0),
|
|
vec3(0.0, 0.0, 1.0));
|
|
float ltcdiff = ltc_evaluate(n, v, dotnv, p, m1, light_area0, light_area1, light_area2, light_area3);
|
|
vec3 direct = albedo * ltcdiff + ltcspec * 0.05;
|
|
|
|
direct *= attenuate(distance(p, lp));
|
|
direct *= light_col;
|
|
direct *= clamp(dotnl + 2.0 * occ * occ - 1.0, 0.0, 1.0); // Micro shadowing
|
|
|
|
#ifdef _Voxel
|
|
float voxshadow = 1.0 - trace_shadow(voxels, voxpos, l);
|
|
direct *= vec3(voxshadow, voxshadow, voxshadow);
|
|
#endif
|
|
|
|
return direct;
|
|
}
|
|
|
|
void main() {
|
|
vec4 g0 = textureLod(gbuffer0, tex_coord, 0.0); // Normal.xy, roughness, metallic/matid
|
|
|
|
vec3 n;
|
|
n.z = 1.0 - abs(g0.x) - abs(g0.y);
|
|
n.xy = n.z >= 0.0 ? g0.xy : octahedron_wrap(g0.xy);
|
|
n = normalize(n);
|
|
|
|
float roughness = g0.b;
|
|
float metallic;
|
|
uint matid;
|
|
unpack_f32_i16(g0.a, metallic, matid);
|
|
vec4 g1 = textureLod(gbuffer1, tex_coord, 0.0); // Basecolor.rgb, occ
|
|
float occ = g1.a;
|
|
vec3 albedo = surface_albedo(g1.rgb, metallic); // g1.rgb - basecolor
|
|
vec3 f0 = surface_f0(g1.rgb, metallic);
|
|
|
|
float depth = textureLod(gbufferD, tex_coord, 0.0).r * 2.0 - 1.0;
|
|
vec3 p = get_pos(eye, eye_look, normalize(view_ray), depth, camera_proj);
|
|
vec3 v = normalize(eye - p);
|
|
float dotnv = max(0.0, dot(n, v));
|
|
|
|
occ = mix(1.0, occ, dotnv); // AO Fresnel
|
|
|
|
vec2 env_brdf = texelFetch(senvmap_brdf, ivec2(vec2(roughness, 1.0 - dotnv) * 256.0), 0).xy;
|
|
|
|
// Envmap
|
|
vec3 envl = sh_irradiance(vec3(n.x * envmap_data.z - n.y * envmap_data.y, n.x * envmap_data.y + n.y * envmap_data.z, n.z), shirr);
|
|
envl /= PI;
|
|
|
|
vec3 reflection_world = reflect(-v, n);
|
|
float lod = mip_from_roughness(roughness, float(envmap_num_mipmaps));
|
|
vec3 prefiltered_color = textureLod(senvmap_radiance, envmap_equirect(reflection_world, envmap_data.x), lod).rgb;
|
|
|
|
envl.rgb *= albedo;
|
|
|
|
// Indirect specular
|
|
envl.rgb += prefiltered_color * (f0 * env_brdf.x + env_brdf.y) * 1.5;
|
|
|
|
envl.rgb *= envmap_data.w * occ;
|
|
|
|
#ifdef _Voxel
|
|
vec3 voxpos = p / voxelgi_half_extents;
|
|
float voxao = 1.0 - trace_ao(voxpos, n, voxels);
|
|
envl.rgb *= vec3(voxao, voxao, voxao);
|
|
#endif
|
|
|
|
frag_color.rgb = envl;
|
|
frag_color.rgb *= textureLod(ssaotex, tex_coord, 0.0).r;
|
|
|
|
if (matid == uint(1)) { // Emission
|
|
frag_color.rgb += g1.rgb; // materialid
|
|
albedo = vec3(0.0, 0.0, 0.0);
|
|
}
|
|
|
|
frag_color.rgb += sample_light(p, n, v, dotnv, point_pos, point_col, albedo, roughness, f0, occ
|
|
#ifdef _Voxel
|
|
, voxels, voxpos
|
|
#endif
|
|
);
|
|
frag_color.a = 1.0; // Mark as opaque
|
|
}
|