Converted rendering engine to reverse-z

This commit is contained in:
TriVoxel
2025-04-29 14:33:13 -06:00
parent 0cdb90bdb8
commit 5b5de92890
16 changed files with 151 additions and 124 deletions

View File

@ -4,6 +4,6 @@ in vec2 texCoord;
out vec4 fragColor;
void main() {
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
gl_FragDepth = 1.0;
fragColor = vec4(0.0,0.0,0.0,1.0);
gl_FragDepth = 0.0;
}

View File

@ -9,7 +9,8 @@
"texture_params": [],
"vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "clear_color_depth_pass.frag.glsl",
"color_attachments": ["_HDR"]
"color_attachments": ["_HDR"],
"clear_depth": 0.0
}
]
}

View File

@ -4,5 +4,5 @@ in vec2 texCoord;
out vec4 fragColor;
void main() {
gl_FragDepth = 1.0;
gl_FragDepth = 0.0;
}

View File

@ -21,10 +21,18 @@ uniform float envmapStrength;
#include "std/shirr.glsl"
#endif
#include "std/environment_sample.glsl"
#include "std/light.glsl"
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
// Gbuffer
//uniform sampler2D depthtex; // Raw depth
uniform sampler2D gbufferD; // Depth (cheap)
uniform sampler2D gbuffer0; // Normal/Metal
uniform sampler2D gbuffer1; // Albedo
uniform vec2 cameraProj;
uniform vec3 eye;
uniform vec3 eyeLook;
uniform mat4 invVP;
#ifdef _gbuffer2
uniform sampler2D gbuffer2;
@ -65,11 +73,6 @@ uniform sampler2D ssaotex;
uniform vec2 lightPlane;
#endif
#ifdef _SSRS
//!uniform mat4 VP;
uniform mat4 invVP;
#endif
#ifdef _LightIES
//!uniform sampler2D texIES;
#endif
@ -99,10 +102,6 @@ uniform mat4 invVP;
#endif
#endif
uniform vec2 cameraProj;
uniform vec3 eye;
uniform vec3 eyeLook;
#ifdef _Clusters
uniform vec4 lightsArray[maxLights * 3];
#ifdef _Spot
@ -204,6 +203,7 @@ in vec3 viewRay;
out vec4 fragColor;
void main() {
fragColor = vec4(0.0);
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, roughness, metallic/matid
vec3 n;
@ -218,14 +218,22 @@ void main() {
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 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
vec3 f0 = surfaceF0(g1.rgb, metallic);
vec3 envl = vec3(0.0);
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
vec3 v = normalize(eye - p);
float dotNV = max(dot(n, v), 0.0);
// world-space position:
float rawDepth = textureLod(gbufferD, texCoord, 0.0).r;
float clipZ = rawDepth * 2.0 - 1.0; // depth -> clip-space
vec4 clipPos = vec4(texCoord * 2.0 - 1.0, clipZ, 1.0);
vec4 worldPos = invVP * clipPos;
vec3 p = worldPos.xyz / worldPos.w;
vec3 v = normalize(eye - p);
float dotNV = max(dot(n, v), 0.0);
// view-space vector for reflection
vec3 viewPos = getPosView(viewRay, rawDepth, cameraProj);
vec3 viewDir = normalize(-viewPos);
#ifdef _gbuffer2
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
@ -252,12 +260,6 @@ void main() {
fragColor.rgb += ambient * ambientIntensity;
#endif
#ifndef _SSR
// Only apply specular environment lighting if SSR is NOT active
vec3 envSpecular = sampleSpecularEnvironment(reflect(viewDir, normal), roughness);
finalColor.rgb += envSpecular * environmentIntensity;
#endif
#ifdef _Rad
vec3 reflectionWorld = reflect(-v, n);
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
@ -298,28 +300,37 @@ void main() {
envl.rgb *= textureLod(voxels_ao, texCoord, 0.0).r;
#endif
// if voxel GI isn't enabled, we fall back to SSR (SSR also processes indirect)
#ifndef _VoxelGI
fragColor.rgb = envl;
fragColor.rgb += envl;
#ifndef _SSR
// if SSR is disabled, we fallback to simple environment texture
vec3 fallbackEnvColor = sampleSpecularEnvironment(reflect(viewDir, n), roughness);
fragColor.rgb += fallbackEnvColor;
#endif
#endif
// Show voxels
// vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99);
// vec3 direction = vec3(0.0, 0.0, -1.0);
// vec4 color = vec4(0.0f);
// for(uint step = 0; step < 400 && color.a < 0.99f; ++step) {
// vec3 point = origin + 0.005 * step * direction;
// color += (1.0f - color.a) * textureLod(voxels, point * 0.5 + 0.5, 0);
// }
// fragColor.rgb += color.rgb;
// Show SSAO
// fragColor.rgb = texture(ssaotex, texCoord).rrr;
// show voxel GI
#ifdef _VoxelGI
// Show voxels
vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99);
vec3 direction = vec3(0.0, 0.0, -1.0);
vec4 color = vec4(0.0f);
for(uint step = 0; step < 400 && color.a < 0.99f; ++step) {
vec3 point = origin + 0.005 * step * direction;
color += (1.0f - color.a) * textureLod(voxels, point * 0.5 + 0.5, 0);
}
fragColor.rgb += color.rgb;
#endif
// show SSAO
#ifdef _SSAO
// #ifdef _RTGI
// fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).rgb;
// #else
fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r;
// #endif
fragColor.rgb = texture(ssaotex, texCoord).rrr;
// #ifdef _RTGI
// fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).rgb;
// #else
fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r;
// #endif
#endif
#ifdef _EmissionShadeless
@ -467,7 +478,8 @@ void main() {
#endif
#ifdef _Clusters
float viewz = linearize(depth * 0.5 + 0.5, cameraProj);
// compute linear depth for clustering directly from the reconstructed view-space pos:
float viewz = length(viewPos);
int clusterI = getClusterI(texCoord, viewz, cameraPlane);
int numLights = int(texelFetch(clustersData, ivec2(clusterI, 0), 0).r * 255);
@ -511,6 +523,7 @@ void main() {
#ifdef _MicroShadowing
, occspec.x
#endif
// TODO: Cleanup. Probably broken
#ifdef _SSRS
, gbufferD, invVP, eye
#endif

View File

@ -49,10 +49,6 @@
"link": "$brdf.png",
"ifdef": ["_Brdf"]
},
{
"name": "cameraProj",
"link": "_cameraPlaneProj"
},
{
"name": "envmapStrength",
"link": "_envmapStrength"

View File

@ -23,8 +23,8 @@ void main() {
// fullscreen triangle: http://de.slideshare.net/DevCentralAMD/vertex-shader-tricks-bill-bilodeau
// gl_Position = vec4((gl_VertexID % 2) * 4.0 - 1.0, (gl_VertexID / 2) * 4.0 - 1.0, 0.0, 1.0);
// NDC (at the back of cube)
vec4 v = vec4(pos.x, pos.y, 1.0, 1.0);
// For reverse-Z, the “far” plane lives at NDC z = 0
vec4 v = vec4(pos.x, pos.y, 0.0, 1.0);
v = vec4(invVP * v);
v.xyz /= v.w;
viewRay = v.xyz - eye;

View File

@ -19,8 +19,9 @@ void main() {
gl_Position = vec4(pos.xy, 0.0, 1.0);
// NDC (at the back of cube)
vec4 v = vec4(pos.x, pos.y, 1.0, 1.0);
v = vec4(invP * v);
// For reverse-Z, far plane sits at NDC z = 0
vec4 clip = vec4(pos.x, pos.y, 0.0, 1.0);
vec4 v = invP * clip;
// reconstruct a viewspace direction
viewRay = vec3(v.xy / v.z, 1.0);
}

View File

@ -17,7 +17,8 @@ uniform float envmapStrength;
#include "std/environment_sample.glsl"
uniform sampler2D tex; // Environment map
uniform sampler2D gbufferD; // Depth buffer
//uniform sampler2D depthtex; // Full Depth buffer
uniform sampler2D gbufferD; // Cheap Depth buffer
uniform sampler2D gbuffer0; // Normal, roughness
uniform sampler2D gbuffer1; // Base color, spec
uniform mat4 P; // Projection matrix
@ -25,15 +26,10 @@ uniform mat3 V3; // View matrix
uniform vec2 cameraProj; // Camera projection params
uniform vec2 invScreenSize; // (1.0/width, 1.0/height)
const float ssrPrecision = 100.0; // 0.0 - 100.0 (user slider control)
const float ssrPrecision = 0.0; // 0.0 - 100.0 (user slider control)
//const float rayThickness = 0.1; // TODO: Adds some thickness to prevent gaps
uniform int coneTraceMode = 2; // 0 = no weighting, 1 = light, 2 = strong
const int coneTraceTapCount = 18; // Number of taps (higher = more precision)
#ifdef _CPostprocess
uniform vec3 PPComp9;
uniform vec3 PPComp10;
#endif
uniform int ssrConetraceMode = 2; // 0 = no weighting, 1 = light, 2 = strong
const int ssrConetraceTaps = 18; // Number of taps (higher = more precision)
in vec3 viewRay;
in vec2 texCoord;
@ -54,17 +50,21 @@ int dynamicMaxSteps() {
}
vec2 getProjectedCoord(const vec3 hit) {
vec4 projectedCoord = P * vec4(hit, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
projectedCoord.xy = clamp(projectedCoord.xy, 0.0, 1.0);
projectedCoord.xy += invScreenSize * 0.5; // half-pixel offset
return projectedCoord.xy;
vec4 clip = P * vec4(hit, 1.0);
vec2 uv = clip.xy / clip.w;
uv = uv * 0.5 + 0.5;
#ifdef _InvY
uv.y = 1.0 - uv.y;
#endif
uv = clamp(uv, 0.0, 1.0);
uv += invScreenSize * 0.5; // half-pixel offset
return uv;
}
float getDeltaDepth(const vec3 hit) {
vec2 screenUV = getProjectedCoord(hit);
float sampledDepth = textureLod(gbufferD, screenUV, 0.0).r;
float raw = textureLod(gbufferD, screenUV, 0.0).r;
float sampledDepth = raw * 2.0 - 1.0;
float linearSampledDepth = linearize(sampledDepth, cameraProj);
return linearSampledDepth - hit.z;
@ -129,16 +129,16 @@ vec3 coneTraceApprox(vec3 reflDir, float roughness) {
float coneSpread = roughness * 0.5; // widen based on roughness
for (int i = 0; i < coneTraceTapCount; ++i) {
float angle = float(i) / float(coneTraceTapCount) * 6.2831853;
for (int i = 0; i < ssrConetraceTaps; ++i) {
float angle = float(i) / float(ssrConetraceTaps) * 6.2831853;
vec2 offset = rot * vec2(cos(angle), sin(angle)) * coneSpread;
vec3 sampleDir = normalize(reflDir + vec3(offset, 0.0));
float weight = 1.0;
if (coneTraceMode == 1) {
if (ssrConetraceMode == 1) {
weight = pow(max(dot(reflDir, sampleDir), 0.0), 2.0); // Light cosine lobe
}
else if (coneTraceMode == 2) {
else if (ssrConetraceMode == 2) {
weight = pow(max(dot(reflDir, sampleDir), 0.0), 8.0); // Strong GGX lobe
}
@ -175,8 +175,11 @@ void main() {
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
if (spec == 0.0) { fragColor.rgb = vec3(0.0); return; }
float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
if (d == 1.0) { fragColor.rgb = vec3(0.0); return; }
// sample raw depth, bail if empty
float dRaw = textureLod(gbufferD, texCoord, 0.0).r;
if (dRaw == 0.0) { fragColor.rgb = vec3(0.0); return; }
// convert to NDC z before reconstructing
float d = dRaw * 2.0 - 1.0;
vec3 n = decode_oct(g0.rg);
vec3 viewNormal = V3 * n;

View File

@ -4,6 +4,7 @@
"name": "ssr_pass",
"depth_write": false,
"compare_mode": "always",
"blend_mode": "replace",
"cull_mode": "none",
"links": [
{
@ -23,14 +24,12 @@
"link": "_cameraPlaneProj"
},
{
"name": "PPComp9",
"link": "_PPComp9",
"ifdef": ["_CPostprocess"]
"name": "coneTraceMode",
"link": "_coneTraceMode"
},
{
"name": "PPComp10",
"link": "_PPComp10",
"ifdef": ["_CPostprocess"]
"name": "coneTraceTapCount",
"link": "_coneTraceTapCount"
}
],
"texture_params": [],

View File

@ -1,5 +1,6 @@
#ifndef _GBUFFER_GLSL_
#define _GBUFFER_GLSL_
#include "std/math.glsl"
vec2 octahedronWrap(const 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));
@ -13,20 +14,17 @@ vec3 getNor(const vec2 enc) {
return n;
}
vec3 getPosView(const vec3 viewRay, const float depth, const vec2 cameraProj) {
float linearDepth = cameraProj.y / (cameraProj.x - depth);
return viewRay * linearDepth;
vec3 getPosView(const vec3 viewRay, float depth, vec2 cameraProj) {
return viewRay * linearize(depth, cameraProj);
}
vec3 getPos(const vec3 eye, const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) {
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
float viewZDist = dot(eyeLook, viewRay);
vec3 wposition = eye + viewRay * (linearDepth / viewZDist);
return wposition;
vec3 getPos(const vec3 eye, mat3 invV, const vec3 viewRay, float depth, vec2 cameraProj) {
vec3 pVS = viewRay * linearize(depth, cameraProj);
return eye + invV * pVS; // invV == inverse of view-rotation
}
vec3 getPosNoEye(const vec3 eyeLook, const vec3 viewRay, const float depth, const vec2 cameraProj) {
float linearDepth = cameraProj.y / ((depth * 0.5 + 0.5) - cameraProj.x);
float linearDepth = linearize(depth, cameraProj);
float viewZDist = dot(eyeLook, viewRay);
vec3 wposition = viewRay * (linearDepth / viewZDist);
return wposition;
@ -44,28 +42,31 @@ vec3 getPos2(const mat4 invVP, const float depth, const vec2 coord) {
return pos.xyz;
}
#if defined(HLSL) || defined(METAL)
vec3 getPosView2(const mat4 invP, const float depth, vec2 coord) {
coord.y = 1.0 - coord.y;
#else
vec3 getPosView2(const mat4 invP, const float depth, const vec2 coord) {
#endif
//#if defined(HLSL) || defined(METAL)
//vec3 getPosView2(const mat4 invP, const float depth, vec2 coord) {
// coord.y = 1.0 - coord.y;
//#else
vec3 getPosView2(mat4 invP, float depth, vec2 coord) {
vec4 clip = vec4(coord * 2.0 - 1.0, depth, 1.0);
vec4 view = invP * clip;
return view.xyz / view.w;
//#endif
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
pos = invP * pos;
pos.xyz /= pos.w;
return pos.xyz;
}
#if defined(HLSL) || defined(METAL)
vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, vec2 coord) {
coord.y = 1.0 - coord.y;
#else
// Reconstruct view-space position from inverse View×Proj
vec3 getPos2NoEye(const vec3 eye, const mat4 invVP, const float depth, const vec2 coord) {
vec2 uv = coord;
#if defined(HLSL) || defined(METAL)
uv.y = 1.0 - uv.y;
#endif
vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
pos = invVP * pos;
pos.xyz /= pos.w;
return pos.xyz - eye;
vec4 clip = vec4(uv * 2.0 - 1.0, depth, 1.0);
vec4 world = invVP * clip;
world.xyz /= world.w;
return world.xyz - eye;
}
// Updated to support separate roughness/metalness storage

View File

@ -34,8 +34,8 @@ vec2 rand2(const vec2 coord) {
}
float linearize(float depth, vec2 cameraProj) {
depth = depth * 2.0 - 1.0;
return cameraProj.y / (cameraProj.x - depth);
return cameraProj.y / (cameraProj.x - max(depth, 1e-6));
//return cameraProj.y / (cameraProj.x - depth);
}
float attenuate(const float dist) {

View File

@ -234,7 +234,7 @@ class Inc {
var shadowmap = getShadowMapAtlas(atlas, false);
path.setTargetStream(shadowmap);
path.clearTarget(null, 1.0);
path.clearTarget(null, 0.0);
for (tile in atlas.activeTiles) {
if (tile.light == null || !tile.light.visible || tile.light.culledLight
@ -490,7 +490,7 @@ class Inc {
for (i in 0...faces) {
if (faces > 1) path.currentFace = i;
path.setTarget(shadowmap);
path.clearTarget(null, 1.0);
path.clearTarget(null, 0.0);
if (l.data.raw.cast_shadow) {
path.drawMeshes("shadowmap");
}
@ -1091,8 +1091,8 @@ class Inc {
var near = camera.data.raw.near_plane;
var far = camera.data.raw.far_plane;
var v = new iron.math.Vec2();
v.x = far / (far - near);
v.y = (-far * near) / (far - near);
v.x = 0.0;
v.y = near;
kha.compute.Compute.setFloat2(voxel_cc3, v.x, v.y);
@ -1166,9 +1166,8 @@ class Inc {
var near = camera.data.raw.near_plane;
var far = camera.data.raw.far_plane;
var v = new iron.math.Vec2();
v.x = far / (far - near);
v.y = (-far * near) / (far - near);
v.x = 0.0;
v.y = near;
kha.compute.Compute.setFloat2(voxel_cc3, v.x, v.y);
@ -1244,8 +1243,8 @@ class Inc {
var near = camera.data.raw.near_plane;
var far = camera.data.raw.far_plane;
var v = new iron.math.Vec2();
v.x = far / (far - near);
v.y = (-far * near) / (far - near);
v.x = 0.0;
v.y = near;
kha.compute.Compute.setFloat2(voxel_cc4, v.x, v.y);

View File

@ -159,7 +159,7 @@ class RenderPathDeferred {
#if rp_depth_texture
{
var t = new RenderTargetRaw();
t.name = "depthtex";
t.name = "gbufferD";
t.width = 0;
t.height = 0;
t.displayp = Inc.getDisplayp();
@ -451,11 +451,11 @@ class RenderPathDeferred {
path.setTarget("gbuffer0"); // Only clear gbuffer0
#if (rp_background == "Clear")
{
path.clearTarget(-1, 1.0);
path.clearTarget(null, 0.0);
}
#else
{
path.clearTarget(null, 1.0);
path.clearTarget(null, 0.0);
}
#end
@ -1017,7 +1017,7 @@ class RenderPathDeferred {
#if rp_overlays
{
path.setTarget(target);
path.clearTarget(null, 1.0);
path.clearTarget(null, 0.0);
path.drawMeshes("overlay");
}
#end
@ -1086,6 +1086,8 @@ class RenderPathDeferred {
path.setTarget("depthtex");
path.bindTarget("_main", "tex");
path.drawShader("shader_datas/copy_pass/copy_pass");
path.drawShader("shader_datas/deferred_light/deferred_light.frag.glsl");
path.drawShader("shader_datas/ssr_pass/ssr_pass.frag.glsl");
#if (!kha_opengl)
path.setDepthFrom("gbuffer0", "tex"); // Re-bind depth

View File

@ -428,11 +428,11 @@ class RenderPathForward {
#if (rp_background == "Clear")
{
path.clearTarget(-1, 1.0);
path.clearTarget(null, 0.0);
}
#else
{
path.clearTarget(null, 1.0);
path.clearTarget(null, 0.0);
}
#end
@ -703,7 +703,7 @@ class RenderPathForward {
#if rp_overlays
{
path.clearTarget(null, 1.0);
path.clearTarget(null, 0.0);
path.drawMeshes("overlay");
}
#end

View File

@ -571,10 +571,18 @@ class LnxRPListItem(bpy.types.PropertyGroup):
update=assets.invalidate_shader_cache
)
lnx_motion_blur_intensity: FloatProperty(name="Intensity", default=1.0, update=assets.invalidate_shader_cache)
lnx_ssr_precision: FloatProperty(name="Precision", default=0, min=0, max=100, subtype='PERCENTAGE', update=assets.invalidate_shader_cache)
lnx_ssr_ray_step: FloatProperty(name="Step", default=0.03, update=assets.invalidate_shader_cache)
lnx_ssr_search_dist: FloatProperty(name="Search", default=5.0, update=assets.invalidate_shader_cache)
lnx_ssr_search_dist: FloatProperty(name="Search", default=100.0, update=assets.invalidate_shader_cache)
lnx_ssr_falloff_exp: FloatProperty(name="Falloff", default=5.0, update=assets.invalidate_shader_cache)
lnx_ssr_jitter: FloatProperty(name="Jitter", default=0.6, update=assets.invalidate_shader_cache)
#lnx_ssr_conetrace_mode: EnumProperty(
# items=[(0, 'Fixed', 'Fastest', 'least quality'),
# (1, 'Slightly Weighted', 'Samples weighted a bit for realism'),
# (2, 'Weighted', 'Samples fully weighted for maximum realism'),
# ],
# name="Conetrace Mode", description="Fastest is fixed, best is weighted", default=2, update=assets.invalidate_shader_cache)
lnx_ssr_conetrace_taps: IntProperty(name="Conetrace Taps", default=18, min=1, update=assets.invalidate_shader_cache)
lnx_ss_refraction_ray_step: FloatProperty(name="Step", default=0.05, update=assets.invalidate_shader_cache)
lnx_ss_refraction_search_dist: FloatProperty(name="Search", default=5.0, update=assets.invalidate_shader_cache)
lnx_ss_refraction_falloff_exp: FloatProperty(name="Falloff", default=5.0, update=assets.invalidate_shader_cache)

View File

@ -1880,10 +1880,14 @@ class LNX_PT_RenderPathPostProcessPanel(bpy.types.Panel):
col.prop(rpdat, 'lnx_ssr_half_res')
col = col.column()
col.enabled = rpdat.rp_ssr
col.prop(rpdat, 'lnx_ssr_precision')
col.prop(rpdat, 'lnx_ssr_ray_step')
col.prop(rpdat, 'lnx_ssr_search_dist')
col.prop(rpdat, 'lnx_ssr_falloff_exp')
col.prop(rpdat, 'lnx_ssr_jitter')
col = col.column()
col.prop(rpdat, 'lnx_ssr_conetrace_taps')
#col.prop(rpdat, 'lnx_ssr_conetrace_mode')
layout.separator()
col = layout.column()