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,

View File

@ -304,10 +304,13 @@ class RenderPath {
currentD = 1;
currentFace = -1;
meshesSorted = false;
sun = null;
for (l in Scene.active.lights) {
if (l.visible) l.buildMatrix(Scene.active.camera);
if (l.data.raw.type == "sun") sun = l;
if (l.data.raw.type == "sun") {
if (sun == null || (!sun.data.raw.cast_shadow && l.data.raw.cast_shadow)) sun = l;
}
else point = l;
}
light = Scene.active.lights[0];
@ -500,7 +503,7 @@ class RenderPath {
}
public function drawMeshes(context: String) {
var isShadows = context == "shadowmap";
var isShadows = context == "shadowmap" || context == "shadowmap_transparent";
if (isShadows) {
// Disabled shadow casting for this light
if (light == null || !light.data.raw.cast_shadow || !light.visible || light.data.raw.strength == 0) return;

View File

@ -72,6 +72,8 @@ class Scene {
public var embedded: Map<String, kha.Image>;
#if (rp_renderer == "Deferred")
public static inline var MAX_MATERIALS = 16;
public static inline var FLOATS_PER_MATERIAL_PARAM = 32; // 8 vec4s per material
public var materialParamsBuffer: kha.arrays.Float32Array;
public var materialParamsDirty: Bool = true;
#end
@ -113,7 +115,7 @@ class Scene {
#end
embedded = new Map();
#if (rp_renderer == "Deferred")
materialParamsBuffer = new kha.arrays.Float32Array(512);
materialParamsBuffer = new kha.arrays.Float32Array(MAX_MATERIALS * FLOATS_PER_MATERIAL_PARAM);
#end
root = new Object();
root.name = "Root";
@ -213,11 +215,14 @@ class Scene {
}
#if (rp_renderer == "Deferred")
public function markMaterialParamsDirty() {
materialParamsDirty = true;
}
public function updateMaterialParams() {
if (!materialParamsDirty) return;
materialParamsDirty = false;
var buf = materialParamsBuffer;
for (i in 0...buf.length) buf[i] = 0.0;
for (m in meshes) {
if (m.materials == null) continue;
for (mat in m.materials) {
@ -237,12 +242,16 @@ class Scene {
break;
}
}
if (slot <= 0 || slot >= 16) continue;
var base = slot * 32;
if (base + 31 >= buf.length) continue;
if (slot < 0 || slot >= MAX_MATERIALS) continue;
var base = slot * FLOATS_PER_MATERIAL_PARAM;
if (base + FLOATS_PER_MATERIAL_PARAM - 1 >= buf.length) continue;
if (bc == null) continue;
for (i in 0...FLOATS_PER_MATERIAL_PARAM) buf[base + i] = 0.0;
buf[base + 6] = 1.5; // coatIOR
buf[base + 12] = 1.45; // ior
buf[base + 13] = 1.0; // thinWall
for (c in bc) {
if (c == null || c.name == null) continue;
if (c == null || c.name == null || c.floatValue == null) continue;
switch (c.name) {
// matp0: vec4(anisotropy, anisoRot, sheen, sheenRough)
case "anisotropy": buf[base + 0] = c.floatValue;
@ -274,8 +283,13 @@ class Scene {
case "subsurfaceColorB": buf[base + 21] = c.floatValue;
case "sheenTintR": buf[base + 22] = c.floatValue;
case "sheenTintG": buf[base + 23] = c.floatValue;
// matp6: vec4(sheenTintB, 0, 0, 0)
// matp6: vec4(sheenTintB, specularTintR, specularTintG, specularTintB)
case "sheenTintB": buf[base + 24] = c.floatValue;
case "specularTintR": buf[base + 25] = c.floatValue;
case "specularTintG": buf[base + 26] = c.floatValue;
case "specularTintB": buf[base + 27] = c.floatValue;
// matp7: vec4(subsurfaceScale, 0, 0, 0)
case "subsurfaceScale": buf[base + 28] = c.floatValue;
}
}
}
@ -431,7 +445,7 @@ class Scene {
var object = new MeshObject(data, materials);
parent != null ? object.setParent(parent) : object.setParent(root);
#if (rp_renderer == "Deferred")
materialParamsDirty = true;
markMaterialParamsDirty();
#end
return object;
}

View File

@ -245,7 +245,12 @@ class LightObject extends Object {
// Snap to texel coords - fix translation swim
var smsize = data.raw.shadowmap_size;
#if lnx_csm // Cascades
smsize = Std.int(smsize / 4);
#if lnx_shadowmap_atlas
var ts = cascade < tileScale.length ? tileScale[cascade] : 1.0;
smsize = Std.int(Math.max(ts * data.raw.shadowmap_size, 1.0));
#else
smsize = Std.int(smsize / cascadeCount);
#end
#end
var worldPerTexelX = (maxx - minx) / smsize;
var worldPerTexelY = (maxy - miny) / smsize;
@ -685,22 +690,6 @@ class LightObject extends Object {
return LWVPMatrixArray;
}
public static inline function getMaxLights(): Int {
#if (rp_max_lights == 8)
return 8;
#elseif (rp_max_lights == 16)
return 16;
#elseif (rp_max_lights == 24)
return 24;
#elseif (rp_max_lights == 32)
return 32;
#elseif (rp_max_lights == 64)
return 64;
#else
return 4;
#end
}
public static inline function getMaxLightsCluster(): Int {
#if (rp_max_lights_cluster == 8)
return 8;
@ -718,6 +707,90 @@ class LightObject extends Object {
}
#end // lnx_clusters
public static inline function getMaxLights(): Int {
#if (rp_max_lights == 8)
return 8;
#elseif (rp_max_lights == 16)
return 16;
#elseif (rp_max_lights == 24)
return 24;
#elseif (rp_max_lights == 32)
return 32;
#elseif (rp_max_lights == 64)
return 64;
#else
return 4;
#end
}
#if (rp_shadowmap && lnx_shadowmap_atlas)
public static var sunTileBoundsArray: Float32Array = null;
public static var tileBoundsDirty: Bool = true;
public static function updateSunTileBoundsArray(): Float32Array {
if (!tileBoundsDirty && sunTileBoundsArray != null) return sunTileBoundsArray;
tileBoundsDirty = false;
var maxLights = getMaxLights();
var numTiles = maxLights * cascadeCount;
if (sunTileBoundsArray == null) {
sunTileBoundsArray = new Float32Array(numTiles * 4);
}
for (k in 0...sunTileBoundsArray.length) sunTileBoundsArray[k] = 0;
var i = 0;
for (light in Scene.active.lights) {
if (i >= maxLights) break;
if (!light.visible || light.data.raw.type != "sun") continue;
if (!light.data.raw.cast_shadow || light.data.raw.strength == 0.0) continue;
for (c in 0...cascadeCount) {
var idx = (i * cascadeCount + c) * 4;
sunTileBoundsArray[idx ] = light.tileOffsetX[c];
sunTileBoundsArray[idx + 2] = light.tileOffsetX[c] + light.tileScale[c];
#if (!kha_opengl)
// flip bounds to match
sunTileBoundsArray[idx + 1] = 1.0 - (light.tileOffsetY[c] + light.tileScale[c]);
sunTileBoundsArray[idx + 3] = 1.0 - light.tileOffsetY[c];
#else
sunTileBoundsArray[idx + 1] = light.tileOffsetY[c];
sunTileBoundsArray[idx + 3] = light.tileOffsetY[c] + light.tileScale[c];
#end
}
i++;
}
return sunTileBoundsArray;
}
#end
#if (rp_shadowmap && lnx_shadowmap_atlas)
public static var spotTileBoundsArray: Float32Array = null;
public static function updateSpotTileBoundsArray(): Float32Array {
var maxLights = getMaxLights();
if (spotTileBoundsArray == null) {
spotTileBoundsArray = new Float32Array(maxLights * 4);
}
for (k in 0...spotTileBoundsArray.length) spotTileBoundsArray[k] = 0;
var i = 0;
for (light in Scene.active.lights) {
if (i >= maxLights) break;
if (!light.visible || light.data.raw.type != "spot") continue;
if (!light.data.raw.cast_shadow || light.data.raw.strength == 0.0) continue;
var idx = i * 4;
spotTileBoundsArray[idx ] = light.tileOffsetX[0];
spotTileBoundsArray[idx + 2] = light.tileOffsetX[0] + light.tileScale[0];
#if (!kha_opengl)
// flip bounds
spotTileBoundsArray[idx + 1] = 1.0 - (light.tileOffsetY[0] + light.tileScale[0]);
spotTileBoundsArray[idx + 3] = 1.0 - light.tileOffsetY[0];
#else
spotTileBoundsArray[idx + 1] = light.tileOffsetY[0];
spotTileBoundsArray[idx + 3] = light.tileOffsetY[0] + light.tileScale[0];
#end
i++;
}
return spotTileBoundsArray;
}
#end
public inline function right(): Vec4 {
return new Vec4(V._00, V._10, V._20);
}

View File

@ -90,7 +90,7 @@ class MeshObject extends Object {
if (tilesheet != null) tilesheet.remove();
if (Scene.active != null) Scene.active.meshes.remove(this);
#if (rp_renderer == "Deferred")
if (Scene.active != null) Scene.active.materialParamsDirty = true;
if (Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
data.refcount--;
super.remove();

View File

@ -827,9 +827,20 @@ class Uniforms {
}
}
case "_shadowMapSize": {
if (light != null && light.data.raw.cast_shadow) {
var shadowLight = light;
if (shadowLight == null || !shadowLight.data.raw.cast_shadow) {
shadowLight = RenderPath.active.sun;
}
if (shadowLight != null && shadowLight.data.raw.cast_shadow) {
v = helpVec;
v.x = v.y = light.data.raw.shadowmap_size;
v.x = v.y = shadowLight.data.raw.shadowmap_size;
#if lnx_csm
#if (!lnx_shadowmap_atlas)
if (shadowLight.data.raw.type == "sun") {
v.x = shadowLight.data.raw.shadowmap_size * LightObject.cascadeCount;
}
#end
#end
}
}
default:
@ -887,9 +898,11 @@ class Uniforms {
case "_envmapIrradiance": {
fa = Scene.active.world == null ? WorldData.getEmptyIrradiance() : Scene.active.world.probe.irradiance;
}
case "_materialParams": {
#if (rp_renderer == "Deferred")
case "_materialParams": {
fa = Scene.active.materialParamsBuffer;
}
#end
#if lnx_clusters
case "_lightsArray": {
fa = LightObject.lightsArray;
@ -906,15 +919,18 @@ class Uniforms {
#end
#end // lnx_clusters
#if lnx_csm
case "_cascadeData": {
for (l in Scene.active.lights) {
if (l.data.raw.type == "sun") {
fa = l.getCascadeData();
break;
}
}
case "_cascadeData": {
var sun = RenderPath.active.sun;
if (sun != null && sun.data.raw.type == "sun") {
fa = sun.getCascadeData();
}
#end
}
#end
#if lnx_shadowmap_atlas
case "_tileBoundsSunArray": {
fa = LightObject.updateSunTileBoundsArray();
}
#end
}
if (fa != null) {
@ -1067,32 +1083,30 @@ class Uniforms {
}
}
case "_biasLightWorldViewProjectionMatrixSun": {
for (l in iron.Scene.active.lights) {
if (l.data.raw.type == "sun") {
// object is null for DrawQuad
object == null ? helpMat.setIdentity() : helpMat.setFrom(object.transform.worldUnpack);
helpMat.multmat(l.VP);
helpMat.multmat(biasMat);
#if lnx_shadowmap_atlas
// tile matrix
helpMat2.setIdentity();
// scale [0-1] coords to [0-tilescale]
helpMat2._00 = l.tileScale[0];
helpMat2._11 = l.tileScale[0];
// offset coordinate start from [0, 0] to [tile-start-x, tile-start-y]
helpMat2._30 = l.tileOffsetX[0];
helpMat2._31 = l.tileOffsetY[0];
helpMat.multmat(helpMat2);
#if (!kha_opengl)
helpMat2.setIdentity();
helpMat2._11 = -1.0;
helpMat2._31 = 1.0;
helpMat.multmat(helpMat2);
#end
#end
m = helpMat;
break;
}
var sun = RenderPath.active.sun;
if (sun != null && sun.data.raw.type == "sun") {
// object is null for DrawQuad
object == null ? helpMat.setIdentity() : helpMat.setFrom(object.transform.worldUnpack);
helpMat.multmat(sun.VP);
helpMat.multmat(biasMat);
#if lnx_shadowmap_atlas
// tile matrix
helpMat2.setIdentity();
// scale [0-1] coords to [0-tilescale]
helpMat2._00 = sun.tileScale[0];
helpMat2._11 = sun.tileScale[0];
// offset coordinate start from [0, 0] to [tile-start-x, tile-start-y]
helpMat2._30 = sun.tileOffsetX[0];
helpMat2._31 = sun.tileOffsetY[0];
helpMat.multmat(helpMat2);
#if (!kha_opengl)
helpMat2.setIdentity();
helpMat2._11 = -1.0;
helpMat2._31 = 1.0;
helpMat.multmat(helpMat2);
#end
#end
m = helpMat;
}
}
#if rp_probes
@ -1376,7 +1390,7 @@ class Uniforms {
if (fa == null) return;
g.setFloats(location, fa);
}
else if (c.type == "int") {
else if (c.type == "int" || c.type == "uint") {
var i: Null<Int> = null;
switch (c.link) {
case "_uid": {

View File

@ -39,7 +39,6 @@ class Inc {
#if (rp_voxels == "Voxel GI")
static var voxel_td1:kha.graphics4.TextureUnit;
static var voxel_te1:kha.graphics4.TextureUnit;
static var voxel_cc1:kha.graphics4.ConstantLocation;
#else
#if lnx_voxelgi_shadows
static var voxel_te1:kha.graphics4.TextureUnit;
@ -137,18 +136,22 @@ class Inc {
break;
if (LightObject.discardLightCulled(light)) continue;
if (light.data.raw.type == "point") {
if (!light.data.raw.cast_shadow) {
if (light.data.raw.cast_shadow) {
for(k in 0...6) {
LightObject.pointLightsData[j ] = light.tileOffsetX[k]; // posx
LightObject.pointLightsData[j + 1] = light.tileOffsetY[k]; // posy
LightObject.pointLightsData[j + 2] = light.tileScale[k]; // tile scale factor relative to atlas
LightObject.pointLightsData[j + 3] = 0; // padding
j += 4;
}
}
else {
j += 4 * 6;
continue;
}
for(k in 0...6) {
LightObject.pointLightsData[j ] = light.tileOffsetX[k]; // posx
LightObject.pointLightsData[j + 1] = light.tileOffsetY[k]; // posy
LightObject.pointLightsData[j + 2] = light.tileScale[k]; // tile scale factor relative to atlas
LightObject.pointLightsData[j + 3] = 0; // padding
j += 4;
}
}
else {
j += 4 * 6; // Reserve slot for non-point lights to keep index aligned
}
i++;
}
}
@ -214,11 +217,13 @@ class Inc {
if (!light.lightInAtlas && !light.culledLight && light.visible && light.shadowMapScale > 0.0
&& light.data.raw.strength > 0.0 && light.data.raw.cast_shadow) {
ShadowMapAtlas.addLight(light, false);
LightObject.tileBoundsDirty = true;
}
#if rp_shadowmap_transparent
if (!light.lightInAtlasTransparent && !light.culledLight && light.visible && light.shadowMapScale > 0.0
&& light.data.raw.strength > 0.0 && light.data.raw.cast_shadow) {
ShadowMapAtlas.addLight(light, true);
LightObject.tileBoundsDirty = true;
}
#end
}
@ -308,6 +313,7 @@ class Inc {
var newTile = ShadowMapTile.assignTiles(tile.light, atlas, tile);
if (newTile != null)
atlas.activeTiles.push(newTile);
LightObject.tileBoundsDirty = true;
}
updatePointLightAtlasData(false);
#end
@ -315,6 +321,7 @@ class Inc {
for (tile in tilesToRemove) {
atlas.activeTiles.remove(tile);
tile.freeTile();
LightObject.tileBoundsDirty = true;
}
}
@ -405,6 +412,7 @@ class Inc {
var newTile = ShadowMapTile.assignTiles(tile.light, atlas, tile);
if (newTile != null)
atlas.activeTiles.push(newTile);
LightObject.tileBoundsDirty = true;
}
updatePointLightAtlasData(true);
#end
@ -412,6 +420,7 @@ class Inc {
for (tile in tilesToRemove) {
atlas.activeTiles.remove(tile);
tile.freeTile();
LightObject.tileBoundsDirty = true;
}
}
#end
@ -419,25 +428,30 @@ class Inc {
}
#else
public static function bindShadowMap() {
for (l in iron.Scene.active.lights) {
if (!l.visible || l.data.raw.type != "sun") continue;
var sun = RenderPath.active.sun;
if (sun != null && sun.visible && sun.data.raw.type == "sun") {
var n = "shadowMap";
path.bindTarget(n, n);
#if rp_shadowmap_transparent
var n = "shadowMapTransparent";
path.bindTarget(n, n);
break;
#end
}
for (i in 0...pointIndex) {
var n = "shadowMapPoint[" + i + "]";
path.bindTarget(n, n);
#if rp_shadowmap_transparent
var n = "shadowMapPointTransparent[" + i + "]";
path.bindTarget(n, n);
#end
}
for (i in 0...spotIndex) {
var n = "shadowMapSpot[" + i + "]";
path.bindTarget(n, n);
#if rp_shadowmap_transparent
var n = "shadowMapSpotTransparent[" + i + "]";
path.bindTarget(n, n);
#end
}
}
@ -500,6 +514,7 @@ class Inc {
spotIndex = 0;
for (l in iron.Scene.active.lights) {
if (!l.visible) continue;
if (l.data.raw.type == "sun" && l != RenderPath.active.sun) continue;
path.light = l;
var shadowmap = Inc.getShadowMap(l, false);
@ -523,6 +538,7 @@ class Inc {
spotIndex = 0;
for (l in iron.Scene.active.lights) {
if (!l.visible) continue;
if (l.data.raw.type == "sun" && l != RenderPath.active.sun) continue;
path.light = l;
var shadowmap_transparent = Inc.getShadowMap(l, true);
@ -719,7 +735,7 @@ class Inc {
#else
t.format = "RGBA32";
#end
t.width = res * (6 + 16);
t.width = res * (6 + Main.diffuseConeCount);
t.height = res * Main.voxelgiClipmapCount;
t.depth = res;
}
@ -840,12 +856,10 @@ class Inc {
voxel_ca1 = voxel_sh1.getConstantLocation("clipmaps");
voxel_cb1 = voxel_sh1.getConstantLocation("clipmapLevel");
voxel_cc1 = voxel_sh1.getConstantLocation("envmapStrength");
#if (rp_voxels == "Voxel GI")
voxel_td1 = voxel_sh1.getTextureUnit("voxelsSampler");
voxel_te1 = voxel_sh1.getTextureUnit("SDF");
voxel_cc1 = voxel_sh1.getConstantLocation("envmapStrength");
#else
#if lnx_voxelgi_shadows
voxel_te1 = voxel_sh1.getTextureUnit("SDF");
@ -884,9 +898,11 @@ class Inc {
#if lnx_brdf
voxel_tg3 = voxel_sh3.getTextureUnit("senvmapBrdf");
#end
#if (rp_voxels == "Voxel AO")
#if lnx_radiance
voxel_th3 = voxel_sh3.getTextureUnit("senvmapRadiance");
#end
#end
voxel_ca3 = voxel_sh3.getConstantLocation("clipmaps");
voxel_cb3 = voxel_sh3.getConstantLocation("InvVP");
voxel_cc3 = voxel_sh3.getConstantLocation("eye");
@ -895,12 +911,14 @@ class Inc {
#if lnx_irradiance
voxel_cf3 = voxel_sh3.getConstantLocation("shirr");
#end
#if (rp_voxels == "Voxel AO")
#if lnx_radiance
voxel_cg3 = voxel_sh3.getConstantLocation("envmapNumMipmaps");
#end
#if lnx_envcol
voxel_ch3 = voxel_sh3.getConstantLocation("backgroundCol");
#end
#end
#end
}
#if (rp_voxels == "Voxel GI")
if (voxel_sh4 == null)
@ -988,7 +1006,6 @@ class Inc {
#if (rp_voxels == "Voxel GI")
g.setTexture(voxel_td1, rts.get("voxelsOutB").image);
g.setImageTexture(voxel_te1, rts.get("voxelsSDF").image);
g.setFloat(voxel_cc1, iron.Scene.active.world == null ? 0.0 : iron.Scene.active.world.probe.raw.strength);
#else
#if lnx_voxelgi_shadows
g.setImageTexture(voxel_te1, rts.get("voxelsSDF").image);
@ -1001,8 +1018,6 @@ class Inc {
g.setInt(voxel_cb1, iron.RenderPath.clipmapLevel);
g.setFloat(voxel_cc1, iron.Scene.active.world == null ? 0.0 : iron.Scene.active.world.probe.raw.strength);
g.compute(Std.int(res / 8), Std.int(res / 8), Std.int(res / 8));
}
@ -1163,9 +1178,6 @@ class Inc {
#if lnx_brdf
g.setTexture(voxel_tg3, iron.Scene.active.embedded.get("brdf.png"));
#end
#if lnx_radiance
g.setTexture(voxel_th3, iron.Scene.active.world.probe.radiance);
#end
var fa = fillVoxelClipmapsArray(clipmaps);
@ -1205,28 +1217,12 @@ class Inc {
iron.Scene.active.world.probe.irradiance;
g.setFloats(voxel_cf3, irradiance);
#end
#if lnx_radiance
g.setFloat(voxel_cg3, iron.Scene.active.world != null ? iron.Scene.active.world.probe.raw.radiance_mipmaps + 1 - 2 : 1);
#end
#if lnx_envcol
var x: kha.FastFloat = 0.0;
var y: kha.FastFloat = 0.0;
var z: kha.FastFloat = 0.0;
if (camera.data.raw.clear_color != null) {
x = camera.data.raw.clear_color[0];
y = camera.data.raw.clear_color[1];
z = camera.data.raw.clear_color[2];
}
g.setFloat3(voxel_ch3, x, y, z);
#end
g.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1);
}
#end
#if (rp_voxels == "Voxel GI")
public static function resolveSpecular(g: kha.graphics4.Graphics) {
var rts = path.renderTargets;
var res = iron.RenderPath.getVoxelRes();
@ -1278,6 +1274,7 @@ class Inc {
g.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1);
}
#end
#if (rp_voxels == "Voxel GI")
#end // GI

View File

@ -27,7 +27,7 @@ class RenderPathDeferred {
#if rp_gbuffer2 "gbuffer2", #end
#if rp_gbuffer_emission "gbuffer_emission", #end
#if (rp_ssrefr || lnx_voxelgi_refract) "gbuffer_refraction", #end
#if lnx_anisotropy "gbuffer3" #end
#if rp_clearcoat "gbuffer_coat_normal", #end
]);
}
@ -155,7 +155,11 @@ class RenderPathDeferred {
t.width = 0;
t.height = 0;
t.displayp = Inc.getDisplayp();
#if rp_hdr
t.format = "RGBA64";
#else
t.format = "RGBA32";
#end
t.scale = Inc.getSuperSampling();
path.createRenderTarget(t);
}
@ -174,19 +178,6 @@ class RenderPathDeferred {
}
#end
#if lnx_anisotropy
{
var t = new RenderTargetRaw();
t.name = "gbuffer3";
t.width = 0;
t.height = 0;
t.displayp = Inc.getDisplayp();
t.format = "RGBA64";
t.scale = Inc.getSuperSampling();
path.createRenderTarget(t);
}
#end
#if rp_material_solid
path.loadShader("shader_datas/deferred_light_solid/deferred_light");
#elseif rp_material_mobile
@ -295,7 +286,7 @@ class RenderPathDeferred {
}
#end
#if ((rp_antialiasing == "SMAA") || (rp_antialiasing == "TAA") || rp_fsr1)
#if ((rp_antialiasing == "SMAA") || (rp_antialiasing == "TAA") || rp_fsr1 || (rp_ssr && !rp_ssr_half))
{
var t = new RenderTargetRaw();
t.name = "bufa";
@ -422,6 +413,19 @@ class RenderPathDeferred {
}
#end
#if rp_clearcoat
{
var t = new RenderTargetRaw();
t.name = "gbuffer_coat_normal";
t.width = 0;
t.height = 0;
t.displayp = Inc.getDisplayp();
t.format = "RGBA64";
t.scale = Inc.getSuperSampling();
path.createRenderTarget(t);
}
#end
#if (rp_ssrefr || lnx_voxelgi_refract)
{
var t = new RenderTargetRaw();
@ -429,7 +433,7 @@ class RenderPathDeferred {
t.width = 0;
t.height = 0;
t.displayp = Inc.getDisplayp();
t.format = "RGBA64";
t.format = "RGBA32";
t.scale = Inc.getSuperSampling();
path.createRenderTarget(t);
}
@ -569,7 +573,14 @@ class RenderPathDeferred {
#if (rp_ssrefr || lnx_voxelgi_refract)
{
path.setTarget("gbuffer_refraction");
path.clearTarget(0xffff00ff);
path.clearTarget(0x000000ff);
}
#end
#if rp_clearcoat
{
path.setTarget("gbuffer_coat_normal");
path.clearTarget(0x00000000);
}
#end
@ -580,12 +591,6 @@ class RenderPathDeferred {
}
#end
#if lnx_anisotropy
{
path.setTarget("gbuffer3");
path.clearTarget(0x00000000);
}
#end
RenderPathCreator.setTargetMeshes();
@ -782,8 +787,10 @@ class RenderPathDeferred {
}
#end
#if lnx_anisotropy
path.bindTarget("gbuffer3", "gbuffer3");
#if rp_clearcoat
{
path.bindTarget("gbuffer_coat_normal", "gbufferCoatNormal");
}
#end
#if rp_ssao
@ -849,6 +856,7 @@ class RenderPathDeferred {
#end
#if rp_material_solid
Scene.active.updateMaterialParams();
path.drawShader("shader_datas/deferred_light_solid/deferred_light");
#elseif rp_material_mobile
Scene.active.updateMaterialParams();
@ -910,7 +918,10 @@ class RenderPathDeferred {
#if rp_water
{
#if (!kha_opengl)
path.setDepthFrom("tex", "gbuffer1");
#end
path.setTarget("buf");
path.bindTarget("tex", "tex");
path.drawShader("shader_datas/copy_pass/copy_pass");
@ -918,7 +929,10 @@ class RenderPathDeferred {
path.bindTarget("_main", "gbufferD");
path.bindTarget("buf", "tex");
path.drawShader("shader_datas/water_pass/water_pass");
#if (!kha_opengl)
path.setDepthFrom("tex", "gbuffer0");
#end
}
#end
@ -934,7 +948,7 @@ class RenderPathDeferred {
var targetb = "ssrb";
#else
var targeta = "buf";
var targetb = "gbuffer1";
var targetb = "bufa";
#end
path.setTarget(targeta);
@ -952,11 +966,21 @@ class RenderPathDeferred {
path.setTarget(targetb);
path.bindTarget(targeta, "tex");
path.bindTarget("gbuffer0", "gbuffer0");
#if rp_ssr_half
path.bindTarget("half", "gbufferD");
#else
path.bindTarget("_main", "gbufferD");
#end
path.drawShader("shader_datas/blur_adaptive_pass/blur_adaptive_pass_x");
path.setTarget("tex");
path.bindTarget(targetb, "tex");
path.bindTarget("gbuffer0", "gbuffer0");
#if rp_ssr_half
path.bindTarget("half", "gbufferD");
#else
path.bindTarget("_main", "gbufferD");
#end
path.drawShader("shader_datas/blur_adaptive_pass/blur_adaptive_pass_y3_blend");
#if (!kha_opengl)
@ -976,12 +1000,14 @@ class RenderPathDeferred {
path.bindTarget("tex", "tex");
path.bindTarget("_main", "gbufferD");
path.bindTarget("gbuffer0", "gbuffer0");
path.bindTarget("gbuffer1", "gbuffer1");
path.drawShader("shader_datas/sss_pass/sss_pass_x");
path.setTarget("tex");
path.bindTarget("buf", "tex");
path.bindTarget("_main", "gbufferD");
path.bindTarget("gbuffer0", "gbuffer0");
path.bindTarget("gbuffer1", "gbuffer1");
path.drawShader("shader_datas/sss_pass/sss_pass_y");
#if (!kha_opengl)
@ -994,20 +1020,20 @@ class RenderPathDeferred {
{
if (leenkx.data.Config.raw.rp_ssrefr != false)
{
//#if (!kha_opengl)
//path.setDepthFrom("gbuffer0", "gbuffer1"); // Unbind depth so we can read it
//path.depthToRenderTarget.set("main", path.renderTargets.get("tex"));
//#end
#if (!kha_opengl)
path.setDepthFrom("gbuffer0", "gbuffer1"); // Unbind depth so we can read it
path.depthToRenderTarget.set("main", path.renderTargets.get("tex"));
#end
//save depth
path.setTarget("gbufferD1");
path.bindTarget("_main", "tex");
path.drawShader("shader_datas/copy_pass/copy_pass");
//#if (!kha_opengl)
//path.setDepthFrom("gbuffer0", "tex"); // Re-bind depth
//path.depthToRenderTarget.set("main", path.renderTargets.get("gbuffer0"));
//#end
#if (!kha_opengl)
path.setDepthFrom("gbuffer0", "tex"); // Re-bind depth
path.depthToRenderTarget.set("main", path.renderTargets.get("gbuffer0"));
#end
//save background color
path.setTarget("refr");
@ -1043,6 +1069,7 @@ class RenderPathDeferred {
path.bindTarget("tex", "tex");
path.bindTarget("gbufferD1", "gbufferD1");
path.bindTarget("gbuffer0", "gbuffer0");
path.bindTarget("gbuffer1", "gbuffer1");
path.bindTarget("refr", "tex1");
path.bindTarget("_main", "gbufferD");
path.bindTarget("gbuffer_refraction", "gbuffer_refraction");

View File

@ -130,7 +130,7 @@ class RenderPathForward {
t.width = 0;
t.height = 0;
t.displayp = Inc.getDisplayp();
t.format = "RGBA64";
t.format = "RGBA32";
t.scale = Inc.getSuperSampling();
path.createRenderTarget(t);
}
@ -489,7 +489,7 @@ class RenderPathForward {
#if (rp_ssrefr || lnx_voxelgi_refract)
{
path.setTarget("gbuffer_refraction");
path.clearTarget(0xffffff00);
path.clearTarget(0x00000000);
}
#end
@ -645,11 +645,21 @@ class RenderPathForward {
path.setTarget(targetb);
path.bindTarget(targeta, "tex");
path.bindTarget("lbuffer1", "gbuffer0");
#if rp_ssr_half
path.bindTarget("half", "gbufferD");
#else
path.bindTarget("_main", "gbufferD");
#end
path.drawShader("shader_datas/blur_adaptive_pass/blur_adaptive_pass_x");
path.setTarget("lbuffer0");
path.bindTarget(targetb, "tex");
path.bindTarget("lbuffer1", "gbuffer0");
#if rp_ssr_half
path.bindTarget("half", "gbufferD");
#else
path.bindTarget("_main", "gbufferD");
#end
path.drawShader("shader_datas/blur_adaptive_pass/blur_adaptive_pass_y3_blend");
}
}

View File

@ -22,7 +22,7 @@ class UniformsManager extends Trait{
static var texturesRegistered = false;
static var texturesMap = new Map<Object, Map<MaterialData, Map<String, kha.Image>>>();
static var sceneRemoveInitalized = false;
static var sceneRemoveInitialized = false;
public var uniformExists = false;
@ -32,7 +32,8 @@ class UniformsManager extends Trait{
notifyOnAdd(init);
notifyOnRemove(removeObject);
if (!sceneRemoveInitalized) {
if (!sceneRemoveInitialized) {
sceneRemoveInitialized = true;
Scene.active.notifyOnRemove(removeScene);
}
}
@ -166,7 +167,12 @@ class UniformsManager extends Trait{
matMap.set(material, entry);
}
entry.set(link, value); // parameter name, value
if (entry.get(link) != value) {
entry.set(link, value);
#if (rp_renderer == "Deferred")
if (Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
}
// Method to set map Object -> Material -> Link -> Vec3
@ -188,7 +194,12 @@ class UniformsManager extends Trait{
matMap.set(material, entry);
}
entry.set(link, value); // parameter name, value
if (entry.get(link) != value) {
entry.set(link, value);
#if (rp_renderer == "Deferred")
if (Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
}
// Method to set map Object -> Material -> Link -> Texture
@ -210,7 +221,12 @@ class UniformsManager extends Trait{
matMap.set(material, entry);
}
entry.set(link, value); // parameter name, value
if (entry.get(link) != value) {
entry.set(link, value);
#if (rp_renderer == "Deferred")
if (Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
}
// Method to get object specific material parameter float value
@ -330,10 +346,15 @@ class UniformsManager extends Trait{
var entry = material.get(mat);
if (entry == null) return;
var existed = entry.exists(link);
entry.remove(link);
if (!entry.keys().hasNext()) material.remove(mat);
if (!material.keys().hasNext()) floatsMap.remove(object);
#if (rp_renderer == "Deferred")
if (existed && Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
public static function removeVectorValue(object: Object, mat:MaterialData, link: String) {
@ -344,10 +365,15 @@ class UniformsManager extends Trait{
var entry = material.get(mat);
if (entry == null) return;
var existed = entry.exists(link);
entry.remove(link);
if (!entry.keys().hasNext()) material.remove(mat);
if (!material.keys().hasNext()) vectorsMap.remove(object);
#if (rp_renderer == "Deferred")
if (existed && Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
public static function removeTextureValue(object: Object, mat:MaterialData, link: String) {
@ -358,10 +384,15 @@ class UniformsManager extends Trait{
var entry = material.get(mat);
if (entry == null) return;
var existed = entry.exists(link);
entry.remove(link);
if (!entry.keys().hasNext()) material.remove(mat);
if (!material.keys().hasNext()) texturesMap.remove(object);
#if (rp_renderer == "Deferred")
if (existed && Scene.active != null) Scene.active.markMaterialParamsDirty();
#end
}
}

View File

@ -2514,6 +2514,9 @@ class LeenkxExporter:
# Ensure the same order for merging materials
self.material_array.sort(key=lambda x: x.name)
from lnx.material import mat_state
mat_state.next_ext_mat_id = 3
if wrd.lnx_batch_materials:
mat_users = self.material_to_object_dict
mat_lnxusers = self.material_to_lnx_object_dict
@ -2526,9 +2529,6 @@ class LeenkxExporter:
decals_used = False
sss_used = False
from lnx.material import mat_state
mat_state.next_ext_mat_id = 3
for material in self.material_array:
# If the material is unlinked, material becomes None
if material is None:

View File

@ -247,7 +247,7 @@ def check_link(
included based on the given defines (`defs`). If that is the case,
the found link is written to the `out` dictionary.
"""
for link in source_context["links"]:
for link in source_context.get("links", []):
if link["name"] == cid:
valid_link = True

View File

@ -133,7 +133,6 @@ def add_world_defs():
assets.add_shader_external(lnx.utils.get_sdk_path() + '/leenkx/Shaders/voxel_offsetprev/voxel_offsetprev.comp.glsl')
assets.add_shader_external(lnx.utils.get_sdk_path() + '/leenkx/Shaders/voxel_temporal/voxel_temporal.comp.glsl')
assets.add_shader_external(lnx.utils.get_sdk_path() + '/leenkx/Shaders/voxel_sdf_jumpflood/voxel_sdf_jumpflood.comp.glsl')
#wrd.world_defs += "_VoxelCones" + rpdat.lnx_voxelgi_cones
if rpdat.lnx_voxelgi_shadows and (point_lights > 0 or '_Sun' in wrd.world_defs):
wrd.world_defs += '_VoxelShadow'
assets.add_khafile_def('lnx_voxelgi_shadows')
@ -173,9 +172,6 @@ def add_world_defs():
wrd.world_defs += '_Brdf'
assets.add_khafile_def("lnx_brdf")
if '_Anisotropy' in wrd.world_defs:
assets.add_khafile_def('lnx_anisotropy')
def build():
rpdat = lnx.utils.get_rp()
project_path = lnx.utils.get_fp()
@ -237,7 +233,7 @@ def build():
assets.add_khafile_def('rp_compositornodes')
compo_depth = False
# wrd.compo_defs += ''
if rpdat.lnx_tonemap != 'Off':
if rpdat.lnx_tonemap != 'Off' and not state.is_viewport:
wrd.compo_defs += '_CTone' + rpdat.lnx_tonemap
if rpdat.lnx_dithering != 'Off':
wrd.compo_defs += '_CDithering' + rpdat.lnx_dithering
@ -444,7 +440,8 @@ def build():
if rpdat.rp_sss:
assets.add_khafile_def('rp_sss')
wrd.world_defs += '_SSS'
if '_SSS' not in wrd.world_defs:
wrd.world_defs += '_SSS'
assets.add_shader_pass('sss_pass')
if (rpdat.rp_ssr and rpdat.lnx_ssr_half_res) or (rpdat.rp_ssao and rpdat.lnx_ssao_half_res) or (rpdat.rp_ssgi and rpdat.lnx_ssgi_half_res) or rpdat.rp_voxels != "Off":
@ -487,13 +484,55 @@ def build():
if ignoreIrr:
wrd.world_defs += '_IgnoreIrr'
# TODO: avoid the prescan correctly
if bpy.app.version >= (4, 0, 0):
coat_name = 'Coat Weight'
sheen_name = 'Sheen Weight'
subsurf_name = 'Subsurface Weight'
trans_name = 'Transmission Weight'
else:
coat_name = 'Clearcoat'
sheen_name = 'Sheen'
subsurf_name = 'Subsurface'
trans_name = 'Transmission'
for mat in bpy.data.materials:
if mat.node_tree is None:
continue
for node in mat.node_tree.nodes:
if node.type == 'BSDF_PRINCIPLED':
coat_socket = node.inputs.get(coat_name)
if coat_socket is not None and (coat_socket.is_linked or coat_socket.default_value > 0.0):
if '_ClearCoat' not in wrd.world_defs:
wrd.world_defs += '_ClearCoat'
aniso_socket = node.inputs.get('Anisotropic')
if aniso_socket is not None and (aniso_socket.is_linked or aniso_socket.default_value > 0.0):
if '_Anisotropy' not in wrd.world_defs:
wrd.world_defs += '_Anisotropy'
sheen_socket = node.inputs.get(sheen_name)
if sheen_socket is not None and (sheen_socket.is_linked or sheen_socket.default_value > 0.0):
if '_Sheen' not in wrd.world_defs:
wrd.world_defs += '_Sheen'
subsurf_socket = node.inputs.get(subsurf_name)
if subsurf_socket is not None and (subsurf_socket.is_linked or subsurf_socket.default_value > 0.0):
if '_SSS' not in wrd.world_defs:
wrd.world_defs += '_SSS'
trans_socket = node.inputs.get(trans_name)
if trans_socket is not None and (trans_socket.is_linked or trans_socket.default_value > 0.0):
if '_Transmission' not in wrd.world_defs:
wrd.world_defs += '_Transmission'
elif node.type == 'SUBSURFACE_SCATTERING':
if '_SSS' not in wrd.world_defs:
wrd.world_defs += '_SSS'
gbuffer2 = '_Veloc' in wrd.world_defs or '_IgnoreIrr' in wrd.world_defs or '_VoxelGI' in wrd.world_defs or '_VoxelShadow' in wrd.world_defs or '_SSGI' in wrd.world_defs
gbuffer2 = '_Veloc' in wrd.world_defs or '_IgnoreIrr' in wrd.world_defs or '_VoxelGI' in wrd.world_defs or '_VoxelShadow' in wrd.world_defs or '_SSGI' in wrd.world_defs or '_Anisotropy' in wrd.world_defs
if gbuffer2:
assets.add_khafile_def('rp_gbuffer2')
wrd.world_defs += '_gbuffer2'
if '_ClearCoat' in wrd.world_defs:
assets.add_khafile_def('rp_clearcoat')
if callback is not None:
callback()
@ -506,7 +545,7 @@ def get_num_gbuffer_rts_deferred()-> int:
refraction_flags = {'_SSRefraction', '_VoxelRefract'}
found_refraction_flag = False
for flag in ('_gbuffer2', '_EmissionShaded', '_SSRefraction', '_VoxelRefract'):
for flag in ('_gbuffer2', '_EmissionShaded', '_SSRefraction', '_VoxelRefract', '_ClearCoat'):
if flag in wrd.world_defs:
if flag in refraction_flags and not found_refraction_flag:
num += 1
@ -514,7 +553,4 @@ def get_num_gbuffer_rts_deferred()-> int:
else:
num += 1
if '_Anisotropy' in wrd.world_defs:
num += 1
return num

View File

@ -192,13 +192,27 @@ def parse(nodes, con: ShaderContext,
import re as _re
def _extract_vec3(s):
m = _re.match(r'vec3\s*\(\s*([^,\s\)]+)\s*\)', s)
if m and ',' not in m.group(1):
v = m.group(1)
return v, v, v
m = _re.match(r'vec3\s*\(\s*([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^,\s\)]+)', s)
if m:
return m.group(1), m.group(2), m.group(3)
s = s.strip()
m = _re.match(r'vec3\s*\((.*)\)\s*$', s)
if not m:
return '1.0', '1.0', '1.0'
inner = m.group(1).strip()
parts = []
depth = 0
start = 0
for i, ch in enumerate(inner):
if ch == '(':
depth += 1
elif ch == ')':
depth -= 1
elif ch == ',' and depth == 0:
parts.append(inner[start:i].strip())
start = i + 1
parts.append(inner[start:].strip())
if len(parts) == 1:
return parts[0], parts[0], parts[0]
if len(parts) == 3:
return parts[0], parts[1], parts[2]
return '1.0', '1.0', '1.0'
def _try_float(val_str, default=0.0):
@ -209,14 +223,10 @@ def parse(nodes, con: ShaderContext,
_sss_r, _sss_g, _sss_b = _extract_vec3(state.out_subsurface_radius)
_sss_scale = state.out_subsurface_scale
_sss_scale_f = _try_float(_sss_scale, 0.05)
if _sss_scale_f != 1.0:
_sss_r = str(_try_float(_sss_r, 1.0) * _sss_scale_f)
_sss_g = str(_try_float(_sss_g, 0.2) * _sss_scale_f)
_sss_b = str(_try_float(_sss_b, 0.1) * _sss_scale_f)
_sheen_tint_r, _sheen_tint_g, _sheen_tint_b = _extract_vec3(state.out_sheen_tint)
_coat_tint_r, _coat_tint_g, _coat_tint_b = _extract_vec3(state.out_coat_tint)
_spec_tint_r, _spec_tint_g, _spec_tint_b = _extract_vec3(state.out_specular_tint)
_sss_color_r, _sss_color_g, _sss_color_b = _extract_vec3(state.out_subsurface_color)
mat_state.features = {
@ -233,6 +243,7 @@ def parse(nodes, con: ShaderContext,
'sheenTintB': _sheen_tint_b,
'subsurface': state.out_subsurface,
'subsurfaceAnisotropy': state.out_subsurface_anisotropy,
'subsurfaceScale': _sss_scale,
'subsurfaceRadiusR': _sss_r,
'subsurfaceRadiusG': _sss_g,
'subsurfaceRadiusB': _sss_b,
@ -245,6 +256,9 @@ def parse(nodes, con: ShaderContext,
'transmissionRough': state.out_transmission_rough,
'ior': state.out_ior,
'thinWall': state.out_thin_wall,
'specularTintR': _spec_tint_r,
'specularTintG': _spec_tint_g,
'specularTintB': _spec_tint_b,
}
state = None
@ -751,11 +765,11 @@ def vector_curve(name, fac, points):
# Map vector
return 'mix({0}[{1}], {0}[{1} + 1], ({2} - {3}[{1}]) * (1.0 / ({3}[{1} + 1] - {3}[{1}]) ))'.format(ys_var, index_var, fac_var, facs_var)
def write_normal(inp):
def write_normal(inp, target_var='n'):
if inp.is_linked and inp.links[0].from_node.type != 'GROUP_INPUT':
normal_res = parse_vector_input(inp)
if normal_res != None:
state.curshader.write('n = {0};'.format(normal_res))
state.curshader.write('{0} = {1};'.format(target_var, normal_res))
def is_parsed(node_store_name: str):

View File

@ -77,17 +77,12 @@ def parse_mixshader(node: bpy.types.ShaderNodeMixShader, out_socket: NodeSocket,
state.curshader.write('{0}float {1} = 1.0 - {2};'.format(prefix, fac_inv_var, fac_var))
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
sss_before_1 = mat_state.needs_sss
o1 = c.parse_shader_input(node.inputs[1])
sss_1 = mat_state.needs_sss
ek1 = mat_state.emission_type
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
mat_state.needs_sss = sss_before_1 # Reset to state before parsing input 1
o2 = c.parse_shader_input(node.inputs[2])
sss_2 = mat_state.needs_sss
ek2 = mat_state.emission_type
mat_state.needs_sss = sss_1 or sss_2
if state.parse_surface:
fm = '{0} * {3} + {1} * {2}' # fac mix template: a*fac_inv + b*fac
@ -126,17 +121,12 @@ def parse_mixshader(node: bpy.types.ShaderNodeMixShader, out_socket: NodeSocket,
def parse_addshader(node: bpy.types.ShaderNodeAddShader, out_socket: NodeSocket, state: ParserState) -> None:
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
sss_before_1 = mat_state.needs_sss
o1 = c.parse_shader_input(node.inputs[0])
sss_1 = mat_state.needs_sss
ek1 = mat_state.emission_type
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
mat_state.needs_sss = sss_before_1 # Reset to state before parsing input 0
o2 = c.parse_shader_input(node.inputs[1])
sss_2 = mat_state.needs_sss
ek2 = mat_state.emission_type
mat_state.needs_sss = sss_1 or sss_2
if state.parse_surface:
am = '{0} * 0.5 + {1} * 0.5' # add mix template (average)
@ -179,8 +169,6 @@ if bpy.app.version < (2, 91, 0):
if state.parse_surface:
c.write_normal(node.inputs['Normal'])
state.out_basecol = c.parse_vector_input(node.inputs['Base Color'])
if node.inputs[SUBSURFACE].is_linked or node.inputs[SUBSURFACE].default_value > 0.0:
mat_state.needs_sss = True
state.out_subsurface = c.parse_value_input(node.inputs[SUBSURFACE])
state.out_subsurface_radius = c.parse_vector_input(node.inputs[SUBSURFACE_RADIUS])
state.out_subsurface_color = c.parse_vector_input(node.inputs[SUBSURFACE_COLOR])
@ -194,6 +182,9 @@ if bpy.app.version < (2, 91, 0):
state.out_sheen_tint = 'vec3({})'.format(c.parse_value_input(node.inputs[SHEEN_TINT]))
state.out_clearcoat = c.parse_value_input(node.inputs[CLEARCOAT])
state.out_clearcoat_rough = c.parse_value_input(node.inputs[CLEARCOAT_ROUGHNESS])
coat_normal_socket = node.inputs.get(CLEARCOAT_NORMAL)
if coat_normal_socket is not None:
c.write_normal(coat_normal_socket, target_var='nCoat')
state.out_transmission = c.parse_value_input(node.inputs[TRANSMISSION])
trans_rough_socket = node.inputs.get(TRANSMISSION_ROUGHNESS)
if trans_rough_socket is not None:
@ -216,8 +207,6 @@ if bpy.app.version >= (2, 91, 0) and bpy.app.version < (4, 0, 0):
if state.parse_surface:
c.write_normal(node.inputs['Normal'])
state.out_basecol = c.parse_vector_input(node.inputs['Base Color'])
if node.inputs[SUBSURFACE].is_linked or node.inputs[SUBSURFACE].default_value > 0.0:
mat_state.needs_sss = True
state.out_subsurface = c.parse_value_input(node.inputs[SUBSURFACE])
state.out_subsurface_radius = c.parse_vector_input(node.inputs[SUBSURFACE_RADIUS])
state.out_subsurface_color = c.parse_vector_input(node.inputs[SUBSURFACE_COLOR])
@ -231,6 +220,9 @@ if bpy.app.version >= (2, 91, 0) and bpy.app.version < (4, 0, 0):
state.out_sheen_tint = 'vec3({})'.format(c.parse_value_input(node.inputs[SHEEN_TINT]))
state.out_clearcoat = c.parse_value_input(node.inputs[CLEARCOAT])
state.out_clearcoat_rough = c.parse_value_input(node.inputs[CLEARCOAT_ROUGHNESS])
coat_normal_socket = node.inputs.get(CLEARCOAT_NORMAL)
if coat_normal_socket is not None:
c.write_normal(coat_normal_socket, target_var='nCoat')
state.out_transmission = c.parse_value_input(node.inputs[TRANSMISSION])
state.out_transmission_rough = c.parse_value_input(node.inputs[TRANSMISSION_ROUGHNESS])
state.out_tangent = c.parse_vector_input(node.inputs[TANGENT])
@ -256,8 +248,6 @@ if bpy.app.version >= (4, 0, 0):
sss_input = node.inputs.get(SUBSURFACE)
if sss_input is not None:
if sss_input.is_linked or sss_input.default_value > 0.0:
mat_state.needs_sss = True
state.out_subsurface = c.parse_value_input(sss_input)
sss_radius_input = node.inputs.get(SUBSURFACE_RADIUS)
@ -331,6 +321,9 @@ if bpy.app.version >= (4, 0, 0):
coat_tint_socket = node.inputs.get(COAT_TINT)
if coat_tint_socket is not None:
state.out_coat_tint = c.parse_vector_input(coat_tint_socket)
coat_normal_socket = node.inputs.get(CLEARCOAT_NORMAL)
if coat_normal_socket is not None:
c.write_normal(coat_normal_socket, target_var='nCoat')
trans_socket = node.inputs.get(TRANSMISSION)
if trans_socket is not None:
@ -507,8 +500,6 @@ def parse_bsdfrefraction(node: bpy.types.ShaderNodeBsdfRefraction, out_socket: N
def parse_subsurfacescattering(node: bpy.types.ShaderNodeSubsurfaceScattering, out_socket: NodeSocket, state: ParserState) -> None:
if state.parse_surface:
# Mark that this material needs SSS
mat_state.needs_sss = True
c.write_normal(node.inputs['Normal'])
state.out_basecol = c.parse_vector_input(node.inputs['Color'])
state.out_subsurface = c.parse_value_input(node.inputs['Scale'])

View File

@ -588,7 +588,7 @@ def parse_tex_voronoi(node: bpy.types.ShaderNodeTexVoronoi, out_socket: bpy.type
co = 'bposition'
scale = c.get_value_input(node, ['Scale'])
exp = c.get_value_input(node, ['Exponent'])
exp = c.get_value_input(node, ['Exponent']) if m == 3 else '1.0'
randomness = c.get_value_input(node, ['Randomness'])
# Color or Position

View File

@ -64,8 +64,6 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
shader_data_name = material.lnx_custom_material
bind_constants = {'mesh': []}
bind_textures = {'mesh': []}
mat_uses_sss = False
make_shader.make_instancing_and_skinning(material, mat_users)
for idx, item in enumerate(material.lnx_bind_textures_list):
@ -82,11 +80,11 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
log.warn(f'Material "{material.name}": skipping export of bind texture at slot {idx + 1} ("{item.uniform_name}") with no image selected')
elif not wrd.lnx_batch_materials or material.name.startswith('lnxdefault'):
rpasses, shader_data, shader_data_name, bind_constants, bind_textures, mat_uses_sss = make_shader.build(material, mat_users, mat_lnxusers)
rpasses, shader_data, shader_data_name, bind_constants, bind_textures = make_shader.build(material, mat_users, mat_lnxusers)
sd = shader_data.sd
else:
result = mat_batch.get(material)
rpasses, shader_data, shader_data_name, bind_constants, bind_textures, mat_uses_sss = result
rpasses, shader_data, shader_data_name, bind_constants, bind_textures = result
sd = shader_data.sd
sss_used = False
@ -107,74 +105,144 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
if material.lnx_material_id != 0:
c['bind_constants'].append({'name': 'materialID', 'intValue': material.lnx_material_id})
if material.lnx_material_id == 2:
wrd.world_defs += '_Hair'
elif rpdat.rp_sss_state != 'Off':
const = {'name': 'materialID'}
# Use per-material SSS flag from shader build
if mat_uses_sss:
const['intValue'] = 2
sss_used = True
if '_SSS' not in wrd.world_defs:
wrd.world_defs += '_SSS'
else:
const['intValue'] = 0
c['bind_constants'].append(const)
# extended BRDF parameters as bind_constants
if rpdat.rp_renderer == 'Deferred':
feats = mat_state.features
def try_float(val_str, default=1.0):
import re as _re_mix
_mix_re = _re_mix.compile(r'^\s*([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)\s*\*\s*\w+\s*([+-])\s*([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)\s*\*\s*\w+\s*$')
_term_re = _re_mix.compile(r'([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)\s*\*\s*[^\s*]+(?:\s*\*\s*[^\s*]+)*')
_term_pair_re = _re_mix.compile(r'([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)\s*\*\s*([^\s*]+(?:\s*\*\s*[^\s*]+)*)')
def _parse_terms(val_str):
val_str = str(val_str).strip()
pairs = _term_pair_re.findall(val_str)
return [(float(c), v.replace(' ', '')) for c, v in pairs]
def eval_filtered_expr(val_str, filter_str):
if val_str is None or filter_str is None:
return None
filter_terms = _parse_terms(filter_str)
if len(filter_terms) < 2:
return None
filter_map = {}
for coeff, var_prod in filter_terms:
filter_map[var_prod] = coeff
val_terms = _parse_terms(val_str)
if len(val_terms) < 2:
return None
filtered_coeffs = []
for coeff, var_prod in val_terms:
fc = filter_map.get(var_prod)
if fc is not None and fc != 0.0:
filtered_coeffs.append(coeff)
if not filtered_coeffs:
return None
if all(c == filtered_coeffs[0] for c in filtered_coeffs):
return filtered_coeffs[0]
return None
def eval_mix_expr(val_str):
if val_str is None:
return None
val_str = str(val_str).strip()
try:
return float(val_str)
except (ValueError, TypeError):
return default
pass
m = _mix_re.match(val_str)
if m:
a = float(m.group(1))
op = m.group(2)
b = float(m.group(3))
if op == '+' and a == b:
return a
if op == '-' and a == b:
return 0.0
terms = _term_re.findall(val_str)
if terms and len(terms) >= 2:
coeffs = [float(t) for t in terms]
nonzero = [c for c in coeffs if c != 0.0]
if not nonzero:
return 0.0
if all(c == nonzero[0] for c in nonzero):
return nonzero[0]
return None
def feat_is_nonzero(val_str):
v = eval_mix_expr(val_str)
if v is None:
return True
return v != 0.0
def try_float(val_str, default=1.0):
v = eval_mix_expr(val_str)
return v if v is not None else default
def is_constant(val_str):
return eval_mix_expr(val_str) is not None
warned_nonconst = set()
def ext_bc(name, val_str, default):
const = is_constant(val_str)
if not const and name not in warned_nonconst:
warned_nonconst.add(name)
log.warn(f'material "{material.name}": deferred ext BRDF param "{name}" has non-constant expression "{val_str}", using default {default} - per-pixel texture-driven params require deferred texturing (Phase 4)')
c['bind_constants'].append({'name': name, 'floatValue': try_float(val_str, default), 'is_constant': const})
has_ext_brdf = False
if feats.get('clearcoat', '0.0') not in ('0.0', '0', ''):
c['bind_constants'].append({'name': 'clearcoat', 'floatValue': try_float(feats.get('clearcoat', '1.0'))})
c['bind_constants'].append({'name': 'clearcoatRough', 'floatValue': try_float(feats.get('clearcoatRough', '0.03'), 0.03)})
c['bind_constants'].append({'name': 'coatIOR', 'floatValue': try_float(feats.get('coatIOR', '1.5'), 1.5)})
c['bind_constants'].append({'name': 'coatTintR', 'floatValue': try_float(feats.get('coatTintR', '1.0'), 1.0)})
c['bind_constants'].append({'name': 'coatTintG', 'floatValue': try_float(feats.get('coatTintG', '1.0'), 1.0)})
c['bind_constants'].append({'name': 'coatTintB', 'floatValue': try_float(feats.get('coatTintB', '1.0'), 1.0)})
if feat_is_nonzero(feats.get('clearcoat', '0.0')):
ext_bc('clearcoat', feats.get('clearcoat', '1.0'), 1.0)
ext_bc('clearcoatRough', feats.get('clearcoatRough', '0.03'), 0.03)
ext_bc('coatIOR', feats.get('coatIOR', '1.5'), 1.5)
ext_bc('coatTintR', feats.get('coatTintR', '1.0'), 1.0)
ext_bc('coatTintG', feats.get('coatTintG', '1.0'), 1.0)
ext_bc('coatTintB', feats.get('coatTintB', '1.0'), 1.0)
if '_ClearCoat' not in wrd.world_defs:
wrd.world_defs += '_ClearCoat'
has_ext_brdf = True
if feats.get('sheen', '0.0') not in ('0.0', '0', ''):
c['bind_constants'].append({'name': 'sheen', 'floatValue': try_float(feats.get('sheen', '1.0'))})
c['bind_constants'].append({'name': 'sheenRough', 'floatValue': try_float(feats.get('sheenRough', '0.5'), 0.5)})
c['bind_constants'].append({'name': 'sheenTintR', 'floatValue': try_float(feats.get('sheenTintR', '1.0'), 1.0)})
c['bind_constants'].append({'name': 'sheenTintG', 'floatValue': try_float(feats.get('sheenTintG', '1.0'), 1.0)})
c['bind_constants'].append({'name': 'sheenTintB', 'floatValue': try_float(feats.get('sheenTintB', '1.0'), 1.0)})
if feat_is_nonzero(feats.get('sheen', '0.0')):
ext_bc('sheen', feats.get('sheen', '1.0'), 1.0)
ext_bc('sheenRough', feats.get('sheenRough', '0.5'), 0.5)
ext_bc('sheenTintR', feats.get('sheenTintR', '1.0'), 1.0)
ext_bc('sheenTintG', feats.get('sheenTintG', '1.0'), 1.0)
ext_bc('sheenTintB', feats.get('sheenTintB', '1.0'), 1.0)
if '_Sheen' not in wrd.world_defs:
wrd.world_defs += '_Sheen'
has_ext_brdf = True
if feats.get('subsurface', '0.0') not in ('0.0', '0', '') and rpdat.rp_sss_state != 'Off' and not mat_uses_sss:
c['bind_constants'].append({'name': 'subsurface', 'floatValue': try_float(feats.get('subsurface', '1.0'))})
c['bind_constants'].append({'name': 'subsurfaceAnisotropy', 'floatValue': try_float(feats.get('subsurfaceAnisotropy', '0.0'), 0.0)})
c['bind_constants'].append({'name': 'subsurfaceRadiusR', 'floatValue': try_float(feats.get('subsurfaceRadiusR', '1.0'), 1.0)})
c['bind_constants'].append({'name': 'subsurfaceRadiusG', 'floatValue': try_float(feats.get('subsurfaceRadiusG', '0.2'), 0.2)})
c['bind_constants'].append({'name': 'subsurfaceRadiusB', 'floatValue': try_float(feats.get('subsurfaceRadiusB', '0.1'), 0.1)})
c['bind_constants'].append({'name': 'subsurfaceColorR', 'floatValue': try_float(feats.get('subsurfaceColorR', '0.8'), 0.8)})
c['bind_constants'].append({'name': 'subsurfaceColorG', 'floatValue': try_float(feats.get('subsurfaceColorG', '0.8'), 0.8)})
c['bind_constants'].append({'name': 'subsurfaceColorB', 'floatValue': try_float(feats.get('subsurfaceColorB', '0.8'), 0.8)})
if '_Subsurface' not in wrd.world_defs:
wrd.world_defs += '_Subsurface'
if feat_is_nonzero(feats.get('subsurface', '0.0')) and rpdat.rp_sss_state != 'Off':
ext_bc('subsurface', feats.get('subsurface', '1.0'), 1.0)
ext_bc('subsurfaceAnisotropy', feats.get('subsurfaceAnisotropy', '0.0'), 0.0)
ext_bc('subsurfaceScale', feats.get('subsurfaceScale', '0.05'), 0.05)
ext_bc('subsurfaceRadiusR', feats.get('subsurfaceRadiusR', '1.0'), 1.0)
ext_bc('subsurfaceRadiusG', feats.get('subsurfaceRadiusG', '0.2'), 0.2)
ext_bc('subsurfaceRadiusB', feats.get('subsurfaceRadiusB', '0.1'), 0.1)
ext_bc('subsurfaceColorR', feats.get('subsurfaceColorR', '0.8'), 0.8)
ext_bc('subsurfaceColorG', feats.get('subsurfaceColorG', '0.8'), 0.8)
ext_bc('subsurfaceColorB', feats.get('subsurfaceColorB', '0.8'), 0.8)
if '_SSS' not in wrd.world_defs:
wrd.world_defs += '_SSS'
has_ext_brdf = True
if feats.get('anisotropy', '0.0') not in ('0.0', '0', ''):
c['bind_constants'].append({'name': 'anisotropy', 'floatValue': try_float(feats.get('anisotropy', '1.0'))})
c['bind_constants'].append({'name': 'anisoRot', 'floatValue': try_float(feats.get('anisoRot', '0.0'), 0.0)})
sss_used = True
if feat_is_nonzero(feats.get('anisotropy', '0.0')):
ext_bc('anisotropy', feats.get('anisotropy', '1.0'), 1.0)
ext_bc('anisoRot', feats.get('anisoRot', '0.0'), 0.0)
if '_Anisotropy' not in wrd.world_defs:
wrd.world_defs += '_Anisotropy'
has_ext_brdf = True
if feats.get('transmission', '0.0') not in ('0.0', '0', ''):
c['bind_constants'].append({'name': 'transmission', 'floatValue': try_float(feats.get('transmission', '1.0'))})
c['bind_constants'].append({'name': 'transmissionRough', 'floatValue': try_float(feats.get('transmissionRough', '0.0'), 0.0)})
c['bind_constants'].append({'name': 'ior', 'floatValue': try_float(feats.get('ior', '1.45'), 1.45)})
c['bind_constants'].append({'name': 'thinWall', 'floatValue': try_float(feats.get('thinWall', '0.0'), 0.0)})
if feat_is_nonzero(feats.get('transmission', '0.0')):
transm_str = feats.get('transmission', '1.0')
ext_bc('transmission', transm_str, 1.0)
ext_bc('transmissionRough', feats.get('transmissionRough', '0.0'), 0.0)
ior_str = feats.get('ior', '1.45')
if not is_constant(ior_str):
filtered = eval_filtered_expr(ior_str, transm_str)
if filtered is not None:
ior_str = str(filtered)
ext_bc('ior', ior_str, 1.45)
ext_bc('thinWall', feats.get('thinWall', '0.0'), 0.0)
if '_Transmission' not in wrd.world_defs:
wrd.world_defs += '_Transmission'
has_ext_brdf = True
@ -182,6 +250,11 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
if has_ext_brdf and '_ExtBRDF' not in wrd.world_defs:
wrd.world_defs += '_ExtBRDF'
if has_ext_brdf:
ext_bc('specularTintR', feats.get('specularTintR', '1.0'), 1.0)
ext_bc('specularTintG', feats.get('specularTintG', '1.0'), 1.0)
ext_bc('specularTintB', feats.get('specularTintB', '1.0'), 1.0)
# assign materialID for extended BRDF if not already set
# coexist with Scene.hx for last materialID in bind_constants
if has_ext_brdf and material.lnx_material_id == 0:
@ -191,6 +264,11 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
c['bind_constants'].append({'name': 'materialID', 'intValue': ext_id})
else:
log.warn(f'material "{material.name}": extended BRDF material limit (15) exceeded, extended BRDF will be disabled for this material')
has_ext_brdf = False
has_matid = any(bc.get('name') == 'materialID' for bc in c['bind_constants'] if isinstance(bc, dict))
if not has_matid:
c['bind_constants'].append({'name': 'materialID', 'intValue': 0})
# TODO: Mesh only material batching
if wrd.lnx_batch_materials:

View File

@ -77,6 +77,8 @@ def write(vert: shader.Shader, frag: shader.Shader):
if is_transparent_shadows:
frag.add_uniform('sampler2D shadowMapSpotTransparent[4]', included=True)
frag.add_uniform('mat4 LWVPSpotArray[maxLightsCluster]', link='_biasLightWorldViewProjectionMatrixSpotArray', included=True)
if is_shadows_atlas:
frag.add_uniform('vec4 tileBoundsSpotArray[maxLightsCluster]', link='_tileBoundsSpotArray', included=True)
frag.write('for (int i = 0; i < min(numLights, maxLightsCluster); i++) {')
frag.write('int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255);')
@ -112,13 +114,13 @@ def write(vert: shader.Shader, frag: shader.Shader):
frag.add_uniform('vec3 eye', '_cameraPosition')
frag.write(', gbufferD, invVP, eye')
if '_ClearCoat' in wrd.world_defs:
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint')
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint, nCoat')
if '_Sheen' in wrd.world_defs:
frag.write(', sheen, sheenRough, sheenTint')
if '_Anisotropy' in wrd.world_defs:
frag.write(', anisotropy, anisoRot, tangent')
if '_Subsurface' in wrd.world_defs:
frag.write(', subsurface, subsurfaceColor, subsurfaceRadius, subsurfaceAnisotropy')
if '_SSS' in wrd.world_defs:
frag.write(', subsurface, subsurfaceColor, subsurfaceRadius * subsurfaceScale, subsurfaceAnisotropy')
if '_Transmission' in wrd.world_defs:
frag.write(', transmission, transmissionRough, ior, thinWall')
frag.write(');')

View File

@ -74,8 +74,6 @@ def make(context_id, rpasses):
con['color_attachments'] = [attachment_format, attachment_format]
if '_gbuffer2' in wrd.world_defs:
con['color_attachments'].append(attachment_format)
if '_Anisotropy' in wrd.world_defs:
con['color_attachments'].append('RGBA64')
con_mesh = mat_state.data.add_context(con)
mat_state.con_mesh = con_mesh
@ -156,6 +154,8 @@ def make_base(con_mesh, parse_opacity):
vert.add_out('vec3 wnormal')
make_attrib.write_norpos(con_mesh, vert)
frag.write_attrib('vec3 n = normalize(wnormal);')
if '_ClearCoat' in wrd.world_defs:
frag.write_attrib('vec3 nCoat = vec3(0.0, 0.0, 0.0);')
if mat_state.material.lnx_two_sided:
frag.write('if (!gl_FrontFacing) n *= -1;') # Flip normal when drawing back-face
@ -254,16 +254,13 @@ def make_deferred(con_mesh, rpasses):
frag.write('n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);')
is_shadeless = mat_state.emission_type == mat_state.EmissionType.SHADELESS
ext_brdf_defs = ('_ClearCoat', '_Sheen', '_Anisotropy', '_Subsurface', '_Transmission')
ext_brdf_defs = ('_ClearCoat', '_Sheen', '_Anisotropy', '_SSS', '_Transmission')
has_ext_brdf = any(d in wrd.world_defs for d in ext_brdf_defs)
if is_shadeless or '_SSS' in wrd.world_defs or '_Hair' in wrd.world_defs or has_ext_brdf:
if is_shadeless or has_ext_brdf:
frag.write('uint matid = 0;')
if is_shadeless:
frag.write('matid = 1;')
frag.write('basecol = emissionCol;')
if '_SSS' in wrd.world_defs or '_Hair' in wrd.world_defs:
frag.add_uniform('int materialID')
frag.write('if (materialID == 2) matid = 2;')
if has_ext_brdf:
frag.add_uniform('int materialID')
frag.write('if (materialID >= 3) matid = uint(materialID);')
@ -283,6 +280,14 @@ def make_deferred(con_mesh, rpasses):
if mat_state.material.lnx_ignore_irradiance:
frag.write('fragColor[GBUF_IDX_2].b = 1.0;')
if '_Anisotropy' in wrd.world_defs:
frag.write('#ifdef _Anisotropy')
if con_mesh.is_elem('tang'):
frag.write('fragColor[GBUF_IDX_2].a = encodeTangent(TBN[0], normalize(wnormal));')
else:
frag.write('fragColor[GBUF_IDX_2].a = -1.0;')
frag.write('#endif')
# Even if the material doesn't use emission we need to write to the
# emission buffer (if used) to prevent undefined behaviour
frag.write('#ifdef _EmissionShaded')
@ -290,14 +295,21 @@ def make_deferred(con_mesh, rpasses):
frag.write('#endif')
if '_SSRefraction' in wrd.world_defs or '_VoxelRefract' in wrd.world_defs:
frag.write('fragColor[GBUF_IDX_REFRACTION] = vec4(1.0, 0.0, 0.0, 1.0);')
frag.write('fragColor[GBUF_IDX_REFRACTION] = vec4(packIOR(1.0), 0.0, 0.0, 1.0);')
if '_Anisotropy' in wrd.world_defs:
frag.write('#ifdef _Anisotropy')
if con_mesh.is_elem('tang'):
frag.write('fragColor[GBUF_IDX_3] = vec4(normalize(TBN[0]), 0.0);')
else:
frag.write('fragColor[GBUF_IDX_3] = vec4(0.0, 0.0, 0.0, 0.0);')
if '_ClearCoat' in wrd.world_defs:
frag.write('#ifdef _ClearCoat')
frag.write('if (dot(nCoat, nCoat) > 0.0) {')
frag.write(' vec3 nCoatNorm = normalize(nCoat);')
frag.write(' nCoatNorm /= (abs(nCoatNorm.x) + abs(nCoatNorm.y) + abs(nCoatNorm.z));')
frag.write(' nCoatNorm.xy = nCoatNorm.z >= 0.0 ? nCoatNorm.xy : octahedronWrap(nCoatNorm.xy);')
frag.write(' fragColor[GBUF_IDX_COAT_NORMAL] = vec4(nCoatNorm.xy, 0.0, 0.0);')
frag.write('} else {')
frag.write(' vec3 nNorm = normalize(n);')
frag.write(' nNorm /= (abs(nNorm.x) + abs(nNorm.y) + abs(nNorm.z));')
frag.write(' nNorm.xy = nNorm.z >= 0.0 ? nNorm.xy : octahedronWrap(nNorm.xy);')
frag.write(' fragColor[GBUF_IDX_COAT_NORMAL] = vec4(nNorm.xy, 0.0, 0.0);')
frag.write('}')
frag.write('#endif')
return con_mesh
@ -403,6 +415,9 @@ def make_forward_mobile(con_mesh):
frag.add_include('std/shadows.glsl')
frag.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True)
frag.add_uniform('vec3 eye', '_cameraPosition')
if is_shadows_atlas:
frag.add_uniform('vec4 tileBoundsSunArray[maxLights * shadowmapCascades]', '_tileBoundsSunArray', included=True)
frag.write('tileBounds = tileBoundsSunArray[0];')
frag.write(f'svisibility = shadowTestCascade({shadowmap_sun}, eye, wposition + n * shadowsBias * 10, shadowsBias, opacity != 1.0);')
else:
frag.write('if (lightPosition.w > 0.0) {')
@ -582,7 +597,7 @@ def make_forward(con_mesh):
frag.write('fragColor[0] = vec4(direct + indirect, packFloat2(occlusion, specular));')
frag.write('fragColor[1] = vec4(n.xy, roughness, metallic);')
if rpdat.rp_ss_refraction or rpdat.lnx_voxelgi_refract:
frag.write(f'fragColor[2] = vec4(1.0, 0.0, 0.0, 1.0);')
frag.write(f'fragColor[2] = vec4(packIOR(1.0), 0.0, 0.0, 1.0);')
else:
frag.add_out('vec4 fragColor[1]')
@ -683,6 +698,8 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
frag.write('vec3 albedo = surfaceAlbedo(basecol, metallic);')
frag.write('vec3 f0 = surfaceF0(basecol, metallic);')
if '_ExtBRDF' in wrd.world_defs:
frag.write('f0 = mix(f0, basecol, specularTint);')
if '_Brdf' in wrd.world_defs:
frag.add_uniform('sampler2D senvmapBrdf', link='$brdf.png')
@ -752,6 +769,18 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
frag.write('}')
frag.write('vec3 direct = vec3(0.0);')
if '_ExtBRDF' in wrd.world_defs:
frag.write('#ifdef _ExtBRDF')
if '_Sheen' in wrd.world_defs:
frag.write('brdf_sheenWeight = sheenAttenuation(sheen, sheenRough, sheenTint, dotNV);')
if '_ClearCoat' in wrd.world_defs:
frag.write('brdf_coatWeight = coatAttenuation(clearcoat, coatIOR, nCoat, vVec);')
frag.write('brdf_coatTintAbsorb = coatTintAttenuation(clearcoat, coatTint, nCoat, vVec);')
frag.write('brdf_coatF0 = (coatIOR - 1.0) / (coatIOR + 1.0); brdf_coatF0 = brdf_coatF0 * brdf_coatF0;')
if '_Transmission' in wrd.world_defs:
frag.write('brdf_transmissionF0 = (ior - 1.0) / (ior + 1.0); brdf_transmissionF0 = brdf_transmissionF0 * brdf_transmissionF0;')
frag.write('#endif')
if '_Sun' in wrd.world_defs:
frag.add_uniform('vec3 sunCol', '_sunColor')
frag.add_uniform('vec3 sunDir', '_sunDirection')
@ -771,6 +800,9 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
frag.add_include('std/shadows.glsl')
frag.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True)
frag.add_uniform('vec3 eye', '_cameraPosition')
if is_shadows_atlas:
frag.add_uniform('vec4 tileBoundsSunArray[maxLights * shadowmapCascades]', '_tileBoundsSunArray', included=True)
frag.write('tileBounds = tileBoundsSunArray[0];')
frag.write(f'svisibility = shadowTestCascade({shadowmap_sun},')
if is_transparent_shadows:
frag.write(f'{shadowmap_sun_tr},')
@ -804,7 +836,21 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
if '_VoxelShadow' in wrd.world_defs:
frag.write('svisibility *= (1.0 - traceShadow(wposition, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy, velocity).r) * voxelgiShad;')
frag.write('}') # receiveShadow
frag.write('direct += (lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;')
if '_ExtBRDF' in wrd.world_defs:
frag.write('float sunLayerWeight;')
frag.write('vec3 sdirect = applyExtBRDFLayers(')
frag.write(' lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular,')
frag.write(' albedo, f0, roughness, sdotNL, dotNV, sdotNH, sdotVH, n, sunDir, vVec, sh')
if '_ClearCoat' in wrd.world_defs:
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint, nCoat')
if '_Sheen' in wrd.world_defs:
frag.write(', sheen, sheenRough, sheenTint')
if '_Transmission' in wrd.world_defs:
frag.write(', transmission, transmissionRough, ior, thinWall')
frag.write(', sunLayerWeight);')
frag.write('direct += sdirect * sunCol * svisibility;')
else:
frag.write('direct += (lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;')
# sun
if '_SinglePoint' in wrd.world_defs:
@ -846,13 +892,13 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
frag.add_uniform('vec3 eye', '_cameraPosition')
frag.write(', gbufferD, invVP, eye')
if '_ClearCoat' in wrd.world_defs:
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint')
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint, nCoat')
if '_Sheen' in wrd.world_defs:
frag.write(', sheen, sheenRough, sheenTint')
if '_Anisotropy' in wrd.world_defs:
frag.write(', anisotropy, anisoRot, tangent')
if '_Subsurface' in wrd.world_defs:
frag.write(', subsurface, subsurfaceColor, subsurfaceRadius, subsurfaceAnisotropy')
if '_SSS' in wrd.world_defs:
frag.write(', subsurface, subsurfaceColor, subsurfaceRadius * subsurfaceScale, subsurfaceAnisotropy')
if '_Transmission' in wrd.world_defs:
frag.write(', transmission, transmissionRough, ior, thinWall')
frag.write(');')
@ -867,7 +913,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
if '_VoxelRefract' in wrd.world_defs and parse_opacity:
frag.write('if (opacity < 1.0) {')
frag.write(' vec3 refraction = traceRefraction(wposition, n, voxels, voxelsSDF, vVec, ior, roughness * roughness, clipmaps, gl_FragCoord.xy, velocity, opacity).rgb * (1.0 - F) * voxelgiRefr;')
frag.write(' vec3 refraction = traceRefraction(wposition, n, voxels, voxelsSDF, vVec, ior, roughness * roughness, clipmaps, gl_FragCoord.xy, velocity, opacity).rgb * (1.0 - F);')
frag.write(' indirect = mix(refraction, indirect, opacity);')
frag.write(' direct = mix(refraction, direct, opacity);')
frag.write('}')
@ -882,25 +928,27 @@ def _write_material_attribs_default(frag: shader.Shader, parse_opacity: bool):
# by the shader compiler
frag.write('vec3 emissionCol;')
# Extended BRDF parameters
frag.write('float subsurface = 0.0;')
frag.write('vec3 subsurfaceRadius = vec3(0.0);')
frag.write('vec3 subsurfaceColor = vec3(0.8);')
frag.write('vec3 specularTint = vec3(1.0);')
frag.write('float anisotropy = 0.0;')
frag.write('float anisoRot = 0.0;')
frag.write('float sheen = 0.0;')
frag.write('float sheenRough = 0.5;')
frag.write('vec3 sheenTint = vec3(1.0);')
frag.write('float clearcoat = 0.0;')
frag.write('float clearcoatRough = 0.03;')
frag.write('float transmission = 0.0;')
frag.write('float transmissionRough = 0.0;')
frag.write('float thinWall = 0.0;')
frag.write('vec3 tangent = vec3(0.0);')
frag.write('float subsurfaceScale = 0.05;')
frag.write('float subsurfaceAnisotropy = 0.0;')
frag.write('float coatIOR = 1.5;')
frag.write('vec3 coatTint = vec3(1.0);')
frag.write('float subsurface;')
frag.write('vec3 subsurfaceRadius;')
frag.write('vec3 subsurfaceColor;')
frag.write('vec3 specularTint;')
frag.write('float anisotropy;')
frag.write('float anisoRot;')
frag.write('float sheen;')
frag.write('float sheenRough;')
frag.write('vec3 sheenTint;')
frag.write('float clearcoat;')
frag.write('float clearcoatRough;')
frag.write('float transmission;')
frag.write('float transmissionRough;')
frag.write('float thinWall;')
frag.write('vec3 tangent;')
frag.write('float subsurfaceScale;')
frag.write('float subsurfaceAnisotropy;')
frag.write('float coatIOR;')
frag.write('vec3 coatTint;')
frag.write('float ior = 1.45;')
if parse_opacity:
frag.write('float opacity;')
frag.write('float ior = 1.45;')
else:
frag.write('float opacity = 1.0;')

View File

@ -40,34 +40,29 @@ def make(context_id):
# Remove fragColor = ...;
frag.main = frag.main[:frag.main.rfind('fragColor')]
frag.write('\n')
wrd = bpy.data.worlds['Lnx']
frag.write('if (opacity <= 0.0) discard;')
frag.write('n /= (abs(n.x) + abs(n.y) + abs(n.z));')
frag.write('n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);')
is_shadeless = mat_state.emission_type == mat_state.EmissionType.SHADELESS
if is_shadeless or '_SSS' in wrd.world_defs or '_Hair' in wrd.world_defs:
if is_shadeless:
frag.write('uint matid = 0;')
if is_shadeless:
frag.write('matid = 1;')
frag.write('basecol = emissionCol;')
if '_SSS' in wrd.world_defs or '_Hair' in wrd.world_defs:
frag.add_uniform('int materialID')
frag.write('if (materialID == 2) matid = 2;')
frag.write('matid = 1;')
frag.write('basecol = emissionCol;')
else:
frag.write('const uint matid = 0;')
if rpdat.rp_renderer == 'Deferred':
frag.write('fragColor[0] = vec4(n.xy, roughness, 1.0);')
frag.write('vec3 finalColor = direct + indirect;')
frag.write('fragColor[1] = vec4(finalColor * opacity, opacity);')
frag.write('fragColor[1] = vec4(finalColor * opacity, 1.0);')
else:
frag.write('vec3 finalColor = direct + indirect;')
frag.write('fragColor[0] = vec4(finalColor * opacity, opacity);')
frag.write('fragColor[0] = vec4(finalColor * opacity, 1.0);')
frag.write('fragColor[1] = vec4(n.xy, roughness, 1.0);')
frag.write('fragColor[2] = vec4(ior, 1.0 - opacity, gl_FragCoord.z, 1.0);')
frag.write('fragColor[2] = vec4(packIOR(ior), 1.0 - opacity, gl_FragCoord.z, 1.0);')
# frag.write('fragColor[2] = vec4(ior, 1.0 - opacity, packFloat2(basecol.r, basecol.g), basecol.b);')
make_finalize.make(con_refract)

View File

@ -57,9 +57,6 @@ def build(material: Material, mat_users: Dict[Material, List[Object]], mat_lnxus
# Place empty material output to keep compiler happy..
mat_state.output_node = mat_state.nodes.new('ShaderNodeOutputMaterial')
# reset for each material
mat_state.needs_sss = False
wrd = bpy.data.worlds['Lnx']
rpdat = lnx.utils.get_rp()
rpasses = mat_utils.get_rpasses(material)
@ -133,9 +130,7 @@ def build(material: Material, mat_users: Dict[Material, List[Object]], mat_lnxus
shader_data_path = lnx.utils.get_fp_build() + '/compiled/Shaders/' + shader_data_name + '.lnx'
assets.add_shader_data(shader_data_path)
# Store SSS state in the return tuple so it's preserved per-material
needs_sss_result = mat_state.needs_sss
return rpasses, mat_state.data, shader_data_name, bind_constants, bind_textures, needs_sss_result
return rpasses, mat_state.data, shader_data_name, bind_constants, bind_textures
def write_shaders(rel_path: str, con: ShaderContext, rpass: str, matname: str) -> None:

View File

@ -69,42 +69,44 @@ def make_gi(context_id):
frag.add_include('std/gbuffer.glsl')
frag.add_include('std/brdf.glsl')
frag.add_include('std/aabb.glsl')
frag.write_header('#define _VoxelPass')
rpdat = lnx.utils.get_rp()
frag.add_uniform('layout(r32ui) uimage3D voxels')
frag.write('vec3 n;')
frag.write('vec3 nCoat = vec3(0.0, 0.0, 0.0);')
frag.write('vec3 wposition;')
frag.write('vec3 basecol;')
frag.write('float roughness;') #
frag.write('float metallic;') #
frag.write('float occlusion;') #
frag.write('float specular;') #
frag.write('vec3 emissionCol = vec3(0.0);')
frag.write('vec3 specularTint = vec3(1.0);')
frag.write('float subsurface = 0.0;')
frag.write('vec3 subsurfaceRadius = vec3(0.0);')
frag.write('vec3 subsurfaceColor = vec3(0.8);')
frag.write('float anisotropy = 0.0;')
frag.write('float anisoRot = 0.0;')
frag.write('float sheen = 0.0;')
frag.write('float sheenRough = 0.5;')
frag.write('vec3 sheenTint = vec3(1.0);')
frag.write('float clearcoat = 0.0;')
frag.write('float clearcoatRough = 0.03;')
frag.write('float transmission = 0.0;')
frag.write('float transmissionRough = 0.0;')
frag.write('float thinWall = 0.0;')
frag.write('vec3 tangent = vec3(0.0);')
frag.write('float subsurfaceScale = 0.05;')
frag.write('float subsurfaceAnisotropy = 0.0;')
frag.write('float coatIOR = 1.5;')
frag.write('vec3 coatTint = vec3(1.0);')
frag.write('vec3 emissionCol;')
frag.write('vec3 specularTint;')
frag.write('float subsurface;')
frag.write('vec3 subsurfaceRadius;')
frag.write('vec3 subsurfaceColor;')
frag.write('float anisotropy;')
frag.write('float anisoRot;')
frag.write('float sheen;')
frag.write('float sheenRough;')
frag.write('vec3 sheenTint;')
frag.write('float clearcoat;')
frag.write('float clearcoatRough;')
frag.write('float transmission;')
frag.write('float transmissionRough;')
frag.write('float thinWall;')
frag.write('vec3 tangent;')
frag.write('float subsurfaceScale;')
frag.write('float subsurfaceAnisotropy;')
frag.write('float coatIOR;')
frag.write('vec3 coatTint;')
blend = mat_state.material.lnx_blending
parse_opacity = blend or mat_utils.is_transluc(mat_state.material)
frag.write('float ior = 1.45;')
if parse_opacity:
frag.write('float opacity;')
frag.write('float ior;')
else:
frag.write('float opacity = 1.0;')
@ -271,10 +273,6 @@ def make_gi(context_id):
frag.write_attrib('vec3 vVec = normalize(eyeDir);')
frag.write_attrib('float dotNV = max(dot(N, vVec), 0.0);')
if '_Brdf' in wrd.world_defs:
frag.add_uniform('sampler2D senvmapBrdf', link='$brdf.png')
frag.write('vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;')
if '_Irr' in wrd.world_defs:
frag.add_include('std/shirr.glsl')
frag.add_uniform('vec4 shirr[7]', link='_envmapIrradiance')
@ -284,31 +282,12 @@ def make_gi(context_id):
else:
frag.write('vec3 envl = vec3(0.0);')
if '_Rad' in wrd.world_defs:
frag.add_uniform('sampler2D senvmapRadiance', link='_envmapRadiance')
frag.add_uniform('int envmapNumMipmaps', link='_envmapNumMipmaps')
frag.write('vec3 reflectionWorld = reflect(-vVec, N);')
frag.write('float lod = getMipFromRoughness(roughness, envmapNumMipmaps);')
frag.write('vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;')
if '_EnvLDR' in wrd.world_defs:
frag.write('envl = pow(envl, vec3(2.2));')
if '_Rad' in wrd.world_defs:
frag.write('prefilteredColor = pow(prefilteredColor, vec3(2.2));')
frag.write('envl *= albedo;')
if '_Brdf' in wrd.world_defs:
frag.write('vec3 F = f0 + (vec3(1.0) - f0) * pow(1.0 - abs(dot(N, vVec)), 5.0);')
frag.write('envl.rgb *= 1.0 - F;')
if '_Rad' in wrd.world_defs:
frag.write('envl += prefilteredColor * F;')
elif '_EnvCol' in wrd.world_defs:
frag.add_uniform('vec3 backgroundCol', link='_backgroundCol')
frag.write('envl += backgroundCol * F;')
frag.add_uniform('float envmapStrength', link='_envmapStrength')
frag.write('envl *= envmapStrength * occlusion;')
frag.write('envl *= envmapStrength * voxelgiEnv * occlusion;')
frag.add_include('std/light.glsl')
is_shadows = '_ShadowMap' in wrd.world_defs
@ -343,6 +322,9 @@ def make_gi(context_id):
frag.add_include('std/shadows.glsl')
frag.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True)
frag.add_uniform('vec3 eye', '_cameraPosition')
if is_shadows_atlas:
frag.add_uniform('vec4 tileBoundsSunArray[maxLights * shadowmapCascades]', '_tileBoundsSunArray', included=True)
frag.write('tileBounds = tileBoundsSunArray[0];')
frag.write(f'svisibility = shadowTestCascade({shadowmap_sun},')
if is_transparent_shadows:
frag.write(f'{shadowmap_sun_tr},')
@ -364,7 +346,7 @@ def make_gi(context_id):
frag.write(', false')
frag.write(');')
frag.write('}') # receiveShadow
frag.write('direct += (lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;')
frag.write('direct += vec3(sdotNL) * sunCol * svisibility;')
# sun
if '_SinglePoint' in wrd.world_defs:
@ -397,13 +379,13 @@ def make_gi(context_id):
if '_Spot' in wrd.world_defs:
frag.write(', true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight')
if '_ClearCoat' in wrd.world_defs:
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint')
frag.write(', clearcoat, clearcoatRough, coatIOR, coatTint, N')
if '_Sheen' in wrd.world_defs:
frag.write(', sheen, sheenRough, sheenTint')
if '_Anisotropy' in wrd.world_defs:
frag.write(', anisotropy, anisoRot, tangent')
if '_Subsurface' in wrd.world_defs:
frag.write(', subsurface, subsurfaceColor, subsurfaceRadius, subsurfaceAnisotropy')
if '_SSS' in wrd.world_defs:
frag.write(', subsurface, subsurfaceColor, subsurfaceRadius * subsurfaceScale, subsurfaceAnisotropy')
if '_Transmission' in wrd.world_defs:
frag.write(', transmission, transmissionRough, ior, thinWall')
frag.write(');')
@ -462,6 +444,8 @@ def make_gi(context_id):
if is_transparent_shadows:
frag.add_uniform('sampler2D shadowMapSpotTransparent[4]', included=True)
frag.add_uniform('mat4 LWVPSpotArray[maxLightsCluster]', link='_biasLightWorldViewProjectionMatrixSpotArray', included=True)
if is_shadows_atlas:
frag.add_uniform('vec4 tileBoundsSpotArray[maxLightsCluster]', link='_tileBoundsSpotArray', included=True)
frag.write('for (int i = 0; i < min(numLights, maxLightsCluster); i++) {')
frag.write('int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255);')
@ -488,13 +472,13 @@ def make_gi(context_id):
frag.write('\t, vec2(lightsArray[li * 3].w, lightsArray[li * 3 + 1].w)') # scale
frag.write('\t, lightsArraySpot[li * 2 + 1].xyz') # right
if '_ClearCoat' in wrd.world_defs:
frag.write('\t, clearcoat, clearcoatRough, coatIOR, coatTint')
frag.write('\t, clearcoat, clearcoatRough, coatIOR, coatTint, N')
if '_Sheen' in wrd.world_defs:
frag.write('\t, sheen, sheenRough, sheenTint')
if '_Anisotropy' in wrd.world_defs:
frag.write('\t, anisotropy, anisoRot, tangent')
if '_Subsurface' in wrd.world_defs:
frag.write('\t, subsurface, subsurfaceColor, subsurfaceRadius, subsurfaceAnisotropy')
if '_SSS' in wrd.world_defs:
frag.write('\t, subsurface, subsurfaceColor, subsurfaceRadius * subsurfaceScale, subsurfaceAnisotropy')
if '_Transmission' in wrd.world_defs:
frag.write('\t, transmission, transmissionRough, ior, thinWall')
frag.write(' );')

View File

@ -38,6 +38,5 @@ texture_grad = False # Sample textures using textureGrad()
con_mesh = None # Mesh context
uses_instancing = False # Whether the current material has at least one user with instancing enabled
emission_type = EmissionType.NO_EMISSION
needs_sss = False
features = {} # tracks extended BRDF features used by current material
next_ext_mat_id = 3 # auto assigned materialID for extended BRDF

View File

@ -118,6 +118,7 @@ class ParserState:
self.out_subsurface_anisotropy: floatstr = '0.0'
self.out_coat_ior: floatstr = '1.5'
self.out_coat_tint: vec3str = 'vec3(1.0)'
self.out_coat_normal: vec3str = 'vec3(0.0)'
def reset_outs(self):
"""Reset the shader output values to their default values."""
@ -148,6 +149,7 @@ class ParserState:
self.out_subsurface_anisotropy = '0.0'
self.out_coat_ior = '1.5'
self.out_coat_tint = 'vec3(1.0)'
self.out_coat_normal = 'vec3(0.0)'
def get_outs(self) -> Tuple:
"""Return the shader output values as a tuple."""

View File

@ -543,12 +543,12 @@ class LnxRPListItem(bpy.types.PropertyGroup):
name="MSAA", description="Samples per pixel usable for render paths drawing directly to framebuffer", default='1')
lnx_voxelgi_cones: EnumProperty(
items=[('9', '9', '9'),
items=[('16', '16', '16'),
('9', '9', '9'),
('5', '5', '5'),
('3', '3', '3'),
('1', '1', '1'),
],
name="Cones", description="Number of cones to trace", default='5', update=assets.invalidate_shader_cache)
name="Cones", description="Number of cones to trace", default='9', update=assets.invalidate_shader_cache)
lnx_voxelgi_diff: FloatProperty(name="Diffuse", description="", default=1.0, update=assets.invalidate_shader_cache)
lnx_voxelgi_spec: FloatProperty(name="Reflection", description="", default=1.0, update=assets.invalidate_shader_cache)
lnx_voxelgi_refr: FloatProperty(name="Refraction", description="", default=1.0, update=assets.invalidate_shader_cache)
@ -559,8 +559,7 @@ class LnxRPListItem(bpy.types.PropertyGroup):
lnx_voxelgi_step: FloatProperty(name="Step", description="Step size", default=1.0, update=assets.invalidate_shader_cache)
lnx_voxelgi_range: FloatProperty(name="Range", description="Maximum range", default=100.0, update=assets.invalidate_shader_cache)
lnx_voxelgi_offset: FloatProperty(name="Offset", description="Multiplicative Offset for dealing with self occlusion", default=1.0, update=assets.invalidate_shader_cache)
lnx_voxelgi_aperture: FloatProperty(name="Aperture", description="Cone aperture for shadow trace", default=0.0, update=assets.invalidate_shader_cache)
lnx_sss_width: FloatProperty(name="Width", description="SSS blur strength", default=1.0, update=assets.invalidate_shader_cache)
lnx_voxelgi_aperture: FloatProperty(name="Aperture", description="Cone aperture for shadow trace", default=0.26, update=assets.invalidate_shader_cache)
lnx_water_color: FloatVectorProperty(name="Color", size=3, default=[1, 1, 1], subtype='COLOR', min=0, max=1, update=assets.invalidate_shader_cache)
lnx_water_level: FloatProperty(name="Level", default=0.0, update=assets.invalidate_shader_cache)
lnx_water_displace: FloatProperty(name="Displace", default=1.0, update=assets.invalidate_shader_cache)

View File

@ -1646,9 +1646,6 @@ class LNX_PT_RenderPathRendererPanel(bpy.types.Panel):
layout.prop(rpdat, 'lnx_samples_per_pixel')
layout.prop(rpdat, 'lnx_texture_filter')
layout.prop(rpdat, 'rp_sss_state')
col = layout.column()
col.enabled = rpdat.rp_sss_state != 'Off'
col.prop(rpdat, 'lnx_sss_width')
layout.prop(rpdat, 'lnx_rp_displacement')
if rpdat.lnx_rp_displacement == 'Tessellation':
layout.label(text='Mesh')
@ -1890,7 +1887,7 @@ class LNX_PT_RenderPathVoxelsPanel(bpy.types.Panel):
col.prop(rpdat, 'lnx_voxelgi_shadows', text='Shadows')
col2.prop(rpdat, 'lnx_voxelgi_refract', text='Refraction')
#col.prop(rpdat, 'lnx_voxelgi_clipmap_count')
#col.prop(rpdat, 'lnx_voxelgi_cones')
col.prop(rpdat, 'lnx_voxelgi_cones')
col.prop(rpdat, 'rp_voxelgi_resolution')
col.prop(rpdat, 'lnx_voxelgi_size')
#col.prop(rpdat, 'rp_voxelgi_resolution_z')
@ -1906,10 +1903,10 @@ class LNX_PT_RenderPathVoxelsPanel(bpy.types.Panel):
col.prop(rpdat, 'lnx_voxelgi_env')
col.prop(rpdat, 'lnx_voxelgi_occ')
col.label(text="Ray")
#col.prop(rpdat, 'lnx_voxelgi_offset')
col.prop(rpdat, 'lnx_voxelgi_offset')
col.prop(rpdat, 'lnx_voxelgi_step')
col.prop(rpdat, 'lnx_voxelgi_range')
#col.prop(rpdat, 'lnx_voxelgi_aperture')
col.prop(rpdat, 'lnx_voxelgi_aperture')
class LNX_PT_RenderPathWorldPanel(bpy.types.Panel):
bl_label = "World"

View File

@ -665,7 +665,8 @@ class Main {
if rpdat.rp_voxels == 'Voxel GI' or rpdat.rp_voxels == 'Voxel AO':
f.write("""
public static inline var voxelgiClipmapCount = """ + str(rpdat.lnx_voxelgi_clipmap_count) + """;
public static inline var voxelgiVoxelSize = """ + str(round(rpdat.lnx_voxelgi_size * 100) / 100) + """;""")
public static inline var voxelgiVoxelSize = """ + str(round(rpdat.lnx_voxelgi_size * 100) / 100) + """;
public static inline var diffuseConeCount = """ + str(rpdat.lnx_voxelgi_cones) + """;""")
if rpdat.rp_bloom:
follow_blender = rpdat.lnx_bloom_follow_blender if bpy.app.version < (4, 3, 0) else False
@ -834,12 +835,12 @@ def write_compiledglsl(defs, make_variants):
if '_SSRefraction' in wrd.world_defs or '_VoxelRefract' in wrd.world_defs:
f.write(f'#define GBUF_IDX_REFRACTION {idx_refraction}\n')
idx_refraction += 1
idx_anisotropy = idx_refraction
if '_Anisotropy' in wrd.world_defs:
f.write(f'#define GBUF_IDX_3 {idx_anisotropy}\n')
if '_ClearCoat' in wrd.world_defs:
f.write(f'#define GBUF_IDX_COAT_NORMAL {idx_refraction}\n')
ext_brdf_defs = ('_ClearCoat', '_Sheen', '_Anisotropy', '_Subsurface', '_Transmission')
ext_brdf_defs = ('_ClearCoat', '_Sheen', '_Anisotropy', '_SSS', '_Transmission')
if any(d in wrd.world_defs for d in ext_brdf_defs):
f.write('#ifndef _ExtBRDF\n')
f.write('#define _ExtBRDF\n')
@ -855,8 +856,12 @@ def write_compiledglsl(defs, make_variants):
if state.target == 'html5' or lnx.utils.get_gapi() == 'direct3d11':
f.write("#define _FlipY\n")
f.write("""const float PI = 3.1415926535;
const float PI2 = PI * 2.0;
f.write("""#ifndef PI
#define PI 3.1415926535
#endif
#ifndef PI2
#define PI2 6.2831853071
#endif
const vec2 shadowmapSize = vec2(""" + str(shadowmap_size) + """, """ + str(shadowmap_size) + """);
const float shadowmapCubePcfSize = """ + str((round(rpdat.lnx_pcfsize * 100) / 100) / 1000) + """;
const int shadowmapCascades = """ + str(rpdat.rp_shadowmap_cascades) + """;
@ -1027,6 +1032,7 @@ const float compoDOFLength = """ + str(round(lens * 100) / 100) +""";
if rpdat.rp_voxels != 'Off':
f.write("""const ivec3 voxelgiResolution = ivec3(""" + str(rpdat.rp_voxelgi_resolution) + """, """ + str(rpdat.rp_voxelgi_resolution) + """, """ + str(rpdat.rp_voxelgi_resolution) + """);
const int voxelgiClipmapCount = """ + str(rpdat.lnx_voxelgi_clipmap_count) + """;
const int diffuseConeCount = """ + str(rpdat.lnx_voxelgi_cones) + """;
const float voxelgiOcc = """ + str(round(rpdat.lnx_voxelgi_occ * 100) / 100) + """;
const float voxelgiVoxelSize = """ + str(round(rpdat.lnx_voxelgi_size * 1000) / 1000) + """;
const float voxelgiStep = """ + str(round(rpdat.lnx_voxelgi_step * 1000) / 1000) + """;
@ -1042,9 +1048,6 @@ const float voxelgiDiff = """ + str(round(rpdat.lnx_voxelgi_diff * 100) / 100) +
const float voxelgiRefl = """ + str(round(rpdat.lnx_voxelgi_spec * 100) / 100) + """;
const float voxelgiRefr = """ + str(round(rpdat.lnx_voxelgi_refr * 100) / 100) + """;
""")
if rpdat.rp_sss or '_SSS' in wrd.world_defs:
f.write(f"const float sssWidth = {rpdat.lnx_sss_width / 10.0};\n")
# Skinning
if rpdat.lnx_skin == 'On':
f.write(