146 lines
5.4 KiB
HLSL
146 lines
5.4 KiB
HLSL
#ifndef RGI_TACUM
|
|
#define RGI_TACUM
|
|
|
|
// Copyright 2022-2026 Kronnect - All Rights Reserved.
|
|
|
|
TEXTURE2D_X(_RadiantPrevResolve);
|
|
TEXTURE2D_X(_RadiantRayBufferRT);
|
|
TEXTURE2D_X(_RadiantRayConfidenceRT);
|
|
|
|
#define TEMPORAL_DEPTH_REJECTION 0.5
|
|
|
|
inline bool any_invalid_h4(half4 v) {
|
|
return any((v != v) | (abs(v) > 1e5h));
|
|
}
|
|
|
|
inline float3 EyeDepthToWorldPos(float2 uv, float eyeDepth) {
|
|
return GetWorldPosition(uv, LinearEyeDepthToRaw(eyeDepth));
|
|
}
|
|
|
|
inline float3 EyeDepthToPrevWorldPos(float2 uv, float eyeDepth) {
|
|
return GetPrevWorldPosition(uv, LinearEyeDepthToRaw(eyeDepth));
|
|
}
|
|
|
|
inline void GetNeighborhoodBox(float2 uv, out half3 boxMin, out half3 boxMax) {
|
|
float2 texel = _MainTex_TexelSize.xy;
|
|
half3 c0 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, uv).rgb;
|
|
half3 c1 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, uv + float2(0, texel.y)).rgb;
|
|
half3 c2 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, uv - float2(0, texel.y)).rgb;
|
|
half3 c3 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, uv - float2(texel.x, 0)).rgb;
|
|
half3 c4 = SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, uv + float2(texel.x, 0)).rgb;
|
|
half3 t0 = min(c0, c1);
|
|
half3 t1 = min(c2, c3);
|
|
half3 t2 = min(t0, t1);
|
|
boxMin = min(t2, c4);
|
|
t0 = max(c0, c1);
|
|
t1 = max(c2, c3);
|
|
t2 = max(t0, t1);
|
|
boxMax = max(t2, c4);
|
|
}
|
|
|
|
half4 FragRGI(VaryingsRGI i) : SV_Target {
|
|
UNITY_SETUP_INSTANCE_ID(i);
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
|
|
float2 uv = UnityStereoTransformScreenSpaceTex(i.uv);
|
|
|
|
half4 newData = SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, uv);
|
|
if (any_invalid_h4(newData) || newData.w == 0) return 0;
|
|
|
|
half2 velocity = GetVelocity(uv);
|
|
float2 prevUV = uv - velocity;
|
|
bool2 oob = (prevUV < 0.0) | (prevUV >= 1.0);
|
|
if (any(oob)) return newData;
|
|
|
|
half4 prevData = SAMPLE_TEXTURE2D_X(_RadiantPrevResolve, sampler_PointClamp, prevUV);
|
|
if (any_invalid_h4(prevData) || prevData.w == 0) return newData;
|
|
|
|
// motion factor
|
|
half wMotion = GetMotionAtten(velocity);
|
|
|
|
// color clamping based on neighborhood
|
|
half3 boxMin, boxMax;
|
|
GetNeighborhoodBox(uv, boxMin, boxMax);
|
|
prevData.rgb = clamp(prevData.rgb, boxMin, boxMax);
|
|
|
|
// blend previous and current frame
|
|
half3 blended = lerp(newData.rgb, prevData.rgb, wMotion);
|
|
return half4(max(0, blended), newData.w);
|
|
}
|
|
|
|
void FragRGI2(VaryingsRGI i, out half4 outColor : SV_Target0, out half outConfidence : SV_Target1) {
|
|
UNITY_SETUP_INSTANCE_ID(i);
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
|
|
float2 uv = UnityStereoTransformScreenSpaceTex(i.uv);
|
|
|
|
half4 newData = SAMPLE_TEXTURE2D_X(_MainTex, sampler_PointClamp, uv);
|
|
if (any_invalid_h4(newData)) {
|
|
outColor = 0;
|
|
outConfidence = 0;
|
|
return;
|
|
}
|
|
if (newData.w == 0) {
|
|
outColor = newData;
|
|
outConfidence = 0;
|
|
return;
|
|
}
|
|
|
|
half2 velocity = GetVelocity(uv);
|
|
float2 prevUV = uv - velocity;
|
|
bool2 oob = (prevUV < 0.0) | (prevUV >= 1.0);
|
|
if (any(oob)) {
|
|
outColor = newData;
|
|
outConfidence = 1;
|
|
return;
|
|
}
|
|
|
|
half prevConfidence = SAMPLE_TEXTURE2D_X(_RadiantRayConfidenceRT, sampler_LinearClamp, prevUV).r;
|
|
if (prevConfidence <= 0) {
|
|
outColor = newData;
|
|
outConfidence = 1;
|
|
return;
|
|
}
|
|
|
|
half4 prevData = SAMPLE_TEXTURE2D_X(_RadiantRayBufferRT, sampler_LinearClamp, prevUV);
|
|
if (any_invalid_h4(prevData) | (prevData.w == 0)) {
|
|
outColor = newData;
|
|
outConfidence = 1;
|
|
return;
|
|
}
|
|
|
|
// disocclusion check with adaptive depth threshold
|
|
float3 currWorldPos = EyeDepthToWorldPos(uv, newData.w);
|
|
float3 prevWorldPos = EyeDepthToPrevWorldPos(prevUV, prevData.w);
|
|
float3 posDiff = currWorldPos - prevWorldPos;
|
|
float distSq = dot(posDiff, posDiff);
|
|
float depthFootprint = newData.w * 0.01;
|
|
float adaptiveThreshold = max(TEMPORAL_DEPTH_REJECTION, depthFootprint);
|
|
float thresholdSq = adaptiveThreshold * adaptiveThreshold;
|
|
bool isValid = distSq < thresholdSq || prevConfidence <= 0;
|
|
|
|
half confidence;
|
|
half motionFactor = 1.0 - GetMotionAtten(velocity);
|
|
|
|
if (isValid) {
|
|
half3 avgColor = (newData.rgb + prevData.rgb) * 0.5;
|
|
half brightness = GetLuma(avgColor);
|
|
half darkThreshold = brightness < DARK_THRESHOLD ? DARK_THRESHOLD_MULTIPLIER * (1.0 - brightness / DARK_THRESHOLD) : 0.0;
|
|
confidence = min(prevConfidence + 1.0h, BLEND_FRAMES_COUNT + darkThreshold) ;
|
|
} else {
|
|
half3 boxMin, boxMax;
|
|
GetNeighborhoodBox(uv, boxMin, boxMax);
|
|
prevData.rgb = clamp(prevData.rgb, boxMin, boxMax);
|
|
confidence = 1;
|
|
prevConfidence = 1;
|
|
}
|
|
|
|
half blendIntensity = prevConfidence * rcp(prevConfidence + 0.5 + motionFactor + CAMERA_TRANSLATION_FACTOR);
|
|
outColor.rgb = lerp(newData.rgb, prevData.rgb, blendIntensity);
|
|
outColor.rgb = max(0, outColor.rgb);
|
|
outColor.w = newData.w;
|
|
|
|
outConfidence = confidence;
|
|
}
|
|
|
|
#endif // RGI_TACUM
|
|
|