Beautify addon

This commit is contained in:
Williams
2026-08-13 16:49:22 +02:00
parent 4c5f11522d
commit d2d75a6656
140 changed files with 9943 additions and 0 deletions
@@ -0,0 +1,52 @@
Shader "Hidden/Kronnect/EdgeFusion/EdgeFusion"
{
SubShader
{
ZTest Always
ZWrite Off
Cull Off
Pass
{
Name "EdgeFusion Blend"
HLSLPROGRAM
#pragma target 3.0
#pragma vertex EFVertFullscreen
#pragma fragment FragBlendEdges
#pragma multi_compile_local_fragment _ EDGE_FUSION_INTRA_OBJECT EDGE_FUSION_CONCAVE_ONLY
#pragma multi_compile_local_fragment _ EDGE_FUSION_ENABLE_JITTER
#pragma multi_compile_local_fragment _ EDGE_FUSION_NOISE
#pragma multi_compile_local_fragment _ EDGE_FUSION_MSAA_EDGE_FIX
#pragma multi_compile_local_fragment _ EDGE_FUSION_ID_EXCLUSION
#pragma multi_compile_local_fragment _ EDGE_FUSION_ANTI_FLICKER
#include "EdgeFusionCommon.hlsl"
#include "EdgeFusionBlendPass.hlsl"
ENDHLSL
}
Pass
{
Name "EdgeFusion Debug"
HLSLPROGRAM
#pragma target 3.0
#pragma vertex EFVertFullscreen
#pragma fragment FragDebug
#pragma multi_compile_local_fragment _ EDGE_FUSION_INTRA_OBJECT EDGE_FUSION_CONCAVE_ONLY
#include "EdgeFusionCommon.hlsl"
#include "EdgeFusionDebugPass.hlsl"
ENDHLSL
}
Pass
{
Name "EdgeFusion Compare"
HLSLPROGRAM
#pragma target 3.0
#pragma vertex EFVertFullscreen
#pragma fragment FragCompare
#include "EdgeFusionCommon.hlsl"
#include "EdgeFusionComparePass.hlsl"
ENDHLSL
}
}
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 9f67763b8beefc748b2814c56b00cb54
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,260 @@
#ifndef EDGE_FUSION_BLEND_LIB_INCLUDED
#define EDGE_FUSION_BLEND_LIB_INCLUDED
static const float2 sunflower_points[32] = {
float2(-0.08756255f, 0.08021447f),
float2(0.01468209f, -0.16729483f),
float2(0.12514433f, 0.16322862f),
float2(-0.23386945f, -0.04136821f),
float2(0.22404494f, -0.14251905f),
float2(-0.07551290f, 0.28090421f),
float2(-0.14480914f, -0.27882118f),
float2(0.31549522f, 0.11521835f),
float2(-0.32929810f, 0.13592947f),
float2(0.15916285f, -0.34012176f),
float2(0.11787271f, 0.37579677f),
float2(-0.35591507f, -0.20626006f),
float2(0.41817273f, -0.09193410f),
float2(-0.25554255f, 0.36348298f),
float2(-0.05910422f, -0.45610320f),
float2(0.36320827f, 0.30611232f),
float2(-0.48920069f, 0.02022998f),
float2(0.35711789f, -0.35537999f),
float2(-0.02390958f, 0.51706675f),
float2(-0.34025894f, -0.40774392f),
float2(0.53932101f, 0.07256488f),
float2(-0.45720732f, 0.31811294f),
float2(0.12499574f, -0.55561858f),
float2(0.28923687f, 0.50475690f),
float2(-0.56566134f, -0.18046139f),
float2(0.54967531f, -0.25396393f),
float2(-0.23821633f, 0.56920574f),
float2(-0.21267188f, -0.59128201f),
float2(0.56606831f, 0.29750964f),
float2(-0.62893715f, 0.16578581f),
float2(0.35758678f, -0.55612960f),
float2(0.11377869f, 0.66204563f)
};
inline float2 GetOffset(int index) {
return sunflower_points[index];
}
float _JitterFrame;
#define dot2(x) dot(x, x)
float3 HashToColor(float x) {
float3 v = frac(sin(float3(x, x * 1.37, x * 2.17)) * 4378.5453);
return saturate(v);
}
float GetLuma(float3 rgb) {
//const float3 lum = float3(0.2627, 0.6780, 0.0593); // Rec.2020 (HDR/wide gamut)
//const float3 lum = float3(0.2126, 0.7152, 0.0722); // Rec709 (sRGB/HD)
const float3 lum = float3(0.299, 0.587, 0.114); // Rec601 (SD/broadcast)
return dot(rgb, lum);
}
float3 ColorLerp(float3 a, float3 b, float t) {
#if UNITY_COLORSPACE_GAMMA
a = SRGBToLinear(a);
b = SRGBToLinear(b);
#endif
float3 c = lerp(a, b, t);
#if UNITY_COLORSPACE_GAMMA
c = LinearToSRGB(c);
#endif
return c;
}
float FindEdgeNeighbour(float2 uvA, out float2 neighbourUV) {
neighbourUV = uvA;
float4 oidA = SampleObjectData(uvA);
if (abs(oidA.r) < 1e-6) return 0.0;
float4 oidEdge = oidA;
float2 edgeUV = uvA;
float linearDepthA = LinearEyeDepth(oidA.y, _ZBufferParams);
float compensatedDefaultRadius = _DefaultRadiusWorld * (1.0 + _DistanceCompensation * linearDepthA);
float maxRadiusWorldSqr = compensatedDefaultRadius * compensatedDefaultRadius;
float bestDistSqr = maxRadiusWorldSqr;
#if EDGE_FUSION_ANTI_FLICKER
float sumSoftW = 0.0;
float2 accumEdgeUV = float2(0.0, 0.0);
float3 accumEdgeWpos = float3(0.0, 0.0, 0.0);
#endif
float3 wposA = GetWorldPos(uvA, oidA.y);
float3 edgeWpos = wposA;
#if EDGE_FUSION_INTRA_OBJECT || EDGE_FUSION_CONCAVE_ONLY
float3 normalA = GetNormal(oidA);
bool edgeCanUseSameIds = normalA.x < 100.0;
#endif
float uvRadiusBase = GetRadiusUV(oidA, linearDepthA);
float radiusLimit = MAX_SCREEN_RADIUS;
float uvRadiusEff = (radiusLimit * uvRadiusBase) / (uvRadiusBase + radiusLimit + 1e-6);
float aspectRatio = _SrcColorTexture_TexelSize.y / _SrcColorTexture_TexelSize.x;
float2 uvRadiusSearch = float2(uvRadiusBase, uvRadiusBase * aspectRatio);
#if EDGE_FUSION_ENABLE_JITTER
float ca, sa;
float2 pixel = uvA * _ScreenParams.xy;
float jitter = InterleavedGradientNoise(pixel, _JitterFrame);
float angle = jitter * 2.0 * 3.1415927;
sincos(angle, sa, ca);
float2 axisX = float2(ca, sa) * uvRadiusSearch;
float2 axisY = float2(-sa, ca) * uvRadiusSearch;
#endif
float edgeFactor = 0.0;
for (int d = 0; d < _SampleCount; d++) {
float2 offset;
float2 pdir = GetOffset(d);
#if EDGE_FUSION_ENABLE_JITTER
offset = axisX * pdir.x + axisY * pdir.y;
#else
offset = pdir * uvRadiusSearch;
#endif
float2 uvB = uvA + offset;
if (uvB.x < 0.0 || uvB.x > 1.0 || uvB.y < 0.0 || uvB.y > 1.0) continue;
float4 oidB = SampleObjectData(uvB);
if (abs(oidB.r) < 1e-6) continue;
// Check if it's a different valid object
bool isSameObject = SameObjectIds(oidB, oidA);
// If intra-object fusion is enabled, check for edges within the same object
#if EDGE_FUSION_INTRA_OBJECT || EDGE_FUSION_CONCAVE_ONLY
bool sameIds = isSameObject && edgeCanUseSameIds;
if (sameIds) {
float3 normalB = GetNormal(oidB);
float normalDot = dot(normalA, normalB);
isSameObject = normalDot >= NORMAL_THRESHOLD;
}
#endif
if (isSameObject) continue;
#if EDGE_FUSION_ID_EXCLUSION
if (IsExcludedIdPair(oidA, oidB)) continue;
#endif
// Binary refine between center (uv) and this outer point (uvB)
float2 a = uvA, b = uvB;
for (int k = 0; k < _BinarySearchSteps; k++) {
float2 m = (a + b) * 0.5;
float4 oidM = SampleObjectData(m);
// Check object ID sameness (inter-object edges)
bool sameM = SameObjectIds(oidM, oidA);
// For intra-object edges, check normal/depth discontinuities
#if EDGE_FUSION_INTRA_OBJECT || EDGE_FUSION_CONCAVE_ONLY
if (sameIds && sameM) {
float3 normalM = GetNormal(oidM);
sameM = dot(normalA, normalM) >= NORMAL_THRESHOLD;
}
#endif
if (sameM) { a = m; } else { b = m; oidB = oidM; }
}
float3 wposB = GetWorldPos(b, oidB.y);
float distSqr = dot2(wposB - wposA);
if (distSqr >= maxRadiusWorldSqr) continue;
#if EDGE_FUSION_ANTI_FLICKER
float softW = 1.0 / (distSqr + 1e-10);
sumSoftW += softW;
accumEdgeUV += b * softW;
accumEdgeWpos += wposB * softW;
#else
if (distSqr >= bestDistSqr) continue;
#endif
// Winner tracking drives oidEdge and the early-exit count. When anti-flicker is OFF, this is also where edgeUV/edgeWpos are set
if (distSqr < bestDistSqr) {
bestDistSqr = distSqr;
oidEdge = oidB;
#if !EDGE_FUSION_ANTI_FLICKER
edgeUV = b;
edgeWpos = wposB;
#endif
edgeFactor++;
if (edgeFactor >= _EarlyExitHits) break;
#if EDGE_FUSION_INTRA_OBJECT || EDGE_FUSION_CONCAVE_ONLY
edgeCanUseSameIds = sameIds;
#endif
}
}
if (edgeFactor <= 0.0) return 0.0;
#if EDGE_FUSION_ANTI_FLICKER
// Replace edgeUV/edgeWpos with the weighted average and recompute bestDistSqr from the resolved edgeWpos
edgeUV = accumEdgeUV / sumSoftW;
edgeWpos = accumEdgeWpos / sumSoftW;
bestDistSqr = dot2(edgeWpos - wposA);
#endif
#if EDGE_FUSION_NOISE
float noise = SAMPLE_TEXTURE3D_LOD(_NoiseTex3D, sampler_LinearRepeat, wposA * NOISE_SCALE, 0).r;
noise = smoothstep(0.5 - NOISE_CONTRAST, 0.5 + NOISE_CONTRAST, noise);
noise *= NOISE_INTENSITY;
edgeUV -= (uvA - edgeUV) * noise;
#endif
// Compute neighbour/mirrored pixel UV
float2 deltaUV = edgeUV - uvA;
neighbourUV = edgeUV + deltaUV;
if (neighbourUV.x < 0.0 || neighbourUV.x > 1.0 || neighbourUV.y < 0.0 || neighbourUV.y > 1.0) return 0.0;
float4 neighbourData = SampleObjectData(neighbourUV);
// Is still different object?
#if !EDGE_FUSION_INTRA_OBJECT && !EDGE_FUSION_CONCAVE_ONLY
if (SameObjectIds(neighbourData, oidA)) return 0.0;
#endif
// Is still the edge object?
if (!SameObjectIds(neighbourData, oidEdge)) return 0.0;
// Check neighbour distance (real 3D, using the neighbour's own depth).
float3 neighbourWpos = GetWorldPos(neighbourUV, neighbourData.y);
float neighbourDistSqr = dot2(neighbourWpos - edgeWpos);
// Distance falloff
float neighbourLinearDepth = LinearEyeDepth(neighbourData.y, _ZBufferParams);
float neighbourUvRadiusBase = GetRadiusUV(neighbourData, neighbourLinearDepth);
float neighbourUvRadiusEff = (radiusLimit * neighbourUvRadiusBase) / (neighbourUvRadiusBase + radiusLimit + 1e-6);
float falloffRadius = min(uvRadiusEff, neighbourUvRadiusEff);
float reductionFactorSS = length(deltaUV) / falloffRadius;
float reductionFactorWS = sqrt( max(bestDistSqr, neighbourDistSqr)) / compensatedDefaultRadius;
edgeFactor = saturate(1.0 - max(reductionFactorSS, reductionFactorWS));
// Concavity test
#if EDGE_FUSION_CONCAVE_ONLY
if (SameObjectIds(neighbourData, oidA)) {
float3 normalNVS = GetNormal(neighbourData);
float3 dVS = mul((float3x3)UNITY_MATRIX_V, neighbourWpos - wposA);
float3 dnVS = normalNVS - normalA;
float s = dot(dVS, dnVS);
float nn = dot(dnVS, dnVS);
const float epsilon = 0.0004;
bool isConcave = (2.0 * s + epsilon * nn) < 0.0;
if (!isConcave) return 0.0;
}
#endif
return edgeFactor;
}
#endif // EDGE_FUSION_BLEND_LIB_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3c0dbc0469bfe9f4faa064a164230120
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,52 @@
#ifndef EDGE_FUSION_BLEND_PASS_INCLUDED
#define EDGE_FUSION_BLEND_PASS_INCLUDED
#include "EdgeFusionBlendLibrary.hlsl"
float4 FragBlendEdges(EFVaryings i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float2 uv = UnityStereoTransformScreenSpaceTex(i.texcoord);
float4 c0 = SampleColor(uv);
float2 uvSurfaceB;
float edgeFactor = FindEdgeNeighbour(uv, uvSurfaceB);
if (edgeFactor <= 0.0) return c0;
#if EDGE_FUSION_MSAA_EDGE_FIX
float2 dir = normalize(uvSurfaceB - uv) * _SrcColorTexture_TexelSize.xy * MSAA_FIX_POWER;
c0 = SampleColor(uv - dir);
float4 surf0 = SampleColor(uvSurfaceB + dir);
#else
float4 surf0 = SampleColor(uvSurfaceB);
#endif
float fallOff = 2;
// screen-edge "vignette" fade
float2 distUV = min(uv, 1.0 - uv);
float edgeFade = min(distUV.x, distUV.y);
float2 distUVB = min(uvSurfaceB, 1.0 - uvSurfaceB);
float edgeFadeB = min(distUVB.x, distUVB.y);
edgeFade = min(edgeFade, edgeFadeB);
edgeFade = 1 - smoothstep(0, 0.05, edgeFade);
fallOff += edgeFade * 4.0;
// avoid brightening shadows
float lumaBase = GetLuma(c0.rgb);
float invLuma2 = rcp(lumaBase * lumaBase + 1e-6);
fallOff += clamp( SHADOW_PROTECTION * invLuma2, 0, 16);
// apply falloff
float blendAmount = pow(edgeFactor, fallOff);
// blend
blendAmount *= GLOBAL_INTENSITY * 0.5;
float3 blended = ColorLerp(c0.rgb, surf0.rgb, blendAmount);
return float4(blended, c0.a);
}
#endif // EDGE_FUSION_BLEND_PASS_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9b2c3aa5891859e42accbbf36354a1ae
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,190 @@
#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
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 90b602d422344ee44ab8925d0c8af36e
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,33 @@
#ifndef EDGE_FUSION_COMPARE_PASS_INCLUDED
#define EDGE_FUSION_COMPARE_PASS_INCLUDED
TEXTURE2D_X(_CompareTex);
float4 _CompareParams; // x: cos(angle), y: sin(angle), z: panning or flag, w: line width
float4 _CompareLineColor; // rgba line color
float4 FragCompare(EFVaryings i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float2 uv = UnityStereoTransformScreenSpaceTex(i.texcoord);
float2 dd = uv - 0.5.xx;
float co = dot(_CompareParams.xy, dd);
float dist = distance(_CompareParams.xy * co, dd);
float aa = saturate((_CompareParams.w - dist) / abs(_SrcColorTexture_TexelSize.y));
float sameSide = (_CompareParams.z > -5);
float2 pixelUV = lerp(uv, float2(uv.x + _CompareParams.z, uv.y), sameSide);
float2 pixelNiceUV = lerp(uv, float2(uv.x - 0.5 + _CompareParams.z, uv.y), sameSide);
float4 original = SAMPLE_TEXTURE2D_X(_SrcColorTexture, sampler_PointClamp, pixelUV);
float4 effected = SAMPLE_TEXTURE2D_X(_CompareTex, sampler_PointClamp, pixelNiceUV);
float2 cp = float2(_CompareParams.y, -_CompareParams.x);
float t = dot(dd, cp) > 0;
float4 outCol = lerp(original, effected, t);
outCol = lerp(outCol, _CompareLineColor, aa);
return outCol;
}
#endif // EDGE_FUSION_COMPARE_PASS_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6f1c46064363fae48801f64dffdebeca
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,72 @@
#ifndef EDGE_FUSION_DEBUG_PASS_INCLUDED
#define EDGE_FUSION_DEBUG_PASS_INCLUDED
#include "EdgeFusionBlendLibrary.hlsl"
// Keep in sync with DebugMode enum in EdgeFusion.cs
#define EF_DEBUG_OBJECT_IDS 1
#define EF_DEBUG_EDGES 2
#define EF_DEBUG_BLENDING 3
#define EF_DEBUG_NORMALS 4
#define EF_DEBUG_DEPTH 5
#define EF_DEBUG_SPECIAL_GROUP 6
float4 FragDebug(EFVaryings i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float2 uv = UnityStereoTransformScreenSpaceTex(i.texcoord);
float4 baseColor = SampleColor(uv);
float4 oidA = SampleObjectData(uv);
float id = oidA.x;
if (abs(id) <= 1e-6) return baseColor;
float3 color = HashToColor(floor(id));
if (_DebugMode == EF_DEBUG_OBJECT_IDS) {
return float4(color, 1.0);
}
float linearDepth = LinearEyeDepth(oidA.y, _ZBufferParams);
if (linearDepth > MAX_BLEND_DISTANCE) return baseColor;
if (_DebugMode == EF_DEBUG_DEPTH) {
float depth01 = saturate(_DepthDebugMultiplier * linearDepth / MAX_BLEND_DISTANCE);
return float4(saturate(depth01).xxx, 1.0);
}
if (_DebugMode == EF_DEBUG_EDGES) {
float2 nearestEdgeUV;
float foundEdge = FindEdgeNeighbour(uv, nearestEdgeUV);
if (foundEdge > 0) {
float edgeDistance = length( (nearestEdgeUV - uv) * _ScreenParams.xy);
if (edgeDistance < 2.0) {
return float4(saturate(1.0 - color.rgb), 1.0);
}
}
return float4(color, 1.0);
}
if (_DebugMode == EF_DEBUG_NORMALS) {
float3 normalA = GetNormal(oidA);
return float4(normalA * 0.5 + 0.5, 1.0);
}
if (_DebugMode == EF_DEBUG_BLENDING) {
float2 uvNeighbour;
float foundEdge = FindEdgeNeighbour(uv, uvNeighbour);
float blendAmount = foundEdge * foundEdge;
blendAmount *= (0.5 * GLOBAL_INTENSITY);
color.rgb = blendAmount;
return float4(color, 1.0);
}
if (_DebugMode == EF_DEBUG_SPECIAL_GROUP) {
bool isSpecial = UnpackIdFromPacked(oidA.r) == 32;
return isSpecial ? float4(1, 0.6, 0.1, 1) : baseColor;
}
return float4(color, 1.0);
}
#endif // EDGE_FUSION_DEBUG_PASS_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 931c347579516b14f93842c44318e58b
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,24 @@
Shader "Hidden/Kronnect/EdgeFusion/EdgeFusionFill"
{
SubShader
{
ZTest Always
ZWrite Off
Cull Off
Pass
{
Name "EdgeFusion Fill Object ID"
HLSLPROGRAM
#pragma target 3.0
#pragma vertex EFVertFullscreen
#pragma fragment FragFillObjectID
#pragma multi_compile_local_fragment _ EDGE_FUSION_SPECIAL_GROUP
#pragma multi_compile_local_fragment _ EDGE_FUSION_INTRA_OBJECT EDGE_FUSION_CONCAVE_ONLY
#pragma multi_compile_local_fragment _ EDGE_FUSION_DEBUG_BLEND_NORMALS
#include "EdgeFusionCommon.hlsl"
#include "EdgeFusionFillPass.hlsl"
ENDHLSL
}
}
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: ab67280516f03c148bb44fbf806aacb1
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,65 @@
#ifndef EDGE_FUSION_FILL_PASS_INCLUDED
#define EDGE_FUSION_FILL_PASS_INCLUDED
#include "EdgeFusionCommon.hlsl"
// Reserved object ID for special group (ID 32)
#define CUSTOM_OBJECT_ID 32.0
// Terrain object ID passed from script (31.0 when blendWithWorld is true, 0.0 otherwise)
float _TerrainObjectId;
float4 FragFillObjectID(EFVaryings i) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
float2 uv = UnityStereoTransformScreenSpaceTex(i.texcoord);
float4 objectData = SampleObjectData(uv);
// Negative depth marks excluded pixels
if (objectData.y < 0) {
return float4(0,0,0,0);
}
// If pixel already has an object ID, keep it unchanged
if (abs(objectData.r) > 1e-6) {
return objectData;
}
// This pixel is empty (terrain/excluded geometry)
float rawDepth = SampleSceneDepth(uv);
float linearDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
// Only fill if within blend distance
if (linearDepth >= MAX_BLEND_DISTANCE) {
return objectData; // Keep empty
}
float3 nVS;
#if EDGE_FUSION_INTRA_OBJECT || EDGE_FUSION_CONCAVE_ONLY || EDGE_FUSION_DEBUG_BLEND_NORMALS
float3 worldPos = GetWorldPos(uv, rawDepth);
float3 nWS = ReconstructNormalWS(worldPos);
nVS = mul((float3x3)UNITY_MATRIX_V, nWS);
nVS = normalize(nVS);
#else
nVS = float3(0, 0, 1);
#endif
#if EDGE_FUSION_SPECIAL_GROUP
float3 marker = SAMPLE_TEXTURE2D_X_LOD(_CustomGroupTexture, sampler_PointClamp, uv, 0).rgb;
bool isCustom = any(marker > 0.0001);
float objectId = isCustom ? CUSTOM_OBJECT_ID : _TerrainObjectId;
#else
float objectId = _TerrainObjectId;
#endif
// If objectId is 0, return empty (no blending for terrain when blendWithWorld is false)
if (objectId < 0.5) {
return objectData;
}
float packedR = PackObjectIdRadius(objectId, _DefaultRadiusWorld / _RadiusScale);
return float4(packedR, rawDepth, nVS.xy);
}
#endif // EDGE_FUSION_FILL_PASS_INCLUDED
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c4a984358a7f7a544832e9bbf7dacde9
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,194 @@
Shader "Kronnect/EdgeFusion/ObjectID"
{
Properties
{
[MainTexture] _BaseMap("Albedo", 2D) = "white" {}
_EdgeFusionRadius("Edge Fusion Radius", Float) = 0
_CustomObjectId("Custom Object ID", Float) = 0
_DisallowIntraFusion("Disallow Intra Fusion", Float) = 0
[HideInInspector] _ZWrite("ZWrite", Int) = 0
[HideInInspector] _ZTest("ZTest", Int) = 3 // Equal = Make it work with cutout materials
}
SubShader
{
Pass
{
Name "Edge Fusion Object ID"
ZWrite [_ZWrite]
ZTest [_ZTest]
Cull [_Cull]
HLSLPROGRAM
#if UNITY_PLATFORM_ANDROID || (UNITY_PLATFORM_WEBGL && !SHADER_API_WEBGPU) || UNITY_PLATFORM_UWP
#pragma target 3.5
#else
#pragma target 4.5
#endif
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#pragma instancing_options nolightprobe nolightmap
#pragma multi_compile_local_fragment _ EDGE_FUSION_MSAA_ON
#pragma multi_compile_local_fragment _ EDGE_FUSION_INTRA_OBJECT EDGE_FUSION_CONCAVE_ONLY
#pragma multi_compile_local_fragment _ EDGE_FUSION_DEBUG_BLEND_NORMALS
#pragma multi_compile _ LOD_FADE_CROSSFADE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityDOTSInstancing.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/UniversalDOTSInstancing.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#include "EdgeFusionCommon.hlsl"
#if defined(LOD_FADE_CROSSFADE)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
#endif
struct ObjIDAttributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
float3 normalOS : NORMAL;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct ObjIDVaryings
{
float4 positionCS : SV_POSITION;
nointerpolation float objectID : TEXCOORD0;
float4 screenPos : TEXCOORD1;
float viewDepth : TEXCOORD2;
float3 worldPos : TEXCOORD3;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
float _MaxBlendDistance;
CBUFFER_START(UnityPerMaterial)
float _EdgeFusionRadius;
float _CustomObjectId;
float _DisallowIntraFusion;
CBUFFER_END
#ifdef UNITY_DOTS_INSTANCING_ENABLED
UNITY_DOTS_INSTANCING_START(ObjectIDMetadata)
UNITY_DOTS_INSTANCED_PROP(float, _EdgeFusionRadius)
UNITY_DOTS_INSTANCED_PROP(float, _CustomObjectId)
UNITY_DOTS_INSTANCED_PROP(float, _DisallowIntraFusion)
UNITY_DOTS_INSTANCING_END(ObjectIDMetadata)
#define _EdgeFusionRadius UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_DEFAULT(float, _EdgeFusionRadius)
#define _CustomObjectId UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_DEFAULT(float, _CustomObjectId)
#define _DisallowIntraFusion UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_DEFAULT(float, _DisallowIntraFusion)
#endif
float GetIdFromObject() {
float4x4 m = UNITY_MATRIX_M;
float3 r0 = m[0].xyz;
float3 r1 = m[1].xyz;
float3 r2 = m[2].xyz;
float3 pos = float3(m[0][3], m[1][3], m[2][3]);
float objectID = dot(r0, float3(73.0, 157.0, 131.0))
+ dot(r1, float3(269.0, 97.0, 211.0))
+ dot(r2, float3(337.0, 41.0, 173.0))
+ dot(pos, float3(521.0, 313.0, 463.0));
return objectID;
}
ObjIDVaryings vert(ObjIDAttributes input)
{
ObjIDVaryings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
float4 positionOS = input.positionOS;
float3 normalOS = input.normalOS;
float3 positionWS = TransformObjectToWorld(positionOS.xyz);
float3 positionVS = TransformWorldToView(positionWS);
output.viewDepth = -positionVS.z;
output.positionCS = TransformObjectToHClip(positionOS.xyz);
output.screenPos = ComputeScreenPos(output.positionCS);
float objectId = _CustomObjectId;
if (objectId < 0.5) {
objectId = GetIdFromObject();
#if UNITY_ANY_INSTANCING_ENABLED
objectId += unity_InstanceID;
#endif
objectId = fmod(abs(objectId), 4096.0);
}
output.objectID = floor(objectId);
output.worldPos = positionWS;
return output;
}
float4 frag(ObjIDVaryings input) : SV_Target0
{
UNITY_SETUP_INSTANCE_ID(input);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
if (input.viewDepth > _MaxBlendDistance) return float4(0, 0, 0, 0);
#if defined(LOD_FADE_CROSSFADE)
LODFadeCrossFade(input.positionCS);
#endif
float objectId = input.objectID;
float radius = _EdgeFusionRadius;
if (radius <= 0) {
radius = _DefaultRadiusWorld;
} else if (radius > 0.9 * _RadiusScale) {
return float4(0, -1, 0, 0);
}
float2 uv = input.screenPos.xy / input.screenPos.w;
float sceneDepth = SampleSceneDepth(uv);
float rawDepth;
#if EDGE_FUSION_MSAA_ON
rawDepth = input.positionCS.z;
#if UNITY_REVERSED_Z
if (rawDepth < sceneDepth) return float4(0, 0, 0, 0);
#else
if (rawDepth > sceneDepth) return float4(0, 0, 0, 0);
#endif
#else
rawDepth = sceneDepth;
#endif
float linearDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
float uvRadius = ConvertWorldRadiusToUV(radius, linearDepth);
float screenRadiusPx = uvRadius * _ScreenParams.y;
if (screenRadiusPx < 2.0) {
return float4(0, -1, 0, 0);
}
float packedR = PackObjectIdRadius(objectId, radius / _RadiusScale);
float3 nVS;
#if EDGE_FUSION_INTRA_OBJECT || EDGE_FUSION_CONCAVE_ONLY || EDGE_FUSION_DEBUG_BLEND_NORMALS
float3 nWS = ReconstructNormalWS(input.worldPos);
nVS = mul((float3x3)UNITY_MATRIX_V, nWS);
nVS = normalize(nVS);
if (_DisallowIntraFusion > 0.5) {
nVS.x = 999.0;
}
#else
nVS = float3(0, 0, 1);
#endif
return float4(packedR, rawDepth, nVS.xy);
}
ENDHLSL
}
}
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 3d4153fbab3b0924c88c7b47c27b3916
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,137 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-2811601345551093397
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: ObjectIdInstancing
m_Shader: {fileID: 4800000, guid: 4da66f2095f944a4d83816603b7009f8, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 1
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EdgeFusionRadius: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _ZTest: 3
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ef085a6fe167a7e47ae0264e8cf12fea
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant: