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,159 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace EdgeFusion {
[Serializable]
public class IdExclusionPair {
public bool enabled = true;
[Range(1, 32)] public int idA = 1;
[Range(1, 32)] public int idB = 31;
}
public enum QualityPreset {
VeryLow = 4,
Low = 8,
Medium = 16,
High = 24,
VeryHigh = 32
}
public enum DebugMode {
None,
ObjectIds,
Edges,
Blending,
Normals,
Depth,
SpecialGroup
}
[Serializable]
public sealed class QualityPresetParameter : VolumeParameter<QualityPreset> {
public QualityPresetParameter (QualityPreset value, bool overrideState = false) : base(value, overrideState) { }
}
[Serializable]
public sealed class DebugModeParameter : VolumeParameter<DebugMode> {
public DebugModeParameter (DebugMode value, bool overrideState = false) : base(value, overrideState) { }
}
// PORT NOTE (Unity 2022.3 / URP 14): RenderingLayerMaskParameter is part of
// com.unity.render-pipelines.core 17.x (Unity 6) and does not exist in URP 14.
// This is a minimal drop-in replacement (same constructor signature and the
// inherited `.value` uint property used everywhere in this codebase) so the
// component compiles and the rendering-layer filters still work as plain
// bitmasks. It draws as a generic uint field in the Inspector rather than the
// specialized Rendering Layer Mask picker Unity 6 provides - you'll type the
// bitmask manually (or wire your own PropertyDrawer) rather than pick names
// from a dropdown.
[Serializable]
public sealed class RenderingLayerMaskParameter : VolumeParameter<uint> {
public RenderingLayerMaskParameter (uint value, bool overrideState = false) : base(value, overrideState) { }
}
[HelpURL("https://kronnect.com/guides/edge-fusion-introduction/")]
[VolumeComponentMenu("Kronnect/Edge Fusion")]
public class EdgeFusion : VolumeComponent {
[Tooltip("Default layers that will be considered for edge fusion blending.")]
public LayerMaskParameter blendLayers = new LayerMaskParameter(-1);
[Tooltip("Optional Rendering Layer Filter for single-sided objects selected by Blend Layers (rendering layer can be specified in the object renderer).")]
public RenderingLayerMaskParameter renderingLayerFilter = new RenderingLayerMaskParameter(uint.MaxValue);
[Tooltip("When enabled, visible geometry not selected by any layer setting will also blend with marked objects. Disable to restrict blending to explicitly selected layers only.")]
public BoolParameter blendWithOthers = new BoolParameter(true);
[Tooltip("Layers that will be rendered double-sided in the ObjectID pass.")]
public LayerMaskParameter doubleSidedLayers = new LayerMaskParameter(0);
[Tooltip("Rendering layer filter for Double-Sided selection.")]
public RenderingLayerMaskParameter doubleSidedRenderingLayerFilter = new RenderingLayerMaskParameter(uint.MaxValue);
[Tooltip("GameObjects that use special vertex shaders that should also blend")]
public LayerMaskParameter specialGroupLayers = new LayerMaskParameter(0);
[Tooltip("Rendering layer filter for Special Group selection.")]
public RenderingLayerMaskParameter specialGroupRenderingLayerFilter = new RenderingLayerMaskParameter(uint.MaxValue);
[Tooltip("Overall intensity of the edge fusion effect.")]
public ClampedFloatParameter intensity = new ClampedFloatParameter(0.0f, 0.0f, 1.0f);
[Tooltip("Default blur radius in world units (meters). Use Distance Compensation to increase effective radius at distance.")]
public ClampedFloatParameter radius = new ClampedFloatParameter(0.035f, 0.0001f, 0.5f);
[Tooltip("Scales the effective radius proportionally with distance from the camera. Use this to keep a small radius up close while increasing it for distant objects.")]
public ClampedFloatParameter distanceCompensation = new ClampedFloatParameter(0f, 0f, 0.1f);
[Tooltip("Enable fusion of edges within the same object (based on normal/depth discontinuities)")]
[InspectorName("Intra-Object Fusion")]
public BoolParameter enableIntraObjectFusion = new BoolParameter(false);
[Tooltip("When enabled, intra-object fusion only runs on renderers that have an Edge Fusion Object component with the effect allowed; fill-pass normals are skipped.")]
public BoolParameter intraObjectFusionPerObject = new BoolParameter(false);
[Tooltip("Fuse concave edges only. When disabled, both concave and convex edges are fused.")]
public BoolParameter concavityTest = new BoolParameter(false);
[Tooltip("Normal threshold for detecting edges within the same object (only used when Intra-Object Fusion is enabled)")]
public ClampedFloatParameter normalThreshold = new ClampedFloatParameter(0.6f, 0.001f, 0.95f);
public ClampedIntParameter sampleCount = new ClampedIntParameter(24, 4, 32);
public BoolParameter jitter = new BoolParameter(false);
public FloatParameter maxBlendDistance = new FloatParameter(50f);
[Tooltip("Number of binary search refinement steps when locating nearest edge")]
public ClampedIntParameter binarySearchSteps = new ClampedIntParameter(7, 1, 10);
[Tooltip("Max number of edge hits before early exiting the neighbour search loop")]
public ClampedIntParameter earlyExitHits = new ClampedIntParameter(5, 1, 32);
[Tooltip("Stabilises the blending when two edge candidates are near-tie in distance. Instead of picking one winner per frame, averages them with a soft-argmin so edgeUV moves continuously. Helps in any scene with sub-pixel motion between frames (VR pose, slow cameras, animated objects, FPS mouse look, camera shake). Disable to match the classic pick-one behaviour.")]
public BoolParameter antiFlicker = new BoolParameter(false);
public DebugModeParameter debugMode = new DebugModeParameter(DebugMode.None);
public ClampedFloatParameter depthDebugMultiplier = new ClampedFloatParameter(1.0f, 0.01f, 100.0f);
[Tooltip("Adjusts color sampling to reduce MSAA edge artifacts (MSAA only).")]
public MinFloatParameter msaaEdgeFixPower = new MinFloatParameter(0f, 0f);
public BoolParameter compareMode = new BoolParameter(false);
public BoolParameter compareSameSide = new BoolParameter(false);
public ClampedFloatParameter comparePanning = new ClampedFloatParameter(0.25f, 0f, 0.5f);
public ClampedFloatParameter compareLineAngle = new ClampedFloatParameter(1.4f, -Mathf.PI, Mathf.PI);
public ClampedFloatParameter compareLineWidth = new ClampedFloatParameter(0.002f, 0.0001f, 0.05f);
public ColorParameter compareLineColor = new ColorParameter(Color.white);
public ClampedFloatParameter maxScreenRadius = new ClampedFloatParameter(0.1f, 0.01f, 0.5f);
[Tooltip("Threshold for shadow detection and blending adjustment")]
public ClampedFloatParameter shadowProtection = new ClampedFloatParameter(0.0002f, 0f, 0.01f);
[Tooltip("Intensity of the 3D noise texture applied to blending (0 = no noise, 1 = full noise influence)")]
public ClampedFloatParameter noiseIntensity = new ClampedFloatParameter(0.0f, 0.0f, 1.0f);
[Tooltip("Scale of the 3D noise texture sampling (higher values = finer noise)")]
public ClampedFloatParameter noiseScale = new ClampedFloatParameter(5.0f, 0.1f, 10.0f);
[Tooltip("Contrast of the noise applied to edge positions (0 = soft, 1 = sharp)")]
public ClampedFloatParameter noiseContrast = new ClampedFloatParameter(0.75f, 0.0f, 1.0f);
[Header("ID Exclusions")]
[Tooltip("Pairs of custom Object IDs that should not blend with each other. IDs 1-30 are user-assignable, 31 = Terrain (non-blend-layer objects), 32 = Special Group.")]
public IdExclusionPair[] idExclusionPairs = System.Array.Empty<IdExclusionPair>();
public bool IsActive () {
return (blendLayers.value != 0 || doubleSidedLayers.value != 0 || specialGroupLayers.value != 0) && intensity.value > 0f;
}
public void OnValidate () {
maxBlendDistance.value = Mathf.Max(maxBlendDistance.value, 0f);
msaaEdgeFixPower.value = Mathf.Max(msaaEdgeFixPower.value, 0f);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fee512453ccf15742b376d2f6e1ddeb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,159 @@
using UnityEngine;
using System.Collections.Generic;
namespace EdgeFusion {
public enum IncludeMode {
OnlyThisObject,
IncludeChildren
}
[AddComponentMenu("Kronnect/Edge Fusion/Edge Fusion Object")]
[ExecuteAlways]
[DisallowMultipleComponent]
[HelpURL("https://kronnect.com/guides/edge-fusion-introduction/")]
public class EdgeFusionObject : MonoBehaviour {
public bool overrideRadius;
[Tooltip("Custom blend radius in meters (0 = disables blending for this object)")]
[Range(0f, 0.5f)]
public float customRadius = 0.05f;
public bool overrideObjectId;
[Tooltip("Custom Object ID (0 = auto, >0 = override). Objects with the same ID are considered the same for inter-object detection.")]
public int customObjectId;
[Tooltip("Use a random Object ID, instead of an Id derived from object position")]
public bool useRandomId;
[Tooltip("Assign a different random ID to each child renderer")]
public bool randomIdPerChild;
[Tooltip("Disable intra-object fusion for this object/children while keeping inter-object fusion.")]
public bool disallowIntraObjectFusion;
public IncludeMode includeMode = IncludeMode.OnlyThisObject;
public LayerMask childLayerMask = ~0;
static MaterialPropertyBlock props;
static readonly List<Material> sharedMaterialsBuffer = new List<Material>(8);
public List<Renderer> renderers { get; private set; } = new List<Renderer>();
[System.NonSerialized] public Material nonInstancingMaterial;
bool initialized;
void BuildRendererList () {
renderers.Clear();
switch (includeMode) {
case IncludeMode.OnlyThisObject:
Renderer thisRenderer = GetComponent<Renderer>();
if (thisRenderer != null) {
renderers.Add(thisRenderer);
}
break;
case IncludeMode.IncludeChildren:
GetComponentsInChildren(true, renderers);
for (int i = renderers.Count - 1; i >= 0; i--) {
Renderer r = renderers[i];
if (r == null || ((1 << r.gameObject.layer) & childLayerMask) == 0) {
renderers.RemoveAt(i);
}
}
break;
}
ValidateRendererMaterials();
}
void OnEnable () {
if (initialized || !Application.isPlaying) {
Refresh();
}
}
void Start () {
if (Application.isPlaying) {
Refresh();
initialized = true;
}
}
void OnValidate () {
customObjectId = Mathf.Abs(customObjectId);
Refresh();
}
void OnDisable () {
UpdateObjectProperties(false);
}
void OnDestroy () {
renderers.Clear();
}
int GetRandomId () {
return Random.Range(1, 851);
}
public void Refresh () {
BuildRendererList();
UpdateObjectProperties(enabled);
}
void UpdateObjectProperties (bool isEnabled) {
if (props == null) props = new MaterialPropertyBlock();
bool isActive = gameObject.activeInHierarchy && isEnabled;
int rnd = useRandomId && !randomIdPerChild ? GetRandomId() : 0;
int rendererCount = renderers.Count;
for (int i = 0; i < rendererCount; i++) {
Renderer renderer = renderers[i];
if (renderer == null) continue;
renderer.GetPropertyBlock(props);
float objectId = 0;
float radius = 0;
float disallowIntraFusion = 0f;
if (isActive) {
if (overrideRadius) {
radius = customRadius > 0 ? customRadius : 1;
}
if (overrideObjectId) {
if (useRandomId) {
objectId = randomIdPerChild ? GetRandomId() : rnd;
}
else if (customObjectId > 0) {
objectId = customObjectId;
}
}
disallowIntraFusion = disallowIntraObjectFusion ? 1f : 0f;
}
props.SetFloat(ShaderParams.EdgeFusionRadius, radius);
props.SetFloat(ShaderParams.CustomObjectId, objectId);
props.SetFloat(ShaderParams.DisallowIntraFusion, disallowIntraFusion);
renderer.SetPropertyBlock(props);
}
}
void ValidateRendererMaterials () {
nonInstancingMaterial = null;
int rendererCount = renderers.Count;
for (int i = 0; i < rendererCount; i++) {
Renderer r = renderers[i];
if (r == null) continue;
sharedMaterialsBuffer.Clear();
r.GetSharedMaterials(sharedMaterialsBuffer);
int matCount = sharedMaterialsBuffer.Count;
for (int j = 0; j < matCount; j++) {
Material mat = sharedMaterialsBuffer[j];
if (mat == null) continue;
if (!mat.enableInstancing) {
nonInstancingMaterial = mat;
sharedMaterialsBuffer.Clear();
return;
}
}
}
sharedMaterialsBuffer.Clear();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 425113f99a2d55f4db2ca1642d02f0b1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,89 @@
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace EdgeFusion {
[HelpURL("https://kronnect.com/guides/edge-fusion-introduction/")]
public class EdgeFusionRenderFeature : ScriptableRendererFeature {
[SerializeField]
[Tooltip("Whether to show the effect in Scene View")]
public bool showInSceneView = true;
[Tooltip("Allows Edge Fusion to be executed even if camera has Post Processing option disabled")]
public bool ignorePostProcessingOption = true;
[Tooltip("If enabled, Edge Fusion skips overlay cameras in a stack and only runs on base cameras. Disable to run on a stacked overlay camera (its layer must still pass the Cameras Layer Mask).")]
public bool ignoreOverlayCameras = true;
[Tooltip("Filter which cameras can render Edge Fusion by their GameObject layer")]
public LayerMask camerasLayerMask = -1;
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
EdgeFusionRenderPass renderPass;
public override void Create () {
renderPass = new EdgeFusionRenderPass(this);
}
public override void AddRenderPasses (ScriptableRenderer renderer, ref RenderingData renderingData) {
if (renderPass == null)
return;
if (renderingData.cameraData.isPreviewCamera || renderingData.cameraData.cameraType == CameraType.Reflection || (!showInSceneView && renderingData.cameraData.cameraType == CameraType.SceneView))
return;
if (ignoreOverlayCameras && renderingData.cameraData.renderType != CameraRenderType.Base)
return;
if ((camerasLayerMask & (1 << renderingData.cameraData.camera.gameObject.layer)) == 0)
return;
if (!ignorePostProcessingOption && !renderingData.cameraData.postProcessEnabled)
return;
if (IsDepthOnlyTarget(renderingData.cameraData.cameraTargetDescriptor))
return;
var settings = VolumeManager.instance.stack.GetComponent<EdgeFusion>();
bool hasSettings = settings != null;
if (!hasSettings) return;
int cameraMask = renderingData.cameraData.camera.cullingMask;
int effectiveBlendLayers = settings.blendLayers.value & cameraMask;
int effectiveDoubleSided = settings.doubleSidedLayers.value & cameraMask;
int effectiveSpecialGroup = settings.specialGroupLayers.value & cameraMask;
int dsMask = effectiveDoubleSided;
int ssMask = effectiveBlendLayers & ~effectiveDoubleSided;
bool hasAnySubset = (dsMask | ssMask | effectiveSpecialGroup) != 0;
if (!hasAnySubset) return;
bool effectActive = settings.intensity.value > 0f;
bool debugging = settings.debugMode.value != DebugMode.None;
if (!debugging && !effectActive) return;
renderPass.UpdateInputRequirement(settings);
renderPass.renderPassEvent = renderPassEvent;
renderer.EnqueuePass(renderPass);
}
protected override void Dispose (bool disposing) {
renderPass?.Cleanup();
}
internal static bool IsDepthOnlyTarget(in RenderTextureDescriptor descriptor) {
if (descriptor.colorFormat == RenderTextureFormat.Depth) {
return true;
}
if (descriptor.graphicsFormat == GraphicsFormat.None) {
return true;
}
return false;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec88e1d72445d4942b578e59d9a6e6a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,600 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace EdgeFusion {
// -------------------------------------------------------------------------------------------
// PORT NOTES (Unity 2022.3 LTS / URP 14 - classic ScriptableRenderPass API)
// -------------------------------------------------------------------------------------------
// The original (Unity 6 / URP 17) implementation is built entirely on the Render Graph API
// (RecordRenderGraph / TextureHandle / RasterGraphContext). URP 14 does not have Render Graph,
// so this version uses the classic Execute(ScriptableRenderContext, ref RenderingData) API with
// manually managed RTHandles, matching the same pass structure and shader contract 1:1:
// 1) ObjectID pass -> objectID RT (+ its own depth RT if the camera uses MSAA)
// 2) Special-group pass -> customGroup RT (only if a special group is configured)
// 3) Fill ObjectID pass -> objectIDFilled RT (only if needed, same condition as original)
// 4) Blend pass -> compare RT (if comparing) or camera color
// 5) Compare pass -> camera color (if comparing)
// 6) Debug pass -> camera color (if a debug mode is active and not comparing)
// 7) Copy-back -> not needed here, see note at the bottom of Execute()
//
// Differences from the Unity 6 version worth knowing about:
// - RTHandles are allocated once and reused/reallocated on demand (RenderingUtils.ReAllocateIfNeeded)
// instead of being requested fresh from the render graph every frame.
// - `Object.FindObjectsByType` (used in the original for id-exclusion lookup) does not exist in
// 2022.3; this file uses the classic `Object.FindObjectsOfType<Volume>()` instead.
// - The classic renderer exposes `ScriptableRenderer.cameraColorTargetHandle` /
// `cameraDepthTargetHandle` directly; there is no `UniversalResourceData`/`UniversalCameraData`
// frame-data container to reroute.
// - Camera-stack detection uses the same UniversalAdditionalCameraData.cameraStack check as the
// original, kept here for parity/documentation even though the classic renderer doesn't need an
// explicit copy-back step (see the note at the end of Execute()).
//
// This file has been ported by careful, line-by-line reading of the Unity 6 implementation and the
// URP 14 classic API; it has not been compiled/run inside the Editor. Please test in your 2022.3
// project (single camera, stacked cameras, MSAA on/off, and XR if you use it) before shipping.
// -------------------------------------------------------------------------------------------
public class EdgeFusionRenderPass : ScriptableRenderPass {
// Shader names
const string OBJECT_ID_SHADER_PATH = "Kronnect/EdgeFusion/ObjectID";
const string FUSION_SHADER_PATH = "Hidden/Kronnect/EdgeFusion/EdgeFusion";
const string FUSION_FILL_SHADER_PATH = "Hidden/Kronnect/EdgeFusion/EdgeFusionFill";
// Texture names
const string OBJECT_ID_TEXTURE_NAME = "EdgeFusion_ObjectID";
const string OBJECT_ID_FILLED_TEXTURE_NAME = "EdgeFusion_ObjectID_Filled";
const string OBJECT_ID_DEPTH_TEXTURE_NAME = "EdgeFusion_ObjectID_Depth";
const string CUSTOM_GROUP_TEXTURE_NAME = "EdgeFusion_CustomGroups";
const string CAMERA_COLOR_TEXTURE_NAME = "EdgeFusion_CameraColor";
const string COMPARE_TEXTURE_NAME = "EdgeFusion_CompareTex";
// Profiling / pass name
const string PROFILING_NAME = "Edge Fusion";
static readonly ProfilingSampler profilingSampler = new ProfilingSampler(PROFILING_NAME);
EdgeFusionRenderFeature feature;
Material objectIDMaterial;
Material fusionMaterial;
Material fusionFillMaterial;
readonly List<ShaderTagId> shaderTags;
GraphicsFormat objectIdTextureFormat;
Texture3D noiseTex;
static readonly float[] exclusionMask = new float[32];
static readonly uint[] exclusionMaskBits = new uint[32];
static Volume cachedExclusionVolume;
static EdgeFusion cachedEdgeFusion;
// RTHandles reused/reallocated across frames
RTHandle objectIDHandle;
RTHandle objectIDFilledHandle;
RTHandle objectIDDepthHandle;
RTHandle customGroupHandle;
RTHandle compareHandle;
RTHandle cameraColorCopyHandle; // holds the pre-effect camera color (blend source & compare source)
static bool CanStoreMaskValue (uint value) {
return (uint)(float)value == value;
}
public EdgeFusionRenderPass (EdgeFusionRenderFeature feature) {
this.feature = feature;
shaderTags = new List<ShaderTagId> {
new ShaderTagId("SRPDefaultUnlit"),
new ShaderTagId("UniversalForward"),
new ShaderTagId("UniversalForwardOnly"),
new ShaderTagId("LightweightForward")
};
var rg32Format = GraphicsFormat.R32G32_SFloat;
bool canUseRG32Format = SystemInfo.IsFormatSupported(rg32Format, FormatUsage.Render);
objectIdTextureFormat = canUseRG32Format ? rg32Format : GraphicsFormat.R32G32B32A32_SFloat;
InitializeMaterials();
}
public void UpdateInputRequirement (EdgeFusion settings) {
ConfigureInput(ScriptableRenderPassInput.Depth);
}
void InitializeMaterials () {
if (objectIDMaterial == null) {
var shader = Shader.Find(OBJECT_ID_SHADER_PATH);
if (shader != null) objectIDMaterial = CoreUtils.CreateEngineMaterial(shader);
if (objectIDMaterial != null) objectIDMaterial.enableInstancing = true;
}
if (fusionMaterial == null) {
var shader = Shader.Find(FUSION_SHADER_PATH);
if (shader != null) fusionMaterial = CoreUtils.CreateEngineMaterial(shader);
}
if (fusionFillMaterial == null) {
var shader = Shader.Find(FUSION_FILL_SHADER_PATH);
if (shader != null) fusionFillMaterial = CoreUtils.CreateEngineMaterial(shader);
}
noiseTex = Resources.Load<Texture3D>("EdgeFusion/Textures/NoiseTex3D");
}
void UpdateMaterialProperties (EdgeFusion settings, bool taa, float effectiveMaxBlendDistance, bool cameraUsesMsaa, bool specialGroupActive) {
float mappedNoiseContrast = Mathf.Lerp(0.5f, 0.01f, settings.noiseContrast.value);
Vector4 blendData1 = new Vector4(
settings.intensity.value, // x: GlobalIntensity
effectiveMaxBlendDistance, // y: MaxBlendDistance
settings.normalThreshold.value, // z: NormalThreshold
mappedNoiseContrast // w: NoiseContrast
);
Vector4 blendData2 = new Vector4(
settings.maxScreenRadius.value, // x: MaxScreenRadius
settings.shadowProtection.value, // y: ShadowProtection
settings.noiseIntensity.value, // z: NoiseIntensity
settings.noiseScale.value // w: NoiseScale
);
float radiusScale = Mathf.Max(1f, settings.radius.value / 0.89f);
fusionMaterial.SetVector(ShaderParams.BlendData1, blendData1);
fusionMaterial.SetVector(ShaderParams.BlendData2, blendData2);
fusionMaterial.SetFloat(ShaderParams.DefaultRadiusWorld, settings.radius.value);
fusionMaterial.SetFloat(ShaderParams.RadiusScale, radiusScale);
fusionMaterial.SetFloat(ShaderParams.DistanceCompensation, settings.distanceCompensation.value);
fusionMaterial.SetInt(ShaderParams.SampleCount, settings.sampleCount.value);
fusionMaterial.SetInt(ShaderParams.BinarySearchSteps, settings.binarySearchSteps.value);
fusionMaterial.SetInt(ShaderParams.EarlyExitHits, settings.earlyExitHits.value);
if (settings.antiFlicker.value) {
fusionMaterial.EnableKeyword(ShaderParams.SKW_ANTI_FLICKER);
}
else {
fusionMaterial.DisableKeyword(ShaderParams.SKW_ANTI_FLICKER);
}
fusionMaterial.SetTexture(ShaderParams.NoiseTex3D, noiseTex);
fusionFillMaterial.SetVector(ShaderParams.BlendData1, blendData1);
fusionFillMaterial.SetVector(ShaderParams.BlendData2, blendData2);
fusionFillMaterial.SetFloat(ShaderParams.DefaultRadiusWorld, settings.radius.value);
fusionFillMaterial.SetFloat(ShaderParams.RadiusScale, radiusScale);
fusionFillMaterial.SetFloat(ShaderParams.DistanceCompensation, settings.distanceCompensation.value);
float msaaFixPower = settings.msaaEdgeFixPower.value;
if (cameraUsesMsaa && msaaFixPower > 0f) {
fusionMaterial.EnableKeyword(ShaderParams.SKW_MSAA_EDGE_FIX);
fusionMaterial.SetFloat(ShaderParams.MsaaFixPower, msaaFixPower);
}
else {
fusionMaterial.DisableKeyword(ShaderParams.SKW_MSAA_EDGE_FIX);
}
// ObjectID material setup
objectIDMaterial.SetFloat(ShaderParams.MaxBlendDistance, effectiveMaxBlendDistance);
objectIDMaterial.SetFloat(ShaderParams.DefaultRadiusWorld, settings.radius.value);
objectIDMaterial.SetFloat(ShaderParams.RadiusScale, radiusScale);
objectIDMaterial.SetFloat(ShaderParams.DistanceCompensation, settings.distanceCompensation.value);
objectIDMaterial.SetVector(ShaderParams.BlendData2, blendData2);
objectIDMaterial.SetInt(ShaderParams.ZWrite, cameraUsesMsaa ? 1 : 0);
objectIDMaterial.SetInt(ShaderParams.ZTest, cameraUsesMsaa ? (int)CompareFunction.LessEqual : (int)CompareFunction.Equal);
objectIDMaterial.SetFloat(ShaderParams.DisallowIntraFusion, settings.intraObjectFusionPerObject.value ? 1f : 0f);
if (cameraUsesMsaa) {
objectIDMaterial.EnableKeyword(ShaderParams.SKW_MSAA_ON);
}
else {
objectIDMaterial.DisableKeyword(ShaderParams.SKW_MSAA_ON);
}
DebugMode debugMode = settings.debugMode.value;
if (debugMode == DebugMode.SpecialGroup && !specialGroupActive) debugMode = DebugMode.None;
fusionMaterial.SetInt(ShaderParams.DebugMode, (int)debugMode);
fusionMaterial.SetFloat(ShaderParams.DepthDebugMultiplier, settings.depthDebugMultiplier.value);
bool normalsDebug = debugMode == DebugMode.Normals;
if (normalsDebug) {
objectIDMaterial.EnableKeyword(ShaderParams.SKW_DEBUG_BLEND_NORMALS);
fusionFillMaterial.EnableKeyword(ShaderParams.SKW_DEBUG_BLEND_NORMALS);
}
else {
objectIDMaterial.DisableKeyword(ShaderParams.SKW_DEBUG_BLEND_NORMALS);
fusionFillMaterial.DisableKeyword(ShaderParams.SKW_DEBUG_BLEND_NORMALS);
}
// Jitter keyword toggle
if (settings.jitter.value) {
fusionMaterial.EnableKeyword(ShaderParams.SKW_ENABLE_JITTER);
fusionMaterial.SetFloat(ShaderParams.JitterFrame, taa ? Time.frameCount : 0);
}
else {
fusionMaterial.DisableKeyword(ShaderParams.SKW_ENABLE_JITTER);
}
fusionMaterial.DisableKeyword(ShaderParams.SKW_INTRA_OBJECT_FUSION);
fusionMaterial.DisableKeyword(ShaderParams.SKW_CONCAVE_ONLY);
objectIDMaterial.DisableKeyword(ShaderParams.SKW_INTRA_OBJECT_FUSION);
objectIDMaterial.DisableKeyword(ShaderParams.SKW_CONCAVE_ONLY);
fusionFillMaterial.DisableKeyword(ShaderParams.SKW_INTRA_OBJECT_FUSION);
fusionFillMaterial.DisableKeyword(ShaderParams.SKW_CONCAVE_ONLY);
bool intraObjectFusionPerObject = settings.intraObjectFusionPerObject.value;
if (settings.enableIntraObjectFusion.value) {
if (settings.concavityTest.value) {
fusionMaterial.EnableKeyword(ShaderParams.SKW_CONCAVE_ONLY);
objectIDMaterial.EnableKeyword(ShaderParams.SKW_CONCAVE_ONLY);
if (!intraObjectFusionPerObject) {
fusionFillMaterial.EnableKeyword(ShaderParams.SKW_CONCAVE_ONLY);
}
}
else {
fusionMaterial.EnableKeyword(ShaderParams.SKW_INTRA_OBJECT_FUSION);
objectIDMaterial.EnableKeyword(ShaderParams.SKW_INTRA_OBJECT_FUSION);
if (!intraObjectFusionPerObject) {
fusionFillMaterial.EnableKeyword(ShaderParams.SKW_INTRA_OBJECT_FUSION);
}
}
}
if (settings.noiseIntensity.value > 0.0f) {
fusionMaterial.EnableKeyword(ShaderParams.SKW_NOISE);
}
else {
fusionMaterial.DisableKeyword(ShaderParams.SKW_NOISE);
}
if (specialGroupActive) {
fusionFillMaterial.EnableKeyword(ShaderParams.SKW_SPECIAL_GROUP);
}
else {
fusionFillMaterial.DisableKeyword(ShaderParams.SKW_SPECIAL_GROUP);
}
var exclusionPairs = GetActiveExclusionPairs();
if (exclusionPairs != null && exclusionPairs.Length > 0) {
System.Array.Clear(exclusionMask, 0, 32);
System.Array.Clear(exclusionMaskBits, 0, 32);
bool hasEnabledPairs = false;
int exclusionPairCount = exclusionPairs.Length;
for (int i = 0; i < exclusionPairCount; i++) {
var pair = exclusionPairs[i];
if (!pair.enabled) continue;
hasEnabledPairs = true;
int a = Mathf.Clamp(pair.idA, 1, 32) - 1;
int b = Mathf.Clamp(pair.idB, 1, 32) - 1;
uint bitForA = 1u << b;
uint bitForB = 1u << a;
if (a == b) {
uint candidate = exclusionMaskBits[a] | bitForA;
if (CanStoreMaskValue(candidate)) {
exclusionMaskBits[a] = candidate;
}
continue;
}
uint candidateA = exclusionMaskBits[a] | bitForA;
uint candidateB = exclusionMaskBits[b] | bitForB;
bool canA = CanStoreMaskValue(candidateA);
bool canB = CanStoreMaskValue(candidateB);
if (canA && (!canB || candidateA <= candidateB)) {
exclusionMaskBits[a] = candidateA;
}
else if (canB) {
exclusionMaskBits[b] = candidateB;
}
}
if (hasEnabledPairs) {
for (int i = 0; i < 32; i++) {
uint maskValue = exclusionMaskBits[i];
exclusionMask[i] = maskValue;
}
fusionMaterial.EnableKeyword(ShaderParams.SKW_ID_EXCLUSION);
fusionMaterial.SetFloatArray(ShaderParams.ExclusionMask, exclusionMask);
}
else {
fusionMaterial.DisableKeyword(ShaderParams.SKW_ID_EXCLUSION);
}
}
else {
fusionMaterial.DisableKeyword(ShaderParams.SKW_ID_EXCLUSION);
}
}
// -----------------------------------------------------------------------------------
// Classic execution
// -----------------------------------------------------------------------------------
public override void Execute (ScriptableRenderContext context, ref RenderingData renderingData) {
if (feature == null) return;
var settings = VolumeManager.instance.stack.GetComponent<EdgeFusion>();
if (settings == null || !settings.IsActive()) return;
if (objectIDMaterial == null || fusionMaterial == null || fusionFillMaterial == null) {
InitializeMaterials();
if (objectIDMaterial == null || fusionMaterial == null || fusionFillMaterial == null) return;
}
ref var cameraData = ref renderingData.cameraData;
if (EdgeFusionRenderFeature.IsDepthOnlyTarget(cameraData.cameraTargetDescriptor)) return;
var renderer = cameraData.renderer;
RTHandle cameraColorTargetHandle = renderer.cameraColorTargetHandle;
RTHandle cameraDepthTargetHandle = renderer.cameraDepthTargetHandle;
if (cameraColorTargetHandle == null) return;
CommandBuffer cmd = CommandBufferPool.Get(PROFILING_NAME);
using (new ProfilingScope(cmd, profilingSampler)) {
bool cameraUsesMsaa = cameraData.cameraTargetDescriptor.msaaSamples > 1;
bool taa = cameraData.antialiasing == AntialiasingMode.TemporalAntiAliasing && !cameraUsesMsaa;
int cameraCullingMask = cameraData.camera.cullingMask;
int effectiveBlendLayers = settings.blendLayers.value & cameraCullingMask;
int effectiveDoubleSided = settings.doubleSidedLayers.value & cameraCullingMask;
int effectiveSpecialGroup = settings.specialGroupLayers.value & cameraCullingMask;
uint rlMaskSingle = settings.renderingLayerFilter.value;
uint rlMaskDouble = settings.doubleSidedRenderingLayerFilter.value;
uint rlMaskSpecial = settings.specialGroupRenderingLayerFilter.value;
int ssMask = effectiveBlendLayers;
int dsMask = effectiveDoubleSided;
int specialMask = effectiveSpecialGroup;
if ((dsMask & specialMask) != 0 && RenderingLayersOverlap(rlMaskSpecial, rlMaskDouble)) {
dsMask &= ~specialMask;
}
if ((ssMask & specialMask) != 0 && RenderingLayersOverlap(rlMaskSpecial, rlMaskSingle)) {
ssMask &= ~specialMask;
}
if ((ssMask & dsMask) != 0 && RenderingLayersOverlap(rlMaskDouble, rlMaskSingle)) {
ssMask &= ~dsMask;
}
bool hasSingleSided = ssMask != 0 && rlMaskSingle != 0u;
bool hasDoubleSided = dsMask != 0 && rlMaskDouble != 0u;
bool hasSpecialGroup = specialMask != 0 && rlMaskSpecial != 0u;
uint specialGroupCombined = hasSpecialGroup ? rlMaskSpecial : 0u;
if (!hasSingleSided && !hasDoubleSided && !hasSpecialGroup) {
CommandBufferPool.Release(cmd);
return;
}
float effectiveMaxBlendDistance = settings.maxBlendDistance.value;
if (cameraData.camera.orthographic) {
effectiveMaxBlendDistance = 1e10f;
}
UpdateMaterialProperties(settings, taa, effectiveMaxBlendDistance, cameraUsesMsaa, hasSpecialGroup);
var baseDesc = cameraData.cameraTargetDescriptor;
// Kept for parity/documentation with the original camera-stack handling; the classic
// renderer already shares cameraColorTargetHandle between base and overlay cameras, so no
// extra copy-back is required (see the note at the bottom of this method).
bool isStackedBase = cameraData.camera.TryGetComponent(out UniversalAdditionalCameraData additionalCameraData)
&& additionalCameraData.cameraStack != null && additionalCameraData.cameraStack.Count > 0;
// ---- Working copy of the pre-effect camera color (blend/compare source) ----
var colorCopyDesc = baseDesc;
colorCopyDesc.depthBufferBits = 0;
colorCopyDesc.msaaSamples = 1;
RenderingUtils.ReAllocateIfNeeded(ref cameraColorCopyHandle, colorCopyDesc, name: CAMERA_COLOR_TEXTURE_NAME);
Blitter.BlitCameraTexture(cmd, cameraColorTargetHandle, cameraColorCopyHandle);
RTHandle colorTarget = cameraColorTargetHandle;
// ---- ObjectID texture ----
var objIdDesc = baseDesc;
bool forcedRGBA32F = settings.enableIntraObjectFusion.value || settings.debugMode.value == DebugMode.Normals;
objIdDesc.graphicsFormat = forcedRGBA32F ? GraphicsFormat.R32G32B32A32_SFloat : objectIdTextureFormat;
objIdDesc.depthBufferBits = 0;
objIdDesc.msaaSamples = 1;
RenderingUtils.ReAllocateIfNeeded(ref objectIDHandle, objIdDesc, name: OBJECT_ID_TEXTURE_NAME);
Color clearColor = SystemInfo.usesReversedZBuffer ? Color.clear : new Color(0, 1, 0, 0);
// ---- Special-group marker texture ----
bool useCustomGroups = hasSpecialGroup;
if (useCustomGroups) {
var customDesc = objIdDesc;
RenderingUtils.ReAllocateIfNeeded(ref customGroupHandle, customDesc, name: CUSTOM_GROUP_TEXTURE_NAME);
}
// ---- Depth used while filling the ObjectID buffer ----
RTHandle depthForObjectID;
if (cameraUsesMsaa) {
var objIdDepthDesc = baseDesc;
objIdDepthDesc.msaaSamples = 1;
objIdDepthDesc.graphicsFormat = GraphicsFormat.None;
objIdDepthDesc.depthBufferBits = 24;
RenderingUtils.ReAllocateIfNeeded(ref objectIDDepthHandle, objIdDepthDesc, name: OBJECT_ID_DEPTH_TEXTURE_NAME);
depthForObjectID = objectIDDepthHandle;
}
else {
// No MSAA: reuse camera depth directly (read/testable, matches original ZTest.Equal setup)
depthForObjectID = cameraDepthTargetHandle != null ? cameraDepthTargetHandle : objectIDDepthHandle;
}
// =========================== 1) ObjectID pass ===========================
// Only clear depth when we own a dedicated depth buffer (MSAA path). In the non-MSAA
// path depthForObjectID is the camera's shared depth target, already populated by the
// opaque pass and needed as-is for the ZTest.Equal comparison below (and by later passes
// that sample _CameraDepthTexture) - clearing it here would corrupt it for the rest of the frame.
ClearFlag objectIdClearFlag = cameraUsesMsaa ? ClearFlag.All : ClearFlag.Color;
CoreUtils.SetRenderTarget(cmd, objectIDHandle, depthForObjectID, objectIdClearFlag, clearColor);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
var drawSettingsObjId = CreateDrawingSettings(shaderTags, ref renderingData, SortingCriteria.CommonOpaque);
drawSettingsObjId.overrideMaterial = objectIDMaterial;
drawSettingsObjId.overrideMaterialPassIndex = 0;
drawSettingsObjId.perObjectData = PerObjectData.None;
drawSettingsObjId.enableInstancing = true;
if (hasSingleSided) {
cmd.SetGlobalInt(ShaderParams.Cull, (int)CullMode.Back);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
var filterSingle = new FilteringSettings(RenderQueueRange.opaque, ssMask, rlMaskSingle);
context.DrawRenderers(renderingData.cullResults, ref drawSettingsObjId, ref filterSingle);
}
if (hasDoubleSided) {
cmd.SetGlobalInt(ShaderParams.Cull, (int)CullMode.Off);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
var filterDouble = new FilteringSettings(RenderQueueRange.opaque, dsMask, rlMaskDouble);
context.DrawRenderers(renderingData.cullResults, ref drawSettingsObjId, ref filterDouble);
cmd.SetGlobalInt(ShaderParams.Cull, (int)CullMode.Back);
}
// =========================== 2) Special-group pass ===========================
if (useCustomGroups) {
CoreUtils.SetRenderTarget(cmd, customGroupHandle, depthForObjectID, ClearFlag.Color, Color.black);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
var drawSettingsSpecial = CreateDrawingSettings(shaderTags, ref renderingData, SortingCriteria.CommonOpaque);
drawSettingsSpecial.overrideMaterial = null; // use original materials to preserve displacement
drawSettingsSpecial.enableInstancing = true;
var filterCustom = new FilteringSettings(RenderQueueRange.opaque, specialMask, specialGroupCombined);
context.DrawRenderers(renderingData.cullResults, ref drawSettingsSpecial, ref filterCustom);
}
// =========================== 3) Fill ObjectID pass ===========================
int layerUnion = ssMask | dsMask;
bool layersExcluded = layerUnion != cameraCullingMask;
bool renderingLayersExcluded = (rlMaskSingle != uint.MaxValue) || (rlMaskDouble != uint.MaxValue) || (rlMaskSpecial != uint.MaxValue);
bool needsOthersFill = (layersExcluded || renderingLayersExcluded) && settings.blendWithOthers.value;
RTHandle objectIDForBlend = objectIDHandle;
if (useCustomGroups || needsOthersFill) {
fusionFillMaterial.SetFloat(ShaderParams.TerrainObjectId, settings.blendWithOthers.value ? 31f : 0f);
RenderingUtils.ReAllocateIfNeeded(ref objectIDFilledHandle, objIdDesc, name: OBJECT_ID_FILLED_TEXTURE_NAME);
cmd.SetGlobalTexture(ShaderParams.ObjectIDTexture, objectIDHandle);
if (useCustomGroups) {
cmd.SetGlobalTexture(ShaderParams.CustomGroupTexture, customGroupHandle);
}
CoreUtils.SetRenderTarget(cmd, objectIDFilledHandle, ClearFlag.None, Color.clear);
CoreUtils.DrawFullScreen(cmd, fusionFillMaterial, null, ShaderParams.FillPassIndex);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
objectIDForBlend = objectIDFilledHandle;
}
// =========================== 4) Blend pass ===========================
bool compareActive = settings.compareMode.value && settings.debugMode.value == DebugMode.None;
if (compareActive) {
RenderingUtils.ReAllocateIfNeeded(ref compareHandle, colorCopyDesc, name: COMPARE_TEXTURE_NAME);
}
cmd.SetGlobalTexture(ShaderParams.SrcColorTexture, cameraColorCopyHandle);
cmd.SetGlobalTexture(ShaderParams.ObjectIDTexture, objectIDForBlend);
RTHandle blendDestination = (compareActive && compareHandle != null) ? compareHandle : colorTarget;
CoreUtils.SetRenderTarget(cmd, blendDestination, ClearFlag.None, Color.clear);
CoreUtils.DrawFullScreen(cmd, fusionMaterial, null, (int)ShaderParams.Passes.Blend);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
// =========================== 5) Compare pass ===========================
if (compareActive && compareHandle != null) {
float angle = settings.compareSameSide.value ? Mathf.PI * 0.5f : settings.compareLineAngle.value;
Vector4 compareParamsValue = new Vector4(Mathf.Cos(angle), Mathf.Sin(angle), settings.compareSameSide.value ? settings.comparePanning.value : -10f, settings.compareLineWidth.value);
Color lineColor = settings.compareLineColor.value;
Vector4 compareLineColor = new Vector4(lineColor.r, lineColor.g, lineColor.b, lineColor.a);
cmd.SetGlobalTexture(ShaderParams.SrcColorTexture, cameraColorCopyHandle);
cmd.SetGlobalTexture(ShaderParams.CompareTex, compareHandle);
cmd.SetGlobalVector(ShaderParams.CompareParams, compareParamsValue);
cmd.SetGlobalVector(ShaderParams.CompareLineColor, compareLineColor);
CoreUtils.SetRenderTarget(cmd, colorTarget, ClearFlag.None, Color.clear);
CoreUtils.DrawFullScreen(cmd, fusionMaterial, null, (int)ShaderParams.Passes.Compare);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
}
// =========================== 6) Debug pass ===========================
if (!compareActive && settings.debugMode.value != DebugMode.None) {
cmd.SetGlobalTexture(ShaderParams.ObjectIDTexture, objectIDForBlend);
CoreUtils.SetRenderTarget(cmd, colorTarget, ClearFlag.None, Color.clear);
CoreUtils.DrawFullScreen(cmd, fusionMaterial, null, (int)ShaderParams.Passes.Debug);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
}
// NOTE on camera stacking: the Unity 6 / Render Graph version has to reroute
// resourceData.cameraColor to a fresh texture and then copy it back into the shared stack
// color at the end, because render-graph resources are re-requested every frame. The
// classic (2022.3) renderer already gives base and overlay cameras the SAME persistent
// cameraColorTargetHandle, and every pass above wrote directly into `colorTarget`
// (== cameraColorTargetHandle), so overlay cameras in the stack already see the result -
// no extra copy-back blit is needed here. `isStackedBase` is kept above only for
// documentation / in case you need to special-case stacked cameras later.
_ = isStackedBase;
}
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
CommandBufferPool.Release(cmd);
}
static bool RenderingLayersOverlap (uint maskA, uint maskB) {
if (maskA == 0u || maskB == 0u) return false;
if (maskA == uint.MaxValue || maskB == uint.MaxValue) return true;
return (maskA & maskB) != 0u;
}
static IdExclusionPair[] GetActiveExclusionPairs () {
if (cachedExclusionVolume != null && cachedExclusionVolume.isActiveAndEnabled && cachedEdgeFusion != null) {
return cachedEdgeFusion.idExclusionPairs;
}
cachedExclusionVolume = null;
cachedEdgeFusion = null;
// Unity 2022.3: Object.FindObjectsByType does not exist yet - use the classic (obsolete but
// functional) FindObjectsOfType instead of the Unity 6 FindObjectsByType overload.
var volumes = Object.FindObjectsOfType<Volume>();
int volumeCount = volumes.Length;
for (int i = 0; i < volumeCount; i++) {
var volume = volumes[i];
if (volume == null || !volume.isActiveAndEnabled || volume.sharedProfile == null) continue;
if (!volume.sharedProfile.TryGet<EdgeFusion>(out var ef)) continue;
if (ef.idExclusionPairs != null) {
cachedExclusionVolume = volume;
cachedEdgeFusion = ef;
return cachedEdgeFusion.idExclusionPairs;
}
}
return null;
}
public void Cleanup () {
CoreUtils.Destroy(objectIDMaterial);
CoreUtils.Destroy(fusionMaterial);
CoreUtils.Destroy(fusionFillMaterial);
objectIDHandle?.Release();
objectIDFilledHandle?.Release();
objectIDDepthHandle?.Release();
customGroupHandle?.Release();
compareHandle?.Release();
cameraColorCopyHandle?.Release();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a3328f16041cee34b8fc0db1a14cdf0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,65 @@
using UnityEngine;
namespace EdgeFusion {
public static class ShaderParams {
public enum Passes {
Blend = 0,
Debug = 1,
Compare = 2
}
public const int FillPassIndex = 0;
// ========== Texture Properties ==========
public static readonly int ObjectIDTexture = Shader.PropertyToID("_ObjectIDTexture");
public static readonly int SrcColorTexture = Shader.PropertyToID("_SrcColorTexture");
public static readonly int CompareTex = Shader.PropertyToID("_CompareTex");
public static readonly int NoiseTex3D = Shader.PropertyToID("_NoiseTex3D");
public static readonly int CustomGroupTexture = Shader.PropertyToID("_CustomGroupTexture");
// ========== ObjectID Pass Parameters ==========
public static readonly int EdgeFusionRadius = Shader.PropertyToID("_EdgeFusionRadius");
public static readonly int DefaultRadiusWorld = Shader.PropertyToID("_DefaultRadiusWorld");
public static readonly int RadiusScale = Shader.PropertyToID("_RadiusScale");
public static readonly int MaxBlendDistance = Shader.PropertyToID("_MaxBlendDistance");
public static readonly int DistanceCompensation = Shader.PropertyToID("_DistanceCompensation");
public static readonly int TerrainObjectId = Shader.PropertyToID("_TerrainObjectId");
public static readonly int ZWrite = Shader.PropertyToID("_ZWrite");
public static readonly int ZTest = Shader.PropertyToID("_ZTest");
public static readonly int Cull = Shader.PropertyToID("_Cull");
public static readonly int CustomObjectId = Shader.PropertyToID("_CustomObjectId");
public static readonly int DisallowIntraFusion = Shader.PropertyToID("_DisallowIntraFusion");
// ========== Blend Pass Parameters ==========
public static readonly int BlendData1 = Shader.PropertyToID("_BlendData1"); // x: GlobalIntensity, y: MaxBlendDistance
public static readonly int BlendData2 = Shader.PropertyToID("_BlendData2"); // x: MaxScreenRadius, y: ShadowProtection, z: NoiseIntensity, w: NoiseScale
public static readonly int SampleCount = Shader.PropertyToID("_SampleCount");
public static readonly int BinarySearchSteps = Shader.PropertyToID("_BinarySearchSteps");
public static readonly int JitterFrame = Shader.PropertyToID("_JitterFrame");
public static readonly int EarlyExitHits = Shader.PropertyToID("_EarlyExitHits");
public static readonly int CompareParams = Shader.PropertyToID("_CompareParams");
public static readonly int CompareLineColor = Shader.PropertyToID("_CompareLineColor");
public static readonly int DepthDebugMultiplier = Shader.PropertyToID("_DepthDebugMultiplier");
public static readonly int DebugMode = Shader.PropertyToID("_DebugMode");
public static readonly int MsaaFixPower = Shader.PropertyToID("_MSAAFixPower");
// ========== ID Exclusion Parameters ==========
public static readonly int ExclusionMask = Shader.PropertyToID("_ExclusionMask");
// ========== Shader Keywords ==========
public const string SKW_DEBUG_BLEND_NORMALS = "EDGE_FUSION_DEBUG_BLEND_NORMALS";
public const string SKW_INTRA_OBJECT_FUSION = "EDGE_FUSION_INTRA_OBJECT";
public const string SKW_ENABLE_JITTER = "EDGE_FUSION_ENABLE_JITTER";
public const string SKW_NOISE = "EDGE_FUSION_NOISE";
public const string SKW_CONCAVE_ONLY = "EDGE_FUSION_CONCAVE_ONLY";
public const string SKW_SPECIAL_GROUP = "EDGE_FUSION_SPECIAL_GROUP";
public const string SKW_MSAA_ON = "EDGE_FUSION_MSAA_ON";
public const string SKW_MSAA_EDGE_FIX = "EDGE_FUSION_MSAA_EDGE_FIX";
public const string SKW_ID_EXCLUSION = "EDGE_FUSION_ID_EXCLUSION";
public const string SKW_ANTI_FLICKER = "EDGE_FUSION_ANTI_FLICKER";
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 493b1e6314df04c40b747bddf88b7184
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: