From a8d6d469d57349da515759270eb31a242c795951 Mon Sep 17 00:00:00 2001 From: yum Date: Tue, 3 Jun 2025 18:24:43 -0700 Subject: Begin work on SSAO - very buggy! --- 2ner.cginc | 2 +- 2ner.shader | 12 +++++++++++ audiolink.cginc | 2 +- cnlohr.cginc | 46 +++++++++++++++++++++++++++++++++++++++++++ features.cginc | 4 ++++ glitter.cginc | 2 +- globals.cginc | 14 +++++++++++++ tessellation.cginc | 2 +- yum_lighting.cginc | 2 +- yum_pbr.cginc | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 10 files changed, 138 insertions(+), 6 deletions(-) diff --git a/2ner.cginc b/2ner.cginc index c0f2ac1..6cea852 100644 --- a/2ner.cginc +++ b/2ner.cginc @@ -147,7 +147,7 @@ v2f vert(appdata v) { #endif o.worldPos = mul(unity_ObjectToWorld, v.vertex); o.objPos = v.vertex; - o.eyeVec.xyz = normalize(o.worldPos - _WorldSpaceCameraPos); + o.eyeVec.xyz = o.worldPos - _WorldSpaceCameraPos; o.eyeVec.w = 1; // These are used to convert normals from tangent space to world space. diff --git a/2ner.shader b/2ner.shader index 42d9b78..258db61 100644 --- a/2ner.shader +++ b/2ner.shader @@ -847,6 +847,18 @@ Shader "yum_food/2ner" [HideInInspector] m_end_False_Color_Visualization("False color", Float) = 0 //endex + //ifex _SSAO_Enabled==0 + [HideInInspector] m_start_SSAO("SSAO", Float) = 0 + [ThryToggle(_SSAO)] _SSAO_Enabled("Enable", Float) = 0 + _SSAO_Radius("Radius", Float) = 1.0 + _SSAO_Samples("Samples", Float) = 5 + _SSAO_Strength("Strength", Float) = 1 + _SSAO_Noise("Noise", 2D) = "black" {} + _SSAO_Bias("Bias", Float) = 0.0 + _SSAO_Frame_Counter("Frame counter", Float) = 0.0 + [HideInInspector] m_end_SSAO("SSAO", Float) = 0 + //endex + //ifex _Letter_Grid_Enabled==0 [HideInInspector] m_start_Letter_Grid("Letter grid", Float) = 0 [ThryToggle(_LETTER_GRID)] _Letter_Grid_Enabled("Enable", Float) = 0 diff --git a/audiolink.cginc b/audiolink.cginc index bb8de54..68ddb60 100644 --- a/audiolink.cginc +++ b/audiolink.cginc @@ -1,7 +1,7 @@ #ifndef __AUDIOLINK #define __AUDIOLINK -#if defined(_SHATTER_WAVE_AUDIOLINK) || defined(_VERTEX_DOMAIN_WARPING_AUDIOLINK) +#if defined(_SHATTER_WAVE_AUDIOLINK) || defined(_VERTEX_DOMAIN_WARPING_AUDIOLINK) || defined(_SSAO) #include "Third_Party/AudioLink.cginc" #endif diff --git a/cnlohr.cginc b/cnlohr.cginc index ce3e883..2a03516 100644 --- a/cnlohr.cginc +++ b/cnlohr.cginc @@ -2,6 +2,7 @@ #define __CNLOHR_INC #include "globals.cginc" +#include "interpolators.cginc" /* * MIT License @@ -58,4 +59,49 @@ bool isVR() { #endif } +float GetLinearZFromZDepth_WorksWithMirrors(float zDepthFromMap, float2 screenUV) +{ + #if defined(UNITY_REVERSED_Z) + zDepthFromMap = 1 - zDepthFromMap; + + // When using a mirror, the far plane is whack. This just checks for it and aborts. + if( zDepthFromMap >= 1.0 ) return _ProjectionParams.z; + #endif + + float4 clipPos = float4(screenUV.xy, zDepthFromMap, 1.0); + clipPos.xyz = 2.0f * clipPos.xyz - 1.0f; + float4 camPos = mul(unity_CameraInvProjection, clipPos); + return -camPos.z / camPos.w; +} + +void GetScreenUVAndPerspectiveFactor(float3 worldPos, float4 clipPos, out float2 screen_uv, out float perspective_factor) { + float3 full_vec_eye_to_geometry = worldPos - _WorldSpaceCameraPos; + float3 world_dir = normalize(worldPos - _WorldSpaceCameraPos); + float perspective_divide = 1.0f / clipPos.w; + perspective_factor = length(full_vec_eye_to_geometry * perspective_divide); + screen_uv = clipPos.xy * perspective_divide; +} + +#if defined(_SSAO) +float GetDepthOfWorldPos(float3 worldPos) +{ + float3 full_vec_eye_to_geometry = worldPos - _WorldSpaceCameraPos; + float4 objPos = mul(unity_WorldToObject, float4(worldPos, 1)); + float4 clipPos = UnityObjectToClipPos(objPos); + + float2 suv = clipPos * float2(0.5, 0.5 * _ProjectionParams.x); + float2 screenPos = TransformStereoScreenSpaceTex(suv + 0.5 * clipPos.w, clipPos.w); + + float perspective_divide = 1.0f / clipPos.w; + float perspective_factor = length(full_vec_eye_to_geometry * perspective_divide); + float2 screen_uv = screenPos.xy * perspective_divide; + + float eye_depth_world = + GetLinearZFromZDepth_WorksWithMirrors( + SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, screen_uv), + screen_uv) * perspective_factor; + return eye_depth_world; +} +#endif + #endif // __CNLOHR_INC diff --git a/features.cginc b/features.cginc index 4bb5594..5fcdfbf 100644 --- a/features.cginc +++ b/features.cginc @@ -204,6 +204,10 @@ #pragma shader_feature_local _3D_SDF //endex +//ifex _SSAO_Enabled==0 +#pragma shader_feature_local _SSAO +//endex + //ifex _False_Color_Visualization_Enabled==0 #pragma shader_feature_local _FALSE_COLOR_VISUALIZATION //endex diff --git a/glitter.cginc b/glitter.cginc index e31bc5c..a8e6aad 100644 --- a/glitter.cginc +++ b/glitter.cginc @@ -69,7 +69,7 @@ float4 getGlitter(v2f i, GlitterParams params, float3 normal) { c_acc = c + (1 - c) * c_acc; } #if defined(_GLITTER_ANGLE_LIMIT) - float VdotN = dot(-i.eyeVec.xyz, normal); + float VdotN = dot(-normalize(i.eyeVec.xyz), normal); float angle_mask = smoothstep( cos(params.angle_limit * PI), cos(params.angle_limit * (1 - params.angle_limit_transition_width) * PI), diff --git a/globals.cginc b/globals.cginc index aeedad5..1d9f291 100644 --- a/globals.cginc +++ b/globals.cginc @@ -3,6 +3,11 @@ #include "features.cginc" +#if defined(_SSAO) +UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); +float4 _CameraDepthTexture_TexelSize; +#endif + SamplerState point_repeat_s; SamplerState linear_repeat_s; SamplerState linear_clamp_s; @@ -521,4 +526,13 @@ float _Custom30_BasicPlatform_Core_D; float3 _Custom30_BasicPlatform_Chamfer_Size; #endif // _CUSTOM30_BASICPLATFORM_CHAMFER +#if defined(_SSAO) +float _SSAO_Radius; +float _SSAO_Samples; +float _SSAO_Strength; +texture2D _SSAO_Noise; +float4 _SSAO_Noise_TexelSize; +float _SSAO_Bias; +#endif // _SSAO + #endif // __GLOBALS_INC diff --git a/tessellation.cginc b/tessellation.cginc index 526d2e3..3665558 100644 --- a/tessellation.cginc +++ b/tessellation.cginc @@ -149,7 +149,7 @@ v2f domain( o.pos = UnityObjectToClipPos(o.objPos); o.worldPos = mul(unity_ObjectToWorld, o.objPos).xyz; - o.eyeVec.xyz = normalize(o.worldPos - _WorldSpaceCameraPos); + o.eyeVec.xyz = o.worldPos - _WorldSpaceCameraPos; o.eyeVec.w = 1; // TODO what about UNITY_LIGHTING_COORDS(7,8) and instance id and shit? diff --git a/yum_lighting.cginc b/yum_lighting.cginc index d7afcef..dab631a 100644 --- a/yum_lighting.cginc +++ b/yum_lighting.cginc @@ -234,7 +234,7 @@ YumLighting GetYumLighting(v2f i, YumPbr pbr) { YumLighting light = (YumLighting) 0; // normalize has no visibile impact in test scene - light.view_dir = -i.eyeVec.xyz; + light.view_dir = -normalize(i.eyeVec.xyz); light.dir = getDirectLightDirection(i); diff --git a/yum_pbr.cginc b/yum_pbr.cginc index e1928f4..6fa12bb 100644 --- a/yum_pbr.cginc +++ b/yum_pbr.cginc @@ -1,6 +1,8 @@ #ifndef __YUM_PBR #define __YUM_PBR +#include "audiolink.cginc" +#include "cnlohr.cginc" #include "decals.cginc" #include "features.cginc" #include "filamented.cginc" @@ -133,9 +135,63 @@ YumPbr GetYumPbr(v2f i) { applyDecals(i, result.albedo, normal_tangent, result.metallic, result.smoothness); propagateRoughness(result.smoothness, result.roughness_perceptual, result.roughness); - float3x3 tangentToWorld = float3x3(i.tangent, i.binormal, i.normal); + const float3x3 tangentToWorld = float3x3(i.tangent, i.binormal, i.normal); result.normal = normalize(mul(normal_tangent, tangentToWorld)); +#if defined(_SSAO) + { + const float fragment_depth = GetDepthOfWorldPos(i.worldPos); + + float2 screen_uv; + float perspective_factor; + GetScreenUVAndPerspectiveFactor(i.worldPos, i.pos, screen_uv, perspective_factor); + + const float2 screen_px = screen_uv * _ScreenParams.xy; + const float ssao_theta = _SSAO_Noise.SampleLevel(point_repeat_s, screen_px * _SSAO_Noise_TexelSize.xy, 0) * TAU; + const float2x2 ssao_rot = float2x2( + cos(ssao_theta), -sin(ssao_theta), + sin(ssao_theta), cos(ssao_theta)); + + const float frame = ((float) AudioLinkData(ALPASS_GENERALVU + int2(1, 0)).x); + + float ssao_occlusion = 0; + const float ssao_eps = 1E-5; + [loop] + for (uint ii = 0; ii < _SSAO_Samples; ii++) { + // Compute random vector in tangent space. + // Get the index of the current pixels, on the range [0, screen_width] x + // [0, screen_height]. + // Map that onto the noise texture's pixels. Add an offset for each + // index. + float2 noise_uv = (float2(ii % _ScreenParams.x, ii * (_ScreenParams.z - 1.0f))) * _SSAO_Noise_TexelSize.xy; + float3 sample_point = _SSAO_Noise.SampleLevel(point_repeat_s, noise_uv, 0).rgb; + // Use a low discrepancy sequence to transform each sample over time. + //sample_point = frac(sample_point + PHI * frame); + sample_point.xy = 2.0 * sample_point.xy - 1.0; + sample_point.xy = mul(ssao_rot, sample_point.xy); + + // Remap to world space. + sample_point = mul(sample_point, tangentToWorld); + float scale = (ii * 1.0f) / _SSAO_Samples; + sample_point *= lerp(0.1f, 1.0f, scale * scale) * _SSAO_Radius; + + sample_point += i.worldPos; + + float sample_depth = GetDepthOfWorldPos(sample_point); + + // Depth values we're working with indicate how far you have to go along + // the view vector before you hit the object in question. Therefore, we + // care when the sample is *closer* to us than the object. + float occlusion_amount = saturate((fragment_depth - sample_depth) - _SSAO_Bias); + + ssao_occlusion += occlusion_amount; + } + + //result.albedo.xyz *= saturate(1.0 - _SSAO_Strength * ssao_occlusion / _SSAO_Samples); + result.albedo.xyz = saturate(1.0 - _SSAO_Strength * ssao_occlusion / _SSAO_Samples); + } +#endif + #if (defined(FORWARD_BASE_PASS) || defined(FORWARD_ADD_PASS)) && defined(_GLITTER) GlitterParams glitter_p; glitter_p.color = _Glitter_Color; -- cgit v1.2.3