This commit is contained in:
2026-02-24 11:44:01 -08:00
parent c9839c9be6
commit 1c3c30e6ce
34 changed files with 1629 additions and 1271 deletions

View File

@ -14,7 +14,7 @@ out vec4 fragColor;
vec2 barrelDistortion(vec2 coord, float amt) {
vec2 cc = coord - 0.5;
float dist = dot(cc, cc);
return coord + cc * dist * amt;
return coord - cc * dist * amt;
}
float sat(float value)
{
@ -56,8 +56,6 @@ void main() {
if (CAType == 1) {
float reci_num_iter_f = 1.0 / float(num_iter);
vec2 resolution = vec2(1,1);
vec2 uv = (texCoord.xy/resolution.xy);
vec4 sumcol = vec4(0.0);
vec4 sumw = vec4(0.0);
for (int i=0; i < num_iter; ++i)
@ -65,19 +63,21 @@ void main() {
float t = float(i) * reci_num_iter_f;
vec4 w = spectrum_offset(t);
sumw += w;
sumcol += w * texture(tex, barrelDistortion(uv, 0.6 * max_distort * t));
vec2 distortedUV = barrelDistortion(texCoord, 0.6 * max_distort * t);
sumcol += w * texture(tex, distortedUV);
}
if (on == 1) fragColor = sumcol / sumw; else fragColor = texture(tex, texCoord);
}
// Simple
// inward sampling to avoid edge artifacts
else {
vec3 col = vec3(0.0);
col.x = texture(tex, texCoord + ((vec2(0.0, 1.0) * max_distort) / vec2(1000.0))).x;
col.y = texture(tex, texCoord + ((vec2(-0.85, -0.5) * max_distort) / vec2(1000.0))).y;
col.z = texture(tex, texCoord + ((vec2(0.85, -0.5) * max_distort) / vec2(1000.0))).z;
if (on == 1) fragColor = vec4(col.x, col.y, col.z, fragColor.w);
vec2 toCenter = (vec2(0.5) - texCoord) * max_distort / 500.0;
col.x = texture(tex, texCoord + toCenter * 0.0).x;
col.y = texture(tex, texCoord + toCenter * 0.5).y;
col.z = texture(tex, texCoord + toCenter * 1.0).z;
if (on == 1) fragColor = vec4(col.x, col.y, col.z, 1.0);
else fragColor = texture(tex, texCoord);
}
}

View File

@ -357,6 +357,12 @@ void main() {
#else
fragColor = textureLod(tex, texCo, 0.0);
#endif
// TODO: re-investigate white artifacts
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);
}
#endif

View File

