Full BSDF

This commit is contained in:
2026-08-07 02:04:01 -07:00
parent 7aeebf2008
commit fe017dd874
55 changed files with 2306 additions and 1215 deletions

View File

@ -6,6 +6,7 @@
uniform sampler2D tex;
uniform sampler2D gbuffer0; // Roughness
uniform sampler2D gbufferD; // Depth
uniform vec2 dirInv;
@ -14,19 +15,46 @@ out vec4 fragColor;
void main() {
float roughness = textureLod(gbuffer0, texCoord, 0.0).b;
// if (roughness == 0.0) { // Always blur for now, non blured output can produce noise
// fragColor.rgb = textureLod(tex, texCoord).rgb;
// return;
// }
if (roughness >= 0.8) { // No reflections
if (roughness >= 0.8) {
fragColor.rgb = textureLod(tex, texCoord, 0.0).rgb;
return;
}
fragColor.rgb = textureLod(tex, texCoord + dirInv * 2.5, 0.0).rgb;
fragColor.rgb += textureLod(tex, texCoord + dirInv * 1.5, 0.0).rgb;
fragColor.rgb += textureLod(tex, texCoord, 0.0).rgb;
fragColor.rgb += textureLod(tex, texCoord - dirInv * 1.5, 0.0).rgb;
fragColor.rgb += textureLod(tex, texCoord - dirInv * 2.5, 0.0).rgb;
fragColor.rgb /= vec3(5.0);
if (roughness < 0.01) {
fragColor.rgb = textureLod(tex, texCoord, 0.0).rgb;
return;
}
float blurRadius = 1.0 + roughness * 4.0;
vec3 center = textureLod(tex, texCoord, 0.0).rgb;
float centerDepth = textureLod(gbufferD, texCoord, 0.0).r;
float w0 = 1.0 / (1.0 + roughness * 2.0);
float w1 = 1.0 / (1.0 + roughness);
float w2 = 1.0 / (1.0 + roughness * 0.5);
float totalW = w0;
fragColor.rgb = center * w0;
vec2 offsets[4];
offsets[0] = dirInv * blurRadius * 2.5;
offsets[1] = dirInv * blurRadius * 1.5;
offsets[2] = -dirInv * blurRadius * 1.5;
offsets[3] = -dirInv * blurRadius * 2.5;
float weights[4];
weights[0] = w2;
weights[1] = w1;
weights[2] = w1;
weights[3] = w2;
for (int i = 0; i < 4; i++) {
vec2 sampleTC = texCoord + offsets[i];
float sampleDepth = textureLod(gbufferD, sampleTC, 0.0).r;
float depthWeight = exp(-abs(centerDepth - sampleDepth) * 100.0);
float w = weights[i] * depthWeight;
fragColor.rgb += textureLod(tex, sampleTC, 0.0).rgb * w;
totalW += w;
}
fragColor.rgb /= vec3(totalW);
}

View File

@ -17,12 +17,12 @@ in vec3 wnormal;
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
| GBUF_IDX_1 | || base color (RGB) | occlusion/specular |
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
| GBUF_IDX_2 | _gbuffer2 || velocity (XY) | ignore radiance | unused |
| GBUF_IDX_2 | _gbuffer2 || velocity (XY) | ignore radiance | tangent angle |
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
| GBUF_IDX_EMISSION | _EmissionShaded || emission color (RGB) | unused |
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
| GBUF_IDX_3 | _Anisotropy || world tangent (XYZ) | unused |
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
| GBUF_IDX_REFRACTION | _SSRefraction || packed IOR | transmittance | surfaceDepth | unused |
| | _VoxelRefract || (0-1 range) | | | |
The indices as well as the GBUF_SIZE define are defined in "compiled.inc".
*/
@ -54,10 +54,10 @@ void main() {
#endif
#ifdef _SSRefraction
fragColor[GBUF_IDX_REFRACTION] = vec4(ior, opacity, 0.0, 0.0);
fragColor[GBUF_IDX_REFRACTION] = vec4(packIOR(ior), opacity, 0.0, 1.0);
#endif
#ifdef _Anisotropy
fragColor[GBUF_IDX_3] = vec4(0.0, 0.0, 0.0, 0.0);
fragColor[GBUF_IDX_2].a = -1.0;
#endif
}

View File

@ -7,7 +7,11 @@ out vec4 fragColor[GBUF_SIZE];
void main() {
fragColor[GBUF_IDX_0] = vec4(1.0, 1.0, 0.0, 1.0);
#if GBUF_SIZE > 1
fragColor[GBUF_IDX_1] = vec4(color, 1.0);
#else
fragColor[GBUF_IDX_0] = vec4(color, 1.0);
#endif
#ifdef _EmissionShaded
fragColor[GBUF_IDX_EMISSION] = vec4(0.0);

View File

@ -8,9 +8,6 @@
#ifdef _Irr
#include "std/shirr.glsl"
#endif
#ifdef _SSS
#include "std/sss.glsl"
#endif
#ifdef _SSRS
#include "std/ssrs.glsl"
#endif
@ -23,12 +20,12 @@ uniform sampler2D gbuffer1;
#ifdef _gbuffer2
uniform sampler2D gbuffer2;
#endif
#ifdef _Anisotropy
uniform sampler2D gbuffer3;
#endif
#ifdef _EmissionShaded
uniform sampler2D gbufferEmission;
#endif
#ifdef _ClearCoat
uniform sampler2D gbufferCoatNormal;
#endif
#ifdef _VoxelGI
uniform sampler2D voxels_diffuse;
@ -95,7 +92,7 @@ uniform mat4 invVP;
#ifdef _SinglePoint
//!uniform sampler2DShadow shadowMapSpot[1];
//!uniform sampler2D shadowMapSpotTransparent[1];
//!uniform mat4 LWVPSpot[1];
//!uniform mat4 LWVPSpotArray[1];
#endif
#ifdef _Clusters
//!uniform sampler2DShadow shadowMapSpot[4];
@ -140,7 +137,7 @@ uniform vec2 cameraPlane;
#ifdef _ShadowMapTransparent
//!uniform sampler2D shadowMapSpotTransparent[1];
#endif
//!uniform mat4 LWVPSpot[1];
//!uniform mat4 LWVPSpotArray[1];
#else
//!uniform samplerCubeShadow shadowMapPoint[1];
#ifdef _ShadowMapTransparent
@ -203,6 +200,7 @@ uniform vec3 sunCol;
uniform sampler2D shadowMapAtlasSunTransparent;
#endif
#endif
//!uniform vec4 tileBoundsSunArray[maxLights * shadowmapCascades];
#else
uniform sampler2DShadow shadowMap;
#ifdef _ShadowMapTransparent
@ -239,6 +237,9 @@ uniform float time;
#endif
#include "std/light.glsl"
#ifdef _SSS
#include "std/sss.glsl"
#endif
in vec2 texCoord;
in vec3 viewRay;
@ -262,8 +263,26 @@ void main() {
matid = min(matid, uint(MAX_MATERIALS - 1));
//!uniform vec4 materialParams[MAX_MATERIALS * 8];
vec4 matp0, matp1, matp2, matp3, matp4, matp5, matp6;
getMaterialParams(matid, matp0, matp1, matp2, matp3, matp4, matp5, matp6);
vec4 matp0 = vec4(0.0), matp1 = vec4(0.0), matp2 = vec4(0.0), matp3 = vec4(0.0);
vec4 matp4 = vec4(0.0), matp5 = vec4(0.0), matp6 = vec4(0.0), matp7 = vec4(0.0);
// TODO: coatIOR=1.5, ior=1.45, thinWall=1.0 move to python make files
matp1.z = 1.5;
matp3.x = 1.45;
matp3.y = 1.0;
if (matid >= 3u) {
getMaterialParams(matid, matp0, matp1, matp2, matp3, matp4, matp5, matp6, matp7);
}
#ifdef _ClearCoat
vec3 coatTintCol = vec3(matp1.w, matp2.x, matp2.y);
#endif
#ifdef _Sheen
vec3 sheenTintCol = vec3(matp5.z, matp5.w, matp6.x);
#endif
#ifdef _SSS
vec3 sssColorVal = vec3(matp4.w, matp5.x, matp5.y);
vec3 sssRadiusBase = vec3(matp4.x, matp4.y, matp4.z);
float sssRadiusScalar = max(max(matp4.x, matp4.y), matp4.z) * matp7.x;
#endif
#endif
vec2 occspec = unpackFloat2(g1.a);
@ -271,7 +290,10 @@ void main() {
vec3 basecolor = min(g1.rgb, vec3(2.0));
vec3 albedo = surfaceAlbedo(basecolor, metallic);
vec3 f0 = surfaceF0(basecolor, metallic);
#ifdef _ExtBRDF
f0 = mix(f0, basecolor, vec3(matp6.y, matp6.z, matp6.w));
#endif
#ifdef _VRStereo
bool isLeftEye = texCoord.x < 0.5;
vec3 eyePos = isLeftEye ? eyeLeft : eyeRight;
@ -290,13 +312,24 @@ void main() {
#endif
float dotNV = max(dot(n, v), 0.0);
#ifdef _ClearCoat
vec4 gCoat = textureLod(gbufferCoatNormal, texCoord, 0.0);
vec3 nCoat;
nCoat.z = 1.0 - abs(gCoat.x) - abs(gCoat.y);
nCoat.xy = nCoat.z >= 0.0 ? gCoat.xy : octahedronWrap(gCoat.xy);
nCoat = normalize(nCoat);
#endif
#ifdef _gbuffer2
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
#endif
#ifdef _Anisotropy
vec4 g3 = textureLod(gbuffer3, texCoord, 0.0);
vec3 wTangent = length(g3.xyz) > 0.0 ? normalize(g3.xyz) : vec3(1.0, 0.0, 0.0);
#ifdef _gbuffer2
vec3 wTangent = decodeTangent(g2.a, n);
#else
vec3 wTangent = vec3(0.0);
#endif
#endif
@ -311,6 +344,44 @@ void main() {
vec3 F = f0;
#endif
#ifdef _ExtBRDF
float iblSheenWeight = 1.0;
float iblCoatWeight = 1.0;
float iblLayerWeight = 1.0;
vec3 coatTintAbsorb = vec3(1.0);
#ifdef _Sheen
float sheenAlb = sheenIBLAlbedo(matp0.z, matp0.w, dotNV);
iblSheenWeight = max(1.0 - sheenAlb *
max(max(sheenTintCol.r, sheenTintCol.g), sheenTintCol.b), 0.0);
#endif
#ifdef _ClearCoat
float dotNVCoat = max(dot(nCoat, v), 0.0);
float coatF = coatIBLFresnel(matp1.x, matp1.z, dotNVCoat);
iblCoatWeight = max(1.0 - coatF, 0.0);
coatTintAbsorb = mix(vec3(1.0), clamp(coatTintCol, 0.0, 1.0),
clamp(1.0 / max(dotNVCoat, 0.3) * 0.2, 0.0, 1.0));
#endif
iblLayerWeight = iblSheenWeight * iblCoatWeight;
brdf_sheenWeight = iblSheenWeight;
brdf_coatWeight = iblCoatWeight;
brdf_coatTintAbsorb = coatTintAbsorb;
#ifdef _Sheen
brdf_sheenAlbedo = sheenAlb;
#endif
#ifdef _ClearCoat
brdf_coatF0 = (matp1.z - 1.0) / (matp1.z + 1.0);
brdf_coatF0 = brdf_coatF0 * brdf_coatF0;
#endif
#ifdef _Transmission
brdf_transmissionF0 = (matp3.x - 1.0) / (matp3.x + 1.0);
brdf_transmissionF0 = brdf_transmissionF0 * brdf_transmissionF0;
#endif
#endif // _ExtBRDF
#ifndef _VoxelAOvar
#ifndef _VoxelGI
// Envmap
@ -318,9 +389,7 @@ void main() {
vec3 envl = shIrradiance(n, shirr);
#ifdef _gbuffer2
if (g2.b < 0.5) {
envl = envl;
} else {
if (g2.b >= 0.5) {
envl = vec3(0.0);
}
#endif
@ -333,16 +402,21 @@ void main() {
#endif
#ifdef _Rad
#ifdef _Anisotropy
vec3 reflectionWorld = anisotropicIBLDirection(n, v, wTangent,
matp0.x, roughness);
#else
vec3 reflectionWorld = reflect(-v, n);
#endif
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
prefilteredColor = min(prefilteredColor, vec3(20.0));
#endif
#ifdef _EnvLDR
envl.rgb = pow(envl.rgb, vec3(2.2));
envl.rgb = srgbToLinear(envl.rgb);
#ifdef _Rad
prefilteredColor = pow(prefilteredColor, vec3(2.2));
prefilteredColor = srgbToLinear(prefilteredColor);
#endif
#endif
@ -360,6 +434,68 @@ void main() {
#endif
#endif
#ifdef _ExtBRDF
envl.rgb *= iblLayerWeight;
#ifdef _Transmission
float transF = transmissionIBLFresnel(matp3.x, dotNV);
float transmittance = 1.0 - transF;
#ifdef _Rad
if (matp2.z > 0.0 && transmittance > 0.0) {
vec3 refrDir;
if (matp3.y > 0.5) {
refrDir = reflect(-v, n);
} else {
refrDir = transmissionIBLDirection(n, v, matp3.x);
}
float transLod = getMipFromRoughness(matp2.w, envmapNumMipmaps);
vec3 transColor = textureLod(senvmapRadiance,
envMapEquirect(refrDir), transLod).rgb;
transColor = min(transColor, vec3(20.0));
#ifdef _EnvLDR
transColor = srgbToLinear(transColor);
#endif
envl.rgb += albedo * matp2.z * transmittance * transColor * dotNV
* iblLayerWeight;
}
#endif
#endif
#ifdef _ClearCoat
envl.rgb *= coatTintAbsorb;
#ifdef _Rad
if (coatF > 0.0) {
float coatLod = getMipFromRoughness(matp1.y, envmapNumMipmaps);
vec3 coatRefl = reflect(-v, nCoat);
vec3 coatColor = textureLod(senvmapRadiance,
envMapEquirect(coatRefl), coatLod).rgb;
coatColor = min(coatColor, vec3(20.0));
#ifdef _EnvLDR
coatColor = srgbToLinear(coatColor);
#endif
envl.rgb += coatColor * coatF * iblSheenWeight;
}
#endif
#endif
#ifdef _Sheen
#ifdef _Rad
if (sheenAlb > 0.0) {
float sheenLod = getMipFromRoughness(matp0.w, envmapNumMipmaps);
vec3 sheenRefl = reflect(-v, n);
vec3 sheenColor = textureLod(senvmapRadiance,
envMapEquirect(sheenRefl), sheenLod).rgb;
sheenColor = min(sheenColor, vec3(20.0));
#ifdef _EnvLDR
sheenColor = srgbToLinear(sheenColor);
#endif
envl.rgb += sheenColor * sheenTintCol * sheenAlb;
}
#endif
#endif
#endif // _ExtBRDF
envl.rgb *= envmapStrength * occspec.x;
fragColor.rgb = envl;
@ -368,11 +504,30 @@ void main() {
#ifdef _VoxelGI
fragColor.rgb = textureLod(voxels_diffuse, texCoord, 0.0).rgb * voxelgiDiff;
if(roughness < 1.0 && occspec.y > 0.0)
fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * occspec.y * voxelgiRefl;
if(roughness < 1.0) {
fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * F * voxelgiRefl * occspec.y;
}
#ifdef _Rad
vec3 iblReflection = reflect(-v, n);
float iblLod = getMipFromRoughness(roughness, envmapNumMipmaps);
vec3 iblPrefiltered = textureLod(senvmapRadiance, envMapEquirect(iblReflection), iblLod).rgb;
iblPrefiltered = min(iblPrefiltered, vec3(20.0));
#ifdef _EnvLDR
iblPrefiltered = srgbToLinear(iblPrefiltered);
#endif
#ifdef _ExtBRDF
iblPrefiltered *= iblLayerWeight;
iblPrefiltered *= coatTintAbsorb;
#endif
fragColor.rgb += iblPrefiltered * F * envmapStrength * occspec.x;
#else
#ifdef _EnvCol
fragColor.rgb += backgroundCol * F * envmapStrength * occspec.x;
#endif
#endif
#else
#ifdef _VoxelAOvar
fragColor.rgb = textureLod(voxels_ao, texCoord, 0.0).rgb * voxelgiOcc;
fragColor.rgb = textureLod(voxels_ao, texCoord, 0.0).rgb;
#endif
#endif
@ -424,7 +579,7 @@ void main() {
vec3 svisibility = vec3(1.0);
#ifdef _Anisotropy
vec3 sdirect;
if (abs(matp0.x) > 0.001) {
if (abs(matp0.x) > 0.001 && dot(wTangent, wTangent) > 0.001) {
vec3 sbitangent = normalize(cross(n, wTangent));
sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
anisotropicBRDF(f0, roughness, matp0.x, matp0.y,
@ -438,36 +593,26 @@ void main() {
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
#endif
float sunSheenWeight = 1.0;
float sunCoatWeight = 1.0;
#ifdef _Sheen
vec3 sunSheen = sheenBRDF(matp0.z, matp0.w, vec3(matp5.z, matp5.w, matp6.x), sdotNL, sdotNH, dotNV);
sunSheenWeight = sheenAttenuation(matp0.z, matp0.w, vec3(matp5.z, matp5.w, matp6.x), dotNV);
#endif
#ifdef _ClearCoat
vec3 sunCoat = clearcoatBRDF(matp1.x, matp1.y, matp1.z, sdotNL, sdotNH, dotNV, sdotVH);
sunCoatWeight = coatAttenuation(matp1.x, matp1.z, dotNV);
#endif
float sunLayerWeight = sunSheenWeight * sunCoatWeight;
sdirect *= sunLayerWeight;
#ifdef _Subsurface
sdirect += subsurfaceBRDF(albedo, vec3(matp4.w, matp5.x, matp5.y), vec3(matp4.x, matp4.y, matp4.z), matp3.z, matp3.w, sdotNL) * sunLayerWeight;
#endif
#ifdef _Transmission
sdirect += transmissionBRDF(albedo, matp2.z, matp2.w, matp3.x, matp3.y, sdotNL, dotNV, sdotVH) * sunLayerWeight;
#endif
#ifdef _ClearCoat
sdirect *= coatTintAttenuation(matp1.x, vec3(matp1.w, matp2.x, matp2.y), dotNV);
sdirect += sunCoat * sunSheenWeight;
#endif
#ifdef _Sheen
sdirect += sunSheen;
#ifdef _ExtBRDF
float sunLayerWeight;
sdirect = applyExtBRDFLayers(sdirect, albedo, f0, roughness,
sdotNL, dotNV, sdotNH, sdotVH, n, sunDir, v, sh
#ifdef _ClearCoat
, matp1.x, matp1.y, matp1.z, coatTintCol, nCoat
#endif
#ifdef _Sheen
, matp0.z, matp0.w, sheenTintCol
#endif
#ifdef _Transmission
, matp2.z, matp2.w, matp3.x, matp3.y
#endif
, sunLayerWeight);
#endif
#ifdef _ShadowMap
#ifdef _ShadowMapAtlas
tileBounds = tileBoundsSunArray[0];
#endif
#ifdef _CSM
svisibility = shadowTestCascade(
#ifdef _ShadowMapAtlas
@ -552,23 +697,17 @@ void main() {
fragColor.rgb += sdirect * sunCol * svisibility;
// #ifdef _Hair // Aniso
// if (matid == 2) {
// const float shinyParallel = roughness;
// const float shinyPerpendicular = 0.1;
// const vec3 v = vec3(0.99146, 0.11664, 0.05832);
// vec3 T = abs(dot(n, v)) > 0.99999 ? cross(n, vec3(0.0, 1.0, 0.0)) : cross(n, v);
// fragColor.rgb = orenNayarDiffuseBRDF(albedo, roughness, dotNV, dotNL, dotVH) + wardSpecular(n, h, dotNL, dotNV, dotNH, T, shinyParallel, shinyPerpendicular) * spec;
// }
// #endif
#ifdef _SSS
if (matid == 2) {
#ifdef _ExtBRDF
if (matid >= 3u && matp3.z > 0.0) {
#ifdef _CSM
int casi, casindex;
mat4 LWVP = getCascadeMat(distance(eye, p), casi, casindex);
#endif
fragColor.rgb += fragColor.rgb * SSSSTransmittance(
vec3 sssColor = sssColorVal;
float sssRadius = sssRadiusScalar;
float sssStrength = matp3.z;
vec3 sssResult = SSSSTransmittance(
LWVP, p, n, sunDir, lightPlane.y,
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
@ -579,12 +718,26 @@ void main() {
#else
shadowMap
#endif
);//TODO implement transparent shadowmaps into the SSSSTransmittance()
, sssColor, sssRadius
#ifdef _ShadowMapAtlas
#ifdef _CSM
, tileBoundsSunArray[casi]
#else
, tileBoundsSunArray[0]
#endif
#endif
);
fragColor.rgb += sunCol * sssStrength * sssResult;
}
#endif
#endif
#endif // _Sun
#ifdef _ShadowMapAtlas
tileBounds = vec4(0.0, 0.0, 1.0, 1.0);
#endif
#ifdef _SinglePoint
#ifdef _VRStereo
@ -614,16 +767,16 @@ void main() {
, gbufferD, invVP, eye
#endif
#ifdef _ClearCoat
, matp1.x, matp1.y, matp1.z, vec3(matp1.w, matp2.x, matp2.y)
, matp1.x, matp1.y, matp1.z, coatTintCol, nCoat
#endif
#ifdef _Sheen
, matp0.z, matp0.w, vec3(matp5.z, matp5.w, matp6.x)
, matp0.z, matp0.w, sheenTintCol
#endif
#ifdef _Anisotropy
, matp0.x, matp0.y, wTangent
#endif
#ifdef _Subsurface
, matp3.z, vec3(matp4.w, matp5.x, matp5.y), vec3(matp4.x, matp4.y, matp4.z), matp3.w
#ifdef _SSS
, matp3.z, sssColorVal, sssRadiusBase * matp7.x, matp3.w
#endif
#ifdef _Transmission
, matp2.z, matp2.w, matp3.x, matp3.y
@ -633,7 +786,33 @@ void main() {
#ifdef _Spot
#ifdef _SSS
#ifdef _ShadowMap
if (matid == 2) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot[0], p, n, normalize(lightPos - p), lightPlane.y, shadowMapSpot[0]);//TODO implement transparent shadowmaps into the SSSSTransmittance()
#ifdef _ExtBRDF
if (matid >= 3u && matp3.z > 0.0) {
vec3 sssColorSpot = sssColorVal;
float sssRadiusSpot = sssRadiusScalar;
float sssStrengthSpot = matp3.z;
fragColor.rgb += pointCol * sssStrengthSpot * SSSSTransmittance(LWVPSpotArray[0], p, n, normalize(lightPos - p), lightPlane.y, shadowMapSpot[0], sssColorSpot, sssRadiusSpot
#ifdef _ShadowMapAtlas
, vec4(0.0, 0.0, 1.0, 1.0)
#endif
);//TODO implement transparent shadowmaps into the SSSSTransmittance()
}
#endif
#endif
#endif
#endif
#ifndef _Spot
#ifdef _SSS
#ifdef _ShadowMap
#ifdef _ExtBRDF
if (matid >= 3u && matp3.z > 0.0) {
vec3 sssColorPoint = sssColorVal;
float sssRadiusPoint = sssRadiusScalar;
float sssStrengthPoint = matp3.z;
fragColor.rgb += pointCol * sssStrengthPoint * SSSSTransmittanceCube(shadowMapPoint[0], lightPos, p, n, normalize(lightPos - p), lightPlane.y, lightProj, sssColorPoint, sssRadiusPoint);
}
#endif
#endif
#endif
#endif
@ -692,21 +871,95 @@ void main() {
, gbufferD, invVP, eye
#endif
#ifdef _ClearCoat
, matp1.x, matp1.y, matp1.z, vec3(matp1.w, matp2.x, matp2.y)
, matp1.x, matp1.y, matp1.z, coatTintCol, nCoat
#endif
#ifdef _Sheen
, matp0.z, matp0.w, vec3(matp5.z, matp5.w, matp6.x)
, matp0.z, matp0.w, sheenTintCol
#endif
#ifdef _Anisotropy
, matp0.x, matp0.y, wTangent
#endif
#ifdef _Subsurface
, matp3.z, vec3(matp4.w, matp5.x, matp5.y), vec3(matp4.x, matp4.y, matp4.z), matp3.w
#ifdef _SSS
, matp3.z, sssColorVal, sssRadiusBase * matp7.x, matp3.w
#endif
#ifdef _Transmission
, matp2.z, matp2.w, matp3.x, matp3.y
#endif
);
#ifdef _SSS
#ifdef _ShadowMap
#ifdef _ExtBRDF
if (matid >= 3u && matp3.z > 0.0) {
vec3 sssColorCL = sssColorVal;
float sssRadiusCL = sssRadiusScalar;
float sssStrengthCL = matp3.z;
vec3 cLightPos = lightsArray[li * 3].xyz;
vec3 cLightCol = lightsArray[li * 3 + 1].xyz;
vec3 cLightDir = normalize(cLightPos - p);
#ifdef _Spot
bool isSpotLight = lightsArray[li * 3 + 2].y != 0.0;
if (isSpotLight) {
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[li], p, n, cLightDir, lightPlane.y, shadowMapAtlasSpot, sssColorCL, sssRadiusCL, tileBoundsSpotArray[li]);
#else
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[li], p, n, cLightDir, lightPlane.y, shadowMapAtlas, sssColorCL, sssRadiusCL, tileBoundsSpotArray[li]);
#endif
#else
if (li == 0) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[0], p, n, cLightDir, lightPlane.y, shadowMapSpot[0], sssColorCL, sssRadiusCL
#ifdef _ShadowMapAtlas
, vec4(0.0, 0.0, 1.0, 1.0)
#endif
);
else if (li == 1) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[1], p, n, cLightDir, lightPlane.y, shadowMapSpot[1], sssColorCL, sssRadiusCL
#ifdef _ShadowMapAtlas
, vec4(0.0, 0.0, 1.0, 1.0)
#endif
);
else if (li == 2) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[2], p, n, cLightDir, lightPlane.y, shadowMapSpot[2], sssColorCL, sssRadiusCL
#ifdef _ShadowMapAtlas
, vec4(0.0, 0.0, 1.0, 1.0)
#endif
);
else if (li == 3) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[3], p, n, cLightDir, lightPlane.y, shadowMapSpot[3], sssColorCL, sssRadiusCL
#ifdef _ShadowMapAtlas
, vec4(0.0, 0.0, 1.0, 1.0)
#endif
);
#endif
} else {
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCubeAtlas(shadowMapAtlasPoint, cLightPos, p, n, cLightDir, lightPlane.y, lightProj, li, sssColorCL, sssRadiusCL);
#else
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCubeAtlas(shadowMapAtlas, cLightPos, p, n, cLightDir, lightPlane.y, lightProj, li, sssColorCL, sssRadiusCL);
#endif
#else
if (li == 0) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[0], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
else if (li == 1) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[1], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
else if (li == 2) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[2], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
else if (li == 3) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[3], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
#endif
}
#else
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCubeAtlas(shadowMapAtlasPoint, cLightPos, p, n, cLightDir, lightPlane.y, lightProj, li, sssColorCL, sssRadiusCL);
#else
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCubeAtlas(shadowMapAtlas, cLightPos, p, n, cLightDir, lightPlane.y, lightProj, li, sssColorCL, sssRadiusCL);
#endif
#else
if (li == 0) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[0], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
else if (li == 1) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[1], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
else if (li == 2) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[2], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
else if (li == 3) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[3], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
#endif
#endif
}
#endif
#endif
#endif
}
#endif // _Clusters

View File

@ -138,6 +138,16 @@
"link": "_cascadeData",
"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
},
{
"name": "tileBoundsSunArray",
"link": "_tileBoundsSunArray",
"ifdef": ["_Sun", "_ShadowMap", "_ShadowMapAtlas"]
},
{
"name": "tileBoundsSpotArray",
"link": "_tileBoundsSpotArray",
"ifdef": ["_Clusters", "_Spot", "_ShadowMap", "_ShadowMapAtlas"]
},
{
"name": "lightPlane",
"link": "_lightPlane",
@ -281,9 +291,11 @@
{
"name": "materialParams",
"link": "_materialParams",
"type": "floats"
"type": "floats",
"ifdef": ["_ExtBRDF"]
}
],
"texture_units": [],
"vertex_shader": "../include/pass_viewray.vert.glsl",
"fragment_shader": "deferred_light.frag.glsl",
"color_attachments": ["RGBA64"]

View File

@ -14,8 +14,11 @@
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
#ifdef _Anisotropy
uniform sampler2D gbuffer3;
#ifdef _gbuffer2
uniform sampler2D gbuffer2;
#endif
#ifdef _ClearCoat
uniform sampler2D gbufferCoatNormal;
#endif
uniform float envmapStrength;
@ -53,7 +56,7 @@ uniform vec2 cameraPlane;
#ifdef _SinglePoint
#ifdef _Spot
//!uniform sampler2DShadow shadowMapSpot[1];
//!uniform mat4 LWVPSpot[1];
//!uniform mat4 LWVPSpotArray[1];
#else
//!uniform samplerCubeShadow shadowMapPoint[1];
//!uniform vec2 lightProj;
@ -95,6 +98,7 @@ uniform vec3 sunCol;
#ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasSun;
#endif
//!uniform vec4 tileBoundsSunArray[maxLights * shadowmapCascades];
#else
uniform sampler2DShadow shadowMap;
#endif
@ -140,23 +144,55 @@ void main() {
matid = min(matid, uint(MAX_MATERIALS - 1));
//!uniform vec4 materialParams[MAX_MATERIALS * 8];
vec4 matp0, matp1, matp2, matp3, matp4, matp5, matp6;
getMaterialParams(matid, matp0, matp1, matp2, matp3, matp4, matp5, matp6);
vec4 matp0 = vec4(0.0), matp1 = vec4(0.0), matp2 = vec4(0.0), matp3 = vec4(0.0);
vec4 matp4 = vec4(0.0), matp5 = vec4(0.0), matp6 = vec4(0.0), matp7 = vec4(0.0);
// TODO: coatIOR=1.5, ior=1.45, thinWall=1.0 move to python make files
matp1.z = 1.5;
matp3.x = 1.45;
matp3.y = 1.0;
if (matid >= 3u) {
getMaterialParams(matid, matp0, matp1, matp2, matp3, matp4, matp5, matp6, matp7);
}
#ifdef _ClearCoat
vec3 coatTintCol = vec3(matp1.w, matp2.x, matp2.y);
#endif
#ifdef _Sheen
vec3 sheenTintCol = vec3(matp5.z, matp5.w, matp6.x);
#endif
#ifdef _SSS
vec3 sssColorVal = vec3(matp4.w, matp5.x, matp5.y);
vec3 sssRadiusScaled = vec3(matp4.x, matp4.y, matp4.z) * matp7.x;
#endif
#endif
vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ
vec2 occspec = unpackFloat2(g1.a);
vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
vec3 f0 = surfaceF0(g1.rgb, metallic);
#ifdef _ExtBRDF
f0 = mix(f0, min(g1.rgb, vec3(2.0)), vec3(matp6.y, matp6.z, matp6.w));
#endif
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
vec3 v = normalize(eye - p);
float dotNV = max(dot(n, v), 0.0);
#ifdef _ClearCoat
vec4 gCoat = textureLod(gbufferCoatNormal, texCoord, 0.0);
vec3 nCoat;
nCoat.z = 1.0 - abs(gCoat.x) - abs(gCoat.y);
nCoat.xy = nCoat.z >= 0.0 ? gCoat.xy : octahedronWrap(gCoat.xy);
nCoat = normalize(nCoat);
#endif
#ifdef _Anisotropy
vec4 g3 = textureLod(gbuffer3, texCoord, 0.0);
vec3 wTangent = length(g3.xyz) > 0.0 ? normalize(g3.xyz) : vec3(1.0, 0.0, 0.0);
#ifdef _gbuffer2
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
vec3 wTangent = decodeTangent(g2.a, n);
#else
vec3 wTangent = vec3(0.0);
#endif
#endif
#ifdef _Brdf
@ -174,15 +210,20 @@ void main() {
#endif
#ifdef _Rad
#ifdef _Anisotropy
vec3 reflectionWorld = anisotropicIBLDirection(n, v, wTangent,
matp0.x, roughness);
#else
vec3 reflectionWorld = reflect(-v, n);
#endif
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
#endif
#ifdef _EnvLDR
envl.rgb = pow(envl.rgb, vec3(2.2));
envl.rgb = srgbToLinear(envl.rgb);
#ifdef _Rad
prefilteredColor = pow(prefilteredColor, vec3(2.2));
prefilteredColor = srgbToLinear(prefilteredColor);
#endif
#endif
@ -196,6 +237,98 @@ void main() {
#endif
#endif
#ifdef _ExtBRDF
float iblSheenWeight = 1.0;
float iblCoatWeight = 1.0;
vec3 coatTintAbsorb = vec3(1.0);
#ifdef _Sheen
float sheenAlb = sheenIBLAlbedo(matp0.z, matp0.w, dotNV);
iblSheenWeight = max(1.0 - sheenAlb *
max(max(sheenTintCol.r, sheenTintCol.g), sheenTintCol.b), 0.0);
#endif
#ifdef _ClearCoat
float dotNVCoat = max(dot(nCoat, v), 0.0);
float coatF = coatIBLFresnel(matp1.x, matp1.z, dotNVCoat);
iblCoatWeight = max(1.0 - coatF, 0.0);
if (matp1.x > 0.0) {
coatTintAbsorb = mix(vec3(1.0), clamp(coatTintCol, 0.0, 1.0),
clamp(1.0 / max(dotNVCoat, 0.3) * 0.2, 0.0, 1.0));
}
#endif
float iblLayerWeight = iblSheenWeight * iblCoatWeight;
envl.rgb *= iblLayerWeight;
brdf_sheenWeight = iblSheenWeight;
brdf_coatWeight = iblCoatWeight;
brdf_coatTintAbsorb = coatTintAbsorb;
#ifdef _Sheen
brdf_sheenAlbedo = sheenAlb;
#endif
#ifdef _ClearCoat
brdf_coatF0 = (matp1.z - 1.0) / (matp1.z + 1.0);
brdf_coatF0 = brdf_coatF0 * brdf_coatF0;
#endif
#ifdef _Transmission
brdf_transmissionF0 = (matp3.x - 1.0) / (matp3.x + 1.0);
brdf_transmissionF0 = brdf_transmissionF0 * brdf_transmissionF0;
#endif
#ifdef _Transmission
float transF = transmissionIBLFresnel(matp3.x, dotNV);
float transmittance = 1.0 - transF;
#ifdef _Rad
if (matp2.z > 0.0 && transmittance > 0.0) {
vec3 refrDir = transmissionIBLDirection(n, v, matp3.x);
float transLod = getMipFromRoughness(matp2.w, envmapNumMipmaps);
vec3 transColor = textureLod(senvmapRadiance,
envMapEquirect(refrDir), transLod).rgb;
transColor = min(transColor, vec3(20.0));
#ifdef _EnvLDR
transColor = srgbToLinear(transColor);
#endif
envl.rgb += albedo * matp2.z * transmittance * transColor * dotNV
* iblLayerWeight;
}
#endif
#endif
#ifdef _ClearCoat
envl.rgb *= coatTintAbsorb;
#ifdef _Rad
if (coatF > 0.0) {
float coatLod = getMipFromRoughness(matp1.y, envmapNumMipmaps);
vec3 coatRefl = reflect(-v, nCoat);
vec3 coatColor = textureLod(senvmapRadiance,
envMapEquirect(coatRefl), coatLod).rgb;
coatColor = min(coatColor, vec3(20.0));
#ifdef _EnvLDR
coatColor = srgbToLinear(coatColor);
#endif
envl.rgb += coatColor * coatF * iblSheenWeight;
}
#endif
#endif
#ifdef _Sheen
#ifdef _Rad
if (sheenAlb > 0.0) {
float sheenLod = getMipFromRoughness(matp0.w, envmapNumMipmaps);
vec3 sheenRefl = reflect(-v, n);
vec3 sheenColor = textureLod(senvmapRadiance,
envMapEquirect(sheenRefl), sheenLod).rgb;
sheenColor = min(sheenColor, vec3(20.0));
#ifdef _EnvLDR
sheenColor = srgbToLinear(sheenColor);
#endif
envl.rgb += sheenColor * sheenTintCol * sheenAlb;
}
#endif
#endif
#endif // _ExtBRDF
envl.rgb *= envmapStrength * occspec.x;
fragColor.rgb = envl;
@ -207,7 +340,7 @@ void main() {
float svisibility = 1.0;
#ifdef _Anisotropy
vec3 sdirect;
if (abs(matp0.x) > 0.001) {
if (abs(matp0.x) > 0.001 && dot(wTangent, wTangent) > 0.001) {
vec3 sbitangent = normalize(cross(n, wTangent));
sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
anisotropicBRDF(f0, roughness, matp0.x, matp0.y,
@ -221,29 +354,24 @@ void main() {
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
#endif
float sunSheenWeight = 1.0;
float sunCoatWeight = 1.0;
float sunSheenWeight = brdf_sheenWeight;
float sunCoatWeight = brdf_coatWeight;
#ifdef _Sheen
vec3 sunSheen = sheenBRDF(matp0.z, matp0.w, vec3(matp5.z, matp5.w, matp6.x), sdotNL, sdotNH, dotNV);
sunSheenWeight = sheenAttenuation(matp0.z, matp0.w, vec3(matp5.z, matp5.w, matp6.x), dotNV);
vec3 sunSheen = sheenBRDF(matp0.z, matp0.w, sheenTintCol, sdotNL, sdotNH, dotNV);
#endif
#ifdef _ClearCoat
vec3 sunCoat = clearcoatBRDF(matp1.x, matp1.y, matp1.z, sdotNL, sdotNH, dotNV, sdotVH);
sunCoatWeight = coatAttenuation(matp1.x, matp1.z, dotNV);
vec3 sunCoat = clearcoatBRDF(matp1.x, matp1.y, matp1.z, nCoat, sunDir, v, sh);
#endif
float sunLayerWeight = sunSheenWeight * sunCoatWeight;
sdirect *= sunLayerWeight;
#ifdef _Subsurface
sdirect += subsurfaceBRDF(albedo, vec3(matp4.w, matp5.x, matp5.y), vec3(matp4.x, matp4.y, matp4.z), matp3.z, matp3.w, sdotNL) * sunLayerWeight;
#endif
#ifdef _Transmission
sdirect += transmissionBRDF(albedo, matp2.z, matp2.w, matp3.x, matp3.y, sdotNL, dotNV, sdotVH) * sunLayerWeight;
#endif
#ifdef _ClearCoat
sdirect *= coatTintAttenuation(matp1.x, vec3(matp1.w, matp2.x, matp2.y), dotNV);
sdirect *= brdf_coatTintAbsorb;
sdirect += sunCoat * sunSheenWeight;
#endif
#ifdef _Sheen
@ -251,6 +379,9 @@ void main() {
#endif
#ifdef _ShadowMap
#ifdef _ShadowMapAtlas
tileBounds = tileBoundsSunArray[0];
#endif
#ifdef _CSM
svisibility = shadowTestCascade(
#ifdef _ShadowMapAtlas
@ -294,16 +425,16 @@ void main() {
, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight // TODO: Test!
#endif
#ifdef _ClearCoat
, matp1.x, matp1.y, matp1.z, vec3(matp1.w, matp2.x, matp2.y)
, matp1.x, matp1.y, matp1.z, coatTintCol, nCoat
#endif
#ifdef _Sheen
, matp0.z, matp0.w, vec3(matp5.z, matp5.w, matp6.x)
, matp0.z, matp0.w, sheenTintCol
#endif
#ifdef _Anisotropy
, matp0.x, matp0.y, wTangent
#endif
#ifdef _Subsurface
, matp3.z, vec3(matp4.w, matp5.x, matp5.y), vec3(matp4.x, matp4.y, matp4.z), matp3.w
#ifdef _SSS
, matp3.z, sssColorVal, sssRadiusScaled, matp3.w
#endif
#ifdef _Transmission
, matp2.z, matp2.w, matp3.x, matp3.y
@ -351,16 +482,16 @@ void main() {
, lightsArraySpot[li * 2 + 1].xyz // right
#endif
#ifdef _ClearCoat
, matp1.x, matp1.y, matp1.z, vec3(matp1.w, matp2.x, matp2.y)
, matp1.x, matp1.y, matp1.z, coatTintCol, nCoat
#endif
#ifdef _Sheen
, matp0.z, matp0.w, vec3(matp5.z, matp5.w, matp6.x)
, matp0.z, matp0.w, sheenTintCol
#endif
#ifdef _Anisotropy
, matp0.x, matp0.y, wTangent
#endif
#ifdef _Subsurface
, matp3.z, vec3(matp4.w, matp5.x, matp5.y), vec3(matp4.x, matp4.y, matp4.z), matp3.w
#ifdef _SSS
, matp3.z, sssColorVal, sssRadiusScaled, matp3.w
#endif
#ifdef _Transmission
, matp2.z, matp2.w, matp3.x, matp3.y
@ -368,4 +499,11 @@ void main() {
);
}
#endif // _Clusters
fragColor.rgb = clamp(fragColor.rgb, vec3(0.0), vec3(65504.0));
if (any(isnan(fragColor.rgb)) || any(isinf(fragColor.rgb))) {
fragColor.rgb = vec3(0.0);
}
fragColor.a = 1.0; // Mark as opaque
}

View File

@ -97,6 +97,16 @@
"link": "_cascadeData",
"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
},
{
"name": "tileBoundsSunArray",
"link": "_tileBoundsSunArray",
"ifdef": ["_Sun", "_ShadowMap", "_ShadowMapAtlas"]
},
{
"name": "tileBoundsSpotArray",
"link": "_tileBoundsSpotArray",
"ifdef": ["_Clusters", "_Spot", "_ShadowMap", "_ShadowMapAtlas"]
},
{
"name": "eyeLookRight",
"link": "_eyeLookRight",
@ -218,7 +228,8 @@
{
"name": "materialParams",
"link": "_materialParams",
"type": "floats"
"type": "floats",
"ifdef": ["_ExtBRDF"]
}
],
"vertex_shader": "../include/pass_viewray.vert.glsl",

View File

@ -11,6 +11,7 @@ uniform sampler2D gbuffer1; // basecol, spec
uniform mat4 P;
uniform mat3 V3;
uniform vec2 cameraProj;
uniform vec2 screenSize;
#ifdef _CPostprocess
uniform vec3 PPComp9;
@ -24,8 +25,8 @@ out vec4 fragColor;
vec3 hitCoord;
float depth;
const int numBinarySearchSteps = 7;
const int maxSteps = int(ceil(1.0 / ssrRayStep) * ssrSearchDist);
const int numBinarySearchSteps = 8;
const int maxSteps = 50;
vec2 getProjectedCoord(const vec3 hit) {
vec4 projectedCoord = P * vec4(hit, 1.0);
@ -38,44 +39,58 @@ vec2 getProjectedCoord(const vec3 hit) {
}
float getDeltaDepth(const vec3 hit) {
depth = textureLod(gbufferD, getProjectedCoord(hit), 0.0).r * 2.0 - 1.0;
vec2 tc = getProjectedCoord(hit);
if (tc.x < 0.0 || tc.x > 1.0 || tc.y < 0.0 || tc.y > 1.0)
return -1.0;
depth = textureLod(gbufferD, tc, 0.0).r * 2.0 - 1.0;
vec3 viewPos = getPosView(viewRay, depth, cameraProj);
return viewPos.z - hit.z;
}
vec4 binarySearch(vec3 dir) {
vec4 binarySearch(vec3 dir, float stepSize) {
float ddepth;
for (int i = 0; i < numBinarySearchSteps; i++) {
dir *= 0.5;
hitCoord -= dir;
stepSize *= 0.5;
hitCoord -= dir * stepSize;
ddepth = getDeltaDepth(hitCoord);
if (ddepth < 0.0) hitCoord += dir;
if (ddepth < 0.0) hitCoord += dir * stepSize;
}
// Ugly discard of hits too far away
#ifdef _CPostprocess
if (abs(ddepth) > PPComp9.z / 500) return vec4(0.0);
float maxDist = PPComp9.z;
#else
if (abs(ddepth) > ssrSearchDist / 500) return vec4(0.0);
float maxDist = ssrSearchDist;
#endif
return vec4(getProjectedCoord(hitCoord), 0.0, 1.0);
if (abs(ddepth) > maxDist * 0.005) return vec4(0.0);
vec2 hitTC = getProjectedCoord(hitCoord);
if (hitTC.x < 0.0 || hitTC.x > 1.0 || hitTC.y < 0.0 || hitTC.y > 1.0)
return vec4(0.0);
return vec4(hitTC, 0.0, 1.0);
}
vec4 rayCast(vec3 dir) {
#ifdef _CPostprocess
dir *= PPComp9.x;
float baseStep = PPComp9.x;
float maxDist = PPComp9.z;
#else
dir *= ssrRayStep;
float baseStep = ssrRayStep;
float maxDist = ssrSearchDist;
#endif
float stepSize = baseStep * max(1.0, -viewRay.z * 0.1);
vec3 startPos = hitCoord;
for (int i = 0; i < maxSteps; i++) {
hitCoord += dir;
if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir);
hitCoord += dir * stepSize;
float dist = length(hitCoord - startPos);
if (dist > maxDist) break;
float ddepth = getDeltaDepth(hitCoord);
if (ddepth > 0.0) return binarySearch(dir, stepSize);
stepSize *= 1.03;
}
return vec4(0.0);
}
void main() {
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
float roughness = unpackFloat(g0.b).y;
float roughness = g0.b;
if (roughness == 1.0) { fragColor.rgb = vec3(0.0); return; }
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
@ -92,30 +107,54 @@ void main() {
vec3 viewNormal = V3 * n;
vec3 viewPos = getPosView(viewRay, d, cameraProj);
vec3 reflected = reflect(viewPos, viewNormal);
float NdotV = clamp(dot(viewNormal, -normalize(viewPos)), 0.0, 1.0);
vec3 reflected = reflect(normalize(viewPos), viewNormal);
hitCoord = viewPos;
#ifdef _CPostprocess
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
vec3 dir = reflected;
// * max(ssrMinRayStep, -viewPos.z)
vec4 coords = rayCast(dir);
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0);
if (coords.w <= 0.0) {
fragColor.rgb = vec3(0.0);
return;
}
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
float screenEdgeFactor = smoothstep(0.5, 0.15, deltaCoords.x)
* smoothstep(0.5, 0.15, deltaCoords.y);
screenEdgeFactor = max(screenEdgeFactor, 0.15);
float hitDepth = textureLod(gbufferD, coords.xy, 0.0).r * 2.0 - 1.0;
vec3 hitViewPos = getPosView(viewRay, hitDepth, cameraProj);
vec3 hitDir = normalize(hitViewPos - viewPos);
float hitNdotV = clamp(dot(viewNormal, -hitDir), 0.0, 1.0);
float hitBackFace = smoothstep(-0.15, 0.3, hitNdotV);
float reflectivity = 1.0 - roughness;
#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 falloffExp = PPComp10.x;
float maxDist = PPComp9.z;
#else
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;
float falloffExp = ssrFalloffExp;
float maxDist = ssrSearchDist;
#endif
float distAttenuation = 1.0 - clamp(length(viewPos - hitCoord) / maxDist, 0.0, 1.0);
distAttenuation = pow(distAttenuation, 1.5);
float fresnel = pow(1.0 - NdotV, 5.0);
fresnel = mix(0.04, 1.0, fresnel);
float intensity = pow(reflectivity, falloffExp) * screenEdgeFactor
* smoothstep(0.0, 0.1, -reflected.z)
* distAttenuation
* hitBackFace
* coords.w;
intensity = clamp(intensity, 0.0, 1.0);
vec3 reflCol = textureLod(tex, coords.xy, 0.0).rgb;
reflCol = clamp(reflCol, 0.0, 1.0);
fragColor.rgb = reflCol * intensity * 0.5;
fragColor.rgb = reflCol * intensity * mix(0.5, 1.0, fresnel);
}

View File

@ -22,6 +22,10 @@
"name": "cameraProj",
"link": "_cameraPlaneProj"
},
{
"name": "screenSize",
"link": "_screenSize"
},
{
"name": "PPComp9",
"link": "_PPComp9",

View File

@ -12,6 +12,7 @@ uniform sampler2D tex1;
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform sampler2D gbufferD1;
uniform sampler2D gbuffer1;
uniform sampler2D gbuffer_refraction; // ior\opacity
uniform mat4 P;
@ -26,7 +27,7 @@ vec3 hitCoord;
float depth;
const int numBinarySearchSteps = 7;
const int maxSteps = int(ceil(1.0 / ss_refractionRayStep) * ss_refractionSearchDist);
const int maxSteps = 50;
vec2 getProjectedCoord(const vec3 hit) {
vec4 projectedCoord = P * vec4(hit, 1.0);
@ -39,45 +40,60 @@ vec2 getProjectedCoord(const vec3 hit) {
}
float getDeltaDepth(const vec3 hit) {
depth = textureLod(gbufferD1, getProjectedCoord(hit), 0.0).r * 2.0 - 1.0;
vec2 tc = getProjectedCoord(hit);
if (tc.x < 0.0 || tc.x > 1.0 || tc.y < 0.0 || tc.y > 1.0)
return -1.0;
depth = textureLod(gbufferD1, tc, 0.0).r * 2.0 - 1.0;
vec3 viewPos = getPosView(viewRay, depth, cameraProj);
return viewPos.z - hit.z;
}
vec4 binarySearch(vec3 dir) {
vec4 binarySearch(vec3 dir, float stepSize) {
float ddepth;
for (int i = 0; i < numBinarySearchSteps; i++) {
dir *= 0.5;
hitCoord -= dir;
stepSize *= 0.5;
hitCoord -= dir * stepSize;
ddepth = getDeltaDepth(hitCoord);
if (ddepth < 0.0) hitCoord += dir;
if (ddepth < 0.0) hitCoord += dir * stepSize;
}
if (abs(ddepth) > ss_refractionSearchDist) return vec4(0.0);
return vec4(getProjectedCoord(hitCoord), 0.0, 1.0);
if (abs(ddepth) > ss_refractionSearchDist * 0.005) return vec4(0.0);
vec2 hitTC = getProjectedCoord(hitCoord);
if (hitTC.x < 0.0 || hitTC.x > 1.0 || hitTC.y < 0.0 || hitTC.y > 1.0)
return vec4(0.0);
return vec4(hitTC, 0.0, 1.0);
}
vec4 rayCast(vec3 dir) {
float ddepth;
dir *= ss_refractionRayStep;
float stepSize = ss_refractionRayStep * max(1.0, -viewRay.z * 0.1);
vec3 startPos = hitCoord;
for (int i = 0; i < maxSteps; i++) {
hitCoord += dir;
ddepth = getDeltaDepth(hitCoord);
if (ddepth > 0.0) return binarySearch(dir);
hitCoord += dir * stepSize;
float dist = length(hitCoord - startPos);
if (dist > ss_refractionSearchDist) break;
float ddepth = getDeltaDepth(hitCoord);
if (ddepth > 0.0) return binarySearch(dir, stepSize);
stepSize *= 1.03;
}
return vec4(texCoord, 0.0, 0.0);
}
void main() {
vec4 gr = textureLod(gbuffer_refraction, texCoord, 0.0);
float ior = gr.x;
float ior = unpackIOR(gr.x);
float transmittance = gr.y;
float surfaceDepth = gr.z;
float d = surfaceDepth * 2.0 - 1.0;
vec4 sceneSample = textureLod(tex, texCoord, 0.0);
if (surfaceDepth == 0.0 || transmittance == 0.0 || ior == 1.0) {
if (surfaceDepth == 0.0 || surfaceDepth == 1.0) {
fragColor = sceneSample;
return;
}
vec4 g1 = textureLod(gbuffer1, texCoord, 0.0);
if (transmittance == 0.0 || ior == 1.0) {
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
fragColor.rgb = sceneSample.rgb + background * (1.0 - sceneSample.a);
fragColor.rgb = g1.rgb + background * transmittance;
fragColor.a = 1.0;
return;
}
@ -96,18 +112,18 @@ void main() {
vec3 refracted = refract(incident, viewNormal, 1.0 / ior);
if (length(refracted) < 0.001) {
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
fragColor.rgb = sceneSample.rgb + background * (1.0 - sceneSample.a);
fragColor.rgb = g1.rgb + background * transmittance;
fragColor.a = 1.0;
return;
}
hitCoord = viewPos;
vec3 dir = refracted * (1.0 - rand(texCoord) * ss_refractionJitter * roughness) * 2.0;
vec3 dir = normalize(refracted);
vec4 coords = rayCast(dir);
vec2 screenEdge = smoothstep(0.0, 0.1, coords.xy) * smoothstep(0.0, 0.1, 1.0 - coords.xy);
float screenEdgeFactor = screenEdge.x * screenEdge.y;
vec2 screenEdge = smoothstep(0.0, 0.05, coords.xy) * smoothstep(0.0, 0.05, 1.0 - coords.xy);
float screenEdgeFactor = max(screenEdge.x * screenEdge.y, 0.05);
float refractivity = 1.0 - roughness;
float intensity = pow(refractivity, ss_refractionFalloffExp) * screenEdgeFactor * coords.w;
@ -118,6 +134,6 @@ void main() {
vec3 behindColor = mix(straightBackground, refractedBackground, intensity);
fragColor.rgb = sceneSample.rgb + behindColor * (1.0 - sceneSample.a);
fragColor.rgb = g1.rgb + behindColor * transmittance;
fragColor.a = 1.0;
}

View File

@ -40,100 +40,148 @@
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
uniform sampler2D tex;
uniform vec2 dir;
uniform vec2 cameraProj;
uniform mat4 projectionMatrix;
#ifdef _ExtBRDF
//!uniform vec4 materialParams[MAX_MATERIALS * 8];
#endif
in vec2 texCoord;
out vec4 fragColor;
const vec3 SKIN_SSS_RADIUS = vec3(4.8, 2.4, 1.5);
const float SSS_DISTANCE_SCALE = 0.001;
// TODO: finish the SSS
const float SSS_SCALE = 0.05;
const float DEPTH_THRESHOLD = 0.05;
// Temp hash func -
float hash13(vec3 p3) {
p3 = fract(p3 * vec3(0.1031, 0.1030, 0.0973));
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}
vec4 SSSSBlur() {
const int SSSS_N_SAMPLES = 15;
vec4 SSSSBlur(vec3 sssRadius, float sssWeight) {
const int SSSS_N_SAMPLES = 11;
vec4 kernel[SSSS_N_SAMPLES];
kernel[0] = vec4(0.233, 0.455, 0.649, 0.0); // Center sample
kernel[1] = vec4(0.100, 0.336, 0.344, 0.37); // +0.37mm
kernel[2] = vec4(0.118, 0.198, 0.0, 0.97); // +0.97mm
kernel[3] = vec4(0.113, 0.007, 0.007, 1.93); // +1.93mm
kernel[4] = vec4(0.358, 0.004, 0.0, 3.87); // +3.87mm
kernel[5] = vec4(0.078, 0.0, 0.0, 6.53); // +6.53mm (red only)
kernel[6] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
kernel[7] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
kernel[8] = vec4(0.100, 0.336, 0.344, -0.37); // -0.37mm
kernel[9] = vec4(0.118, 0.198, 0.0, -0.97); // -0.97mm
kernel[10] = vec4(0.113, 0.007, 0.007, -1.93); // -1.93mm
kernel[11] = vec4(0.358, 0.004, 0.0, -3.87); // -3.87mm
kernel[12] = vec4(0.078, 0.0, 0.0, -6.53); // -6.53mm (red only)
kernel[13] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
kernel[14] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
vec4 colorM = textureLod(tex, texCoord, 0.0);
float depth = textureLod(gbufferD, texCoord, 0.0).r;
kernel[0] = vec4(0.233, 0.455, 0.649, 0.0); // Center sample
kernel[1] = vec4(0.100, 0.336, 0.344, 0.37); // +0.37
kernel[2] = vec4(0.118, 0.198, 0.0, 0.97); // +0.97
kernel[3] = vec4(0.113, 0.007, 0.007, 1.93); // +1.93
kernel[4] = vec4(0.358, 0.004, 0.0, 3.87); // +3.87
kernel[5] = vec4(0.078, 0.0, 0.0, 6.53); // +6.53 (red only)
kernel[6] = vec4(0.100, 0.336, 0.344, -0.37); // -0.37
kernel[7] = vec4(0.118, 0.198, 0.0, -0.97); // -0.97
kernel[8] = vec4(0.113, 0.007, 0.007, -1.93); // -1.93
kernel[9] = vec4(0.358, 0.004, 0.0, -3.87); // -3.87
kernel[10] = vec4(0.078, 0.0, 0.0, -6.53); // -6.53 (red only)
vec2 texSize = vec2(textureSize(tex, 0));
ivec2 texelCoord = ivec2(texCoord * texSize);
vec4 colorM = texelFetch(tex, texelCoord, 0);
vec3 albedo = texelFetch(gbuffer1, texelCoord, 0).rgb;
vec3 irradianceM = colorM.rgb / max(albedo, vec3(0.00001));
float depth = texelFetch(gbufferD, texelCoord, 0).r;
float depthM = cameraProj.y / (depth - cameraProj.x);
float distanceScale = 1.0 / max(depthM, 0.1);
vec2 finalStep = sssWidth * distanceScale * dir * SSS_DISTANCE_SCALE;
float blurWidth = max(max(sssRadius.r, sssRadius.g), sssRadius.b);
float projScale = dot(dir, vec2(projectionMatrix[0][0], projectionMatrix[1][1]));
vec2 finalStep = blurWidth * (1.0 / depthM) * dir * projScale * SSS_SCALE;
vec3 jitterSeed = vec3(texCoord.xy * 1000.0, fract(cameraProj.x * 0.0001));
float jitterOffset = (hash13(jitterSeed) * 2.0 - 1.0) * 0.15;
finalStep *= (1.0 + jitterOffset);
vec3 colorBlurred = vec3(0.0);
vec3 weightSum = vec3(0.0);
colorBlurred += colorM.rgb * kernel[0].rgb;
weightSum += kernel[0].rgb;
vec3 colorBlurred = irradianceM * kernel[0].rgb;
vec3 weightSum = kernel[0].rgb;
for (int i = 1; i < SSSS_N_SAMPLES; i++) {
float sampleJitter = hash13(vec3(texCoord.xy * 720.0, float(i) * 37.45)) * 0.1 - 0.05;
vec2 offset = texCoord + (kernel[i].a + sampleJitter) * finalStep;
vec4 color = textureLod(tex, offset, 0.0);
const float DEPTH_THRESHOLD = 0.05;
float sampleDepth = textureLod(gbufferD, offset, 0.0).r;
float sampleDepthM = cameraProj.y / (sampleDepth - cameraProj.x);
float depthDiff = abs(depthM - sampleDepthM);
float depthWeight = exp(-depthDiff * 10.0);
if (depthDiff > DEPTH_THRESHOLD) {
color.rgb = mix(colorM.rgb, color.rgb, depthWeight);
vec3 irradiance = irradianceM;
float s = 0.0;
if (all(greaterThanEqual(offset, vec2(0.0))) && all(lessThan(offset, vec2(1.0)))) {
ivec2 sampleTexel = ivec2(offset * texSize);
float sampleDepth = texelFetch(gbufferD, sampleTexel, 0).r;
float sampleDepthM = cameraProj.y / (sampleDepth - cameraProj.x);
float depthDiff = abs(depthM - sampleDepthM);
if (depthDiff < 1.0) {
vec4 sampleG0 = texelFetch(gbuffer0, sampleTexel, 0);
float sampleMetallic;
uint sampleMatid;
unpackFloatInt16(sampleG0.a, sampleMetallic, sampleMatid);
bool sampleIsSSS = false;
#ifdef _ExtBRDF
if (sampleMatid >= 3u && sampleMatid < uint(MAX_MATERIALS)) {
if (materialParams[sampleMatid * 8u + 3u].z > 0.0) sampleIsSSS = true;
}
#endif
if (sampleIsSSS) {
vec3 sampleColor = texelFetch(tex, sampleTexel, 0).rgb;
vec3 sampleAlbedo = texelFetch(gbuffer1, sampleTexel, 0).rgb;
irradiance = sampleColor / max(sampleAlbedo, vec3(0.00001));
}
if (depthDiff <= DEPTH_THRESHOLD) {
s = 1.0;
} else {
s = exp(-depthDiff * 10.0);
}
}
}
colorBlurred += color.rgb * kernel[i].rgb;
colorBlurred += kernel[i].rgb * mix(irradianceM, irradiance, s);
weightSum += kernel[i].rgb;
}
vec3 normalizedColor = colorBlurred / max(weightSum, vec3(0.00001));
vec3 normalizedIrradiance = colorBlurred / max(weightSum, vec3(0.00001));
float dither = hash13(vec3(texCoord * 1333.0, 0.0)) * 0.003 - 0.0015;
normalizedColor = max(normalizedColor + vec3(dither), vec3(0.0));
return vec4(normalizedColor, colorM.a);
normalizedIrradiance = max(normalizedIrradiance + vec3(dither), vec3(0.0));
vec3 blurredColor = normalizedIrradiance * albedo;
vec3 result = mix(colorM.rgb, blurredColor, sssWeight);
return vec4(result, colorM.a);
}
void main() {
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
vec2 texSize0 = vec2(textureSize(gbuffer0, 0));
ivec2 texelCoord0 = ivec2(texCoord * texSize0);
vec4 g0 = texelFetch(gbuffer0, texelCoord0, 0);
float metallic;
uint matid;
unpackFloatInt16(g0.a, metallic, matid);
if (matid == 2u) {
vec4 originalColor = textureLod(tex, texCoord, 0.0);
vec4 blurredColor = SSSSBlur();
vec4 sssContribution = blurredColor - originalColor;
vec4 combined = originalColor + max(vec4(0.0), sssContribution) * 0.8;
fragColor = max(vec4(0.0), min(combined, vec4(10.0)));
bool applySSS = false;
vec3 sssRadius = vec3(1.0);
float sssWeight = 1.0;
vec4 matp0, matp1, matp2, matp3, matp4, matp5, matp6, matp7;
#ifdef _ExtBRDF
if (matid >= 3u && matid < uint(MAX_MATERIALS)) {
getMaterialParams(matid, matp0, matp1, matp2, matp3, matp4, matp5, matp6, matp7);
// matp3.z = subsurface, matp4.xyz = subsurfaceRadiusRGB, matp7.x = subsurfaceScale
if (matp3.z > 0.0) {
applySSS = true;
sssRadius = matp4.xyz * matp7.x;
sssWeight = matp3.z;
}
}
#endif
if (applySSS) {
fragColor = SSSSBlur(sssRadius, sssWeight);
} else {
fragColor = textureLod(tex, texCoord, 0.0);
vec2 texSizeMain = vec2(textureSize(tex, 0));
ivec2 texelCoordMain = ivec2(texCoord * texSizeMain);
fragColor = texelFetch(tex, texelCoordMain, 0);
}
}

View File

@ -13,6 +13,16 @@
{
"name": "cameraProj",
"link": "_cameraPlaneProj"
},
{
"name": "projectionMatrix",
"link": "_projectionMatrix"
},
{
"name": "materialParams",
"link": "_materialParams",
"type": "floats",
"ifdef": ["_ExtBRDF"]
}
],
"texture_params": [],
@ -32,6 +42,16 @@
{
"name": "cameraProj",
"link": "_cameraPlaneProj"
},
{
"name": "projectionMatrix",
"link": "_projectionMatrix"
},
{
"name": "materialParams",
"link": "_materialParams",
"type": "floats",
"ifdef": ["_ExtBRDF"]
}
],
"texture_params": [],

View File

@ -1,10 +1,30 @@
#ifndef _BRDF_GLSL_
#define _BRDF_GLSL_
#ifndef PI
#define PI 3.1415926535
#endif
#ifndef INV_PI
#define INV_PI 0.3183098861
#endif
#ifndef INV_TWO_PI
#define INV_TWO_PI 0.1591549430
#endif
#ifndef SCHLICK_A
#define SCHLICK_A -5.55473
#endif
#ifndef SCHLICK_B
#define SCHLICK_B -6.98316
#endif
#ifndef SRGB_GAMMA
#define SRGB_GAMMA 2.2
#endif
#define srgbToLinear(x) pow(x, vec3(SRGB_GAMMA))
// http://xlgames-inc.github.io/posts/improvedibl/
// http://blog.selfshadow.com/publications/s2013-shading-course/
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((SCHLICK_A * vh + SCHLICK_B) * vh);
}
float v_smithschlick(const float nl, const float nv, const float a) {
@ -31,7 +51,7 @@ float d_ggx(const float nh, const float a) {
float a2 = a * a;
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 */);
return a2 * (1.0 / 3.1415926535) / denom;
return a2 * INV_PI / denom;
}
vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) {
@ -44,11 +64,10 @@ vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const fl
// 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);
float D = alphaSqr / (PI * denom * denom);
// F
const float F_a = 1.0;
float F_b = pow(1.0 - dotLH, 5.0);
@ -65,21 +84,8 @@ vec3 specularBRDFb(const vec3 f0, const float roughness, const float dotNL, cons
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 * (1.0 / 3.1415926535) * nl;
return albedo * INV_PI * nl;
}
vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) {
@ -95,24 +101,6 @@ float getMipFromRoughness(const float roughness, const float numMipmaps) {
return roughness * numMipmaps;
}
float wardSpecular(vec3 N, vec3 H, float dotNL, float dotNV, float dotNH, vec3 fiberDirection, float shinyParallel, float shinyPerpendicular) {
if(dotNL < 0.0 || dotNV < 0.0) {
return 0.0;
}
// fiberDirection - parse from rotation
// shinyParallel - roughness
// shinyPerpendicular - anisotropy
vec3 fiberParallel = normalize(fiberDirection);
vec3 fiberPerpendicular = normalize(cross(N, fiberDirection));
float dotXH = dot(fiberParallel, H);
float dotYH = dot(fiberPerpendicular, H);
const float PI = 3.1415926535;
float coeff = sqrt(dotNL/dotNV) / (4.0 * PI * shinyParallel * shinyPerpendicular);
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);
}
// https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
// vec3 EnvBRDFApprox(vec3 SpecularColor, float Roughness, float NoV) {
// const vec4 c0 = { -1, -0.0275, -0.572, 0.022 };
@ -139,38 +127,39 @@ float D_Approx(const float Roughness, const float RoL) {
}
#ifdef _ClearCoat
float brdf_coatF0;
vec3 clearcoatBRDF(const float clearcoat, const float clearcoat_rough,
const float coat_ior,
const float dotNL, const float dotNH, const float dotNV, const float dotVH) {
const float coat_ior, const vec3 coatN, const vec3 l, const vec3 v, const vec3 h) {
if (clearcoat <= 0.0) return vec3(0.0);
float cdotNL = max(0.0, dot(coatN, l));
float cdotNH = max(0.0, dot(coatN, h));
float cdotNV = max(0.0, dot(coatN, v));
float cdotVH = max(0.0, dot(v, h));
float a = clearcoat_rough * clearcoat_rough;
// F0 from Fresnel equation for dielectric
float ccF0 = (coat_ior - 1.0) / (coat_ior + 1.0);
ccF0 = ccF0 * ccF0;
float F = ccF0 + (1.0 - ccF0) * pow(1.0 - dotVH, 5.0);
float D = d_ggx(dotNH, a);
float G = g2_approx(dotNL, dotNV, a);
return vec3(clearcoat * D * G * F / max(4.0 * dotNV, 1e-5));
float F = brdf_coatF0 + (1.0 - brdf_coatF0) * exp2((SCHLICK_A * cdotVH + SCHLICK_B) * cdotVH);
float D = d_ggx(cdotNH, a);
float G = g2_approx(cdotNL, cdotNV, a);
return vec3(clearcoat * D * G * F / max(4.0 * cdotNV, 1e-5));
}
float coatAttenuation(const float clearcoat,
const float coat_ior, const float dotNV) {
const float coat_ior, const vec3 coatN, const vec3 v) {
if (clearcoat <= 0.0) return 1.0;
float ccF0 = (coat_ior - 1.0) / (coat_ior + 1.0);
ccF0 = ccF0 * ccF0;
// Schlick with pow(.,5) - cheaper than exp2
float F = ccF0 + (1.0 - ccF0) * pow(1.0 - dotNV, 5.0);
float cdotNV = max(0.0, dot(coatN, v));
float F = brdf_coatF0 + (1.0 - brdf_coatF0) * exp2((SCHLICK_A * cdotNV + SCHLICK_B) * cdotNV);
return max(1.0 - F * clearcoat, 0.0);
}
vec3 coatTintAttenuation(const float clearcoat, const vec3 coat_tint, const float dotNV) {
vec3 coatTintAttenuation(const float clearcoat, const vec3 coat_tint, const vec3 coatN, const vec3 v) {
if (clearcoat <= 0.0) return vec3(1.0);
float absorption = 1.0 / max(dotNV, 0.3);
return mix(vec3(1.0), coat_tint, clamp(absorption * 0.2, 0.0, 1.0));
float cdotNV = max(0.0, dot(coatN, v));
float absorption = 1.0 / max(cdotNV, 0.3);
return mix(vec3(1.0), clamp(coat_tint, 0.0, 1.0), clamp(absorption * 0.2, 0.0, 1.0));
}
#endif
#ifdef _Sheen
float brdf_sheenAlbedo;
// based on Blender sheen model/Frostbite PBR
vec3 sheenBRDF(const float sheen, const float sheen_rough,
const vec3 sheen_tint, const float dotNL, const float dotNH, const float dotNV) {
@ -179,18 +168,16 @@ vec3 sheenBRDF(const float sheen, const float sheen_rough,
float a = rough * rough;
float sinNH2 = 1.0 - dotNH * dotNH;
float a2 = a * a;
float D = (2.0 + a2) * sinNH2 / (2.0 * 3.1415926535 * pow(1.0 + a2 * sinNH2, 2.0));
float denom = 1.0 + a2 * sinNH2;
float D = (2.0 + a2) * sinNH2 * INV_TWO_PI / (denom * denom);
float V = 1.0 / (4.0 * dotNL * dotNV + 1e-5);
float sheenAlbedo = (1.0 - 0.5 * rough) * mix(1.0, dotNV, 0.5);
return sheen_tint * sheen * D * V * dotNL * sheenAlbedo;
return sheen_tint * sheen * D * V * dotNL * brdf_sheenAlbedo;
}
float sheenAttenuation(const float sheen, const float sheen_rough,
const vec3 sheen_tint, const float dotNV) {
if (sheen <= 0.0) return 1.0;
float rough = clamp(sheen_rough, 1e-3, 1.0);
float sheenAlbedo = (1.0 - 0.5 * rough) * mix(1.0, dotNV, 0.5);
float maxComp = sheen * max(max(sheen_tint.r, sheen_tint.g), sheen_tint.b) * sheenAlbedo;
float maxComp = sheen * max(max(sheen_tint.r, sheen_tint.g), sheen_tint.b) * brdf_sheenAlbedo;
return max(1.0 - maxComp, 0.0);
}
#endif
@ -202,7 +189,7 @@ vec3 anisotropicBRDF(const vec3 f0, const float roughness, const float anisotrop
const vec3 n, const vec3 l, const vec3 v,
const float dotNL, const float dotNV) {
if (abs(anisotropy) <= 0.001) return vec3(0.0);
float rot = aniso_rot * 3.1415926535 * 2.0;
float rot = aniso_rot * PI * 2.0;
float cr = cos(rot);
float sr = sin(rot);
vec3 t = normalize(tangent * cr + bitangent * sr);
@ -221,7 +208,7 @@ vec3 anisotropicBRDF(const vec3 f0, const float roughness, const float anisotrop
float dotTL = dot(t, l);
float dotBL = dot(b, l);
float denom = max(dotTH * dotTH / at2 + dotBH * dotBH / ab2, 1e-7);
float D = 1.0 / (3.1415926535 * at * ab * denom * denom);
float D = INV_PI / (at * ab * denom * denom);
float V = 1.0 / max(dotNL * (dotTL / at + dotBL / ab) * (dotTV / at + dotBV / ab), 1e-5);
float dotVH = max(dot(v, h), 0.0);
vec3 F = f_schlick(f0, dotVH);
@ -229,46 +216,117 @@ vec3 anisotropicBRDF(const vec3 f0, const float roughness, const float anisotrop
}
#endif
#ifdef _Subsurface
// Blenders bssrdf_burley implementation
vec3 subsurfaceBRDF(const vec3 albedo, const vec3 sss_color,
const vec3 sss_radius, const float subsurface, const float sss_anisotropy,
const float dotNL) {
if (subsurface <= 0.0) return vec3(0.0);
vec3 mfp = sss_radius * (0.25 / 3.1415926535);
vec3 A = clamp(albedo, 0.0, 1.0);
vec3 d = 1.9 - A + 3.5 * (A - 0.8) * (A - 0.8);
d = mfp / max(d, 1e-5);
float aniso = clamp(sss_anisotropy, 0.0, 0.9);
float scatter = subsurface * (1.0 / 3.1415926535);
vec3 sssDiffuse = sss_color * scatter * dotNL;
float backScatter = max(0.0, 1.0 - dotNL) * (1.0 - aniso) * 0.5;
vec3 sssBack = sss_color * subsurface * backScatter;
float dist = max(0.0, 1.0 - dotNL);
vec3 rcp_d = 1.0 / max(d, vec3(1e-5));
vec3 x = vec3(dist) * rcp_d;
vec3 extinction = 1.0 / (1.0 + x + 0.5 * x * x);
return sssDiffuse * extinction + sssBack * (vec3(1.0) - extinction);
}
#endif
#ifdef _Transmission
float brdf_transmissionF0;
// Blenders microfacet glass/refraction model
vec3 transmissionBRDF(const vec3 albedo, const float transmission,
const float trans_rough, const float ior, const float thin_wall,
const float dotNL, const float dotNV, const float dotVH) {
if (transmission <= 0.0) return vec3(0.0);
float F0 = (ior - 1.0) / (ior + 1.0);
F0 = F0 * F0;
float F = F0 + (1.0 - F0) * pow(1.0 - dotVH, 5.0);
float F = brdf_transmissionF0 + (1.0 - brdf_transmissionF0) * exp2((SCHLICK_A * dotVH + SCHLICK_B) * dotVH);
float transmittance = 1.0 - F;
if (thin_wall > 0.5) {
return albedo * transmission * transmittance * dotNL;
}
float a = trans_rough * trans_rough;
float rough_atten = mix(1.0, 1.0 / max(dotNV, 0.1), a);
float rough_atten = min(mix(1.0, 1.0 / max(dotNV, 0.1), a), 4.0);
return albedo * transmission * transmittance * rough_atten * dotNL;
}
#endif
#ifdef _ExtBRDF
float brdf_sheenWeight = 1.0;
float brdf_coatWeight = 1.0;
vec3 brdf_coatTintAbsorb = vec3(1.0);
vec3 applyExtBRDFLayers(
const vec3 direct,
const vec3 albedo,
const vec3 f0,
const float roughness,
const float dotNL, const float dotNV, const float dotNH, const float dotVH,
const vec3 n, const vec3 l, const vec3 v, const vec3 h,
#ifdef _ClearCoat
const float clearcoat, const float clearcoatRough, const float coatIOR,
const vec3 coatTint, const vec3 coatN,
#endif
#ifdef _Sheen
const float sheen, const float sheenRough, const vec3 sheenTint,
#endif
#ifdef _Transmission
const float transmission, const float transRough, const float ior, const float thinWall,
#endif
out float layerWeight
) {
float sheenWeight = brdf_sheenWeight;
float coatWeight = brdf_coatWeight;
#ifdef _Sheen
vec3 sheenContrib = sheenBRDF(sheen, sheenRough, sheenTint, dotNL, dotNH, dotNV);
#endif
#ifdef _ClearCoat
vec3 coatContrib = clearcoatBRDF(clearcoat, clearcoatRough, coatIOR, coatN, l, v, h);
#endif
layerWeight = sheenWeight * coatWeight;
vec3 result = direct * layerWeight;
#ifdef _Transmission
result += transmissionBRDF(albedo, transmission, transRough, ior, thinWall, dotNL, dotNV, dotVH) * layerWeight;
#endif
#ifdef _ClearCoat
result *= brdf_coatTintAbsorb;
result += coatContrib * sheenWeight;
#endif
#ifdef _Sheen
result += sheenContrib;
#endif
return result;
}
#endif
#ifdef _ClearCoat
float coatIBLFresnel(const float clearcoat, const float coat_ior,
const float dotNV_coat) {
if (clearcoat <= 0.0) return 0.0;
float F = brdf_coatF0 + (1.0 - brdf_coatF0) * exp2((SCHLICK_A * dotNV_coat + SCHLICK_B) * dotNV_coat);
return F * clearcoat;
}
#endif
#ifdef _Sheen
float sheenIBLAlbedo(const float sheen, const float sheen_rough,
const float dotNV) {
if (sheen <= 0.0) return 0.0;
float rough = clamp(sheen_rough, 1e-3, 1.0);
return sheen * (1.0 - 0.5 * rough) * mix(1.0, dotNV, 0.5);
}
#endif
#ifdef _Anisotropy
vec3 anisotropicIBLDirection(const vec3 n, const vec3 v, const vec3 tangent,
const float anisotropy, const float roughness) {
if (abs(anisotropy) <= 0.001 || dot(tangent, tangent) < 0.001)
return reflect(-v, n);
vec3 bitangent = normalize(cross(n, tangent));
vec3 r = reflect(-v, n);
float aniso_abs = abs(anisotropy);
vec3 stretchDir = anisotropy > 0.0 ? tangent : bitangent;
float stretchAmt = aniso_abs * roughness;
return normalize(r + stretchDir * stretchAmt * dot(r, stretchDir) * 0.5);
}
#endif
#ifdef _Transmission
float transmissionIBLFresnel(const float ior, const float dotNV) {
return brdf_transmissionF0 + (1.0 - brdf_transmissionF0) * exp2((SCHLICK_A * dotNV + SCHLICK_B) * dotNV);
}
vec3 transmissionIBLDirection(const vec3 n, const vec3 v, const float ior) {
float eta = 1.0 / ior;
vec3 refrDir = refract(-v, n, eta);
if (dot(refrDir, refrDir) < 0.001) {
refrDir = reflect(-v, n);
}
return refrDir;
}
#endif
#endif

View File

@ -34,17 +34,19 @@ THE SOFTWARE.
// https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf
const float MAX_DISTANCE = voxelgiRange;
const int MAX_CONE_STEPS = 32;
#ifdef _VoxelGI
uniform sampler3D dummy;
vec4 sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCount * 10], const float clipmap_index, const float step_dist, const int precomputed_direction, const vec3 face_offset, const vec3 direction_weight) {
vec4 col = vec4(0.0);
vec3 tc = (P - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
int base = int(clipmap_index * 10);
float voxelSize = float(clipmaps[base]);
vec3 tc = (P - vec3(clipmaps[base + 4], clipmaps[base + 5], clipmaps[base + 6])) / (voxelSize * voxelgiResolution);
vec3 half_texel = vec3(0.5) / voxelgiResolution;
tc = tc * 0.5 + 0.5;
tc = clamp(tc, half_texel, 1.0 - half_texel);
tc.x = (tc.x + precomputed_direction) / (6 + DIFFUSE_CONE_COUNT);
tc.x = (tc.x + precomputed_direction) / (6 + diffuseConeCount);
tc.y = (tc.y + clipmap_index) / voxelgiClipmapCount;
if (precomputed_direction == 0) {
@ -55,7 +57,7 @@ vec4 sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCo
else
col = textureLod(voxels, tc, 0);
col *= step_dist / float(clipmaps[int(clipmap_index * 10)]);
col *= step_dist / voxelSize;
return col;
}
@ -64,11 +66,13 @@ vec4 sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCo
#ifdef _VoxelAOvar
float sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCount * 10], const float clipmap_index, const float step_dist, const int precomputed_direction, const vec3 face_offset, const vec3 direction_weight) {
float opac = 0.0;
vec3 tc = (P - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
int base = int(clipmap_index * 10);
float voxelSize = float(clipmaps[base]);
vec3 tc = (P - vec3(clipmaps[base + 4], clipmaps[base + 5], clipmaps[base + 6])) / (voxelSize * voxelgiResolution);
vec3 half_texel = vec3(0.5) / voxelgiResolution;
tc = tc * 0.5 + 0.5;
tc = clamp(tc, half_texel, 1.0 - half_texel);
tc.x = (tc.x + precomputed_direction) / (6 + DIFFUSE_CONE_COUNT);
tc.x = (tc.x + precomputed_direction) / (6 + diffuseConeCount);
tc.y = (tc.y + clipmap_index) / voxelgiClipmapCount;
if (precomputed_direction == 0) {
@ -79,7 +83,7 @@ float sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapC
else
opac = textureLod(voxels, tc, 0).r;
opac *= step_dist / float(clipmaps[int(clipmap_index * 10)]);
opac *= step_dist / voxelSize;
return opac;
}
@ -92,7 +96,7 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
float dist = voxelSize0;
float step_dist = dist;
vec3 samplePos;
vec3 start_pos = origin + n * voxelSize0;
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
int clipmap_index0 = 0;
vec3 aniso_direction = -dir;
@ -100,12 +104,14 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
aniso_direction.x > 0.0 ? 0.0 : 1.0,
aniso_direction.y > 0.0 ? 2.0 : 3.0,
aniso_direction.z > 0.0 ? 4.0 : 5.0
) / (6 + DIFFUSE_CONE_COUNT);
) / (6 + diffuseConeCount);
vec3 direction_weight = abs(dir);
float coneCoefficient = 2.0 * tan(aperture * 0.5);
while (sampleCol.a < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) {
const vec3 half_texel = vec3(0.5) / voxelgiResolution;
int steps = 0;
while (sampleCol.a < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount && steps < MAX_CONE_STEPS) {
vec4 mipSample = vec4(0.0);
float diam = max(voxelSize0, dist * coneCoefficient);
float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
@ -113,7 +119,9 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
float clipmap_blend = smoothstep(0.0, 1.0, fract(lod));
vec3 p0 = start_pos + dir * dist;
samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
int base = int(clipmap_index * 10);
float voxelSize = float(clipmaps[base]);
samplePos = (p0 - vec3(clipmaps[base + 4], clipmaps[base + 5], clipmaps[base + 6])) / (voxelSize * voxelgiResolution);
samplePos = samplePos * 0.5 + 0.5;
if (any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0)))) {
@ -129,8 +137,11 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, precomputed_direction, face_offset, direction_weight);
if(totalBlend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
if(totalBlend > 0.05 && clipmap_index < voxelgiClipmapCount - 1) {
vec4 mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
int baseNext = int((clipmap_index + 1.0) * 10);
float voxelSizeCoarse = float(clipmaps[baseNext]);
mipSampleNext *= voxelSizeCoarse / voxelSize;
mipSample = mix(mipSample, mipSampleNext, totalBlend);
}
@ -138,8 +149,6 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
float stepSizeCurrent = step_size;
if (use_sdf) {
// half texel correction is applied to avoid sampling over current clipmap:
const vec3 half_texel = vec3(0.5) / voxelgiResolution;
vec3 tc0 = clamp(samplePos, half_texel, 1 - half_texel);
tc0.y = (tc0.y + clipmap_index) / voxelgiClipmapCount; // remap into clipmap
float sdf = textureLod(voxelsSDF, tc0, 0).r;
@ -147,6 +156,7 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
}
step_dist = diam * stepSizeCurrent;
dist += step_dist;
steps++;
}
return sampleCol;
}
@ -154,13 +164,13 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
float sum = 0.0;
vec4 amount = vec4(0.0);
for (int i = 0; i < DIFFUSE_CONE_COUNT; ++i) {
vec3 coneDir = DIFFUSE_CONE_DIRECTIONS[i];
for (int i = 0; i < diffuseConeCount; ++i) {
vec3 coneDir = diffuseConeDirections[i];
const float cosTheta = dot(normal, coneDir);
if (cosTheta <= 0)
continue;
int precomputed_direction = 6 + i;
amount += traceCone(voxels, dummy, origin, normal, coneDir, precomputed_direction, false, DIFFUSE_CONE_APERTURE, 1.0, clipmaps) * cosTheta;
amount += traceCone(voxels, voxels, origin, normal, coneDir, precomputed_direction, false, diffuseConeAperture, 1.0, clipmaps) * cosTheta;
sum += cosTheta;
}
@ -191,7 +201,7 @@ vec4 traceRefraction(const vec3 origin, const vec3 normal, sampler3D voxels, sam
amount.rgb = max(vec3(0.0), amount.rgb);
amount.a = clamp(amount.a, 0.0, 1.0);
return amount * voxelgiOcc;
return amount * voxelgiOcc * voxelgiRefr;
}
#endif
@ -202,7 +212,7 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
float dist = voxelSize0;
float step_dist = dist;
vec3 samplePos;
vec3 start_pos = origin + n * voxelSize0;
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
int clipmap_index0 = 0;
vec3 aniso_direction = -dir;
@ -210,12 +220,13 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
aniso_direction.x > 0.0 ? 0.0 : 1.0,
aniso_direction.y > 0.0 ? 2.0 : 3.0,
aniso_direction.z > 0.0 ? 4.0 : 5.0
) / (6 + DIFFUSE_CONE_COUNT);
) / (6 + diffuseConeCount);
vec3 direction_weight = abs(dir);
float coneCoefficient = 2.0 * tan(aperture * 0.5);
while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) {
int steps = 0;
while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount && steps < MAX_CONE_STEPS) {
float mipSample = 0.0;
float diam = max(voxelSize0, dist * coneCoefficient);
float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
@ -223,7 +234,9 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
float clipmap_blend = smoothstep(0.0, 1.0, fract(lod));
vec3 p0 = start_pos + dir * dist;
samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
int base = int(clipmap_index * 10);
float voxelSize = float(clipmaps[base]);
samplePos = (p0 - vec3(clipmaps[base + 4], clipmaps[base + 5], clipmaps[base + 6])) / (voxelSize * voxelgiResolution);
samplePos = samplePos * 0.5 + 0.5;
if ((any(notEqual(clamp(samplePos, 0.0, 1.0), samplePos)))) {
@ -239,8 +252,11 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, precomputed_direction, face_offset, direction_weight);
if(totalBlend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
if(totalBlend > 0.05 && clipmap_index < voxelgiClipmapCount - 1) {
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
int baseNext = int((clipmap_index + 1.0) * 10);
float voxelSizeCoarse = float(clipmaps[baseNext]);
mipSampleNext *= voxelSizeCoarse / voxelSize;
mipSample = mix(mipSample, mipSampleNext, totalBlend);
}
@ -248,6 +264,7 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
step_dist = diam * step_size;
dist += step_dist;
steps++;
}
return sampleCol;
}
@ -256,18 +273,18 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
float traceAO(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
float sum = 0.0;
float amount = 0.0;
for (int i = 0; i < DIFFUSE_CONE_COUNT; i++) {
vec3 coneDir = DIFFUSE_CONE_DIRECTIONS[i];
for (int i = 0; i < diffuseConeCount; i++) {
vec3 coneDir = diffuseConeDirections[i];
int precomputed_direction = 6 + i;
const float cosTheta = dot(normal, coneDir);
if (cosTheta <= 0)
continue;
amount += traceConeAO(voxels, origin, normal, coneDir, precomputed_direction, DIFFUSE_CONE_APERTURE, 1.0, clipmaps) * cosTheta;
amount += traceConeAO(voxels, origin, normal, coneDir, precomputed_direction, diffuseConeAperture, 1.0, clipmaps) * cosTheta;
sum += cosTheta;
}
amount /= max(sum, 0.0001);
amount = clamp(amount, 0.0, 1.0);
return amount * voxelgiOcc;
return amount;
}
#endif
@ -278,7 +295,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
float dist = voxelSize0;
float step_dist = dist;
vec3 samplePos;
vec3 start_pos = origin + n * voxelSize0;
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
int clipmap_index0 = 0;
vec3 aniso_direction = -dir;
@ -286,11 +303,13 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
aniso_direction.x > 0.0 ? 0.0 : 1.0,
aniso_direction.y > 0.0 ? 2.0 : 3.0,
aniso_direction.z > 0.0 ? 4.0 : 5.0
) / (6 + DIFFUSE_CONE_COUNT);
) / (6 + diffuseConeCount);
vec3 direction_weight = abs(dir);
float coneCoefficient = 2.0 * tan(aperture * 0.5);
while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) {
const vec3 half_texel = vec3(0.5) / voxelgiResolution;
int steps = 0;
while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount && steps < MAX_CONE_STEPS) {
float mipSample = 0.0;
float diam = max(voxelSize0, dist * coneCoefficient);
float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
@ -298,7 +317,9 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
float clipmap_blend = smoothstep(0.0, 1.0, fract(lod));
vec3 p0 = start_pos + dir * dist;
samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
int base = int(clipmap_index * 10);
float voxelSize = float(clipmaps[base]);
samplePos = (p0 - vec3(clipmaps[base + 4], clipmaps[base + 5], clipmaps[base + 6])) / (voxelSize * voxelgiResolution);
samplePos = samplePos * 0.5 + 0.5;
if ((any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0))))) {
@ -318,11 +339,14 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, 0, face_offset, direction_weight).a;
#endif
if(totalBlend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
if(totalBlend > 0.05 && clipmap_index < voxelgiClipmapCount - 1) {
int baseNext = int((clipmap_index + 1.0) * 10);
float voxelSizeCoarse = float(clipmaps[baseNext]);
float scaleRatio = voxelSizeCoarse / voxelSize;
#ifdef _VoxelAOvar
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, 0, face_offset, direction_weight);
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, 0, face_offset, direction_weight) * scaleRatio;
#else
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, 0, face_offset, direction_weight).a;
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, 0, face_offset, direction_weight).a * scaleRatio;
#endif
mipSample = mix(mipSample, mipSampleNext, totalBlend);
}
@ -331,8 +355,6 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
float stepSizeCurrent = step_size;
// half texel correction is applied to avoid sampling over current clipmap:
const vec3 half_texel = vec3(0.5) / voxelgiResolution;
vec3 tc0 = clamp(samplePos, half_texel, 1 - half_texel);
tc0.y = (tc0.y + clipmap_index) / voxelgiClipmapCount; // remap into clipmap
float sdf = textureLod(voxelsSDF, tc0, 0.0).r;
@ -340,6 +362,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
step_dist = diam * stepSizeCurrent;
dist += step_dist;
steps++;
}
return sampleCol;
}
@ -347,7 +370,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
vec3 P = origin + dir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, SHADOW_CONE_APERTURE, voxelgiStep, clipmaps);
float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, voxelgiAperture, voxelgiStep, clipmaps);
amount = clamp(amount, 0.0, 1.0);
return amount * voxelgiOcc;
}

View File

@ -20,13 +20,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
const int DIFFUSE_CONE_COUNT = 16;
const float diffuseConeAperture = radians(39.0);
const float SHADOW_CONE_APERTURE = radians(15.0);
const float DIFFUSE_CONE_APERTURE = 1.0;
const vec3 DIFFUSE_CONE_DIRECTIONS[16] = vec3[](
const vec3 diffuseConeDirections[16] = vec3[](
vec3( 0.3480, 0.0000, 0.9375),
vec3(-0.4299, 0.3938, 0.8125),
vec3( 0.0635, -0.7234, 0.6875),

View File

@ -173,16 +173,85 @@ void unpackFloatInt16(float val, out float f, out uint i) {
#ifdef _ExtBRDF
// extended material parameters by material slot ID returns vec4s (28 floats) of extended BRDF parameters
void getMaterialParams(uint matid, out vec4 p0, out vec4 p1, out vec4 p2, out vec4 p3,
out vec4 p4, out vec4 p5, out vec4 p6) {
out vec4 p4, out vec4 p5, out vec4 p6, out vec4 p7) {
uint base = matid * 8u;
#if defined(_Anisotropy) || defined(_Sheen)
p0 = materialParams[base];
#else
p0 = vec4(0.0);
#endif
#if defined(_ClearCoat)
p1 = materialParams[base + 1u];
#else
p1 = vec4(0.0);
#endif
#if defined(_ClearCoat) || defined(_Transmission)
p2 = materialParams[base + 2u];
#else
p2 = vec4(0.0);
#endif
#if defined(_Transmission) || defined(_SSS)
p3 = materialParams[base + 3u];
#else
p3 = vec4(0.0);
#endif
#if defined(_SSS)
p4 = materialParams[base + 4u];
#else
p4 = vec4(0.0);
#endif
#if defined(_Sheen) || defined(_SSS)
p5 = materialParams[base + 5u];
#else
p5 = vec4(0.0);
#endif
#if defined(_ExtBRDF)
p6 = materialParams[base + 6u];
#else
p6 = vec4(0.0);
#endif
#if defined(_SSS)
p7 = materialParams[base + 7u];
#else
p7 = vec4(0.0);
#endif
}
#endif
float packIOR(float ior) {
return clamp((ior - 1.0) / 1.5, 0.0, 1.0);
}
float unpackIOR(float packed) {
return packed * 1.5 + 1.0;
}
#ifndef PI
#define PI 3.1415926535
#endif
#ifndef PI2
#define PI2 6.2831853071
#endif
float encodeTangent(vec3 tangent, vec3 normal) {
if (length(tangent) < 0.5) return -1.0;
vec3 t = normalize(tangent);
vec3 n = normalize(normal);
vec3 ref = abs(n.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
vec3 r = normalize(ref - n * dot(ref, n));
vec3 b = cross(n, r);
float angle = atan(dot(t, b), dot(t, r));
return (angle / (2.0 * PI) + 0.5);
}
vec3 decodeTangent(float enc, vec3 normal) {
if (enc < 0.0) return vec3(1.0, 0.0, 0.0);
vec3 n = normalize(normal);
vec3 ref = abs(n.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
vec3 r = normalize(ref - n * dot(ref, n));
vec3 b = cross(n, r);
float angle = (enc - 0.5) * 2.0 * PI;
return normalize(r * cos(angle) + b * sin(angle));
}
#endif

View File

@ -3,7 +3,9 @@ uniform sampler2D texIES;
float iesAttenuation(vec3 l) {
const float PI = 3.1415926535;
#ifndef PI
#define PI 3.1415926535
#endif
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
// Sample direction into light space
// vec3 iesSampleDirection = mul(light.worldToLight , -L);

View File

@ -51,7 +51,9 @@
//!uniform sampler2D shadowMapAtlasTransparent;
#endif
#endif
#ifndef _SinglePoint
uniform vec2 lightProj;
#endif
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasPoint;
@ -92,7 +94,6 @@ uniform vec3 lightArea3;
uniform sampler2D sltcMat;
uniform sampler2D sltcMag;
#ifdef _ShadowMap
#ifndef _Spot
#ifdef _SinglePoint
uniform sampler2DShadow shadowMapSpot[1];
#ifdef _ShadowMapTransparent
@ -100,18 +101,10 @@ uniform sampler2D sltcMag;
#endif
uniform mat4 LWVPSpotArray[1];
#endif
#ifdef _Clusters
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
#ifdef _ShadowMapTransparent
uniform sampler2D shadowMapSpotTransparent[maxLightsCluster];
#endif
uniform mat4 LWVPSpotArray[maxLightsCluster];
#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 sampleLightCore(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
#ifdef _ShadowMap
, int index, float bias, bool receiveShadow
@ -122,17 +115,8 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#ifdef _Spot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
#ifdef _VoxelShadow
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount], vec2 velocity
#endif
#ifdef _MicroShadowing
, float occ
#endif
#ifdef _SSRS
, sampler2D gbufferD, mat4 invVP, vec3 eye
#endif
#ifdef _ClearCoat
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint, vec3 coatN
#endif
#ifdef _Sheen
, float sheen, float sheenRough, vec3 sheenTint
@ -140,20 +124,25 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#ifdef _Anisotropy
, float anisotropy, float anisoRot, vec3 tangent
#endif
#ifdef _Subsurface
#ifdef _SSS
, float subsurface, vec3 sssColor, vec3 sssRadius, float sssAnisotropy
#endif
#ifdef _Transmission
, float transmission, float transRough, float ior, float thinWall
#endif
, out vec3 l_out
) {
vec3 ld = lp - p;
vec3 l = normalize(ld);
float dist = length(ld);
vec3 l = ld / dist;
vec3 h = normalize(v + l);
float dotNH = max(0.0, dot(n, h));
float dotVH = max(0.0, dot(v, h));
float dotNL = max(0.0, dot(n, l));
#ifdef _VoxelPass
vec3 direct = vec3(dotNL);
#else
#ifdef _LTC
float theta = acos(dotNV);
vec2 tuv = vec2(rough, theta / (0.5 * PI));
@ -170,7 +159,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#else
#ifdef _Anisotropy
vec3 direct;
if (abs(anisotropy) > 0.001) {
if (abs(anisotropy) > 0.001 && dot(tangent, tangent) > 0.001) {
vec3 bitangent = normalize(cross(n, tangent));
direct = lambertDiffuseBRDF(albedo, dotNL) +
anisotropicBRDF(f0, rough, anisotropy, anisoRot,
@ -181,62 +170,36 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
}
#else
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
#endif
#endif
// before attenuate/shadow so everything is properly shadowed in one pass
float sheenWeight = 1.0;
float coatWeight = 1.0;
#ifdef _Sheen
vec3 sheenContrib = sheenBRDF(sheen, sheenRough, sheenTint, dotNL, dotNH, dotNV);
sheenWeight = sheenAttenuation(sheen, sheenRough, sheenTint, dotNV);
#ifdef _ExtBRDF
float layerWeight;
direct = applyExtBRDFLayers(direct, albedo, f0, rough,
dotNL, dotNV, dotNH, dotVH, n, l, v, h
#ifdef _ClearCoat
, clearcoat, clearcoatRough, coatIOR, coatTint, coatN
#endif
#ifdef _Sheen
, sheen, sheenRough, sheenTint
#endif
#ifdef _Transmission
, transmission, transRough, ior, thinWall
#endif
, layerWeight);
#endif
#ifdef _ClearCoat
vec3 coatContrib = clearcoatBRDF(clearcoat, clearcoatRough, coatIOR, dotNL, dotNH, dotNV, dotVH);
coatWeight = coatAttenuation(clearcoat, coatIOR, dotNV);
#endif
float layerWeight = sheenWeight * coatWeight;
direct *= layerWeight;
#ifdef _Subsurface
direct += subsurfaceBRDF(albedo, sssColor, sssRadius, subsurface, sssAnisotropy, dotNL) * layerWeight;
#endif
#ifdef _Transmission
direct += transmissionBRDF(albedo, transmission, transRough, ior, thinWall, dotNL, dotNV, dotVH) * layerWeight;
#endif
#ifdef _ClearCoat
direct *= coatTintAttenuation(clearcoat, coatTint, dotNV);
direct += coatContrib * sheenWeight;
#endif
#ifdef _Sheen
direct += sheenContrib;
#endif
direct *= attenuate(distance(p, lp));
direct *= attenuate(dist);
direct *= min(lightCol, vec3(100.0));
#ifdef _MicroShadowing
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
#endif
#ifdef _SSRS
direct *= traceShadowSS(l, p, gbufferD, invVP, eye);
#endif
#ifdef _VoxelShadow
vec3 lightDir = l;
#ifdef _Spot
if (isSpot)
lightDir = spotDir;
#endif
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, lightDir, clipmaps, gl_FragCoord.xy, velocity).r) * voxelgiShad;
#endif
#ifdef _LTC
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
@ -248,7 +211,29 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 10, 1.0);
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
#ifdef _ShadowMapAtlas
tileBounds = tileBoundsSpotArray[index];
direct *= shadowTest(
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSpot
#else
shadowMapAtlas
#endif
#endif
, lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
@ -286,8 +271,10 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#endif
);
#endif
#endif
}
#endif
l_out = l;
return direct;
#endif
@ -312,25 +299,26 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
#ifdef _ShadowMapAtlas
direct *= shadowTest(
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSpot
#else
shadowMapAtlas
#endif
#endif
, lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
tileBounds = tileBoundsSpotArray[index];
direct *= shadowTest(
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSpot
#else
shadowMapAtlas
#endif
#endif
, lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
@ -372,6 +360,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#endif
}
#endif
l_out = l;
return direct;
}
#endif
@ -458,9 +447,157 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
}
#endif
l_out = l;
return direct;
}
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
#ifdef _ShadowMap
, int index, float bias, bool receiveShadow
#ifdef _ShadowMapTransparent
, bool transparent
#endif
#endif
#ifdef _Spot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
#ifdef _VoxelShadow
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount], vec2 velocity
#endif
#ifdef _MicroShadowing
, float occ
#endif
#ifdef _SSRS
, sampler2D gbufferD, mat4 invVP, vec3 eye
#endif
#ifdef _ClearCoat
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint, vec3 coatN
#endif
#ifdef _Sheen
, float sheen, float sheenRough, vec3 sheenTint
#endif
#ifdef _Anisotropy
, float anisotropy, float anisoRot, vec3 tangent
#endif
#ifdef _SSS
, float subsurface, vec3 sssColor, vec3 sssRadius, float sssAnisotropy
#endif
#ifdef _Transmission
, float transmission, float transRough, float ior, float thinWall
#endif
) {
vec3 l;
vec3 direct = sampleLightCore(p, n, v, dotNV, lp, lightCol, albedo, rough, spec, f0
#ifdef _ShadowMap
, index, bias, receiveShadow
#ifdef _ShadowMapTransparent
, transparent
#endif
#endif
#ifdef _Spot
, isSpot, spotSize, spotBlend, spotDir, scale, right
#endif
#ifdef _ClearCoat
, clearcoat, clearcoatRough, coatIOR, coatTint, coatN
#endif
#ifdef _Sheen
, sheen, sheenRough, sheenTint
#endif
#ifdef _Anisotropy
, anisotropy, anisoRot, tangent
#endif
#ifdef _SSS
, subsurface, sssColor, sssRadius, sssAnisotropy
#endif
#ifdef _Transmission
, transmission, transRough, ior, thinWall
#endif
, l);
float dotNL = max(0.0, dot(n, l));
#ifdef _MicroShadowing
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
#endif
#ifdef _SSRS
direct *= traceShadowSS(l, p, gbufferD, invVP, eye);
#endif
#ifdef _VoxelShadow
vec3 lightDir = l;
#ifdef _Spot
if (isSpot)
lightDir = spotDir;
#endif
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, lightDir, clipmaps, gl_FragCoord.xy, velocity).r) * voxelgiShad;
#endif
return direct;
}
// Backward-compatible overload for generated shaders that don't pass extended BRDF params
#ifdef _ExtBRDF
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
#ifdef _ShadowMap
, int index, float bias, bool receiveShadow
#ifdef _ShadowMapTransparent
, bool transparent
#endif
#endif
#ifdef _Spot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
#ifdef _VoxelShadow
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount], vec2 velocity
#endif
#ifdef _MicroShadowing
, float occ
#endif
#ifdef _SSRS
, sampler2D gbufferD, mat4 invVP, vec3 eye
#endif
) {
return sampleLight(p, n, v, dotNV, lp, lightCol, albedo, rough, spec, f0
#ifdef _ShadowMap
, index, bias, receiveShadow
#ifdef _ShadowMapTransparent
, transparent
#endif
#endif
#ifdef _Spot
, isSpot, spotSize, spotBlend, spotDir, scale, right
#endif
#ifdef _VoxelShadow
, voxels, voxelsSDF, clipmaps, velocity
#endif
#ifdef _MicroShadowing
, occ
#endif
#ifdef _SSRS
, gbufferD, invVP, eye
#endif
#ifdef _ClearCoat
, 0.0, 0.0, 1.5, vec3(1.0), n
#endif
#ifdef _Sheen
, 0.0, 0.0, vec3(1.0)
#endif
#ifdef _Anisotropy
, 0.0, 0.0, vec3(0.0)
#endif
#ifdef _SSS
, 0.0, vec3(0.0), vec3(0.0), 0.0
#endif
#ifdef _Transmission
, 0.0, 0.0, 1.45, 1.0
#endif
);
}
#endif // _ExtBRDF
#ifdef _VoxelGI
vec3 sampleLightVoxels(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
@ -474,7 +611,7 @@ vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
#ifdef _ClearCoat
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint, vec3 coatN
#endif
#ifdef _Sheen
, float sheen, float sheenRough, vec3 sheenTint
@ -482,295 +619,85 @@ vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dot
#ifdef _Anisotropy
, float anisotropy, float anisoRot, vec3 tangent
#endif
#ifdef _Subsurface
#ifdef _SSS
, float subsurface, vec3 sssColor, vec3 sssRadius, float sssAnisotropy
#endif
#ifdef _Transmission
, float transmission, float transRough, float ior, float thinWall
#endif
) {
vec3 ld = lp - p;
vec3 l = normalize(ld);
vec3 h = normalize(v + l);
float dotNH = max(0.0, dot(n, h));
float dotVH = max(0.0, dot(v, h));
float dotNL = max(0.0, dot(n, l));
#ifdef _LTC
float theta = acos(dotNV);
vec2 tuv = vec2(rough, theta / (0.5 * PI));
tuv = tuv * LUT_SCALE + LUT_BIAS;
vec4 t = textureLod(sltcMat, tuv, 0.0);
mat3 invM = mat3(
vec3(1.0, 0.0, t.y),
vec3(0.0, t.z, 0.0),
vec3(t.w, 0.0, t.x));
float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3);
ltcspec *= textureLod(sltcMag, tuv, 0.0).a;
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
#else
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
#endif
float sheenWeight = 1.0;
float coatWeight = 1.0;
#ifdef _Sheen
vec3 sheenContrib = sheenBRDF(sheen, sheenRough, sheenTint, dotNL, dotNH, dotNV);
sheenWeight = sheenAttenuation(sheen, sheenRough, sheenTint, dotNV);
#endif
#ifdef _ClearCoat
vec3 coatContrib = clearcoatBRDF(clearcoat, clearcoatRough, coatIOR, dotNL, dotNH, dotNV, dotVH);
coatWeight = coatAttenuation(clearcoat, coatIOR, dotNV);
#endif
float layerWeight = sheenWeight * coatWeight;
direct *= layerWeight;
#ifdef _Subsurface
direct += subsurfaceBRDF(albedo, sssColor, sssRadius, subsurface, sssAnisotropy, dotNL) * layerWeight;
#endif
#ifdef _Transmission
direct += transmissionBRDF(albedo, transmission, transRough, ior, thinWall, dotNL, dotNV, dotVH) * layerWeight;
#endif
#ifdef _ClearCoat
direct *= coatTintAttenuation(clearcoat, coatTint, dotNV);
direct += coatContrib * sheenWeight;
#endif
#ifdef _Sheen
direct += sheenContrib;
#endif
direct *= attenuate(distance(p, lp));
// CRITICAL: Clamp light color to prevent extreme HDR values causing white sphere artifacts
direct *= min(lightCol, vec3(100.0));
#ifdef _LTC
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 10, 1.0);
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[1],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[2],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[3],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
}
#endif
return direct;
#endif
#ifdef _Spot
if (isSpot) {
direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
) {
vec3 l;
return sampleLightCore(p, n, v, dotNV, lp, lightCol, albedo, rough, spec, f0
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
#ifdef _ShadowMapAtlas
direct *= shadowTest(
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSpot
#else
shadowMapAtlas
#endif
#endif
, lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[1],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[2],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[3],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#endif
}
, index, bias, receiveShadow
#ifdef _ShadowMapTransparent
, transparent
#endif
return direct;
}
#endif
#ifdef _LightIES
direct *= iesAttenuation(-l);
#endif
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
#ifndef _Spot
direct *= PCFCube(shadowMapPoint[0],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[0],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#endif
#ifdef _Clusters
#ifdef _ShadowMapAtlas
direct *= PCFFakeCube(
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasPoint, shadowMapAtlasPointTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasPoint
#else
shadowMapAtlas
#endif
#endif
, ld, -l, bias, lightProj, n, index
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else
if (index == 0) direct *= PCFCube(shadowMapPoint[0],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[0],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 1) direct *= PCFCube(shadowMapPoint[1],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[1],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 2) direct *= PCFCube(shadowMapPoint[2],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[2],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
else if (index == 3) direct *= PCFCube(shadowMapPoint[3],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[3],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#endif
}
#endif
return direct;
#endif
#ifdef _Spot
, isSpot, spotSize, spotBlend, spotDir, scale, right
#endif
#ifdef _ClearCoat
, clearcoat, clearcoatRough, coatIOR, coatTint, coatN
#endif
#ifdef _Sheen
, sheen, sheenRough, sheenTint
#endif
#ifdef _Anisotropy
, anisotropy, anisoRot, tangent
#endif
#ifdef _SSS
, subsurface, sssColor, sssRadius, sssAnisotropy
#endif
#ifdef _Transmission
, transmission, transRough, ior, thinWall
#endif
, l);
}
// Backward-compatible overload for generated shaders that don't pass extended BRDF params
#ifdef _ExtBRDF
vec3 sampleLightVoxels(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
#ifdef _ShadowMap
, int index, float bias, bool receiveShadow
#ifdef _ShadowMapTransparent
, bool transparent
#endif
#endif
#ifdef _Spot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
) {
vec3 l;
return sampleLightCore(p, n, v, dotNV, lp, lightCol, albedo, rough, spec, f0
#ifdef _ShadowMap
, index, bias, receiveShadow
#ifdef _ShadowMapTransparent
, transparent
#endif
#endif
#ifdef _Spot
, isSpot, spotSize, spotBlend, spotDir, scale, right
#endif
#ifdef _ClearCoat
, 0.0, 0.0, 1.5, vec3(1.0), n
#endif
#ifdef _Sheen
, 0.0, 0.0, vec3(1.0)
#endif
#ifdef _Anisotropy
, 0.0, 0.0, vec3(0.0)
#endif
#ifdef _SSS
, 0.0, vec3(0.0), vec3(0.0), 0.0
#endif
#ifdef _Transmission
, 0.0, 0.0, 1.45, 1.0
#endif
, l);
}
#endif // _ExtBRDF
#endif
#endif

View File

@ -14,7 +14,7 @@
#ifdef _SinglePoint
#ifdef _Spot
uniform sampler2DShadow shadowMapSpot[1];
uniform mat4 LWVPSpot[1];
uniform mat4 LWVPSpotArray[1];
#else
uniform samplerCubeShadow shadowMapPoint[1];
uniform vec2 lightProj;
@ -24,7 +24,9 @@
#ifdef _SingleAtlas
//!uniform sampler2DShadow shadowMapAtlas;
#endif
#ifndef _SinglePoint
uniform vec2 lightProj;
#endif
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasPoint;
@ -54,7 +56,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
, bool isSpot, float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
#ifdef _ClearCoat
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint, vec3 coatN
#endif
#ifdef _Sheen
, float sheen, float sheenRough, vec3 sheenTint
@ -62,7 +64,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#ifdef _Anisotropy
, float anisotropy, float anisoRot, vec3 tangent
#endif
#ifdef _Subsurface
#ifdef _SSS
, float subsurface, vec3 sssColor, vec3 sssRadius, float sssAnisotropy
#endif
#ifdef _Transmission
@ -70,7 +72,8 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#endif
) {
vec3 ld = lp - p;
vec3 l = normalize(ld);
float dist = length(ld);
vec3 l = ld / dist;
vec3 h = normalize(v + l);
float dotNH = max(0.0, dot(n, h));
float dotVH = max(0.0, dot(v, h));
@ -78,7 +81,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#ifdef _Anisotropy
vec3 direct;
if (abs(anisotropy) > 0.001) {
if (abs(anisotropy) > 0.001 && dot(tangent, tangent) > 0.001) {
vec3 bitangent = normalize(cross(n, tangent));
direct = lambertDiffuseBRDF(albedo, dotNL) +
anisotropicBRDF(f0, rough, anisotropy, anisoRot,
@ -92,34 +95,24 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
#endif
float sheenWeight = 1.0;
float coatWeight = 1.0;
#ifdef _Sheen
vec3 sheenContrib = sheenBRDF(sheen, sheenRough, sheenTint, dotNL, dotNH, dotNV);
sheenWeight = sheenAttenuation(sheen, sheenRough, sheenTint, dotNV);
#endif
#ifdef _ClearCoat
vec3 coatContrib = clearcoatBRDF(clearcoat, clearcoatRough, coatIOR, dotNL, dotNH, dotNV, dotVH);
coatWeight = coatAttenuation(clearcoat, coatIOR, dotNV);
#endif
float layerWeight = sheenWeight * coatWeight;
direct *= layerWeight;
#ifdef _Subsurface
direct += subsurfaceBRDF(albedo, sssColor, sssRadius, subsurface, sssAnisotropy, dotNL) * layerWeight;
#endif
#ifdef _Transmission
direct += transmissionBRDF(albedo, transmission, transRough, ior, thinWall, dotNL, dotNV, dotVH) * layerWeight;
#endif
#ifdef _ClearCoat
direct *= coatTintAttenuation(clearcoat, coatTint, dotNV);
direct += coatContrib * sheenWeight;
#endif
#ifdef _Sheen
direct += sheenContrib;
#ifdef _ExtBRDF
float layerWeight;
direct = applyExtBRDFLayers(direct, albedo, f0, rough, dotNL, dotNV, dotNH, dotVH, n, l, v, h
#ifdef _ClearCoat
, clearcoat, clearcoatRough, coatIOR, coatTint, coatN
#endif
#ifdef _Sheen
, sheen, sheenRough, sheenTint
#endif
#ifdef _Transmission
, transmission, transRough, ior, thinWall
#endif
, layerWeight
);
#endif
direct *= lightCol;
direct *= attenuate(distance(p, lp));
direct *= attenuate(dist);
#ifdef _Spot
if (isSpot) {
@ -128,12 +121,13 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
#ifdef _ShadowMapAtlas
tileBounds = tileBoundsSpotArray[index];
direct *= shadowTest(
#ifndef _SingleAtlas
shadowMapAtlasSpot
@ -186,4 +180,41 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
return direct;
}
// Backward-compatible overload for generated shaders that don't pass extended BRDF params
#ifdef _ExtBRDF
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
#ifdef _ShadowMap
, int index, float bias, bool receiveShadow
#endif
#ifdef _Spot
, bool isSpot, float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
) {
return sampleLight(p, n, v, dotNV, lp, lightCol, albedo, rough, spec, f0
#ifdef _ShadowMap
, index, bias, receiveShadow
#endif
#ifdef _Spot
, isSpot, spotSize, spotBlend, spotDir, scale, right
#endif
#ifdef _ClearCoat
, 0.0, 0.0, 1.5, vec3(1.0), n
#endif
#ifdef _Sheen
, 0.0, 0.0, vec3(1.0)
#endif
#ifdef _Anisotropy
, 0.0, 0.0, vec3(0.0)
#endif
#ifdef _SSS
, 0.0, vec3(0.0), vec3(0.0), 0.0
#endif
#ifdef _Transmission
, 0.0, 0.0, 1.45, 1.0
#endif
);
}
#endif // _ExtBRDF
#endif

View File

@ -8,8 +8,12 @@ float hash(const vec2 p) {
}
vec2 envMapEquirect(const vec3 normal) {
const float PI = 3.1415926535;
const float PI2 = PI * 2.0;
#ifndef PI
#define PI 3.1415926535
#endif
#ifndef PI2
#define PI2 6.2831853071
#endif
float phi = acos(normal.z);
float theta = atan(-normal.y, normal.x) + PI;
return vec2(theta / PI2, phi / PI);

View File

@ -22,6 +22,14 @@ uniform vec2 smSizeUniform;
#endif
#endif
#ifdef _ShadowMapAtlas
uniform vec4 tileBoundsSunArray[maxLights * shadowmapCascades];
#if defined(_Clusters) && defined(_Spot) && defined(_ShadowMap)
uniform vec4 tileBoundsSpotArray[maxLightsCluster];
#endif
vec4 tileBounds = vec4(0.0, 0.0, 1.0, 1.0);
#endif
#ifdef _ShadowMapAtlas
// PCF that clamps samples to tile boundaries to prevent bleeding
vec3 PCFTileAware(sampler2DShadow shadowMap,
@ -291,13 +299,13 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap,
, const bool transparent
#endif
) {
const vec2 smSize = smSizeUniform; // TODO: incorrect...
const float compare = lpToDepth(lp, lightProj) - bias * 1.5;
ml = ml + n * bias * 20;
int faceIndex = 0;
const int lightIndex = index * 6;
const vec2 uv = sampleCube(ml, faceIndex);
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
const vec2 smSize = smSizeUniform; // TODO: incorrect...
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
#ifdef _FlipY
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
@ -387,10 +395,6 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap,
}
#endif
#ifdef _ShadowMapAtlas
uniform vec4 tileBounds;
#endif
vec3 shadowTest(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
@ -405,9 +409,9 @@ vec3 shadowTest(sampler2DShadow shadowMap,
#ifdef _ShadowMapAtlas
// use tile PCF
#ifdef _SMSizeUniform
vec2 smSizeAtlas = smSizeUniform;
vec2 smSizeAtlas = smSizeUniform * (tileBounds.zw - tileBounds.xy);
#else
const vec2 smSizeAtlas = shadowmapSize;
vec2 smSizeAtlas = shadowmapSize * (tileBounds.zw - tileBounds.xy);
#endif
return PCFTileAware(shadowMap,
#ifdef _ShadowMapTransparent
@ -455,7 +459,7 @@ mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
float(d > casData[c * 4].y),
float(d > casData[c * 4].z),
float(d > casData[c * 4].w));
casi = int(min(dot(ci, comp), c));
casi = int(min(dot(ci, comp), float(c - 1)));
// Get cascade mat
casIndex = casi * 4;
return mat4(
@ -479,8 +483,12 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
#ifdef _SMSizeUniform
vec2 smSize = smSizeUniform;
#else
#ifdef _ShadowMapAtlas
vec2 smSize = shadowmapSize * (tileBoundsSunArray[0].zw - tileBoundsSunArray[0].xy);
#else
const vec2 smSize = shadowmapSize * vec2(shadowmapCascades, 1.0);
#endif
#endif
const int c = shadowmapCascades;
float d = distance(eye, p);
int casi;
@ -489,16 +497,35 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
vec4 lPos = LWVP * vec4(p, 1.0);
lPos.xyz /= lPos.w;
#ifdef _ShadowMapAtlas
tileBounds = tileBoundsSunArray[casi];
#endif
vec3 visibility = vec3(1.0);
if (lPos.w > 0.0) visibility = PCF(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
if (lPos.w > 0.0) {
#ifdef _ShadowMapAtlas
visibility = PCFTileAware(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize,
tileBounds.xy, tileBounds.zw
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else
visibility = PCF(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
}
// Blend cascade
// https://github.com/TheRealMJP/Shadows
@ -518,15 +545,33 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
lPos2.xyz /= lPos2.w;
vec3 visibility2 = vec3(1.0);
// use lPos2 coordinates for second cascade, not lPos
if (lPos2.w > 0.0) visibility2 = PCF(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos2.xy, lPos2.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#ifdef _ShadowMapAtlas
tileBounds = tileBoundsSunArray[casi + 1];
#endif
if (lPos2.w > 0.0) {
#ifdef _ShadowMapAtlas
visibility2 = PCFTileAware(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos2.xy, lPos2.z - shadowsBias, smSize,
tileBounds.xy, tileBounds.zw
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else
visibility2 = PCF(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos2.xy, lPos2.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
}
float lerpAmt = smoothstep(0.0, blendThres, splitDist);
return mix(visibility2, visibility, lerpAmt);

View File

@ -26,7 +26,7 @@ uniform sampler2D singleScatterLUT;
uniform vec2 skyDensity;
#ifndef PI
#define PI 3.141592
#define PI 3.1415926535
#endif
#ifndef HALF_PI
#define HALF_PI 1.570796

View File

@ -1,15 +1,25 @@
// Separable SSS Transmittance Function, ref to sss_pass
vec3 SSSSTransmittance(mat4 LWVP, vec3 p, vec3 n, vec3 l, float lightFar, sampler2DShadow shadowMap) {
const float translucency = 1.0;
vec3 SSSSTransmittance(mat4 LWVP, vec3 p, vec3 n, vec3 l, float lightFar, sampler2DShadow shadowMap, vec3 sssColor, float sssRadius
#ifdef _ShadowMapAtlas
, vec4 tileBounds
#endif
) {
const float translucency = 0.85;
vec4 shrinkedPos = vec4(p - 0.005 * n, 1.0);
vec4 shadowPos = LWVP * shrinkedPos;
float scale = 8.25 * (1.0 - translucency) / (sssWidth / 10.0);
float d1 = texture(shadowMap, vec3(shadowPos.xy / shadowPos.w, shadowPos.z)).r; // 'd1' has a range of 0..1
float d2 = shadowPos.z; // 'd2' has a range of 0..'lightFarPlane'
d1 *= lightFar; // So we scale 'd1' accordingly:
float d = scale * abs(d1 - d2);
vec2 shadowUV = shadowPos.xy / shadowPos.w;
#ifdef _ShadowMapAtlas
shadowUV = clamp(shadowUV, tileBounds.xy, tileBounds.zw);
#endif
float scale = 2.5 * (1.0 - translucency) / max(sssRadius, 0.001);
float d1 = texture(shadowMap, vec3(shadowUV, shadowPos.z)).r;
float d2 = shadowPos.z;
d1 *= lightFar;
d2 *= lightFar;
float d = scale * abs(d1 - d2) * 1000.0;
if (d > 10.0) return vec3(0.0);
float dd = -d * d;
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
@ -17,10 +27,70 @@ vec3 SSSSTransmittance(mat4 LWVP, vec3 p, vec3 n, vec3 l, float lightFar, sample
vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
return profile * clamp(0.3 + dot(l, -n), 0.0, 1.0);
profile *= mix(vec3(1.0), sssColor, 0.8);
return profile * clamp(0.5 + dot(l, -n), 0.0, 1.0);
}
vec3 SSSSTransmittanceCube(float translucency, vec4 shadowPos, vec3 n, vec3 l, float lightFar) {
// TODO
return vec3(0.0);
#ifdef _ShadowMapAtlas
vec3 SSSSTransmittanceCubeAtlas(sampler2DShadow shadowMap, vec3 lightPos, vec3 p, vec3 n, vec3 l, float lightFar, vec2 lightProj, int index, vec3 sssColor, float sssRadius) {
const float translucency = 0.85;
vec3 shrinkedPos = p - 0.005 * n;
vec3 ld = normalize(shrinkedPos - lightPos);
#ifdef _InvY
ld.y = -ld.y;
#endif
float d2 = lpToDepth(ld, lightProj);
int faceIndex = 0;
int lightIndex = index * 6;
vec2 uv = sampleCube(ld, faceIndex);
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex];
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
#ifdef _FlipY
uvtiled.y = 1.0 - uvtiled.y;
#endif
float d1 = texture(shadowMap, vec3(uvtiled, d2)).r;
d1 *= lightFar;
d2 *= lightFar;
float scale = 2.5 * (1.0 - translucency) / max(sssRadius, 0.001);
// d1/d2 are in meters, sssRadius is in mm, exponential constants are in mm^2
float d = scale * abs(d1 - d2) * 1000.0; // Convert distance to mm
if (d > 10.0) return vec3(0.0);
float dd = -d * d;
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
profile *= mix(vec3(1.0), sssColor, 0.8);
return profile * clamp(0.5 + dot(l, -n), 0.0, 1.0);
}
#endif
vec3 SSSSTransmittanceCube(samplerCubeShadow shadowMapCube, vec3 lightPos, vec3 p, vec3 n, vec3 l, float lightFar, vec2 lightProj, vec3 sssColor, float sssRadius) {
const float translucency = 0.85;
vec3 shrinkedPos = p - 0.005 * n;
vec3 ld = normalize(shrinkedPos - lightPos);
#ifdef _InvY
ld.y = -ld.y;
#endif
float d2 = lpToDepth(ld, lightProj);
float d1 = texture(shadowMapCube, vec4(ld, d2)).r;
d1 *= lightFar;
d2 *= lightFar;
float scale = 2.5 * (1.0 - translucency) / max(sssRadius, 0.001);
// d1/d2 are in meters, sssRadius is in mm, exponential constants are in mm^2
float d = scale * abs(d1 - d2) * 1000.0; // Convert distance to mm
if (d > 10.0) return vec3(0.0);
float dd = -d * d;
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
profile *= mix(vec3(1.0), sssColor, 0.8);
return profile * clamp(0.5 + dot(l, -n), 0.0, 1.0);
}

View File

@ -38,7 +38,6 @@ uniform layout(r8) image3D voxelsOut;
#endif
uniform int clipmapLevel;
uniform float voxelBlend;
uniform float clipmaps[voxelgiClipmapCount * 10];
@ -47,7 +46,7 @@ void main() {
ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
src.y += clipmapLevel * res;
for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++)
for (int i = 0; i < 6 + diffuseConeCount; i++)
{
vec4 col = vec4(0.0);

View File

@ -165,7 +165,7 @@ void main() {
#endif
#endif
envl.rgb *= envmapStrength * occspec.x;
envl.rgb *= envmapStrength * voxelgiEnv * occspec.x;
vec3 occ = envl * (1.0 - traceAO(P, n, voxels, clipmaps));

View File

@ -53,13 +53,6 @@ uniform float shirr[7 * 4];
#ifdef _Brdf
uniform sampler2D senvmapBrdf;
#endif
#ifdef _Rad
uniform sampler2D senvmapRadiance;
uniform int envmapNumMipmaps;
#endif
#ifdef _EnvCol
uniform vec3 backgroundCol;
#endif
void main() {
const vec2 pixel = gl_GlobalInvocationID.xy;
@ -140,17 +133,8 @@ void main() {
vec3 envl = vec3(0.0);
#endif
#ifdef _Rad
vec3 reflectionWorld = reflect(-v, n);
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
#endif
#ifdef _EnvLDR
envl.rgb = pow(envl.rgb, vec3(2.2));
#ifdef _Rad
prefilteredColor = pow(prefilteredColor, vec3(2.2));
#endif
#endif
envl.rgb *= albedo;
@ -159,15 +143,7 @@ void main() {
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
#endif
#ifdef _Rad // Indirect specular
envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
#else
#ifdef _EnvCol
envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
#endif
#endif
envl.rgb *= envmapStrength * occspec.x;
envl.rgb *= envmapStrength * voxelgiEnv * occspec.x;
vec4 trace = traceDiffuse(P, n, voxels, clipmaps);
vec3 color = trace.rgb * albedo * (1.0 - F);

View File

@ -48,13 +48,15 @@ void main() {
const vec2 pixel = gl_GlobalInvocationID.xy;
vec2 uv = (pixel + 0.5) / postprocess_resolution;
#ifdef _InvY
uv.y = 1.0 - uv.y
uv.y = 1.0 - uv.y;
#endif
float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
if (depth == 0) return;
vec2 ior_opac = textureLod(gbuffer_refraction, uv, 0.0).xy;
float ior = unpackIOR(ior_opac.x);
float opacity = ior_opac.y;
float x = uv.x * 2 - 1;
float y = uv.y * 2 - 1;
@ -72,8 +74,8 @@ void main() {
n = normalize(n);
vec3 color = vec3(0.0);
if(ior_opac.y < 1.0)
color = traceRefraction(P, n, voxels, voxelsSDF, normalize(eye - P), ior_opac.x, g0.b, clipmaps, pixel).rgb;
if(opacity < 1.0)
color = traceRefraction(P, n, voxels, voxelsSDF, normalize(eye - P), ior, g0.b, clipmaps, pixel).rgb;
imageStore(voxels_refraction, ivec2(pixel), vec4(color, 1.0));
}

View File

@ -66,9 +66,13 @@ void main() {
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
n = normalize(n);
float roughness = g0.b;
vec3 v = normalize(eye - P);
vec2 velocity = -textureLod(sveloc, uv, 0.0).rg;
vec3 color = traceSpecular(P, n, voxels, voxelsSDF, normalize(eye - P), g0.z * g0.z, clipmaps, pixel, velocity).rgb;
vec3 color = traceSpecular(P, n, voxels, voxelsSDF, v, roughness * roughness, clipmaps, pixel, velocity).rgb;
imageStore(voxels_specular, ivec2(pixel), vec4(color, 1.0));
}

View File

@ -79,7 +79,7 @@ void main() {
float aniso_colors[6];
#endif
for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++)
for (int i = 0; i < 6 + diffuseConeCount; i++)
{
ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
src.x += i * res;
@ -136,7 +136,7 @@ void main() {
radiance = basecol;
vec4 trace = traceDiffuse(wposition, wnormal, voxelsSampler, clipmaps);
vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a);
radiance.rgb *= light.rgb + indirect.rgb;
radiance.rgb *= light.rgb * INV_PI + indirect.rgb;
radiance.rgb += emission.rgb;
}
@ -195,7 +195,7 @@ void main() {
}
else {
// precompute cone sampling:
vec3 coneDirection = DIFFUSE_CONE_DIRECTIONS[i - 6];
vec3 coneDirection = diffuseConeDirections[i - 6];
vec3 aniso_direction = -coneDirection;
uvec3 face_offsets = uvec3(
aniso_direction.x > 0 ? 0 : 1,