Okay, so we're re-doing the render pipeline...!

This commit is contained in:
TriVoxel
2025-04-25 10:17:34 -06:00
parent 06319131fd
commit ddc3a071f4
4 changed files with 388 additions and 438 deletions

View File

@ -4,6 +4,7 @@
#include "std/math.glsl" #include "std/math.glsl"
#include "std/gbuffer.glsl" #include "std/gbuffer.glsl"
uniform samplerCube probeTex;
uniform sampler2D tex; uniform sampler2D tex;
uniform sampler2D gbufferD; uniform sampler2D gbufferD;
uniform sampler2D gbuffer0; // Normal, roughness uniform sampler2D gbuffer0; // Normal, roughness
@ -27,95 +28,106 @@ float depth;
const int numBinarySearchSteps = 7; const int numBinarySearchSteps = 7;
const int maxSteps = int(ceil(1.0 / ssrRayStep) * ssrSearchDist); const int maxSteps = int(ceil(1.0 / ssrRayStep) * ssrSearchDist);
// Project a view-space hit coordinate into screen UVs
vec2 getProjectedCoord(const vec3 hit) { vec2 getProjectedCoord(const vec3 hit) {
vec4 projectedCoord = P * vec4(hit, 1.0); vec4 projectedCoord = P * vec4(hit, 1.0);
projectedCoord.xy /= projectedCoord.w; projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5; projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
#ifdef _InvY #ifdef _InvY
projectedCoord.y = 1.0 - projectedCoord.y; projectedCoord.y = 1.0 - projectedCoord.y;
#endif #endif
return projectedCoord.xy; return projectedCoord.xy;
} }
// Compute depth difference between current ray hit and gbuffer depth
float getDeltaDepth(const vec3 hit) { float getDeltaDepth(const vec3 hit) {
depth = textureLod(gbufferD, getProjectedCoord(hit), 0.0).r * 2.0 - 1.0; depth = textureLod(gbufferD, getProjectedCoord(hit), 0.0).r * 2.0 - 1.0;
vec3 viewPos = getPosView(viewRay, depth, cameraProj); vec3 viewPos = getPosView(viewRay, depth, cameraProj);
return viewPos.z - hit.z; return viewPos.z - hit.z;
} }
// Refine hit using binary search
vec4 binarySearch(vec3 dir) { vec4 binarySearch(vec3 dir) {
float ddepth; float ddepth;
for (int i = 0; i < numBinarySearchSteps; i++) { for (int i = 0; i < numBinarySearchSteps; i++) {
dir *= 0.5; dir *= 0.5;
hitCoord -= dir; hitCoord -= dir;
ddepth = getDeltaDepth(hitCoord); ddepth = getDeltaDepth(hitCoord);
if (ddepth < 0.0) hitCoord += dir; if (ddepth < 0.0) hitCoord += dir;
} }
// Ugly discard of hits too far away #ifdef _CPostprocess
#ifdef _CPostprocess if (abs(ddepth) > PPComp9.z / 500) return vec4(0.0);
if (abs(ddepth) > PPComp9.z / 500) return vec4(0.0); #else
#else if (abs(ddepth) > ssrSearchDist / 500) return vec4(0.0);
if (abs(ddepth) > ssrSearchDist / 500) return vec4(0.0); #endif
#endif return vec4(getProjectedCoord(hitCoord), 0.0, 1.0);
return vec4(getProjectedCoord(hitCoord), 0.0, 1.0);
} }
// Perform raymarching using view-space direction
vec4 rayCast(vec3 dir) { vec4 rayCast(vec3 dir) {
#ifdef _CPostprocess #ifdef _CPostprocess
dir *= PPComp9.x; dir *= PPComp9.x;
#else #else
dir *= ssrRayStep; dir *= ssrRayStep;
#endif #endif
for (int i = 0; i < maxSteps; i++) { for (int i = 0; i < maxSteps; i++) {
hitCoord += dir; hitCoord += dir;
if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir); if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir);
} }
return vec4(0.0); return vec4(0.0);
} }
void main() { void main() {
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
float roughness = unpackFloat(g0.b).y; float roughness = unpackFloat(g0.b).y;
if (roughness == 1.0) { fragColor.rgb = vec3(0.0); return; } if (roughness >= 1.0) { fragColor.rgb = vec3(0.0); return; }
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a); float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
if (spec == 0.0) { fragColor.rgb = vec3(0.0); return; } if (spec == 0.0) { fragColor.rgb = vec3(0.0); return; }
float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
if (d == 1.0) { fragColor.rgb = vec3(0.0); return; } if (d == 1.0) { fragColor.rgb = vec3(0.0); return; }
vec2 enc = g0.rg; // Decode octahedral normal
vec3 n; vec2 enc = g0.rg;
n.z = 1.0 - abs(enc.x) - abs(enc.y); vec3 n;
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy); n.z = 1.0 - abs(enc.x) - abs(enc.y);
n = normalize(n); n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
n = normalize(n);
vec3 viewNormal = normalize(V3 * n);
vec3 viewNormal = V3 * n; // View-space position and reflection
vec3 viewPos = getPosView(viewRay, d, cameraProj); vec3 viewPos = getPosView(viewRay, d, cameraProj);
vec3 reflected = reflect(viewPos, viewNormal); vec3 viewDir = normalize(viewPos);
hitCoord = viewPos; vec3 reflected = normalize(reflect(viewDir, viewNormal));
#ifdef _CPostprocess hitCoord = viewPos;
vec3 dir = reflected * (1.0 - rand(texCoord) * PPComp10.y * roughness) * 2.0;
#else
vec3 dir = reflected * (1.0 - rand(texCoord) * ssrJitter * roughness) * 2.0;
#endif
// * max(ssrMinRayStep, -viewPos.z) // Importance sampling jitter based on roughness
vec4 coords = rayCast(dir); float jitterStrength = roughness * roughness;
vec3 randVec = normalize(vec3(rand(texCoord), rand(texCoord * 1.3), rand(texCoord * 2.7)) * 2.0 - 1.0);
vec3 dir = normalize(mix(reflected, randVec, jitterStrength));
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy); vec4 coords = rayCast(dir);
float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0); vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0);
float reflectivity = 1.0 - roughness; float reflectivity = 1.0 - roughness;
#ifdef _CPostprocess #ifdef _CPostprocess
float intensity = pow(reflectivity, PPComp10.x) * screenEdgeFactor * clamp(-reflected.z, 0.0, 1.0) * clamp((PPComp9.z - length(viewPos - hitCoord)) * (1.0 / PPComp9.z), 0.0, 1.0) * coords.w; float distAtten = clamp((PPComp9.z - length(viewPos - hitCoord)) / PPComp9.z, 0.0, 1.0);
#else float intensity = pow(reflectivity, PPComp10.x) * screenEdgeFactor * clamp(-reflected.z, 0.0, 1.0) * distAtten * coords.w;
float intensity = pow(reflectivity, ssrFalloffExp) * screenEdgeFactor * clamp(-reflected.z, 0.0, 1.0) * clamp((ssrSearchDist - length(viewPos - hitCoord)) * (1.0 / ssrSearchDist), 0.0, 1.0) * coords.w; #else
#endif float distAtten = clamp((ssrSearchDist - length(viewPos - hitCoord)) / ssrSearchDist, 0.0, 1.0);
float intensity = pow(reflectivity, ssrFalloffExp) * screenEdgeFactor * clamp(-reflected.z, 0.0, 1.0) * distAtten * coords.w;
#endif
intensity = clamp(intensity, 0.0, 1.0); intensity = clamp(intensity, 0.0, 1.0);
vec3 reflCol = textureLod(tex, coords.xy, 0.0).rgb; vec3 ssrColor = textureLod(tex, coords.xy, roughness * 4.0).rgb;
reflCol = clamp(reflCol, 0.0, 1.0); ssrColor = clamp(ssrColor, 0.0, 1.0);
fragColor.rgb = reflCol * intensity * 0.5;
// Cubemap fallback with roughness-aware LOD sampling
vec3 cubemapColor = textureLod(probeTex, reflected, roughness * 6.0).rgb;
// Additively blend SSR with cubemap fallback
fragColor.rgb = mix(cubemapColor, ssrColor, intensity) * spec;
} }

View File

@ -1,8 +1,10 @@
#ifndef _BRDF_GLSL_ #ifndef _BRDF_GLSL_
#define _BRDF_GLSL_ #define _BRDF_GLSL_
// http://xlgames-inc.github.io/posts/improvedibl/ // Constants
// http://blog.selfshadow.com/publications/s2013-shading-course/ //const float PI = 3.1415926535;
// Fresnel-Schlick with optimized exponential approximation
vec3 f_schlick(const vec3 f0, const float vh) { vec3 f_schlick(const vec3 f0, const float vh) {
return f0 + (1.0 - f0) * exp2((-5.55473 * vh - 6.98316) * vh); return f0 + (1.0 - f0) * exp2((-5.55473 * vh - 6.98316) * vh);
} }
@ -11,82 +13,11 @@ float v_smithschlick(const float nl, const float nv, const float a) {
return 1.0 / ((nl * (1.0 - a) + a) * (nv * (1.0 - a) + a)); return 1.0 / ((nl * (1.0 - a) + a) * (nv * (1.0 - a) + a));
} }
//Uncorrelated masking/shadowing (info below) function
//Because it is uncorrelated, G1(NdotL, a) gives us shadowing, and G1(NdotV, a) gives us masking function.
//Approximation from: https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2017/Presentations/Hammon_Earl_PBR_Diffuse_Lighting.pdf
float g1_approx(const float NdotX, const float alpha)
{
return (2.0 * NdotX) * (1.0 / (NdotX * (2.0 - alpha) + alpha));
}
//Uncorrelated masking-shadowing function
//Approximation from: https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2017/Presentations/Hammon_Earl_PBR_Diffuse_Lighting.pdf
float g2_approx(const float NdotL, const float NdotV, const float alpha)
{
vec2 helper = (2.0 * vec2(NdotL, NdotV)) * (1.0 / (vec2(NdotL, NdotV) * (2.0 - alpha) + alpha));
return max(helper.x * helper.y, 0.0); //This can go negative, let's fix that
}
float d_ggx(const float nh, const float a) { float d_ggx(const float nh, const float a) {
float a2 = a * a; float a2 = a * a;
float denom = nh * nh * (a2 - 1.0) + 1.0; float denom = nh * nh * (a2 - 1.0) + 1.0;
denom = max(denom * denom, 0.00006103515625 /* 2^-14 = smallest possible half float value, prevent div by zero */); denom = max(denom * denom, 2e-6);
return a2 * (1.0 / 3.1415926535) / denom; return a2 / (PI * denom);
}
vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) {
float a = roughness * roughness;
return d_ggx(nh, a) * g2_approx(nl, nv, a) * f_schlick(f0, vh) / max(4.0 * nv, 1e-5); //NdotL cancels out later
}
// John Hable - Optimizing GGX Shaders
// http://filmicworlds.com/blog/optimizing-ggx-shaders-with-dotlh/
vec3 specularBRDFb(const vec3 f0, const float roughness, const float dotNL, const float dotNH, const float dotLH) {
// D
const float pi = 3.1415926535;
float alpha = roughness * roughness;
float alphaSqr = alpha * alpha;
float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0;
float D = alphaSqr / (pi * denom * denom);
// F
const float F_a = 1.0;
float F_b = pow(1.0 - dotLH, 5.0);
// V
float vis;
float k = alpha / 2.0;
float k2 = k * k;
float invK2 = 1.0 - k2;
vis = 1.0 / (dotLH * dotLH * invK2 + k2);
vec2 FV_helper = vec2((F_a - F_b) * vis, F_b * vis);
vec3 FV = f0 * FV_helper.x + FV_helper.y;
vec3 specular = clamp(dotNL, 0.0, 1.0) * D * FV;
return specular / 4.0; // TODO: get rid of / 4.0
}
vec3 orenNayarDiffuseBRDF(const vec3 albedo, const float roughness, const float nv, const float nl, const float vh) {
float a = roughness * roughness;
float s = a;
float s2 = s * s;
float vl = 2.0 * vh * vh - 1.0; // Double angle identity
float Cosri = vl - nv * nl;
float C1 = 1.0 - 0.5 * s2 / (s2 + 0.33);
float test = 1.0;
if (Cosri >= 0.0) test = (1.0 / (max(nl, nv)));
float C2 = 0.45 * s2 / (s2 + 0.09) * Cosri * test;
return albedo * max(0.0, nl) * (C1 + C2) * (1.0 + roughness * 0.5);
}
vec3 lambertDiffuseBRDF(const vec3 albedo, const float nl) {
return albedo * nl;
}
vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) {
return mix(baseColor, vec3(0.0), metalness);
}
vec3 surfaceF0(const vec3 baseColor, const float metalness) {
return mix(vec3(0.04), baseColor, metalness);
} }
float getMipFromRoughness(const float roughness, const float numMipmaps) { float getMipFromRoughness(const float roughness, const float numMipmaps) {
@ -94,47 +25,64 @@ float getMipFromRoughness(const float roughness, const float numMipmaps) {
return roughness * numMipmaps; return roughness * numMipmaps;
} }
float wardSpecular(vec3 N, vec3 H, float dotNL, float dotNV, float dotNH, vec3 fiberDirection, float shinyParallel, float shinyPerpendicular) { vec3 specularBRDF(vec3 N, vec3 V, vec3 L, vec3 F0, float roughness)
if(dotNL < 0.0 || dotNV < 0.0) { {
return 0.0; vec3 H = normalize(V + L);
}
// fiberDirection - parse from rotation
// shinyParallel - roughness
// shinyPerpendicular - anisotropy
vec3 fiberParallel = normalize(fiberDirection); float NdotL = max(dot(N, L), 0.0);
vec3 fiberPerpendicular = normalize(cross(N, fiberDirection)); float NdotV = max(dot(N, V), 0.0);
float dotXH = dot(fiberParallel, H); float NdotH = max(dot(N, H), 0.0);
float dotYH = dot(fiberPerpendicular, H); float VdotH = max(dot(V, H), 0.0);
const float PI = 3.1415926535;
float coeff = sqrt(dotNL/dotNV) / (4.0 * PI * shinyParallel * shinyPerpendicular); float alpha = roughness * roughness;
float theta = (pow(dotXH/shinyParallel, 2.0) + pow(dotYH/shinyPerpendicular, 2.0)) / (1.0 + dotNH);
return clamp(coeff * exp(-2.0 * theta), 0.0, 1.0); float D = d_ggx(NdotH, alpha);
float k = alpha / 2.0;
float G_V = NdotV / (NdotV * (1.0 - k) + k + 1e-5);
float G_L = NdotL / (NdotL * (1.0 - k) + k + 1e-5);
float G = G_V * G_L;
vec3 F = f_schlick(F0, VdotH);
return F * D * G / max(4.0 * NdotL * NdotV, 1e-5);
} }
// https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile vec3 burleyDiffuseBRDF(vec3 N, vec3 V, vec3 L, vec3 albedo, float roughness)
// vec3 EnvBRDFApprox(vec3 SpecularColor, float Roughness, float NoV) { {
// const vec4 c0 = { -1, -0.0275, -0.572, 0.022 }; float NdotL = max(dot(N, L), 0.0);
// const vec4 c1 = { 1, 0.0425, 1.04, -0.04 }; float NdotV = max(dot(N, V), 0.0);
// vec4 r = Roughness * c0 + c1; float LdotH = max(dot(L, normalize(L + V)), 0.0);
// float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
// vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw; float FD90 = 0.5 + 2.0 * LdotH * LdotH * roughness;
// return SpecularColor * AB.x + AB.y; float FL = pow(1.0 - NdotL, 5.0);
// } float FV = pow(1.0 - NdotV, 5.0);
// float EnvBRDFApproxNonmetal(float Roughness, float NoV) {
// // Same as EnvBRDFApprox( 0.04, Roughness, NoV ) float diffuse = (1.0 + (FD90 - 1.0) * FL) * (1.0 + (FD90 - 1.0) * FV);
// const vec2 c0 = { -1, -0.0275 }; return albedo * (1.0 / PI) * diffuse * NdotL;
// const vec2 c1 = { 1, 0.0425 }; }
// vec2 r = Roughness * c0 + c1;
// return min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y; // Energy-conserving material albedo (fades out for metals)
// } vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) {
float D_Approx(const float Roughness, const float RoL) { return baseColor * (1.0 - metalness);
float a = Roughness * Roughness; }
float a2 = a * a;
float rcp_a2 = 1.0 / a2;//rcp(a2); // Metal-aware F0 blending
// 0.5 / ln(2), 0.275 / ln(2) vec3 surfaceF0(vec3 baseColor, float metalness) {
float c = 0.72134752 * rcp_a2 + 0.39674113; return mix(vec3(0.04), baseColor, metalness);
return rcp_a2 * exp2( c * RoL - c ); }
// LUT-based approximation of IBL BRDF (Unreal-style)
vec2 EnvBRDFApprox(float Roughness, float NoV) {
const vec4 c0 = vec4(-1, -0.0275, -0.572, 0.022);
const vec4 c1 = vec4(1, 0.0425, 1.04, -0.04);
vec4 r = Roughness * c0 + c1;
float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;
return vec2(-1.04, 1.04) * a004 + r.zw;
}
vec3 IBLSpecularApprox(vec3 specColor, float roughness, float NoV) {
vec2 brdf = EnvBRDFApprox(roughness, NoV);
return specColor * brdf.x + brdf.y;
} }
#endif #endif