@ -57,10 +57,10 @@ uniform vec3 backgroundCol;
#ifdef _SSAO
uniform sampler2D ssaotex;
#else
#ifdef _SSGI
uniform sampler2D ssaotex;
#endif
#ifdef _SSGI
uniform sampler2D ssgitex;
#endif
#ifdef _SSS
@ -102,8 +102,23 @@ uniform mat4 invVP;
#endif
uniform vec2 cameraProj;
#ifdef _VRStereo
uniform vec3 eye; // center camera position
uniform vec3 eyeLook; // center camera look
uniform vec3 eyeLeft;
uniform vec3 eyeRight;
uniform vec3 eyeLookLeft;
uniform vec3 eyeLookRight;
uniform mat4 invVPLeft;
uniform mat4 invVPRight;
#ifdef _SinglePoint
uniform vec3 pointPosLeft;
uniform vec3 pointPosRight;
#endif
#else
uniform vec3 eye;
uniform vec3 eyeLook;
#endif
#ifdef _Clusters
uniform vec4 lightsArray[maxLights * 3];
@ -200,7 +215,9 @@ uniform vec3 sunCol;
#endif
#ifdef _SinglePoint // Fast path for single light
#ifndef _VRStereo
uniform vec3 pointPos;
#endif
uniform vec3 pointCol;
#ifdef _ShadowMap
uniform float pointBias;
@ -225,6 +242,8 @@ out vec4 fragColor;
void main() {
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, roughness, metallic/matid
vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
vec3 n;
n.z = 1.0 - abs(g0.x) - abs(g0.y);
@ -236,14 +255,28 @@ void main() {
uint matid;
unpackFloatInt16(g0.a, metallic, matid);
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);
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
// re-investigate clamp basecolor to prevent extreme values causing glitches
vec3 basecolor = min(g1.rgb, vec3(2.0));
vec3 albedo = surfaceAlbedo(basecolor, metallic);
vec3 f0 = surfaceF0(basecolor, metallic);
#ifdef _VRStereo
bool isLeftEye = texCoord.x < 0.5;
vec3 eyePos = isLeftEye ? eyeLeft : eyeRight;
mat4 invVP_eye = isLeftEye ? invVPLeft : invVPRight;
vec2 eyeTexCoord = vec2(
isLeftEye ? texCoord.x * 2.0 : (texCoord.x - 0.5) * 2.0,
texCoord.y
);
vec3 p = getPos2(invVP_eye, depth, eyeTexCoord);
vec3 v = normalize(eyePos - p);
#else
vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
vec3 v = normalize(eye - p);
#endif
float dotNV = max(dot(n, v), 0.0);
#ifdef _gbuffer2
@ -287,6 +320,7 @@ void main() {
vec3 reflectionWorld = reflect(-v, n);
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
prefilteredColor = min(prefilteredColor, vec3(20.0));
#endif
#ifdef _EnvLDR
@ -340,15 +374,12 @@ void main() {
// fragColor.rgb = texture(ssaotex, texCoord).rrr;
#ifdef _SSAO
// #ifdef _RTGI
// fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).rgb;
// #else
fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r;
// #endif
#else
#ifdef _SSGI
fragColor.rgb += textureLod(ssaotex, texCoord, 0.0).rgb;
#endif
#ifdef _SSGI
vec3 ssgiColor = textureLod(ssgitex, texCoord, 0.0).rgb;
fragColor.rgb += ssgiColor * albedo;
#endif
#ifdef _EmissionShadeless
@ -381,62 +412,62 @@ void main() {
#ifdef _ShadowMap
#ifdef _CSM
svisibility = shadowTestCascade(
#ifdef _ShadowMapAtlas
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasSun, shadowMapAtlasSunTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSun
#else
shadowMapAtlas
#endif
#endif
#else
#ifdef _ShadowMapTransparent
shadowMap, shadowMapTransparent
#else
shadowMap
#endif
#endif
, eye, p + n * shadowsBias * 10, shadowsBias
#ifdef _ShadowMapTransparent
, false
#endif
);
#ifdef _ShadowMapAtlas
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasSun, shadowMapAtlasSunTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSun
#else
shadowMapAtlas
#endif
#endif
#else
#ifdef _ShadowMapTransparent
shadowMap, shadowMapTransparent
#else
shadowMap
#endif
#endif
, eye, p + n * shadowsBias * 2, shadowsBias
#ifdef _ShadowMapTransparent
, false
#endif
);
#else
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 2, 1.0);
if (lPos.w > 0.0) {
svisibility = shadowTest(
#ifdef _ShadowMapAtlas
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasSun, shadowMapAtlasSunTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSun
#else
shadowMapAtlas
#endif
#endif
#else
#ifdef _ShadowMapTransparent
shadowMap, shadowMapTransparent
#else
shadowMap
#endif
#endif
, lPos.xyz / lPos.w, shadowsBias
#ifdef _ShadowMapTransparent
, false
#endif
);
#ifdef _ShadowMapAtlas
#ifdef _ShadowMapTransparent
#ifndef _SingleAtlas
shadowMapAtlasSun, shadowMapAtlasSunTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
#ifndef _SingleAtlas
shadowMapAtlasSun
#else
shadowMapAtlas
#endif
#endif
#else
#ifdef _ShadowMapTransparent
shadowMap, shadowMapTransparent
#else
shadowMap
#endif
#endif
, lPos.xyz / lPos.w, shadowsBias
#ifdef _ShadowMapTransparent
, false
#endif
);
}
#endif
#endif
@ -498,8 +529,14 @@ void main() {
#ifdef _SinglePoint
#ifdef _VRStereo
vec3 lightPos = pointPosLeft;
#else
vec3 lightPos = pointPos;
#endif
fragColor.rgb += sampleLight(
p, n, v, dotNV, pointPos, pointCol, albedo, roughness, occspec.y, f0
p, n, v, dotNV, lightPos, pointCol, albedo, roughness, occspec.y, f0
#ifdef _ShadowMap
, 0, pointBias, true
#ifdef _ShadowMapTransparent
@ -522,7 +559,9 @@ void main() {
#ifdef _Spot
#ifdef _SSS
if (matid == 2) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot[0], p, n, normalize(pointPos - p), lightPlane.y, shadowMapSpot[0]);//TODO implement transparent shadowmaps into the SSSSTransmittance()
#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()
#endif
#endif
#endif
@ -582,5 +621,11 @@ void main() {
);
}
#endif // _Clusters
fragColor.rgb = clamp(fragColor.rgb, vec3(0.0), vec3(65504.0));
if (any(isnan(fragColor.rgb)) || any(isinf(fragColor.rgb))) {
fragColor.rgb = vec3(0.0);
}
fragColor.a = 1.0; // Mark as opaque
}

View File

@ -20,6 +20,36 @@
"name": "eyeLook",
"link": "_cameraLook"
},
{
"name": "eyeLeft",
"link": "_eyeLeft",
"ifdef": ["_VRStereo"]
},
{
"name": "eyeRight",
"link": "_eyeRight",
"ifdef": ["_VRStereo"]
},
{
"name": "eyeLookLeft",
"link": "_eyeLookLeft",
"ifdef": ["_VRStereo"]
},
{
"name": "eyeLookRight",
"link": "_eyeLookRight",
"ifdef": ["_VRStereo"]
},
{
"name": "invVPLeft",
"link": "_inverseViewProjectionMatrixLeft",
"ifdef": ["_VRStereo"]
},
{
"name": "invVPRight",
"link": "_inverseViewProjectionMatrixRight",
"ifdef": ["_VRStereo"]
},
{
"name": "clipmaps",
"link": "_clipmaps",
@ -176,8 +206,19 @@
{
"name": "pointPos",
"link": "_pointPosition",
"ifndef": ["_VRStereo"],
"ifdef": ["_SinglePoint"]
},
{
"name": "pointPosLeft",
"link": "_pointPositionLeft",
"ifdef": ["_VRStereo", "_SinglePoint"]
},
{
"name": "pointPosRight",
"link": "_pointPositionRight",
"ifdef": ["_VRStereo", "_SinglePoint"]
},
{
"name": "pointCol",
"link": "_pointColor",

View File

@ -97,6 +97,31 @@
"link": "_cascadeData",
"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
},
{
"name": "eyeLookRight",
"link": "_eyeLookRight",
"ifdef": ["_VRStereo"]
},
{
"name": "invVPLeft",
"link": "_inverseViewProjectionMatrixLeft",
"ifdef": ["_VRStereo"]
},
{
"name": "invVPRight",
"link": "_inverseViewProjectionMatrixRight",
"ifdef": ["_VRStereo"]
},
{
"name": "invVP",
"link": "_viewProjectionMatrix",
"ifdef": ["_SSRS"]
},
{
"name": "smSizeUniform",
"link": "_shadowMapSize",
"ifdef": ["_SMSizeUniform"]
},
{
"name": "lightPlane",
"link": "_lightPlane",
@ -108,8 +133,6 @@
"ifdef": ["_SSRS"]
},
{
"name": "smSizeUniform",
"link": "_shadowMapSize",
"ifdef": ["_SMSizeUniform"]
},
{
@ -120,8 +143,19 @@
{
"name": "pointPos",
"link": "_pointPosition",
"ifndef": ["_VRStereo"],
"ifdef": ["_SinglePoint"]
},
{
"name": "pointPosLeft",
"link": "_pointPositionLeft",
"ifdef": ["_VRStereo", "_SinglePoint"]
},
{
"name": "pointPosRight",
"link": "_pointPositionRight",
"ifdef": ["_VRStereo", "_SinglePoint"]
},
{
"name": "pointCol",
"link": "_pointColor",

View File

@ -0,0 +1,9 @@
https://gpuopen.com/manuals/fidelityfx_sdk/license/
Copyright © 2024 Advanced Micro Devices, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and /or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,157 @@
#version 450
// AMD FidelityFX Super Resolution 1.0.2 - EASU (Edge Adaptive Spatial Upsampling)
#include "compiled.inc"
uniform sampler2D tex;
uniform vec2 screenSize;
in vec2 texCoord;
out vec4 fragColor;
// Helper functions from AMD ffx_a.h
float APrxLoRcpF1(float a) {
return uintBitsToFloat(uint(0x7ef07ebb) - floatBitsToUint(a));
}
float AMax3F1(float x, float y, float z) {
return max(x, max(y, z));
}
float AMin3F1(float x, float y, float z) {
return min(x, min(y, z));
}
// Attempt to use textureGather for efficiency when available
#if __VERSION__ >= 400
void FsrEasuTap(
inout vec3 aC,
inout float aW,
vec2 off,
vec2 dir,
vec2 len,
float lob,
float clp,
vec3 c
) {
vec2 v = off * dir;
float d2 = v.x + v.y;
d2 = clamp(d2 * APrxLoRcpF1(max(abs(v.x), abs(v.y))), 0.0, 1.0);
d2 = d2 * d2;
d2 = d2 * len.x + len.y;
float wB = 2.0 / 5.0 * d2 - 1.0;
float wA = lob * d2 - 1.0;
wB *= wB;
wA *= wA;
float w = 25.0 / 16.0 * wA * wB;
w = min(w, clp);
w = max(w, 0.0);
aC += c * w;
aW += w;
}
vec3 FsrEasuF(vec2 ip) {
vec2 inputSize = textureSize(tex, 0);
vec2 inputRcp = 1.0 / inputSize;
// Position in input pixels
vec2 pp = ip * inputSize - 0.5;
vec2 fp = floor(pp);
pp -= fp;
// 12-tap kernel
// b c
// e f g h
// i j k l
// n o
ivec2 sp = ivec2(fp);
vec3 b = texelFetch(tex, sp + ivec2(0, -1), 0).rgb;
vec3 c = texelFetch(tex, sp + ivec2(1, -1), 0).rgb;
vec3 e = texelFetch(tex, sp + ivec2(-1, 0), 0).rgb;
vec3 f = texelFetch(tex, sp + ivec2(0, 0), 0).rgb;
vec3 g = texelFetch(tex, sp + ivec2(1, 0), 0).rgb;
vec3 h = texelFetch(tex, sp + ivec2(2, 0), 0).rgb;
vec3 i = texelFetch(tex, sp + ivec2(-1, 1), 0).rgb;
vec3 j = texelFetch(tex, sp + ivec2(0, 1), 0).rgb;
vec3 k = texelFetch(tex, sp + ivec2(1, 1), 0).rgb;
vec3 l = texelFetch(tex, sp + ivec2(2, 1), 0).rgb;
vec3 n = texelFetch(tex, sp + ivec2(0, 2), 0).rgb;
vec3 o = texelFetch(tex, sp + ivec2(1, 2), 0).rgb;
// Luma for edge detection (using green channel approximation)
float bL = b.g + 0.5 * (b.r + b.b);
float cL = c.g + 0.5 * (c.r + c.b);
float eL = e.g + 0.5 * (e.r + e.b);
float fL = f.g + 0.5 * (f.r + f.b);
float gL = g.g + 0.5 * (g.r + g.b);
float hL = h.g + 0.5 * (h.r + h.b);
float iL = i.g + 0.5 * (i.r + i.b);
float jL = j.g + 0.5 * (j.r + j.b);
float kL = k.g + 0.5 * (k.r + k.b);
float lL = l.g + 0.5 * (l.r + l.b);
float nL = n.g + 0.5 * (n.r + n.b);
float oL = o.g + 0.5 * (o.r + o.b);
// Gradient detection
float dirX = (cL - bL) + (gL - fL) + (kL - jL) + (oL - nL);
float dirY = (eL - iL) + (fL - jL) + (gL - kL) + (hL - lL);
// Normalize direction
float dirR = APrxLoRcpF1(max(abs(dirX), abs(dirY)));
dirX *= dirR;
dirY *= dirR;
// Calculate stretch based on edge direction
float len = length(vec2(dirX, dirY));
len = len * 0.5;
len *= len;
float stretch = (dirX * dirX + dirY * dirY) * APrxLoRcpF1(max(abs(dirX), abs(dirY)));
vec2 len2 = vec2(1.0 + (stretch - 1.0) * len, 1.0 - 0.5 * len);
float lob = 0.5 + (0.25 - 0.04 - 0.5) * len;
float clp = APrxLoRcpF1(lob);
// Accumulate samples
vec3 aC = vec3(0.0);
float aW = 0.0;
vec2 dir = vec2(dirX, dirY);
FsrEasuTap(aC, aW, vec2(0.0, -1.0) - pp, dir, len2, lob, clp, b);
FsrEasuTap(aC, aW, vec2(1.0, -1.0) - pp, dir, len2, lob, clp, c);
FsrEasuTap(aC, aW, vec2(-1.0, 0.0) - pp, dir, len2, lob, clp, e);
FsrEasuTap(aC, aW, vec2(0.0, 0.0) - pp, dir, len2, lob, clp, f);
FsrEasuTap(aC, aW, vec2(1.0, 0.0) - pp, dir, len2, lob, clp, g);
FsrEasuTap(aC, aW, vec2(2.0, 0.0) - pp, dir, len2, lob, clp, h);
FsrEasuTap(aC, aW, vec2(-1.0, 1.0) - pp, dir, len2, lob, clp, i);
FsrEasuTap(aC, aW, vec2(0.0, 1.0) - pp, dir, len2, lob, clp, j);
FsrEasuTap(aC, aW, vec2(1.0, 1.0) - pp, dir, len2, lob, clp, k);
FsrEasuTap(aC, aW, vec2(2.0, 1.0) - pp, dir, len2, lob, clp, l);
FsrEasuTap(aC, aW, vec2(0.0, 2.0) - pp, dir, len2, lob, clp, n);
FsrEasuTap(aC, aW, vec2(1.0, 2.0) - pp, dir, len2, lob, clp, o);
// Normalize
vec3 pix = aC / aW;
// Clamp to neighborhood min/max to prevent ringing
vec3 mn = min(min(min(f, g), j), k);
vec3 mx = max(max(max(f, g), j), k);
pix = clamp(pix, mn, mx);
return pix;
}
#else
// Fallback for older GLSL - simple bilinear
vec3 FsrEasuF(vec2 ip) {
return texture(tex, ip).rgb;
}
#endif
void main() {
vec3 col = FsrEasuF(texCoord);
fragColor = vec4(col, 1.0);
}

View File

@ -0,0 +1,19 @@
{
"contexts": [
{
"name": "fsr1_easu_pass",
"depth_write": false,
"compare_mode": "always",
"cull_mode": "none",
"links": [
{
"name": "screenSize",
"link": "_screenSize"
}
],
"texture_params": [],
"vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "fsr1_easu_pass.frag.glsl"
}
]
}

View File

@ -0,0 +1,9 @@
https://gpuopen.com/manuals/fidelityfx_sdk/license/
Copyright © 2024 Advanced Micro Devices, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and /or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,116 @@
#version 450
// AMD FidelityFX Super Resolution 1.0.2 - RCAS (Robust Contrast Adaptive Sharpening)
#include "compiled.inc"
uniform sampler2D tex;
// Sharpness in "stops": 0.0 = maximum sharpness, higher = less sharp
// Converted to linear via exp2(-sharpness)
#ifdef _FSR1_Ultra_Quality
const float SHARPNESS_STOPS = 0.0;
#elif defined(_FSR1_Balanced)
const float SHARPNESS_STOPS = 1.0;
#elif defined(_FSR1_Performance)
const float SHARPNESS_STOPS = 2.0;
#elif defined(_FSR1_Custom)
uniform vec4 PPComp15;
#define SHARPNESS_STOPS (PPComp15.x * 2.0)
#else
const float SHARPNESS_STOPS = 0.5; // Quality (default)
#endif
// FSR RCAS limit - prevents unnatural sharpening artifacts
#define FSR_RCAS_LIMIT (0.25 - (1.0 / 16.0))
in vec2 texCoord;
out vec4 fragColor;
// AMD helper functions from ffx_a.h
float AMin3F1(float x, float y, float z) { return min(x, min(y, z)); }
float AMax3F1(float x, float y, float z) { return max(x, max(y, z)); }
// High precision reciprocal (required for limiters per AMD docs)
// Added epsilon to prevent division by zero in dark areas
float ARcpF1(float a) {
return 1.0 / max(a, 1e-8);
}
// Medium precision reciprocal approximation (from AMD ffx_a.h)
// Only used for noise detection and final resolve
float APrxMedRcpF1(float a) {
return uintBitsToFloat(uint(0x7ef19fff) - floatBitsToUint(a));
}
void main() {
// Get texture size and texel offset
vec2 texSize = vec2(textureSize(tex, 0));
vec2 texelSize = 1.0 / texSize;
// Algorithm uses minimal 3x3 pixel neighborhood
// b
// d e f
// h
// Clamp inputs to [0,1] - FSR expects sRGB normalized input
vec3 b = clamp(texture(tex, texCoord + vec2(0.0, -texelSize.y)).rgb, 0.0, 1.0);
vec3 d = clamp(texture(tex, texCoord + vec2(-texelSize.x, 0.0)).rgb, 0.0, 1.0);
vec4 ee = texture(tex, texCoord);
vec3 e = clamp(ee.rgb, 0.0, 1.0);
vec3 f = clamp(texture(tex, texCoord + vec2(texelSize.x, 0.0)).rgb, 0.0, 1.0);
vec3 h = clamp(texture(tex, texCoord + vec2(0.0, texelSize.y)).rgb, 0.0, 1.0);
// Luma times 2 (AMD's luma calculation: B*0.5 + R*0.5 + G)
float bL = b.b * 0.5 + (b.r * 0.5 + b.g);
float dL = d.b * 0.5 + (d.r * 0.5 + d.g);
float eL = e.b * 0.5 + (e.r * 0.5 + e.g);
float fL = f.b * 0.5 + (f.r * 0.5 + f.g);
float hL = h.b * 0.5 + (h.r * 0.5 + h.g);
// Noise detection (official AMD algorithm with safety for flat areas)
float nz = 0.25 * bL + 0.25 * dL + 0.25 * fL + 0.25 * hL - eL;
float range = AMax3F1(AMax3F1(bL, dL, eL), fL, hL) - AMin3F1(AMin3F1(bL, dL, eL), fL, hL);
// Use safe division instead of APrxMedRcpF1 for range to avoid NaN in flat areas
nz = clamp(abs(nz) / max(range, 1e-5), 0.0, 1.0);
nz = -0.5 * nz + 1.0;
// Min and max of ring (per channel)
float mn4R = min(AMin3F1(b.r, d.r, f.r), h.r);
float mn4G = min(AMin3F1(b.g, d.g, f.g), h.g);
float mn4B = min(AMin3F1(b.b, d.b, f.b), h.b);
float mx4R = max(AMax3F1(b.r, d.r, f.r), h.r);
float mx4G = max(AMax3F1(b.g, d.g, f.g), h.g);
float mx4B = max(AMax3F1(b.b, d.b, f.b), h.b);
// Immediate constants for peak range
vec2 peakC = vec2(1.0, -4.0);
// Limiters - these need HIGH PRECISION reciprocals (per AMD docs)
float hitMinR = min(mn4R, e.r) * ARcpF1(4.0 * mx4R);
float hitMinG = min(mn4G, e.g) * ARcpF1(4.0 * mx4G);
float hitMinB = min(mn4B, e.b) * ARcpF1(4.0 * mx4B);
float hitMaxR = (peakC.x - max(mx4R, e.r)) * ARcpF1(4.0 * mn4R + peakC.y);
float hitMaxG = (peakC.x - max(mx4G, e.g)) * ARcpF1(4.0 * mn4G + peakC.y);
float hitMaxB = (peakC.x - max(mx4B, e.b)) * ARcpF1(4.0 * mn4B + peakC.y);
float lobeR = max(-hitMinR, hitMaxR);
float lobeG = max(-hitMinG, hitMaxG);
float lobeB = max(-hitMinB, hitMaxB);
// Apply sharpness (convert from stops to linear)
float sharpness = exp2(-SHARPNESS_STOPS);
float lobe = max(-FSR_RCAS_LIMIT, min(AMax3F1(lobeR, lobeG, lobeB), 0.0)) * sharpness;
// Apply noise removal
lobe *= nz;
// Resolve using safe reciprocal to avoid any edge case issues
float denom = 4.0 * lobe + 1.0;
float rcpL = 1.0 / max(denom, 0.25); // denom should be in [0.25, 1.0] range
vec3 pix;
pix.r = (lobe * b.r + lobe * d.r + lobe * h.r + lobe * f.r + e.r) * rcpL;
pix.g = (lobe * b.g + lobe * d.g + lobe * h.g + lobe * f.g + e.g) * rcpL;
pix.b = (lobe * b.b + lobe * d.b + lobe * h.b + lobe * f.b + e.b) * rcpL;
// Ensure output is clamped to valid range
fragColor = vec4(clamp(pix, 0.0, 1.0), ee.a);
}

View File

@ -0,0 +1,24 @@
{
"contexts": [
{
"name": "fsr1_rcas_pass",
"depth_write": false,
"compare_mode": "always",
"cull_mode": "none",
"links": [
{
"name": "screenSize",
"link": "_screenSize"
},
{
"name": "PPComp15",
"link": "_PPComp15",
"ifdef": ["_FSR1_Custom"]
}
],
"texture_params": [],
"vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "fsr1_rcas_pass.frag.glsl"
}
]
}

View File

@ -8,6 +8,7 @@ uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
uniform mat4 invVP;
uniform mat4 invW;
uniform vec3 probep;
uniform vec3 eye;
@ -25,19 +26,27 @@ void main() {
float roughness = g0.b;
if (roughness > 0.95) {
fragColor.rgb = vec3(0.0);
fragColor = vec4(0.0);
return;
}
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
if (spec == 0.0) {
fragColor.rgb = vec3(0.0);
fragColor = vec4(0.0);
return;
}
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
vec3 wp = getPos2(invVP, depth, texCoord);
vec3 localPos = (invW * vec4(wp, 1.0)).xyz;
// return if surface is inside probe volume bounds
if (abs(localPos.x) > 1.0 || abs(localPos.y) > 1.0 || abs(localPos.z) > 1.0) {
fragColor = vec4(0.0);
return;
}
vec2 enc = g0.rg;
vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y);
@ -50,5 +59,5 @@ void main() {
r.y = -r.y;
#endif
float intensity = clamp((1.0 - roughness) * dot(wp - probep, n), 0.0, 1.0);
fragColor.rgb = texture(probeTex, r).rgb * intensity;
fragColor = vec4(texture(probeTex, r).rgb * intensity, 1.0);
}

View File

@ -20,6 +20,10 @@
"name": "invVP",
"link": "_inverseViewProjectionMatrix"
},
{
"name": "invW",
"link": "_inverseWorldMatrix"
},
{
"name": "probep",
"link": "_probePosition"

View File

@ -25,13 +25,13 @@ void main() {
float roughness = g0.b;
if (roughness > 0.95) {
fragColor.rgb = vec3(0.0);
fragColor = vec4(0.0);
return;
}
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
if (spec == 0.0) {
fragColor.rgb = vec3(0.0);
fragColor = vec4(0.0);
return;
}
@ -50,5 +50,5 @@ void main() {
n = normalize(n);
float intensity = clamp((1.0 - roughness) * dot(n, proben), 0.0, 1.0);
fragColor.rgb = texture(probeTex, tc).rgb * intensity;
fragColor = vec4(texture(probeTex, tc).rgb * intensity, 1.0);
}

View File

@ -5,42 +5,56 @@
uniform sampler2D tex;
uniform sampler2D gbuffer0;
uniform sampler2D gbufferD;
uniform vec2 dirInv; // texStep
in vec2 texCoord;
out float fragColor;
out vec3 fragColor;
const float blurWeights[5] = float[] (0.227027, 0.1945946, 0.1216216, 0.054054, 0.016216);
// const float blurWeights[10] = float[] (0.132572, 0.125472, 0.106373, 0.08078, 0.05495, 0.033482, 0.018275, 0.008934, 0.003912, 0.001535);
const float discardThreshold = 0.95;
float doBlur(const float blurWeight, const int pos, const vec3 nor, const vec2 texCoord) {
const float posadd = pos + 0.5;
vec3 nor2 = getNor(textureLod(gbuffer0, texCoord + pos * dirInv, 0.0).rg);
float influenceFactor = step(discardThreshold, dot(nor2, nor));
float col = textureLod(tex, texCoord + posadd * dirInv, 0.0).r;
fragColor += col * blurWeight * influenceFactor;
float weight = blurWeight * influenceFactor;
nor2 = getNor(textureLod(gbuffer0, texCoord - pos * dirInv, 0.0).rg);
influenceFactor = step(discardThreshold, dot(nor2, nor));
col = textureLod(tex, texCoord - posadd * dirInv, 0.0).r;
fragColor += col * blurWeight * influenceFactor;
weight += blurWeight * influenceFactor;
return weight;
}
const int KERNEL_SIZE = 13;
const float blurWeights[13] = float[](0.1, 0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.025, 0.02, 0.015, 0.01, 0.005);
void main() {
vec3 nor = getNor(textureLod(gbuffer0, texCoord, 0.0).rg);
vec3 centerNor = getNor(textureLod(gbuffer0, texCoord, 0.0).rg);
float centerDepth = textureLod(gbufferD, texCoord, 0.0).r;
fragColor = textureLod(tex, texCoord, 0.0).r * blurWeights[0];
float weight = blurWeights[0];
for (int i = 1; i < 5; i++) {
weight += doBlur(blurWeights[i], i, nor, texCoord);
// skip sky pixels
if (centerDepth == 1.0) {
fragColor = vec3(0.0);
return;
}
fragColor = textureLod(tex, texCoord, 0.0).rgb * blurWeights[0];
float totalWeight = blurWeights[0];
for (int i = 1; i < KERNEL_SIZE; i++) {
vec2 offset = float(i) * dirInv;
vec2 uvPos = texCoord + offset;
vec3 norPos = getNor(textureLod(gbuffer0, uvPos, 0.0).rg);
float depthPos = textureLod(gbufferD, uvPos, 0.0).r;
float normalWeight = max(0.0, dot(norPos, centerNor));
normalWeight = pow(normalWeight, 8.0); // Softer normal falloff for better blending
float depthWeight = 1.0 - smoothstep(0.0, 0.02, abs(depthPos - centerDepth));
float w = blurWeights[i] * normalWeight * depthWeight;
fragColor += textureLod(tex, uvPos, 0.0).rgb * w;
totalWeight += w;
vec2 uvNeg = texCoord - offset;
vec3 norNeg = getNor(textureLod(gbuffer0, uvNeg, 0.0).rg);
float depthNeg = textureLod(gbufferD, uvNeg, 0.0).r;
normalWeight = max(0.0, dot(norNeg, centerNor));
normalWeight = pow(normalWeight, 8.0);
depthWeight = 1.0 - smoothstep(0.0, 0.02, abs(depthNeg - centerDepth));
w = blurWeights[i] * normalWeight * depthWeight;
fragColor += textureLod(tex, uvNeg, 0.0).rgb * w;
totalWeight += w;
}
fragColor = fragColor / weight;
fragColor /= totalWeight;
}

View File

@ -1,25 +1,8 @@
#version 450
#include "compiled.inc"
#include "std/gbuffer.glsl"
#include "std/brdf.glsl"
#include "std/math.glsl"
#ifdef _Clusters
#include "std/clusters.glsl"
#endif
#ifdef _ShadowMap
#include "std/shadows.glsl"
#endif
#ifdef _LTC
#include "std/ltc.glsl"
#endif
#ifdef _LightIES
#include "std/ies.glsl"
#endif
#ifdef _Spot
#include "std/light_common.glsl"
#endif
#include "std/constants.glsl"
#include "std/gbuffer.glsl"
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
@ -27,480 +10,179 @@ uniform sampler2D gbufferD;
#ifdef _EmissionShaded
uniform sampler2D gbufferEmission;
#endif
uniform sampler2D sveloc;
uniform vec2 cameraProj;
uniform vec3 eye;
uniform vec3 eyeLook;
uniform vec2 screenSize;
uniform mat4 invVP;
in vec2 texCoord;
in vec3 viewRay;
out vec3 fragColor;
float metallic;
uint matid;
#ifdef _SMSizeUniform
//!uniform vec2 smSizeUniform;
#endif
#ifdef _Clusters
uniform vec4 lightsArray[maxLights * 3];
#ifdef _Spot
uniform vec4 lightsArraySpot[maxLights * 2];
#endif
uniform sampler2D clustersData;
uniform vec2 cameraPlane;
#endif
#ifdef _SinglePoint // Fast path for single light
uniform vec3 pointPos;
uniform vec3 pointCol;
#ifdef _ShadowMap
uniform float pointBias;
#endif
#ifdef _Spot
uniform vec3 spotDir;
uniform vec3 spotRight;
uniform vec4 spotData;
#endif
#endif
#ifdef _CPostprocess
uniform vec3 PPComp12;
#endif
#ifdef _ShadowMap
#ifdef _SinglePoint
#ifdef _Spot
#ifndef _LTC
uniform sampler2DShadow shadowMapSpot[1];
uniform sampler2D shadowMapSpotTransparent[1];
uniform mat4 LWVPSpot[1];
#endif
#else
uniform samplerCubeShadow shadowMapPoint[1];
uniform samplerCube shadowMapPointTransparent[1];
uniform vec2 lightProj;
#endif
#endif
#ifdef _Clusters
#ifdef _SingleAtlas
uniform sampler2DShadow shadowMapAtlas;
uniform sampler2D shadowMapAtlasTransparent;
#endif
uniform vec2 lightProj;
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasPoint;
uniform sampler2D shadowMapAtlasPointTransparent;
//!uniform vec4 pointLightDataArray[maxLightsCluster * 6];
#else
uniform samplerCubeShadow shadowMapPoint[4];
uniform samplerCube shadowMapPointTransparent[4];
#endif
#endif
#ifdef _Spot
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasSpot;
uniform sampler2D shadowMapAtlasSpotTransparent;
#endif
#else
uniform sampler2DShadow shadowMapSpot[4];
uniform sampler2D shadowMapSpotTransparent[4];
#endif
uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif
#endif
#endif
#ifdef _LTC
uniform vec3 lightArea0;
uniform vec3 lightArea1;
uniform vec3 lightArea2;
uniform vec3 lightArea3;
uniform sampler2D sltcMat;
uniform sampler2D sltcMag;
#ifdef _ShadowMap
#ifndef _Spot
#ifdef _SinglePoint
uniform sampler2DShadow shadowMapSpot[1];
uniform sampler2D shadowMapSpotTransparent[1];
uniform mat4 LWVPSpot[1];
#endif
#ifdef _Clusters
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
uniform mat4 LWVPSpotArray[maxLightsCluster];
#endif
#endif
#endif
#endif
uniform mat4 P;
uniform mat4 invP;
uniform mat3 V3;
#ifdef _Sun
uniform vec3 sunDir;
uniform vec3 sunCol;
#ifdef _ShadowMap
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
uniform sampler2DShadow shadowMapAtlasSun;
uniform sampler2D shadowMapAtlasSunTransparent;
#endif
#else
uniform sampler2DShadow shadowMap;
uniform sampler2D shadowMapTransparent;
#endif
uniform float shadowsBias;
#ifdef _CSM
//!uniform vec4 casData[shadowmapCascades * 4 + 4];
#else
uniform mat4 LWVP;
#endif
#endif // _ShadowMap
#endif
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 lp, const vec3 lightCol
#ifdef _ShadowMap
, int index, float bias, bool receiveShadow, bool transparent
#endif
#ifdef _Spot
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
#endif
) {
vec3 ld = lp - p;
vec3 l = normalize(ld);
vec3 visibility = lightCol;
visibility *= attenuate(distance(p, lp));
#ifdef _LTC
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
visibility *= shadowTest(shadowMapSpot[0],
shadowMapSpotTransparent[0],
lPos.xyz / lPos.w, bias, transparent);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
if (index == 0) visibility *= shadowTest(shadowMapSpot[0],
shadowMapSpotTransparent[0],
lPos.xyz / lPos.w, bias, transparent);
else if (index == 1) visibility *= shadowTest(shadowMapSpot[1],
shadowMapSpotTransparent[1],
, lPos.xyz / lPos.w, bias, transparent);
else if (index == 2) visibility *= shadowTest(shadowMapSpot[2],
shadowMapSpotTransparent[2],
lPos.xyz / lPos.w, bias, transparent);
else if (index == 3) visibility *= shadowTest(shadowMapSpot[3],
shadowMapSpotTransparent[3],
lPos.xyz / lPos.w, bias, transparent);
#endif
}
#endif
return visibility;
#endif
#ifdef _Spot
if (isSpot) {
visibility *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
visibility *= shadowTest(shadowMapSpot[0],
shadowMapSpotTransparent[0],
lPos.xyz / lPos.w, bias, transparent);
#endif
#ifdef _Clusters
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
#ifdef _ShadowMapAtlas
visibility *= shadowTest(
#ifndef _SingleAtlas
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
, lPos.xyz / lPos.w, bias, transparent
);
#else
if (index == 0) visibility *= shadowTest(shadowMapSpot[0],
shadowMapSpotTransparent[0],
lPos.xyz / lPos.w, bias, transparent);
else if (index == 1) visibility *= shadowTest(shadowMapSpot[1],
shadowMapSpotTransparent[1],
lPos.xyz / lPos.w, bias, transparent);
else if (index == 2) visibility *= shadowTest(shadowMapSpot[2],
shadowMapSpotTransparent[2],
lPos.xyz / lPos.w, bias, transparent);
else if (index == 3) visibility *= shadowTest(shadowMapSpot[3],
shadowMapSpotTransparent[3],
lPos.xyz / lPos.w, bias, transparent);
#endif
#endif
}
#endif
return visibility;
}
#endif
#ifdef _LightIES
visibility *= iesAttenuation(-l);
#endif
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
#ifndef _Spot
visibility *= PCFCube(shadowMapPoint[0],
shadowMapPointTransparent[0],
ld, -l, bias, lightProj, n, transparent);
#endif
#endif
#ifdef _Clusters
#ifdef _ShadowMapAtlas
visibility *= PCFFakeCube(
#ifndef _SingleAtlas
shadowMapAtlasPoint, shadowMapAtlasPointTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
, ld, -l, bias, lightProj, n, index, transparent
);
#else
if (index == 0) visibility *= PCFCube(shadowMapPoint[0],
shadowMapPointTransparent[0],
ld, -l, bias, lightProj, n, transparent);
else if (index == 1) visibility *= PCFCube(shadowMapPoint[1],
shadowMapPointTransparent[1],
ld, -l, bias, lightProj, n, transparent);
else if (index == 2) visibility *= PCFCube(shadowMapPoint[2],
shadowMapPointTransparent[2],
ld, -l, bias, lightProj, n, transparent);
else if (index == 3) visibility *= PCFCube(shadowMapPoint[3],
shadowMapPointTransparent[3],
ld, -l, bias, lightProj, n, transparent);
#endif
#endif
}
#endif
return visibility;
}
vec3 getVisibility(vec3 p, vec3 n, float depth, vec2 uv) {
vec3 visibility = vec3(0.0);
#ifdef _Sun
#ifdef _ShadowMap
#ifdef _CSM
visibility = shadowTestCascade(
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
shadowMapAtlasSun, shadowMapAtlasSunTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
shadowMap, shadowMapTransparent
#endif
, eye, p + n * shadowsBias * 10, shadowsBias, false
);
#else
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
if (lPos.w > 0.0) {
visibility = shadowTest(
#ifdef _ShadowMapAtlas
#ifndef _SingleAtlas
shadowMapAtlasSun, shadowMapAtlasSunTransparent
#else
shadowMapAtlas, shadowMapAtlasTransparent
#endif
#else
shadowMap, shadowMapTransparent
#endif
, lPos.xyz / lPos.w, shadowsBias, false
);
}
#endif
#endif
#ifdef _CPostprocess
uniform vec3 PPComp12;
#endif
#ifdef _SinglePoint
visibility += sampleLight(
p, n, pointPos, pointCol
#ifdef _ShadowMap
, 0, pointBias, true, false
#endif
#ifdef _Spot
, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight
#endif
);
#endif
in vec2 texCoord;
out vec4 fragColor;
#ifdef _Clusters
float viewz = linearize(depth, cameraProj);
int clusterI = getClusterI(uv, viewz, cameraPlane);
int numLights = int(texelFetch(clustersData, ivec2(clusterI, 0), 0).r * 255);
#ifdef HLSL
viewz += textureLod(clustersData, vec2(0.0), 0.0).r * 1e-9; // TODO: krafix bug, needs to generate sampler
#endif
#ifdef _Spot
int numSpots = int(texelFetch(clustersData, ivec2(clusterI, 1 + maxLightsCluster), 0).r * 255);
int numPoints = numLights - numSpots;
#endif
for (int i = 0; i < min(numLights, maxLightsCluster); i++) {
int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255);
visibility += sampleLight(
p,
n,
lightsArray[li * 3].xyz, // lp
lightsArray[li * 3 + 1].xyz // lightCol
#ifdef _ShadowMap
// light index, shadow bias, cast_shadows
, li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0, false
#endif
#ifdef _Spot
, lightsArray[li * 3 + 2].y != 0.0
, lightsArray[li * 3 + 2].y // spot size (cutoff)
, lightsArraySpot[li * 2].w // spot blend (exponent)
, lightsArraySpot[li * 2].xyz // spotDir
, vec2(lightsArray[li * 3].w, lightsArray[li * 3 + 1].w) // scale
, lightsArraySpot[li * 2 + 1].xyz // right
#endif
);
}
#endif // _Clusters
return visibility;
}
vec3 getWorldPos(vec2 uv, float depth) {
vec4 pos = invVP * vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
return pos.xyz / pos.w;
}
vec3 getNormal(vec2 uv) {
vec4 g0 = textureLod(gbuffer0, uv, 0.0);
vec2 enc = g0.rg;
vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y);
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
return normalize(n);
}
vec3 calculateIndirectLight(vec2 uv, vec3 pos, vec3 normal, float depth) {
// Simplified visibility - replace with your full visibility function if needed
vec3 sampleColor = textureLod(gbuffer1, uv, 0.0).rgb * getVisibility(pos, normal, depth, uv);
#ifdef _EmissionShadeless
if (matid == 1) { // pure emissive material, color stored in basecol
sampleColor += textureLod(gbuffer1, uv, 0.0).rgb;
}
#endif
#ifdef _EmissionShaded
#ifdef _EmissionShadeless
else {
#endif
vec3 sampleEmission = textureLod(gbufferEmission, uv, 0.0).rgb;
sampleColor += sampleEmission; // Emission should be added directly
#ifdef _EmissionShadeless
}
#endif
#endif
return sampleColor;
}
// Improved sampling parameters
const float GOLDEN_ANGLE = 2.39996323;
const float MAX_DEPTH_DIFFERENCE = 0.9; // More conservative depth threshold
const float SAMPLE_BIAS = 0.01; // Small offset to avoid self-occlusion
const int RAY_STEPS = 12;
vec2 getProjectedCoord(const vec3 viewPos) {
vec4 projectedCoord = P * vec4(viewPos, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
#ifdef _InvY
projectedCoord.y = 1.0 - projectedCoord.y;
#endif
return projectedCoord.xy;
}
vec3 cosineSampleHemisphere(vec3 n, vec2 rand) {
float phi = PI * 2.0 * rand.x;
float cosTheta = sqrt(1.0 - rand.y);
float sinTheta = sqrt(rand.y);
vec3 h = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
vec3 tangent, bitangent;
vec3 absN = abs(n);
if (absN.x <= absN.y && absN.x <= absN.z) {
tangent = normalize(cross(n, vec3(1.0, 0.0, 0.0)));
} else if (absN.y <= absN.z) {
tangent = normalize(cross(n, vec3(0.0, 1.0, 0.0)));
} else {
tangent = normalize(cross(n, vec3(0.0, 0.0, 1.0)));
}
bitangent = cross(n, tangent);
return normalize(tangent * h.x + bitangent * h.y + n * h.z);
}
vec3 traceRay(vec3 origin, vec3 dir, float maxDist, float minDist) {
float stepSize = maxDist / float(RAY_STEPS);
vec3 pos = origin + dir * minDist;
float prevDepthDiff = 0.0;
float hadValidPrev = 0.0;
for (int i = 1; i <= RAY_STEPS; i++) {
pos += dir * stepSize;
vec2 uv = getProjectedCoord(pos);
vec2 sampleUV = clamp(uv, vec2(0.001), vec2(0.999));
float sampleDepth = textureLod(gbufferD, sampleUV, 0.0).r * 2.0 - 1.0;
if (sampleDepth == 1.0) {
hadValidPrev = 0.0;
continue;
}
vec3 sampleViewPos = getPosView2(invP, sampleDepth, sampleUV);
float depthDiff = pos.z - sampleViewPos.z;
float rayDist = length(pos - origin);
float thickness = 0.15 + rayDist * 0.25;
float crossed = hadValidPrev * step(0.0, prevDepthDiff) * step(depthDiff, 0.0);
float withinThickness = step(abs(depthDiff), thickness);
if (crossed > 0.5 || withinThickness > 0.5) {
float distWeight = 1.0 - (rayDist / maxDist);
distWeight = max(0.0, distWeight * distWeight);
return vec3(sampleUV, distWeight);
}
prevDepthDiff = depthDiff;
hadValidPrev = 1.0;
}
return vec3(-1.0);
}
void main() {
float depth = textureLod(gbufferD, texCoord, 0.0).r;
if (depth >= 1.0) {
fragColor = vec3(0.0);
return;
}
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, roughness, metallic/matid
unpackFloatInt16(g0.a, metallic, matid);
vec2 velocity = -textureLod(sveloc, texCoord, 0.0).rg;
vec3 n;
n.z = 1.0 - abs(g0.x) - abs(g0.y);
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
n = normalize(n);
vec3 pos = getWorldPos(texCoord, depth);
vec3 normal = getNormal(texCoord);
vec3 centerColor = textureLod(gbuffer1, texCoord, 0.0).rgb;
float radius = ssaoRadius;
vec3 gi = vec3(0.0);
float totalWeight = 0.0;
float angle = fract(sin(dot(texCoord, vec2(12.9898, 78.233))) * 100.0);
for (int i = 0; i < ssgiSamples; i++) {
// Use quasi-random sequence for better coverage
float r = sqrt((float(i) + 0.5) / float(ssgiSamples)) * radius;
float a = (float(i) * GOLDEN_ANGLE) + angle;
vec2 offset = vec2(cos(a), sin(a)) * r * radius;
vec2 sampleUV = clamp(texCoord + offset * (BayerMatrix8[int(gl_FragCoord.x + velocity.x) % 8][int(gl_FragCoord.y + velocity.y) % 8] - 0.5) / screenSize, vec2(0.001), vec2(0.999));
float sampleDepth = textureLod(gbufferD, sampleUV, 0.0).r;
if (sampleDepth >= 1.0) continue;
vec3 samplePos = getWorldPos(sampleUV, sampleDepth);
vec3 sampleNormal = getNormal(sampleUV);
// Apply small bias to sample position to avoid self-occlusion
samplePos += sampleNormal * SAMPLE_BIAS;
vec3 dir = pos - samplePos;
float dist = length(dir);
if (abs(pos.z - samplePos.z) > MAX_DEPTH_DIFFERENCE) continue;;
vec3 sampleColor = calculateIndirectLight(sampleUV, samplePos, sampleNormal, sampleDepth);
float weight = 1.0 / (1.0 + dist * dist * 2.0) * max(dot(sampleNormal, n), 0.0);
gi += sampleColor * weight;
totalWeight += weight;
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
if (depth == 1.0) {
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
// Normalize and apply intensity
if (totalWeight > 0.0) {
gi /= totalWeight;
#ifdef _CPostprocess
gi *= PPComp12.x;
#else
gi *= ssaoStrength;
#endif
}
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
vec2 enc = g0.rg;
vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y);
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
n = normalize(n);
#ifdef _EmissionShadeless
if (matid == 1) { // pure emissive material, color stored in basecol
gi += textureLod(gbuffer1, texCoord, 0.0).rgb;
}
vec3 viewNormal = V3 * n;
vec3 viewPos = getPosView2(invP, depth, texCoord);
#ifdef _CPostprocess
float radius = PPComp12.y;
float strength = PPComp12.x;
#else
float radius = ssgiRadius;
float strength = ssgiStrength;
#endif
float noise = fract(52.9829189 * fract(0.06711056 * texCoord.x * 1000.0 + 0.00583715 * texCoord.y * 1000.0));
vec3 gi = vec3(0.0);
int validSamples = 0;
// min distance to avoid self shadowing artiffacts
float minDist = radius * 0.05;
for (int i = 0; i < ssgiSamples; i++) {
float fi = float(i) + noise;
vec2 rand = vec2(
fract(fi * 0.7548776662 + noise),
fract(fi * 0.5698402909 + noise * 1.5)
);
vec3 rayDir = cosineSampleHemisphere(viewNormal, rand);
vec3 hitResult = traceRay(viewPos, rayDir, radius, minDist);
if (hitResult.x < 0.0) continue;
vec2 hitUV = hitResult.xy;
float distWeight = hitResult.z;
vec3 hitAlbedo = textureLod(gbuffer1, hitUV, 1.0).rgb;
#ifdef _Sun
vec4 hitG0 = textureLod(gbuffer0, hitUV, 0.0);
vec2 hitEnc = hitG0.rg;
vec3 hitN;
hitN.z = 1.0 - abs(hitEnc.x) - abs(hitEnc.y);
hitN.xy = hitN.z >= 0.0 ? hitEnc.xy : octahedronWrap(hitEnc.xy);
hitN = normalize(hitN);
float hitNdotL = max(0.0, dot(hitN, sunDir));
vec3 hitRadiance = hitAlbedo * sunCol * hitNdotL;
#else
vec3 hitRadiance = hitAlbedo * 0.5;
#endif
#ifdef _EmissionShaded
hitRadiance += textureLod(gbufferEmission, hitUV, 0.0).rgb;
#endif
gi += hitRadiance * distWeight;
validSamples++;
}
if (validSamples > 0) {
gi /= float(validSamples);
}
gi *= strength;
#ifdef _EmissionShaded
#ifdef _EmissionShadeless
else {
#endif
gi += textureLod(gbufferEmission, texCoord, 0.0).rgb;
#ifdef _EmissionShadeless
}
#endif
gi += textureLod(gbufferEmission, texCoord, 0.0).rgb * 0.3;
#endif
fragColor = gi / (gi + vec3(1.0)); // Reinhard tone mapping
fragColor = vec4(min(gi, vec3(2.0)), 1.0);
}

View File

@ -6,60 +6,18 @@
"compare_mode": "always",
"cull_mode": "none",
"links": [
{
"name": "invVP",
"link": "_inverseViewProjectionMatrix"
},
{
"name": "P",
"link": "_projectionMatrix"
},
{
"name": "invP",
"link": "_inverseProjectionMatrix"
},
{
"name": "V3",
"link": "_viewMatrix3"
},
{
"name": "eye",
"link": "_cameraPosition"
},
{
"name": "eyeLook",
"link": "_cameraLook"
},
{
"name": "cameraProj",
"link": "_cameraPlaneProj"
},
{
"name": "screenSize",
"link": "_screenSize"
},
{
"name": "PPComp12",
"link": "_PPComp12",
"ifdef": ["_CPostprocess"]
},
{
"name": "lightsArraySpot",
"link": "_lightsArraySpot",
"ifdef": ["_Clusters", "_Spot"]
},
{
"name": "lightsArray",
"link": "_lightsArray",
"ifdef": ["_Clusters"]
},
{
"name": "clustersData",
"link": "_clustersData",
"ifdef": ["_Clusters"]
},
{
"name": "cameraPlane",
"link": "_cameraPlane",
"ifdef": ["_Clusters"]
},
{
"name": "sunDir",
"link": "_sunDirection",
@ -71,128 +29,13 @@
"ifdef": ["_Sun"]
},
{
"name": "shadowsBias",
"link": "_sunShadowsBias",
"ifdef": ["_Sun", "_ShadowMap"]
},
{
"name": "LWVP",
"link": "_biasLightWorldViewProjectionMatrixSun",
"ifndef": ["_CSM"],
"ifdef": ["_Sun", "_ShadowMap"]
},
{
"name": "casData",
"link": "_cascadeData",
"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
},
{
"name": "lightArea0",
"link": "_lightArea0",
"ifdef": ["_LTC"]
},
{
"name": "lightArea1",
"link": "_lightArea1",
"ifdef": ["_LTC"]
},
{
"name": "lightArea2",
"link": "_lightArea2",
"ifdef": ["_LTC"]
},
{
"name": "lightArea3",
"link": "_lightArea3",
"ifdef": ["_LTC"]
},
{
"name": "sltcMat",
"link": "_ltcMat",
"ifdef": ["_LTC"]
},
{
"name": "sltcMag",
"link": "_ltcMag",
"ifdef": ["_LTC"]
},
{
"name": "smSizeUniform",
"link": "_shadowMapSize",
"ifdef": ["_SMSizeUniform"]
},
{
"name": "lightProj",
"link": "_lightPlaneProj",
"ifdef": ["_ShadowMap"]
},
{
"name": "pointPos",
"link": "_pointPosition",
"ifdef": ["_SinglePoint"]
},
{
"name": "pointCol",
"link": "_pointColor",
"ifdef": ["_SinglePoint"]
},
{
"name": "pointBias",
"link": "_pointShadowsBias",
"ifdef": ["_SinglePoint", "_ShadowMap"]
},
{
"name": "spotDir",
"link": "_spotDirection",
"ifdef": ["_SinglePoint", "_Spot"]
},
{
"name": "spotData",
"link": "_spotData",
"ifdef": ["_SinglePoint", "_Spot"]
},
{
"name": "spotRight",
"link": "_spotRight",
"ifdef": ["_SinglePoint", "_Spot"]
},
{
"name": "LWVPSpotArray",
"link": "_biasLightWorldViewProjectionMatrixSpotArray",
"ifdef": ["_Clusters", "_ShadowMap", "_Spot"]
},
{
"name": "pointLightDataArray",
"link": "_pointLightsAtlasArray",
"ifdef": ["_Clusters", "_ShadowMap", "_ShadowMapAtlas"]
},
{
"name": "LWVPSpot[0]",
"link": "_biasLightWorldViewProjectionMatrixSpot0",
"ifndef": ["_ShadowMapAtlas"],
"ifdef": ["_LTC", "_ShadowMap"]
},
{
"name": "LWVPSpot[1]",
"link": "_biasLightWorldViewProjectionMatrixSpot1",
"ifndef": ["_ShadowMapAtlas"],
"ifdef": ["_LTC", "_ShadowMap"]
},
{
"name": "LWVPSpot[2]",
"link": "_biasLightWorldViewProjectionMatrixSpot2",
"ifndef": ["_ShadowMapAtlas"],
"ifdef": ["_LTC", "_ShadowMap"]
},
{
"name": "LWVPSpot[3]",
"link": "_biasLightWorldViewProjectionMatrixSpot3",
"ifndef": ["_ShadowMapAtlas"],
"ifdef": ["_LTC", "_ShadowMap"]
"name": "PPComp12",
"link": "_PPComp12",
"ifdef": ["_CPostprocess"]
}
],
"texture_params": [],
"vertex_shader": "../include/pass_viewray.vert.glsl",
"vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "ssgi_pass.frag.glsl"
}
]

View File

@ -64,21 +64,26 @@ vec4 rayCast(vec3 dir) {
ddepth = getDeltaDepth(hitCoord);
if (ddepth > 0.0) return binarySearch(dir);
}
return vec4(texCoord, 0.0, 1.0);
return vec4(texCoord, 0.0, 0.0);
}
void main() {
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
float roughness = g0.z;
vec4 gr = textureLod(gbuffer_refraction, texCoord, 0.0);
float ior = gr.x;
float opac = 1.0 - gr.y;
float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
if (d == 0.0 || d == 1.0 || opac == 1.0 || ior == 1.0) {
fragColor.rgb = textureLod(tex1, texCoord, 0.0).rgb;
fragColor.a = opac;
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) {
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
fragColor.rgb = sceneSample.rgb + background * (1.0 - sceneSample.a);
fragColor.a = 1.0;
return;
}
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
float roughness = g0.z;
vec2 enc = g0.rg;
vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y);
@ -87,24 +92,32 @@ void main() {
vec3 viewNormal = V3 * n;
vec3 viewPos = getPosView(viewRay, d, cameraProj);
vec3 refracted = refract(normalize(viewPos), viewNormal, 1.0 / ior);
vec3 incident = normalize(viewPos);
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.a = 1.0;
return;
}
hitCoord = viewPos;
vec3 dir = refracted * (1.0 - rand(texCoord) * ss_refractionJitter * roughness) * 2.0;
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);
vec2 screenEdge = smoothstep(0.0, 0.1, coords.xy) * smoothstep(0.0, 0.1, 1.0 - coords.xy);
float screenEdgeFactor = screenEdge.x * screenEdge.y;
float refractivity = 1.0 - roughness;
float intensity = pow(refractivity, ss_refractionFalloffExp) * screenEdgeFactor * \
clamp(-refracted.z, 0.0, 1.0) * clamp((length(viewPos - hitCoord)), 0.0, 1.0) * coords.w;
float intensity = pow(refractivity, ss_refractionFalloffExp) * screenEdgeFactor * coords.w;
intensity = clamp(intensity, 0.0, 1.0);
vec4 refractionCol = textureLod(tex1, coords.xy, 0.0).rgba;
refractionCol.a = opac;
//refractionCol *= intensity;
vec4 color = textureLod(tex, texCoord.xy, 0.0).rgba;
color.a = opac;
fragColor.rgba = mix(refractionCol, color, opac);
fragColor.a = opac;
vec3 refractedBackground = textureLod(tex1, coords.xy, 0.0).rgb;
vec3 straightBackground = textureLod(tex1, texCoord, 0.0).rgb;
vec3 behindColor = mix(straightBackground, refractedBackground, intensity);
fragColor.rgb = sceneSample.rgb + behindColor * (1.0 - sceneSample.a);
fragColor.a = 1.0;
}

View File

@ -5,12 +5,9 @@
"depth_write": false,
"compare_mode": "always",
"cull_mode": "none",
"blend_source": "source_alpha",
"blend_destination": "inverse_source_alpha",
"blend_source": "blend_one",
"blend_destination": "blend_zero",
"blend_operation": "add",
"alpha_blend_source": "blend_one",
"alpha_blend_destination": "blend_one",
"alpha_blend_operation": "add",
"links": [
{
"name": "P",

View File

@ -1,7 +1,6 @@
//
// Copyright (C) 2012 Jorge Jimenez (jorge@iryoku.com)
// Copyright (C) 2012 Diego Gutierrez (diegog@unizar.es)
// Copyright (C) 2025 Onek8 (info@leenkx.com)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -34,17 +33,10 @@
// policies, either expressed or implied, of the copyright holders.
//
// TODO:
// Add real sss radius
// Add real sss scale
// Move temp hash, reorganize shader utility functions
// Add compiler flag for quality presets or with samples parameter
// Clean up + Document comment
#version 450
#include "compiled.inc"
#include "std/gbuffer.glsl"
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
@ -56,7 +48,8 @@ uniform vec2 cameraProj;
in vec2 texCoord;
out vec4 fragColor;
const float SSSS_FOVY = 108.0;
const vec3 SKIN_SSS_RADIUS = vec3(4.8, 2.4, 1.5);
const float SSS_DISTANCE_SCALE = 0.001;
// Temp hash func -
float hash13(vec3 p3) {
@ -69,63 +62,54 @@ vec4 SSSSBlur() {
const int SSSS_N_SAMPLES = 15;
vec4 kernel[SSSS_N_SAMPLES];
// color neutral kernel weights to prevent color shifting
kernel[0] = vec4(0.2, 0.2, 0.2, 0.0);
kernel[1] = vec4(0.12, 0.12, 0.12, 0.2);
kernel[2] = vec4(0.09, 0.09, 0.09, 0.4);
kernel[3] = vec4(0.06, 0.06, 0.06, 0.8);
kernel[4] = vec4(0.04, 0.04, 0.04, 1.2);
kernel[5] = vec4(0.025, 0.025, 0.025, 1.6);
kernel[6] = vec4(0.015, 0.015, 0.015, 2.0);
kernel[7] = vec4(0.005, 0.005, 0.005, 2.5);
kernel[8] = vec4(0.12, 0.12, 0.12, -0.2);
kernel[9] = vec4(0.09, 0.09, 0.09, -0.4);
kernel[10] = vec4(0.06, 0.06, 0.06, -0.8);
kernel[11] = vec4(0.04, 0.04, 0.04, -1.2);
kernel[12] = vec4(0.025, 0.025, 0.025, -1.6);
kernel[13] = vec4(0.015, 0.015, 0.015, -2.0);
kernel[14] = vec4(0.005, 0.005, 0.005, -2.5);
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;
float depthM = cameraProj.y / (depth - cameraProj.x);
float distanceToProjectionWindow = 1.0 / tan(0.5 * radians(SSSS_FOVY));
float scale = distanceToProjectionWindow / depthM;
vec2 finalStep = sssWidth * scale * dir;
float distanceScale = 1.0 / max(depthM, 0.1);
vec2 finalStep = sssWidth * distanceScale * dir * SSS_DISTANCE_SCALE;
vec3 jitterSeed = vec3(texCoord.xy * 1000.0, fract(cameraProj.x * 0.0001));
float jitterOffset = (hash13(jitterSeed) * 2.0 - 1.0) * 0.15; // 15% jitteR
float jitterOffset = (hash13(jitterSeed) * 2.0 - 1.0) * 0.15;
finalStep *= (1.0 + jitterOffset);
finalStep *= 0.05;
vec3 colorBlurred = vec3(0.0);
vec3 weightSum = vec3(0.0);
colorBlurred += colorM.rgb * kernel[0].rgb;
weightSum += kernel[0].rgb;
// Accumulate the other samples with per-pixel jittering to reduce banding
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);
// ADJUST FOR SURFACE FOLLOWING
// 0.0 = disabled (maximum SSS but with bleeding), 1.0 = fully enabled (prevents bleeding but might reduce SSS effect)
const float SURFACE_FOLLOWING_STRENGTH = 0.15; // Reduced to preserve more SSS effect
float depthDiff = abs(depthM - sampleDepthM);
float depthWeight = exp(-depthDiff * 10.0);
if (SURFACE_FOLLOWING_STRENGTH > 0.0) {
float sampleDepth = textureLod(gbufferD, offset, 0.0).r;
float depthScale = 5.0;
float depthDiff = abs(depth - sampleDepth) * depthScale;
if (depthDiff > 0.3) {
float blendFactor = clamp(depthDiff - 0.3, 0.0, 1.0) * SURFACE_FOLLOWING_STRENGTH;
color.rgb = mix(color.rgb, colorM.rgb, blendFactor);
}
if (depthDiff > DEPTH_THRESHOLD) {
color.rgb = mix(colorM.rgb, color.rgb, depthWeight);
}
colorBlurred += color.rgb * kernel[i].rgb;
@ -133,17 +117,22 @@ vec4 SSSSBlur() {
}
vec3 normalizedColor = colorBlurred / max(weightSum, vec3(0.00001));
float dither = hash13(vec3(texCoord * 1333.0, 0.0)) * 0.003 - 0.0015;
return vec4(normalizedColor + vec3(dither), colorM.a);
normalizedColor = max(normalizedColor + vec3(dither), vec3(0.0));
return vec4(normalizedColor, colorM.a);
}
void main() {
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
float metallic;
uint matid;
unpackFloatInt16(g0.a, metallic, matid);
if (textureLod(gbuffer0, texCoord, 0.0).a == 8192.0) {
if (matid == 2u) {
vec4 originalColor = textureLod(tex, texCoord, 0.0);
vec4 blurredColor = SSSSBlur();
vec4 finalColor = mix(blurredColor, originalColor, 0.15);
fragColor = clamp(finalColor, 0.0, 1.0);
vec4 sssContribution = blurredColor - originalColor;
vec4 combined = originalColor + max(vec4(0.0), sssContribution) * 0.8;
fragColor = max(vec4(0.0), min(combined, vec4(10.0)));
} else {
fragColor = textureLod(tex, texCoord, 0.0);
}

View File

@ -36,7 +36,8 @@ float d_ggx(const float nh, const float a) {
vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) {
float a = roughness * roughness;
return d_ggx(nh, a) * g2_approx(nl, nv, a) * f_schlick(f0, vh) / max(4.0 * nv, 1e-5); //NdotL cancels out later
vec3 result = d_ggx(nh, a) * g2_approx(nl, nv, a) * f_schlick(f0, vh) / max(4.0 * nv, 1e-5); //NdotL cancels out later
return min(result, vec3(200.0));
}
// John Hable - Optimizing GGX Shaders

View File

@ -24,7 +24,7 @@ const int DIFFUSE_CONE_COUNT = 16;
const float SHADOW_CONE_APERTURE = radians(15.0);
const float DIFFUSE_CONE_APERTURE = 0.872665; // 50 degrees in radians
const float DIFFUSE_CONE_APERTURE = 0.872665;
mat3 makeTangentBasis(const vec3 normal) {
// Create a tangent basis from normal vector

View File

@ -8,10 +8,10 @@
// const float compoDOFLength = 160.0; // Focal length in mm 18-200
// const float compoDOFFstop = 128.0; // F-stop value
const int samples = 6; // Samples on the first ring
const int samples = 8; // Samples on the first ring
const int rings = 6; // Ring count
const vec2 focus = vec2(0.5, 0.5);
const float coc = 0.11; // Circle of confusion size in mm (35mm film = 0.03mm)
const float coc = 0.03; // Circle of confusion size in mm (35mm film = 0.03mm)
const float maxblur = 1.0;
const float threshold = 0.5; // Highlight threshold
const float gain = 2.0; // Highlight gain
@ -55,21 +55,26 @@ vec3 dof(
float f = DOFLength; // Focal length in mm
float d = fDepth * 1000.0; // Focal plane in mm
float o = depth * 1000.0; // Depth in mm
float a = (o * f) / (o - f);
float b = (d * f) / (d - f);
float c = (d - f) / (d * DOFFStop * coc);
float a = (o > f) ? (o * f) / (o - f) : 0.0;
float b = (d > f) ? (d * f) / (d - f) : 0.0;
float sensorSize = max(DOFFStop, 10.0);
float c = (d - f) / (d * sensorSize * coc);
float blur = abs(a - b) * c;
blur = clamp(blur, 0.0, 1.0);
vec2 noise = rand2(texCoord) * namount * blur;
float w = (texStep.x) * blur * maxblur + noise.x;
float h = (texStep.y) * blur * maxblur + noise.y;
vec3 col = vec3(0.0);
if (blur < 0.05) {
col = textureLod(tex, texCoord, 0.0).rgb;
}
else {
col = textureLod(tex, texCoord, 0.0).rgb;
vec3 sharpCol = textureLod(tex, texCoord, 0.0).rgb;
vec3 col = sharpCol;
float blurThreshold = 0.02;
float blurRange = 0.06;
if (blur > blurThreshold) {
float blurAmount = smoothstep(blurThreshold, blurThreshold + blurRange, blur);
vec3 blurredCol = sharpCol;
float s = 1.0;
int ringsamples;
@ -81,11 +86,12 @@ vec3 dof(
float ph = (sin(float(j) * step) * float(i));
float p = 1.0;
// if (pentagon) p = penta(vec2(pw, ph));
col += color(texCoord + vec2(pw * w, ph * h), blur, tex, texStep) * mix(1.0, (float(i)) / (float(rings)), bias) * p;
blurredCol += color(texCoord + vec2(pw * w, ph * h), blur, tex, texStep) * mix(1.0, (float(i)) / (float(rings)), bias) * p;
s += 1.0 * mix(1.0, (float(i)) / (float(rings)), bias) * p;
}
}
col /= s;
blurredCol /= s;
col = mix(sharpCol, blurredCol, blurAmount);
}
return col;
}

View File

@ -1,11 +1,11 @@
#ifndef _GBUFFER_GLSL_
#define _GBUFFER_GLSL_
vec2 octahedronWrap(const vec2 v) {
vec2 octahedronWrap(vec2 v) {
return (1.0 - abs(v.yx)) * (vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0));
}
vec3 getNor(const vec2 enc) {
vec3 getNor(vec2 enc) {
vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y);
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
@ -13,13 +13,13 @@ vec3 getNor(const vec2 enc) {
return n;
}
vec3 getPosView(const vec3 viewRay, const float depth, const vec2 cameraProj) {
vec3 getPosView(vec3 viewRay, float depth, vec2 cameraProj) {
float linearDepth = cameraProj.y / (cameraProj.x - depth);
//float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
return viewRay * linearDepth;
}
vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) {
vec3 getPos(vec3 eye, vec3 eyeLook, vec3 viewRay, float depth, vec2 cameraProj) {
// eyeLook, viewRay should be normalized
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
float viewZDist = dot(eyeLook, viewRay);
@ -27,7 +27,7 @@ vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float
return wposition;
}
vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) {
vec3 getPosNoEye(vec3 eyeLook, vec3 viewRay, float depth, vec2 cameraProj) {
// eyeLook, viewRay should be normalized
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
float viewZDist = dot(eyeLook, viewRay);
@ -36,10 +36,10 @@ vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, cons
}
#if defined(HLSL) || defined(METAL)
vec3 getPos2(const mat4 invVP, const float depth, vec2 coord) {
vec3 getPos2(mat4 invVP, float depth, vec2 coord) {
coord.y = 1.0 - coord.y;
#else
vec3 getPos2(const mat4 invVP, const float depth, const vec2 coord) {
vec3 getPos2(mat4 invVP, float depth, vec2 coord) {
#endif
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
pos = invVP * pos;
@ -48,10 +48,10 @@ vec3 getPos2(const mat4 invVP, const float depth, const vec2 coord) {
}
#if defined(HLSL) || defined(METAL)
vec3 getPosView2(const mat4 invP, const float depth, vec2 coord) {
vec3 getPosView2(mat4 invP, float depth, vec2 coord) {
coord.y = 1.0 - coord.y;
#else
vec3 getPosView2(const mat4 invP, const float depth, const vec2 coord) {
vec3 getPosView2(mat4 invP, float depth, vec2 coord) {
#endif
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
pos = invP * pos;
@ -60,10 +60,10 @@ vec3 getPosView2(const mat4 invP, const float depth, const vec2 coord) {
}
#if defined(HLSL) || defined(METAL)
vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, vec2 coord) {
vec3 getPos2NoEye(vec3 eye, mat4 invVP, float depth, vec2 coord) {
coord.y = 1.0 - coord.y;
#else
vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, const vec2 coord) {
vec3 getPos2NoEye(vec3 eye, mat4 invVP, float depth, vec2 coord) {
#endif
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
pos = invVP * pos;
@ -71,24 +71,24 @@ vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, const vec
return pos.xyz - eye;
}
float packFloat(const float f1, const float f2) {
float packFloat(float f1, float f2) {
return floor(f1 * 100.0) + min(f2, 1.0 - 1.0 / 100.0);
}
vec2 unpackFloat(const float f) {
vec2 unpackFloat(float f) {
return vec2(floor(f) / 100.0, fract(f));
}
float packFloat2(const float f1, const float f2) {
float packFloat2(float f1, float f2) {
// Higher f1 = less precise f2
return floor(f1 * 255.0) + min(f2, 1.0 - 1.0 / 100.0);
}
vec2 unpackFloat2(const float f) {
vec2 unpackFloat2(float f) {
return vec2(floor(f) / 255.0, fract(f));
}
vec4 encodeRGBM(const vec3 rgb) {
vec4 encodeRGBM(vec3 rgb) {
const float maxRange = 6.0;
float maxRGB = max(rgb.x, max(rgb.g, rgb.b));
float m = maxRGB / maxRange;
@ -96,7 +96,7 @@ vec4 encodeRGBM(const vec3 rgb) {
return vec4(rgb / (m * maxRange), m);
}
vec3 decodeRGBM(const vec4 rgbm) {
vec3 decodeRGBM(vec4 rgbm) {
const float maxRange = 6.0;
return rgbm.rgb * rgbm.a * maxRange;
}
@ -150,7 +150,7 @@ vec3 decNor(uint val) {
/**
Packs a float in [0, 1] and an integer in [0..15] into a single 16 bit float value.
**/
float packFloatInt16(const float f, const uint i) {
float packFloatInt16(float f, uint i) {
const uint numBitFloat = 12;
const float maxValFloat = float((1 << numBitFloat) - 1);
@ -160,7 +160,7 @@ float packFloatInt16(const float f, const uint i) {
return float(bitsInt | bitsFloat);
}
void unpackFloatInt16(const float val, out float f, out uint i) {
void unpackFloatInt16(float val, out float f, out uint i) {
const uint numBitFloat = 12;
const float maxValFloat = float((1 << numBitFloat) - 1);

View File

@ -158,7 +158,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#endif
direct *= attenuate(distance(p, lp));
direct *= lightCol;
direct *= min(lightCol, vec3(100.0));
#ifdef _MicroShadowing
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
@ -181,55 +181,55 @@ 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 = LWVPSpot[0] * vec4(p + n * bias * 2, 1.0);
direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#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);
vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 2, 1.0);
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#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
);
#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
);
#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
);
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[3],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
}
#endif
@ -243,76 +243,76 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 2, 1.0);
direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#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);
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 2, 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
);
#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
);
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
);
#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
);
#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
);
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[3],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#endif
}
@ -330,74 +330,74 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
#ifdef _SinglePoint
#ifndef _Spot
direct *= PCFCube(shadowMapPoint[0],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[0],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#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
);
#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
);
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
);
#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
);
#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
);
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[3],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#endif
}
@ -445,61 +445,62 @@ vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dot
#endif
direct *= attenuate(distance(p, lp));
direct *= lightCol;
// 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);
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 2, 1.0);
direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#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);
vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 2, 1.0);
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#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
);
#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
);
#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
);
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[3],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
}
#endif
@ -513,76 +514,76 @@ vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dot
#ifdef _ShadowMap
if (receiveShadow) {
#ifdef _SinglePoint
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 2, 1.0);
direct *= shadowTest(shadowMapSpot[0],
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[0],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#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);
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 2, 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
);
#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
);
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
);
#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
);
#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
);
#ifdef _ShadowMapTransparent
shadowMapSpotTransparent[3],
#endif
lPos.xyz / lPos.w, bias
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#endif
}
@ -600,74 +601,74 @@ vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dot
#ifdef _SinglePoint
#ifndef _Spot
direct *= PCFCube(shadowMapPoint[0],
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[0],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#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
);
#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
);
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
);
#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
);
#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
);
#ifdef _ShadowMapTransparent
shadowMapPointTransparent[3],
#endif
ld, -l, bias, lightProj, n
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
#endif
}

View File

@ -5,6 +5,7 @@ uniform vec2 morphDataDim;
uniform vec4 morphWeights[8];
void getMorphedVertex(vec2 uvCoord, inout vec3 A){
vec3 totalDelta = vec3(0.0);
for(int i = 0; i<8; i++ )
{
vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y,
@ -13,21 +14,28 @@ void getMorphedVertex(vec2 uvCoord, inout vec3 A){
uvCoord.y - (i * 4 + 3) * morphDataDim.y);
vec3 morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.x)).rgb * morphScaleOffset.x + morphScaleOffset.y;
A += morphWeights[i].x * morph;
totalDelta += morphWeights[i].x * morph;
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.y)).rgb * morphScaleOffset.x + morphScaleOffset.y;
A += morphWeights[i].y * morph;
totalDelta += morphWeights[i].y * morph;
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.z)).rgb * morphScaleOffset.x + morphScaleOffset.y;
A += morphWeights[i].z * morph;
totalDelta += morphWeights[i].z * morph;
morph = texture(morphDataPos, vec2(uvCoord.x, tempCoordY.w)).rgb * morphScaleOffset.x + morphScaleOffset.y;
A += morphWeights[i].w * morph;
totalDelta += morphWeights[i].w * morph;
}
//float deltaLength = length(totalDelta);
//if (deltaLength > 5.0) {
// clamp corrupted data
//totalDelta = normalize(totalDelta) * 5.0;
//}
A += totalDelta;
}
void getMorphedNormal(vec2 uvCoord, vec3 oldNor, inout vec3 morphNor){
vec3 normalDelta = vec3(0.0);
for(int i = 0; i<8; i++ )
{
vec4 tempCoordY = vec4( uvCoord.y - (i * 4) * morphDataDim.y,
@ -35,19 +43,11 @@ void getMorphedNormal(vec2 uvCoord, vec3 oldNor, inout vec3 morphNor){
uvCoord.y - (i * 4 + 2) * morphDataDim.y,
uvCoord.y - (i * 4 + 3) * morphDataDim.y);
vec3 norm = oldNor + morphWeights[i].x * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.x)).rgb * 2.0 - 1.0);
morphNor += norm;
norm = oldNor + morphWeights[i].y * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.y)).rgb * 2.0 - 1.0);
morphNor += norm;
norm = oldNor + morphWeights[i].z * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.z)).rgb * 2.0 - 1.0);
morphNor += norm;
norm = oldNor + morphWeights[i].w * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.w)).rgb * 2.0 - 1.0);
morphNor += norm;
normalDelta += morphWeights[i].x * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.x)).rgb * 2.0 - 1.0);
normalDelta += morphWeights[i].y * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.y)).rgb * 2.0 - 1.0);
normalDelta += morphWeights[i].z * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.z)).rgb * 2.0 - 1.0);
normalDelta += morphWeights[i].w * (texture(morphDataNor, vec2(uvCoord.x, tempCoordY.w)).rgb * 2.0 - 1.0);
}
morphNor = normalize(morphNor);
morphNor = normalize(oldNor + normalDelta);
}

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD>shader_datas<EFBFBD><EFBFBD><EFBFBD>name<EFBFBD>copy_pass<EFBFBD>contexts<EFBFBD><EFBFBD><EFBFBD>name<EFBFBD>copy_pass<EFBFBD>constants<EFBFBD><EFBFBD>texture_units<EFBFBD><EFBFBD><EFBFBD>name<EFBFBD>tex<EFBFBD>vertex_elements<EFBFBD><EFBFBD><EFBFBD>data<EFBFBD>float2<EFBFBD>name<EFBFBD>pos<EFBFBD>vertex_shader<EFBFBD>pass.vert<72>fragment_shader<65>pass_copy.frag<61>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E><65>name<6D>compositor_pass<73>contexts<74><73><EFBFBD>name<6D>compositor_pass<73>constants<74><73>texture_units<74><73><EFBFBD>name<6D>tex<65>vertex_elements<74><73><EFBFBD>data<74>float2<74>name<6D>pos<6F>vertex_shader<65>compositor_pass.vert<72>fragment_shader<65>compositor_pass.frag<61>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E><65>name<6D>deferred_light<68>contexts<74><73><EFBFBD>name<6D>deferred_light<68>constants<74><73><EFBFBD>type<70>mat4<74>name<6D>invVP<56>link<6E>_inverseViewProjectionMatrix<69><78>type<70>vec3<63>name<6D>eye<79>link<6E>_cameraPosition<6F><6E>type<70>float<61>name<6D>envmapStrength<74>link<6E>_envmapStrength<74><68>type<70>floats<74>name<6D>shirr<72>link<6E>_envmapIrradiance<63><65>type<70>int<6E>name<6D>envmapNumMipmaps<70>link<6E>_envmapNumMipmaps<70><73>type<70>vec2<63>name<6D>cameraProj<6F>link<6E>_cameraPlaneProj<6F><6A>type<70>vec3<63>name<6D>eyeLook<6F>link<6E>_cameraLook<6F><6B>type<70>vec2<63>name<6D>lightProj<6F>link<6E>_lightPlaneProj<6F><6A>type<70>vec3<63>name<6D>pointPos<6F>link<6E>_pointPosition<6F><6E>type<70>vec3<63>name<6D>pointCol<6F>link<6E>_pointColor<6F><72>type<70>float<61>name<6D>pointBias<61>link<6E>_pointShadowsBias<61>texture_units<74><73><EFBFBD>name<6D>gbufferD<72><44>name<6D>gbuffer0<72><30>name<6D>gbuffer1<72><31>name<6D>senvmapBrdf<64>link<6E>$brdf.png<6E><67>name<6D>senvmapRadiance<63>link<6E>_envmapRadiance<63><65>name<6D>shadowMapPoint[0]<5D>vertex_elements<74><73><EFBFBD>data<74>float2<74>name<6D>pos<6F>vertex_shader<65>pass_viewray.vert<72>fragment_shader<65>deferred_light.frag<61>color_attachments<74><73>RGBA64<36>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E><65>name<6D>water_pass<73>contexts<74><73><EFBFBD>name<6D>water_pass<73>constants<74><73><EFBFBD>type<70>mat4<74>name<6D>invVP<56><50>type<70>vec3<63>name<6D>eye<79>link<6E>_cameraPosition<6F><6E>type<70>float<61>name<6D>time<6D>link<6E>_time<6D><65>type<70>float<61>name<6D>holoOverallStrength<74><68>type<70>vec2<63>name<6D>cameraProj<6F>link<6E>_cameraPlaneProj<6F><6A>type<70>vec3<63>name<6D>eyeLook<6F>link<6E>_cameraLook<6F><6B>type<70>vec3<63>name<6D>ld<6C>link<6E>_lightDirection<6F>texture_units<74><73><EFBFBD>name<6D>tex<65><78>name<6D>gbufferD<72><44>name<6D>gbuffer0<72>vertex_elements<74><73><EFBFBD>data<74>float2<74>name<6D>pos<6F>vertex_shader<65>pass_viewray.vert<72>fragment_shader<65>water_pass.frag<61>depth_write¬compare_mode<64>always<79>cull_mode<64>none<6E>blend_source<63>source_alpha<68>blend_destination<6F>inverse_source_alpha<68>blend_operation<6F>add<64>alpha_blend_source<63>blend_one<6E>alpha_blend_destination<6F>blend_one<6E>alpha_blend_operation<6F>add<64><64>contexts<74><73><EFBFBD>name<6D>World_World<6C>depth_write¬compare_mode<64>less<73>cull_mode<64>clockwise<73>vertex_elements<74><73><EFBFBD>name<6D>pos<6F>data<74>float3<74><33>name<6D>nor<6F>data<74>float3<74>color_attachments<74><73>_HDR<44>texture_units<74><73>constants<74><73><EFBFBD>name<6D>SMVP<56>type<70>mat4<74>link<6E>_skydomeMatrix<69>vertex_shader<65>World_World.vert<72>fragment_shader<65>World_World.frag<61>name<6D>World_World

View File

@ -23,6 +23,59 @@ uniform vec2 smSizeUniform;
#endif
#ifdef _ShadowMapAtlas
// PCF that clamps samples to tile boundaries to prevent bleeding
vec3 PCFTileAware(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec2 uv, const float compare, const vec2 smSize,
const vec2 tileMin, const vec2 tileMax
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
vec3 result = vec3(0.0);
vec2 offset;
offset = vec2(-1.0, -1.0) / smSize;
result.x = texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(-1.0, 0.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(-1.0, 1.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(0.0, -1.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
result.x += texture(shadowMap, vec3(uv, compare));
offset = vec2(0.0, 1.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(1.0, -1.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(1.0, 0.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
offset = vec2(1.0, 1.0) / smSize;
result.x += texture(shadowMap, vec3(clamp(uv + offset, tileMin, tileMax), compare));
result = result.xxx / 9.0;
#ifdef _ShadowMapTransparent
if (transparent == false) {
vec4 shadowmap_transparent = texture(shadowMapTransparent, uv);
if (shadowmap_transparent.a < compare)
result *= shadowmap_transparent.rgb;
}
#endif
return result;
}
// https://www.khronos.org/registry/OpenGL/specs/gl/glspec20.pdf // p:168
// https://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/5337472/
vec2 sampleCube(vec3 dir, out int faceIndex) {
@ -251,7 +304,7 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap,
#endif
if (any(lessThan(uvtiled, vec2(0.0))) || any(greaterThan(uvtiled, vec2(1.0)))) {
return vec3(1.0); // Handle edge cases by returning full light
return vec3(1.0);
}
vec3 result = vec3(0.0);
@ -334,30 +387,55 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap,
}
#endif
#ifdef _ShadowMapAtlas
uniform vec4 tileBounds;
#endif
vec3 shadowTest(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec3 lPos, const float shadowsBias
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec3 lPos, const float shadowsBias
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return vec3(1.0);
#ifdef _ShadowMapAtlas
// use tile PCF
#ifdef _SMSizeUniform
vec2 smSizeAtlas = smSizeUniform;
#else
const vec2 smSizeAtlas = shadowmapSize;
#endif
return PCFTileAware(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSizeAtlas,
tileBounds.xy, tileBounds.zw
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#else
// use PCF for non-atlas shadows
#ifdef _SMSizeUniform
vec2 smSize = smSizeUniform;
#else
const vec2 smSize = shadowmapSize;
#endif
if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return vec3(1.0);
return PCF(shadowMap,
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#endif
}
#ifdef _CSM
@ -390,14 +468,14 @@ mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
}
vec3 shadowTestCascade(sampler2DShadow shadowMap,
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec3 eye, const vec3 p, const float shadowsBias
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
#ifdef _ShadowMapTransparent
sampler2D shadowMapTransparent,
#endif
const vec3 eye, const vec3 p, const float shadowsBias
#ifdef _ShadowMapTransparent
, const bool transparent
#endif
) {
#ifdef _SMSizeUniform
vec2 smSize = smSizeUniform;
#else
@ -413,14 +491,14 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
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
);
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos.xy, lPos.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
// Blend cascade
// https://github.com/TheRealMJP/Shadows
@ -439,15 +517,16 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
vec4 lPos2 = LWVP2 * vec4(p, 1.0);
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
lPos.xy, lPos.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
#ifdef _ShadowMapTransparent
shadowMapTransparent,
#endif
lPos2.xy, lPos2.z - shadowsBias, smSize
#ifdef _ShadowMapTransparent
, transparent
#endif
);
float lerpAmt = smoothstep(0.0, blendThres, splitDist);
return mix(visibility2, visibility, lerpAmt);

View File

@ -0,0 +1,56 @@
/*
Copyright (c) 2024 Turánszki János
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
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 DIFFUSE_CONE_APERTURE = radians(45.0);
const vec3 DIFFUSE_CONE_DIRECTIONS[16] = {
vec3(0.0000, 0.0000, 1.0000), // Central direction
vec3(0.3827, 0.0000, 0.9239), // Ring 1
vec3(-0.3827, 0.0000, 0.9239),
vec3(0.0000, 0.3827, 0.9239),
vec3(0.0000, -0.3827, 0.9239),
vec3(0.2706, 0.2706, 0.9239), // Ring 2
vec3(-0.2706, 0.2706, 0.9239),
vec3(0.2706, -0.2706, 0.9239),
vec3(-0.2706, -0.2706, 0.9239),
vec3(0.1802, 0.3604, 0.9239), // Ring 3
vec3(-0.1802, 0.3604, 0.9239),
vec3(0.1802, -0.3604, 0.9239),
vec3(-0.1802, -0.3604, 0.9239),
vec3(0.3604, 0.1802, 0.9239),
vec3(-0.3604, 0.1802, 0.9239),
vec3(0.3604, -0.1802, 0.9239)
};
const float BayerMatrix8[8][8] =
{
{ 1.0 / 65.0, 49.0 / 65.0, 13.0 / 65.0, 61.0 / 65.0, 4.0 / 65.0, 52.0 / 65.0, 16.0 / 65.0, 64.0 / 65.0 },
{ 33.0 / 65.0, 17.0 / 65.0, 45.0 / 65.0, 29.0 / 65.0, 36.0 / 65.0, 20.0 / 65.0, 48.0 / 65.0, 32.0 / 65.0 },
{ 9.0 / 65.0, 57.0 / 65.0, 5.0 / 65.0, 53.0 / 65.0, 12.0 / 65.0, 60.0 / 65.0, 8.0 / 65.0, 56.0 / 65.0 },
{ 41.0 / 65.0, 25.0 / 65.0, 37.0 / 65.0, 21.0 / 65.0, 44.0 / 65.0, 28.0 / 65.0, 40.0 / 65.0, 24.0 / 65.0 },
{ 3.0 / 65.0, 51.0 / 65.0, 15.0 / 65.0, 63.0 / 65.0, 2.0 / 65.0, 50.0 / 65.0, 14.0 / 65.0, 62.0 / 65.0 },
{ 35.0 / 65.0, 19.0 / 65.0, 47.0 / 65.0, 31.0 / 65.0, 34.0 / 65.0, 18.0 / 65.0, 46.0 / 65.0, 30.0 / 65.0 },
{ 11.0 / 65.0, 59.0 / 65.0, 7.0 / 65.0, 55.0 / 65.0, 10.0 / 65.0, 58.0 / 65.0, 6.0 / 65.0, 54.0 / 65.0 },
{ 43.0 / 65.0, 27.0 / 65.0, 39.0 / 65.0, 23.0 / 65.0, 42.0 / 65.0, 26.0 / 65.0, 38.0 / 65.0, 22.0 / 65.0 }
};

View File

@ -13,32 +13,80 @@ out vec4 fragColor;
const float SMAA_REPROJECTION_WEIGHT_SCALE = 30.0;
// TODO: Move to a utility
bool isInvalidValue(float v) {
return (v != v) || (v > 65000.0) || (v < -65000.0);
}
bool hasInvalidValues(vec3 v) {
return isInvalidValue(v.x) || isInvalidValue(v.y) || isInvalidValue(v.z);
}
void main() {
vec4 current = textureLod(tex, texCoord, 0.0);
current.rgb = clamp(current.rgb, vec3(0.0), vec3(10.0));
current.a = clamp(current.a, 0.0, 1.0);
if (hasInvalidValues(current.rgb)) {
current = vec4(0.0, 0.0, 0.0, 1.0);
}
#ifdef _Veloc
// Velocity is assumed to be calculated for motion blur, so we need to inverse it for reprojection
vec2 velocity = -textureLod(sveloc, texCoord, 0.0).rg;
velocity = clamp(velocity, vec2(-1.0), vec2(1.0));
if (isInvalidValue(velocity.x) || isInvalidValue(velocity.y)) {
velocity = vec2(0.0);
}
#ifdef _InvY
velocity.y = -velocity.y;
#endif
// Reproject current coordinates and fetch previous pixel
vec4 previous = textureLod(tex2, texCoord + velocity, 0.0);
vec2 prevCoord = texCoord + velocity;
prevCoord = clamp(prevCoord, vec2(0.0), vec2(1.0));
vec4 previous = textureLod(tex2, prevCoord, 0.0);
previous.rgb = clamp(previous.rgb, vec3(0.0), vec3(10.0));
previous.a = clamp(previous.a, 0.0, 1.0);
if (hasInvalidValues(previous.rgb)) {
previous = current; // Fallback to current frame if previous is corrupted
}
// Attenuate the previous pixel if the velocity is different
#ifdef _SMAA
float delta = abs(current.a * current.a - previous.a * previous.a) / 5.0;
float currentAlpha = clamp(current.a, 0.0, 1.0);
float previousAlpha = clamp(previous.a, 0.0, 1.0);
float delta = abs(currentAlpha * currentAlpha - previousAlpha * previousAlpha) / 5.0;
delta = clamp(delta, 0.0, 1.0); // Ensure delta is in valid range
#else
const float delta = 0.0;
#endif
float weight = 0.5 * clamp(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE, 0.0, 1.0);
float weight = 0.5 * clamp(1.0 - sqrt(max(delta, 0.0)) * SMAA_REPROJECTION_WEIGHT_SCALE, 0.0, 1.0);
// Blend the pixels according to the calculated weight:
fragColor = vec4(mix(current.rgb, previous.rgb, weight), 1.0);
vec3 blended = mix(current.rgb, previous.rgb, weight);
blended = clamp(blended, vec3(0.0), vec3(10.0));
if (hasInvalidValues(blended)) {
blended = current.rgb;
}
fragColor = vec4(blended, 1.0);
#else
vec4 previous = textureLod(tex2, texCoord, 0.0);
fragColor = vec4(mix(current.rgb, previous.rgb, 0.5), 1.0);
previous.rgb = clamp(previous.rgb, vec3(0.0), vec3(10.0));
if (hasInvalidValues(previous.rgb)) {
previous.rgb = current.rgb;
}
vec3 blended = mix(current.rgb, previous.rgb, 0.5);
blended = clamp(blended, vec3(0.0), vec3(10.0));
if (hasInvalidValues(blended)) {
blended = current.rgb;
}
fragColor = vec4(blended, 1.0);
#endif
}

View File

@ -0,0 +1,79 @@
/*
Copyright (c) 2024 Turánszki János
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#version 450
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#include "compiled.inc"
#include "std/math.glsl"
#include "std/gbuffer.glsl"
#include "std/imageatomic.glsl"
#include "std/conetrace.glsl"
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform sampler3D voxels;
uniform sampler3D voxelsSDF;
uniform sampler2D gbuffer_refraction;
uniform layout(rgba8) image2D voxels_refraction;
uniform float clipmaps[voxelgiClipmapCount * 10];
uniform mat4 InvVP;
uniform vec2 cameraProj;
uniform vec3 eye;
uniform vec3 eyeLook;
uniform vec2 postprocess_resolution;
void main() {
const vec2 pixel = gl_GlobalInvocationID.xy;
vec2 uv = (pixel + 0.5) / postprocess_resolution;
#ifdef _InvY
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 x = uv.x * 2 - 1;
float y = uv.y * 2 - 1;
vec4 v = vec4(x, y, 1.0, 1.0);
v = vec4(InvVP * v);
v.xyz /= v.w;
vec3 viewRay = v.xyz - eye;
vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
vec4 g0 = textureLod(gbuffer0, uv, 0.0);
vec3 n;
n.z = 1.0 - abs(g0.x) - abs(g0.y);
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
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;
imageStore(voxels_refraction, ivec2(pixel), vec4(color, 1.0));
}

View File

@ -0,0 +1,75 @@
/*
Copyright (c) 2024 Turánszki János
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#version 450
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#include "compiled.inc"
#include "std/math.glsl"
#include "std/gbuffer.glsl"
#include "std/imageatomic.glsl"
#include "std/conetrace.glsl"
uniform sampler3D voxels;
uniform sampler3D voxelsSDF;
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform layout(r16) image2D voxels_shadows;
uniform float clipmaps[voxelgiClipmapCount * 10];
uniform mat4 InvVP;
uniform vec2 cameraProj;
uniform vec3 eye;
uniform vec3 eyeLook;
uniform vec2 postprocess_resolution;
uniform vec3 lPos;
void main() {
const vec2 pixel = gl_GlobalInvocationID.xy;
vec2 uv = (pixel + 0.5) / postprocess_resolution;
#ifdef _InvY
uv.y = 1.0 - uv.y;
#endif
float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
if (depth == 0) return;
float x = uv.x * 2 - 1;
float y = uv.y * 2 - 1;
vec4 v = vec4(x, y, 1.0, 1.0);
v = vec4(InvVP * v);
v.xyz /= v.w;
vec3 viewRay = v.xyz - eye;
vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
vec4 g0 = textureLod(gbuffer0, uv, 0.0);
vec3 n;
n.z = 1.0 - abs(g0.x) - abs(g0.y);
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
n = normalize(n);
float occ = 1.0 - traceShadow(P, n, voxels, voxelsSDF, normalize(lPos - P), clipmaps, pixel);
imageStore(voxels_shadows, ivec2(pixel), vec4(occ));
}

View File

@ -75,17 +75,16 @@ vec4 binarySearch(vec3 dir) {
}
vec4 rayCast(vec3 dir) {
float ddepth;
dir *= ss_refractionRayStep;
for (int i = 0; i < maxSteps; i++) {
hitCoord += dir;
ddepth = getDeltaDepth(hitCoord);
if (ddepth > 0.0)
return binarySearch(dir);
}
// No hit — fallback to projecting the ray to UV space
vec2 fallbackUV = getProjectedCoord(hitCoord);
return vec4(fallbackUV, 0.0, 0.5); // We set .w lower to indicate fallback
#ifdef _CPostprocess
dir *= PPComp9.x;
#else
dir *= ssrRayStep;
#endif
for (int i = 0; i < maxSteps; i++) {
hitCoord += dir;
if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir);
}
return vec4(0.0);
}
#endif //SSR