forked from LeenkxTeam/LNXSDK
Full BSDF
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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"]
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -22,6 +22,10 @@
|
||||
"name": "cameraProj",
|
||||
"link": "_cameraPlaneProj"
|
||||
},
|
||||
{
|
||||
"name": "screenSize",
|
||||
"link": "_screenSize"
|
||||
},
|
||||
{
|
||||
"name": "PPComp9",
|
||||
"link": "_PPComp9",
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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": [],
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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'])
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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(');')
|
||||
|
||||
@ -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;')
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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(' );')
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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."""
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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(
|
||||
|
||||
Reference in New Issue
Block a user