Files
ToriaAssets/Imports/Beautify addon/Runtime/Resources/EdgeFusion/Shaders/EdgeFusionCommon.hlsl
T
2026-08-13 16:49:22 +02:00

191 lines
5.9 KiB
HLSL

#ifndef EDGE_FUSION_COMMON_INCLUDED
#define EDGE_FUSION_COMMON_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
TEXTURE2D_X(_ObjectIDTexture);
TEXTURE2D_X(_SrcColorTexture);
TEXTURE3D(_NoiseTex3D);
TEXTURE2D_X(_CustomGroupTexture);
// Packed float parameters
float4 _BlendData1; // x: GlobalIntensity, y: MaxBlendDistance, z: NormalThreshold, w: NoiseContrast
float4 _BlendData2; // x: MaxScreenRadius, y: ShadowProtection, z: NoiseIntensity, w: NoiseScale
// Macros for accessing packed parameters
#define GLOBAL_INTENSITY _BlendData1.x
#define MAX_BLEND_DISTANCE _BlendData1.y
#define NORMAL_THRESHOLD _BlendData1.z
#define NOISE_CONTRAST _BlendData1.w
#define MAX_SCREEN_RADIUS _BlendData2.x
#define SHADOW_PROTECTION _BlendData2.y
#define NOISE_INTENSITY _BlendData2.z
#define NOISE_SCALE _BlendData2.w
float _DefaultRadiusWorld;
float _RadiusScale;
float _DistanceCompensation;
int _SampleCount;
int _BinarySearchSteps;
int _EarlyExitHits;
int _DebugMode;
float _DepthDebugMultiplier;
float4 _SrcColorTexture_TexelSize;
float4 _CameraDepthTexture_TexelSize;
float _MSAAFixPower;
#define MSAA_FIX_POWER _MSAAFixPower
inline float4 SampleColor(float2 uv) {
return SAMPLE_TEXTURE2D_X_LOD(_SrcColorTexture, sampler_LinearClamp, uv, 0);
}
inline float4 SampleObjectData(float2 uv) {
return SAMPLE_TEXTURE2D_X_LOD(_ObjectIDTexture, sampler_PointClamp, uv, 0);
}
inline bool SameObjectIds(float4 objA, float4 objB) {
return abs(objA.r - objB.r) < 0.8;
}
// Packing helpers: pack object ID and normalized radius into the red channel
#define EF_PACK_QUANT 0.01
inline float PackObjectIdRadius(float objectId, float radius) {
#if defined(SHADER_API_MOBILE) || defined(SHADER_API_GLES3) || defined(SHADER_API_GLES) || defined(SHADER_API_WEBGPU)
uint id = asuint(objectId);
id = ((id >> 16) ^ id) * 0x45d9f3b;
id = ((id >> 16) ^ id) * 0x45d9f3b;
id = (id >> 16) ^ id;
float baseId = float(id % 32u);
#else
float baseId = floor(objectId / EF_PACK_QUANT);
baseId = fmod(baseId, 4096.0);
#endif
return baseId + radius;
}
inline float UnpackIdFromPacked(float packed) {
#if defined(SHADER_API_MOBILE) || defined(SHADER_API_GLES3) || defined(SHADER_API_GLES) || defined(SHADER_API_WEBGPU)
return float(uint(floor(packed) + 0.5));
#else
return floor(packed) * EF_PACK_QUANT;
#endif
}
inline float UnpackRadiusFromPacked(float packed) {
return frac(packed);
}
float ConvertWorldRadiusToUV(float radius, float linearDepth) {
radius *= (1.0 + _DistanceCompensation * linearDepth);
float denom = lerp(max(linearDepth, 1.0), 1.0, unity_OrthoParams.w);
return 0.5 * radius * unity_CameraProjection._m11 / denom;
}
float GetRadiusUV(float4 objectData, float linearDepth) {
float radius = UnpackRadiusFromPacked(objectData.r) * _RadiusScale;
return ConvertWorldRadiusToUV(radius, linearDepth);
}
float3 GetWorldPos(float2 uv, float depth) {
#if !UNITY_REVERSED_Z
depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, depth);
#endif
float3 viewPos = ComputeViewSpacePosition(uv, depth, UNITY_MATRIX_I_P);
return mul(UNITY_MATRIX_I_V, float4(viewPos, 1.0)).xyz;
}
float3 ReconstructNormal(float2 uv, float depthC) {
// Use 3-tap reconstruction
float2 texelSize = _CameraDepthTexture_TexelSize.xy;
// Sample depths at neighbor pixels
float depthR = SAMPLE_TEXTURE2D_X_LOD(_CameraDepthTexture, sampler_PointClamp, uv + float2(texelSize.x, 0), 0).r;
float depthU = SAMPLE_TEXTURE2D_X_LOD(_CameraDepthTexture, sampler_PointClamp, uv + float2(0, texelSize.y), 0).r;
// Convert to world positions
float3 pC = GetWorldPos(uv, depthC);
float3 pR = GetWorldPos(uv + float2(texelSize.x, 0), depthR);
float3 pU = GetWorldPos(uv + float2(0, texelSize.y), depthU);
// Compute derivatives
float3 dpdx = normalize(pR - pC);
float3 dpdy = normalize(pU - pC);
// Cross product for normal
float3 n = cross(dpdy, dpdx);
return n;
}
float3 ReconstructNormalWS(float3 worldPos) {
float3 dpdx = ddx(worldPos);
float3 dpdy = ddy(worldPos);
float3 normalWS = cross(dpdy, dpdx);
return dot(normalWS, normalWS) != 0 ? normalize(normalWS) : float3(0, 0, 1);
}
inline float3 GetNormal(float4 objectData) {
float2 nxy = objectData.zw;
float nz = sqrt(saturate(1.0 - dot(nxy, nxy)));
return float3(nxy, nz);
}
float2 WorldToScreenPos(float3 wpos) {
float4 clip = TransformWorldToHClip(wpos);
float4 sp = ComputeScreenPos(clip);
float2 uv = saturate(sp.xy / sp.w);
return UnityStereoTransformScreenSpaceTex(uv);
}
struct EFVaryings
{
float4 positionCS : SV_POSITION;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
struct EFFullscreenAttributes
{
uint vertexID : SV_VertexID;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
EFVaryings EFVertFullscreen(EFFullscreenAttributes input)
{
EFVaryings o;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
o.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
return o;
}
#if EDGE_FUSION_ID_EXCLUSION
float _ExclusionMask[32];
inline uint GetExclusionSlot(float4 objData) {
float id = UnpackIdFromPacked(objData.r);
uint slot = uint(id + 0.5);
return (slot >= 1u && slot <= 32u) ? slot : 0u;
}
inline bool IsExcludedIdPair(float4 objA, float4 objB) {
uint slotA = GetExclusionSlot(objA);
uint slotB = GetExclusionSlot(objB);
if (slotA == 0u || slotB == 0u) return false;
uint idxA = slotA - 1u;
uint idxB = slotB - 1u;
return (((uint)_ExclusionMask[idxA] & (1u << idxB)) |
((uint)_ExclusionMask[idxB] & (1u << idxA))) != 0u;
}
#endif
#endif // EDGE_FUSION_COMMON_INCLUDED