View File

@ -15,12 +15,10 @@ vec3 getNor(const vec2 enc) {
vec3 getPosView(const vec3 viewRay, const float depth, const vec2 cameraProj) { vec3 getPosView(const vec3 viewRay, const float depth, const vec2 cameraProj) {
float linearDepth = cameraProj.y / (cameraProj.x - depth); float linearDepth = cameraProj.y / (cameraProj.x - depth);
//float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
return viewRay * linearDepth; return viewRay * linearDepth;
} }
vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) { vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) {
// eyeLook, viewRay should be normalized
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x); float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
float viewZDist = dot(eyeLook, viewRay); float viewZDist = dot(eyeLook, viewRay);
vec3 wposition = eye + viewRay * (linearDepth / viewZDist); vec3 wposition = eye + viewRay * (linearDepth / viewZDist);
@ -28,7 +26,6 @@ vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float
} }
vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) { vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) {
// eyeLook, viewRay should be normalized
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x); float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
float viewZDist = dot(eyeLook, viewRay); float viewZDist = dot(eyeLook, viewRay);
vec3 wposition = viewRay * (linearDepth / viewZDist); vec3 wposition = viewRay * (linearDepth / viewZDist);
@ -71,6 +68,7 @@ vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, const vec
return pos.xyz - eye; return pos.xyz - eye;
} }
// Updated to support separate roughness/metalness storage
float packFloat(const float f1, const float f2) { float packFloat(const float f1, const float f2) {
return floor(f1 * 100.0) + min(f2, 1.0 - 1.0 / 100.0); return floor(f1 * 100.0) + min(f2, 1.0 - 1.0 / 100.0);
} }
@ -80,7 +78,6 @@ vec2 unpackFloat(const float f) {
} }
float packFloat2(const float f1, const float f2) { float packFloat2(const float f1, const float f2) {
// Higher f1 = less precise f2
return floor(f1 * 255.0) + min(f2, 1.0 - 1.0 / 100.0); return floor(f1 * 255.0) + min(f2, 1.0 - 1.0 / 100.0);
} }
@ -101,21 +98,16 @@ vec3 decodeRGBM(const vec4 rgbm) {
return rgbm.rgb * rgbm.a * maxRange; return rgbm.rgb * rgbm.a * maxRange;
} }
vec2 signNotZero(vec2 v) vec2 signNotZero(vec2 v) {
{
return vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0); return vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);
} }
vec2 encode_oct(vec3 v) vec2 encode_oct(vec3 v) {
{
// Project the sphere onto the octahedron, and then onto the xy plane
vec2 p = v.xy * (1.0 / (abs(v.x) + abs(v.y) + abs(v.z))); vec2 p = v.xy * (1.0 / (abs(v.x) + abs(v.y) + abs(v.z)));
// Reflect the folds of the lower hemisphere over the diagonals
return (v.z <= 0.0) ? ((1.0 - abs(p.yx)) * signNotZero(p)) : p; return (v.z <= 0.0) ? ((1.0 - abs(p.yx)) * signNotZero(p)) : p;
} }
vec3 decode_oct(vec2 e) vec3 decode_oct(vec2 e) {
{
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
if (v.z < 0) v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy); if (v.z < 0) v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);
return normalize(v); return normalize(v);
@ -147,9 +139,6 @@ vec3 decNor(uint val) {
return normal; return normal;
} }
/**
Packs a float in [0, 1] and an integer in [0..15] into a single 16 bit float value.
**/
float packFloatInt16(const float f, const uint i) { float packFloatInt16(const float f, const uint i) {
const uint numBitFloat = 12; const uint numBitFloat = 12;
const float maxValFloat = float((1 << numBitFloat) - 1); const float maxValFloat = float((1 << numBitFloat) - 1);
@ -165,9 +154,8 @@ void unpackFloatInt16(const float val, out float f, out uint i) {
const float maxValFloat = float((1 << numBitFloat) - 1); const float maxValFloat = float((1 << numBitFloat) - 1);
const uint bitsValue = uint(val); const uint bitsValue = uint(val);
i = bitsValue >> numBitFloat; i = bitsValue >> numBitFloat;
f = (bitsValue & ~(0xF << numBitFloat)) / maxValFloat; f = (bitsValue & ~(0xF << numBitFloat)) / maxValFloat;
} }
#endif #endif

View File

@ -1,239 +1,241 @@
#ifndef _LIGHT_GLSL_ #ifndef _LIGHT_GLSL_
#define _LIGHT_GLSL_ #define _LIGHT_GLSL_
#include "compiled.inc" #include "compiled.inc"
#include "std/brdf.glsl" #include "std/brdf.glsl"
#include "std/math.glsl" #include "std/math.glsl"
#ifdef _ShadowMap #ifdef _ShadowMap
#include "std/shadows.glsl" #include "std/shadows.glsl"
#endif #endif
#ifdef _VoxelShadow #ifdef _VoxelShadow
#include "std/conetrace.glsl" #include "std/conetrace.glsl"
//!uniform sampler2D voxels_shadows; //!uniform sampler2D voxels_shadows;
#endif #endif
#ifdef _LTC #ifdef _LTC
#include "std/ltc.glsl" #include "std/ltc.glsl"
#endif #endif
#ifdef _LightIES #ifdef _LightIES
#include "std/ies.glsl" #include "std/ies.glsl"
#endif #endif
#ifdef _SSRS #ifdef _SSRS
#include "std/ssrs.glsl" #include "std/ssrs.glsl"
#endif #endif
#ifdef _Spot #ifdef _Spot
#include "std/light_common.glsl" #include "std/light_common.glsl"
#endif #endif
#ifdef _ShadowMap #ifdef _ShadowMap
#ifdef _SinglePoint #ifdef _SinglePoint
#ifdef _Spot #ifdef _Spot
#ifndef _LTC #ifndef _LTC
uniform sampler2DShadow shadowMapSpot[1]; uniform sampler2DShadow shadowMapSpot[1];
uniform sampler2D shadowMapSpotTransparent[1]; uniform sampler2D shadowMapSpotTransparent[1];
uniform mat4 LWVPSpot[1]; uniform mat4 LWVPSpot[1];
#endif #endif
#else #else
uniform samplerCubeShadow shadowMapPoint[1]; uniform samplerCubeShadow shadowMapPoint[1];
uniform samplerCube shadowMapPointTransparent[1]; uniform samplerCube shadowMapPointTransparent[1];
uniform vec2 lightProj; uniform vec2 lightProj;
#endif #endif
#endif #endif
#ifdef _Clusters #ifdef _Clusters
#ifdef _SingleAtlas #ifdef _SingleAtlas
//!uniform sampler2DShadow shadowMapAtlas; //!uniform sampler2DShadow shadowMapAtlas;
//!uniform sampler2D shadowMapAtlasTransparent; //!uniform sampler2D shadowMapAtlasTransparent;
#endif #endif
uniform vec2 lightProj; uniform vec2 lightProj;
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
#ifndef _SingleAtlas #ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasPoint; uniform sampler2DShadow shadowMapAtlasPoint;
uniform sampler2D shadowMapAtlasPointTransparent; uniform sampler2D shadowMapAtlasPointTransparent;
#endif #endif
#else #else
uniform samplerCubeShadow shadowMapPoint[4]; uniform samplerCubeShadow shadowMapPoint[4];
uniform samplerCube shadowMapPointTransparent[4]; uniform samplerCube shadowMapPointTransparent[4];
#endif #endif
#ifdef _Spot #ifdef _Spot
#ifdef _ShadowMapAtlas #ifdef _ShadowMapAtlas
#ifndef _SingleAtlas #ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasSpot; uniform sampler2DShadow shadowMapAtlasSpot;
uniform sampler2D shadowMapAtlasSpotTransparent; uniform sampler2D shadowMapAtlasSpotTransparent;
#endif #endif
#else #else
uniform sampler2DShadow shadowMapSpot[4]; uniform sampler2DShadow shadowMapSpot[4];
uniform sampler2D shadowMapSpotTransparent[4]; uniform sampler2D shadowMapSpotTransparent[4];
#endif #endif
uniform mat4 LWVPSpotArray[maxLightsCluster]; uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif #endif
#endif #endif
#endif #endif
#ifdef _LTC #ifdef _LTC
uniform vec3 lightArea0; uniform vec3 lightArea0;
uniform vec3 lightArea1; uniform vec3 lightArea1;
uniform vec3 lightArea2; uniform vec3 lightArea2;
uniform vec3 lightArea3; uniform vec3 lightArea3;
uniform sampler2D sltcMat; uniform sampler2D sltcMat;
uniform sampler2D sltcMag; uniform sampler2D sltcMag;
#ifdef _ShadowMap #ifdef _ShadowMap
#ifndef _Spot #ifndef _Spot
#ifdef _SinglePoint #ifdef _SinglePoint
uniform sampler2DShadow shadowMapSpot[1]; uniform sampler2DShadow shadowMapSpot[1];
uniform sampler2D shadowMapSpotTransparent[1]; uniform sampler2D shadowMapSpotTransparent[1];
uniform mat4 LWVPSpot[1]; uniform mat4 LWVPSpot[1];
#endif #endif
#ifdef _Clusters #ifdef _Clusters
uniform sampler2DShadow shadowMapSpot[maxLightsCluster]; uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
uniform sampler2D shadowMapSpotTransparent[maxLightsCluster]; uniform sampler2D shadowMapSpotTransparent[maxLightsCluster];
uniform mat4 LWVPSpotArray[maxLightsCluster]; uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif #endif
#endif #endif
#endif #endif
#endif #endif
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol, vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
const vec3 albedo, const float rough, const float spec, const vec3 f0 const vec3 albedo, const float rough, const float spec, const vec3 f0
#ifdef _ShadowMap #ifdef _ShadowMap
, int index, float bias, bool receiveShadow, bool transparent , int index, float bias, bool receiveShadow, bool transparent
#endif #endif
#ifdef _Spot #ifdef _Spot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right , const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif #endif
#ifdef _VoxelShadow #ifdef _VoxelShadow
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount] , sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount]
#endif #endif
#ifdef _MicroShadowing #ifdef _MicroShadowing
, float occ , float occ
#endif #endif
#ifdef _SSRS #ifdef _SSRS
, sampler2D gbufferD, mat4 invVP, vec3 eye , sampler2D gbufferD, mat4 invVP, vec3 eye
#endif #endif
) { ) {
vec3 ld = lp - p; vec3 ld = lp - p;
vec3 l = normalize(ld); vec3 l = normalize(ld);
vec3 h = normalize(v + l); vec3 h = normalize(v + l);
float dotNH = max(0.0, dot(n, h)); float dotNH = max(0.0, dot(n, h));
float dotVH = max(0.0, dot(v, h)); float dotVH = max(0.0, dot(v, h));
float dotNL = max(0.0, dot(n, l)); float dotNL = max(0.0, dot(n, l));
#ifdef _LTC #ifdef _LTC
float theta = acos(dotNV); float theta = acos(dotNV);
vec2 tuv = vec2(rough, theta / (0.5 * PI)); vec2 tuv = vec2(rough, theta / (0.5 * PI));
tuv = tuv * LUT_SCALE + LUT_BIAS; tuv = tuv * LUT_SCALE + LUT_BIAS;
vec4 t = textureLod(sltcMat, tuv, 0.0); vec4 t = textureLod(sltcMat, tuv, 0.0);
mat3 invM = mat3( mat3 invM = mat3(
vec3(1.0, 0.0, t.y), vec3(1.0, 0.0, t.y),
vec3(0.0, t.z, 0.0), vec3(0.0, t.z, 0.0),
vec3(t.w, 0.0, t.x)); vec3(t.w, 0.0, t.x));
float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3); float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3);
ltcspec *= textureLod(sltcMag, tuv, 0.0).a; ltcspec *= textureLod(sltcMag, tuv, 0.0).a;
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3); float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05; vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
#else #else
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) + vec3 F0 = surfaceF0(albedo, spec); // spec used as the metalness value
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
#endif vec3 direct = burleyDiffuseBRDF(n, v, l, albedo, rough) * (1.0 - spec) +
specularBRDF(n, v, l, f0, rough) * spec;
direct *= attenuate(distance(p, lp)); #endif
direct *= lightCol;
direct *= attenuate(distance(p, lp));
#ifdef _MicroShadowing direct *= lightCol;
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
#endif #ifdef _MicroShadowing
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
#ifdef _SSRS #endif
direct *= traceShadowSS(l, p, gbufferD, invVP, eye);
#endif #ifdef _SSRS
direct *= traceShadowSS(l, p, gbufferD, invVP, eye);
#ifdef _VoxelShadow #endif
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps, gl_FragCoord.xy).r) * voxelgiShad;
#endif #ifdef _VoxelShadow
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps, gl_FragCoord.xy).r) * voxelgiShad;
#ifdef _LTC #endif
#ifdef _ShadowMap
if (receiveShadow) { #ifdef _LTC
#ifdef _SinglePoint #ifdef _ShadowMap
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0); if (receiveShadow) {
direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent); #ifdef _SinglePoint
#endif vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
#ifdef _Clusters direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0); #endif
if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent); #ifdef _Clusters
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent); vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent); if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent); else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent);
#endif else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent);
} else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent);
#endif #endif
return direct; }
#endif #endif
return direct;
#ifdef _Spot #endif
if (isSpot) {
direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend); #ifdef _Spot
if (isSpot) {
#ifdef _ShadowMap direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
if (receiveShadow) {
#ifdef _SinglePoint #ifdef _ShadowMap
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0); if (receiveShadow) {
direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent); #ifdef _SinglePoint
#endif vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
#ifdef _Clusters direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0); #endif
#ifdef _ShadowMapAtlas #ifdef _Clusters
direct *= shadowTest( vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
#ifndef _SingleAtlas #ifdef _ShadowMapAtlas
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent direct *= shadowTest(
#else #ifndef _SingleAtlas
shadowMapAtlas, shadowMapAtlasTransparent shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
#endif #else
, lPos.xyz / lPos.w, bias, transparent shadowMapAtlas, shadowMapAtlasTransparent
); #endif
#else , lPos.xyz / lPos.w, bias, transparent
if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent); );
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent); #else
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent); if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent); else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent);
#endif else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent);
#endif else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent);
} #endif
#endif #endif
return direct; }
} #endif
#endif return direct;
}
#ifdef _LightIES #endif
direct *= iesAttenuation(-l);
#endif #ifdef _LightIES
direct *= iesAttenuation(-l);
#ifdef _ShadowMap #endif
if (receiveShadow) {
#ifdef _SinglePoint #ifdef _ShadowMap
#ifndef _Spot if (receiveShadow) {
direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent); #ifdef _SinglePoint
#endif #ifndef _Spot
#endif direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent);
#ifdef _Clusters #endif
#ifdef _ShadowMapAtlas #endif
direct *= PCFFakeCube( #ifdef _Clusters
#ifndef _SingleAtlas #ifdef _ShadowMapAtlas
shadowMapAtlasPoint, shadowMapAtlasPointTransparent direct *= PCFFakeCube(
#else #ifndef _SingleAtlas
shadowMapAtlas, shadowMapAtlasTransparent shadowMapAtlasPoint, shadowMapAtlasPointTransparent
#endif #else
, ld, -l, bias, lightProj, n, index, transparent shadowMapAtlas, shadowMapAtlasTransparent
); #endif
#else , ld, -l, bias, lightProj, n, index, transparent
if (index == 0) direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent); );
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], shadowMapPointTransparent[1], ld, -l, bias, lightProj, n, transparent); #else
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], shadowMapPointTransparent[2], ld, -l, bias, lightProj, n, transparent); if (index == 0) direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent);
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], shadowMapPointTransparent[3], ld, -l, bias, lightProj, n, transparent); else if (index == 1) direct *= PCFCube(shadowMapPoint[1], shadowMapPointTransparent[1], ld, -l, bias, lightProj, n, transparent);
#endif else if (index == 2) direct *= PCFCube(shadowMapPoint[2], shadowMapPointTransparent[2], ld, -l, bias, lightProj, n, transparent);
#endif else if (index == 3) direct *= PCFCube(shadowMapPoint[3], shadowMapPointTransparent[3], ld, -l, bias, lightProj, n, transparent);
} #endif
#endif #endif
}
return direct; #endif
}
return direct;
#endif }
#endif