2026-03-18 허수아비 추가

This commit is contained in:
2026-03-18 18:06:38 +09:00
parent acf120a837
commit c7ae384376
47 changed files with 1567 additions and 170701 deletions

Binary file not shown.

View File

@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 50ffa7506ebaa5a4b8a92c160c4bfa2a
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 327778
packageName: Outline Plus - Post Processing Edge Detection for URP
packageVersion: 1.0
assetPath: Assets/Ilumisoft/Outline Plus/Get Started.pdf
uploadId: 782589

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5a22abadb745a2a45ab95a0840e52cff
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8c8fd3bfbcdb32940886b38f2fb2f287
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
using UnityEditor;
namespace Ilumisoft.Rendering
{
[CustomEditor(typeof(OutlineRendererFeature))]
public class OutlineRendererFeatureEditor : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
EditorGUILayout.HelpBox("Add the Outline override to a Post-processing Volume to further adjust the appearance of the outlines.", MessageType.Info);
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 52c9e5f2c261c9e4f83f233c1ead1899
AssetOrigin:
serializedVersion: 1
productId: 327778
packageName: Outline Plus - Post Processing Edge Detection for URP
packageVersion: 1.0
assetPath: Assets/Ilumisoft/Outline Plus/Scripts/Editor/OutlineRendererFeatureEditor.cs
uploadId: 782589

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0e32bd9ee22bd924997a1de85dba93f5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,206 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;
using UnityEngine.Rendering.Universal;
namespace Ilumisoft.Rendering
{
[SupportedOnRenderer(typeof(UniversalRendererData))]
[DisallowMultipleRendererFeature("Outline")]
public class OutlineRendererFeature : ScriptableRendererFeature
{
public enum InjectionPoint
{
BeforeRenderingTransparents = 450,
BeforeRenderingPostProcessing = 550
}
public enum OutlineMode
{
DepthOnly,
[InspectorName("Depth + Normal")]
DepthNormal
}
public struct Settings
{
public OutlineMode Mode;
public bool ScaleWithResolution;
public int ReferenceHeight;
}
class OutlineRenderPass : ScriptableRenderPass
{
private readonly int LUMINANCE_CONTRAST = Shader.PropertyToID("_LuminanceContrast");
private readonly int LUMINANCE_POWER = Shader.PropertyToID("_LuminancePower");
private readonly int BACKGROUND_COLOR = Shader.PropertyToID("_BackgroundColor");
private readonly int BACKGROUND_COLOR_OPACITY = Shader.PropertyToID("_BackgroundColorOpacity");
private readonly int DEPTH_EDGE = Shader.PropertyToID("_DepthEdge");
private readonly int NORMAL_EDGE = Shader.PropertyToID("_NormalEdge");
private readonly int IS_FADE_ENABLED = Shader.PropertyToID("_IsFadeEnabled");
private readonly int FADE_START = Shader.PropertyToID("_FadeStart");
private readonly int FADE_END = Shader.PropertyToID("_FadeEnd");
private readonly int REFERENCE_HEIGHT = Shader.PropertyToID("_ReferenceHeight");
private readonly int OUTLINE_THICKNESS_ID = Shader.PropertyToID("_OutlineThickness");
private readonly int OUTLINE_COLOR_ID = Shader.PropertyToID("_OutlineColor");
Material material;
Settings settings;
public void Setup(Material material, Settings settings)
{
this.material = material;
this.settings = settings;
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
var volumeComponent = VolumeManager.instance.stack.GetComponent<OutlineVolumeComponent>();
// Get settings from volume component
int thickness = volumeComponent.thickness.value;
Color outlineColor = volumeComponent.outlineColor.value;
Color backgroundColor = volumeComponent.backgroundColor.value;
bool isDistanceFadeEnabled = volumeComponent.distanceFade.value;
float distanceFadeStart = volumeComponent.fadeStart.value;
float distanceFadeDistance = volumeComponent.fadeDistance.value;
bool backgroundFill = volumeComponent.backgroundFill.value;
Vector2 depthEdge = volumeComponent.depthSmoothstep.value;
Vector2 normalEdge = volumeComponent.normalSmoothstep.value;
float luminancePower = volumeComponent.luminanceDetail.value;
float luminanceContrast = volumeComponent.luminanceContrast.value;
int referenceHeight = settings.ReferenceHeight;
// Cancel if outline are disabled
if (thickness == 0)
{
return;
}
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
var sourceHandle = resourceData.activeColorTexture;
var descriptor = sourceHandle.GetDescriptor(renderGraph);
descriptor.clearBuffer = false;
descriptor.name = "_CameraColorOutline";
if (!sourceHandle.IsValid())
{
return;
}
// Get current image height if outlines should not be scaled by a reference resolution
if (!settings.ScaleWithResolution)
{
referenceHeight = descriptor.height;
}
// Set material properties
material.SetColor(OUTLINE_COLOR_ID, outlineColor);
material.SetInt(OUTLINE_THICKNESS_ID, thickness);
material.SetInt(REFERENCE_HEIGHT, referenceHeight);
material.SetInt(IS_FADE_ENABLED, isDistanceFadeEnabled ? 1 : 0);
material.SetFloat(FADE_START, distanceFadeStart);
material.SetFloat(FADE_END, distanceFadeStart + distanceFadeDistance);
material.SetColor(BACKGROUND_COLOR, backgroundColor);
material.SetFloat(BACKGROUND_COLOR_OPACITY, backgroundFill ? 1 : 0);
material.SetVector(DEPTH_EDGE, depthEdge);
material.SetVector(NORMAL_EDGE, normalEdge);
material.SetFloat(LUMINANCE_POWER, luminancePower);
material.SetFloat(LUMINANCE_CONTRAST, luminanceContrast);
// Outline blit
TextureHandle targetHandle = renderGraph.CreateTexture(descriptor);
var parameters = new RenderGraphUtils.BlitMaterialParameters(sourceHandle, targetHandle, material, (int)settings.Mode);
renderGraph.AddBlitPass(parameters, passName: "Draw Outlines");
resourceData.cameraColor = targetHandle;
}
}
[Tooltip("Specifies where in the frame this pass will be injected.")]
public InjectionPoint injectionPoint = InjectionPoint.BeforeRenderingTransparents;
[Tooltip("Determines which scene data is used for edge detection. 'Depth Only' uses depth differences. 'Depth + Normal' uses surface angle changes as well.")]
public OutlineMode mode = OutlineMode.DepthNormal;
[Tooltip("When enabled, outline thickness scales proportionally with screen resolution to maintain visual consistency across different screen resolutions.")]
public bool scaleWithResolution = true;
[Tooltip("The vertical resolution used as a baseline for outline thickness scaling. A value of 1080 means the effect appears 1:1 at 1080p.")]
[Min(720)]
public int referenceHeight = 1080;
public bool showInSceneView = false;
Shader shader;
Material material;
OutlineRenderPass renderPass;
public override void Create()
{
shader = Shader.Find("Hidden/Ilumisoft/PostProcessing/Outline");
if (shader == null)
{
Debug.LogWarning("Outline Renderer Feature: Could not find outline shader");
return;
}
material = CoreUtils.CreateEngineMaterial(shader);
renderPass = new OutlineRenderPass();
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (renderPass == null || material == null)
{
return;
}
if (renderingData.cameraData.cameraType == CameraType.Preview || renderingData.cameraData.cameraType == CameraType.Reflection || UniversalRenderer.IsOffscreenDepthTexture(ref renderingData.cameraData))
{
return;
}
if (renderingData.cameraData.cameraType != CameraType.Game && !(showInSceneView && renderingData.cameraData.cameraType == CameraType.SceneView))
{
return;
}
var inputRequirements = ScriptableRenderPassInput.Depth;
if (mode == OutlineMode.DepthNormal)
{
inputRequirements |= ScriptableRenderPassInput.Normal;
}
renderPass.ConfigureInput(inputRequirements);
renderPass.requiresIntermediateTexture = true;
renderPass.renderPassEvent = injectionPoint switch
{
InjectionPoint.BeforeRenderingTransparents => RenderPassEvent.BeforeRenderingTransparents,
InjectionPoint.BeforeRenderingPostProcessing => RenderPassEvent.BeforeRenderingPostProcessing,
_ => RenderPassEvent.BeforeRenderingTransparents,
};
renderPass.Setup(material, new Settings()
{
Mode = mode,
ReferenceHeight = referenceHeight,
ScaleWithResolution = scaleWithResolution
});
renderer.EnqueuePass(renderPass);
}
protected override void Dispose(bool disposing)
{
CoreUtils.Destroy(material);
renderPass = null;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: fb259e2f978090e4f987a7c376e9b952
AssetOrigin:
serializedVersion: 1
productId: 327778
packageName: Outline Plus - Post Processing Edge Detection for URP
packageVersion: 1.0
assetPath: Assets/Ilumisoft/Outline Plus/Scripts/Runtime/OutlineRendererFeature.cs
uploadId: 782589

View File

@@ -0,0 +1,57 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace Ilumisoft.Rendering
{
[Serializable]
[DisplayInfo(name = "Outline")]
[VolumeComponentMenu("Post-processing/Outline")]
[VolumeRequiresRendererFeatures(typeof(OutlineRendererFeature))]
public class OutlineVolumeComponent : VolumeComponent
{
[Header("Outline Settings")]
[Tooltip("The width of the outline in pixels. A value of 0 will disable outlines.")]
public ClampedIntParameter thickness = new ClampedIntParameter(1, 0, 4);
[Tooltip("The color used for the outline.")]
public ColorParameter outlineColor = new ColorParameter(Color.black);
[Header("Edge Detection Sensitivity")]
[Tooltip("Depth sensitivity for edge detection. Defines the lower and upper threshold used in the smoothstep function. Smaller values make the effect more sensitive to depth differences.")]
public FloatRangeParameter depthSmoothstep = new FloatRangeParameter(new Vector2(0.1f, 0.2f), 0, 1);
[Tooltip("Normal sensitivity for edge detection. Defines the lower and upper threshold used in the smoothstep function. Smaller values make the effect more sensitive to surface angle changes.")]
public FloatRangeParameter normalSmoothstep = new FloatRangeParameter(new Vector2(0.2f, 0.7f), 0, 1);
[Header("Background Fill (Optional)")]
[Tooltip("Enable fill of the background color.")]
public BoolParameter backgroundFill = new BoolParameter(false);
[Tooltip("Optional background color fill. Only visible if 'Background Fill' is enabled.")]
public ColorParameter backgroundColor = new ColorParameter(Color.white);
[Tooltip("Controls how much detail from the original images luminance is preserved in the background fill. A value of 0 results in a flat fill, 1 keeps full luminance detail.")]
public ClampedFloatParameter luminanceDetail = new ClampedFloatParameter(1, 0, 1);
[Tooltip("Applies a contrast adjustment to the luminance before blending with the fill color. Higher values increase the brightness difference between dark and light areas.")]
public MinFloatParameter luminanceContrast = new MinFloatParameter(1, 0);
[Header("Distance-Based Fading")]
[Tooltip("Enable distance-based fading of the outline effect.")]
public BoolParameter distanceFade = new BoolParameter(false);
[Tooltip("The distance from the camera (in metres) at which outline fading begins. Only used if Distance Fade is enabled.")]
public MinFloatParameter fadeStart = new MinFloatParameter(0, 0);
[Tooltip("How far from the fade start point (in metres) the outlines will fully fade out. Only used if Distance Fade is enabled.")]
public MinFloatParameter fadeDistance = new MinFloatParameter(100, 0);
protected override void OnEnable()
{
base.OnEnable();
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: ffbcdfc145ceaa7468c1bc9b6c4e3e9e
AssetOrigin:
serializedVersion: 1
productId: 327778
packageName: Outline Plus - Post Processing Edge Detection for URP
packageVersion: 1.0
assetPath: Assets/Ilumisoft/Outline Plus/Scripts/Runtime/OutlineVolumeComponent.cs
uploadId: 782589

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8e30cc0484d05e748a85bc726b197657
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,203 @@
Shader "Hidden/Ilumisoft/PostProcessing/Outline"
{
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl"
float4 _OutlineColor;
float4 _BackgroundColor;
float _BackgroundColorOpacity;
float _ReferenceHeight;
int _OutlineThickness;
int _IsFadeEnabled;
float _FadeStart;
float _FadeEnd;
float2 _DepthEdge;
float2 _NormalEdge;
float _LuminancePower;
float _LuminanceContrast;
// Samples the scene normals remapped to [0,1]
inline float3 SampleNormal(float2 uv)
{
return SampleSceneNormals(uv) * 0.5 + 0.5;
}
// Samples the scene color
inline float3 SampleColor(float2 uv)
{
return SAMPLE_TEXTURE2D(_BlitTexture,sampler_LinearClamp, uv).rgb;
}
// Samples the scene depth linear01
inline float SampleDepthLinear01(float2 uv)
{
return Linear01Depth(SampleSceneDepth(uv),_ZBufferParams);
}
float GetNormalOutline(float3 topLeft, float3 bottomRight, float3 topRight, float3 bottomLeft)
{
float3 delta = abs(topLeft-bottomRight) + abs(topRight-bottomLeft);
float normalOutline = saturate(max(delta.r, max(delta.g, delta.b)));
return smoothstep(_NormalEdge.x, _NormalEdge.y, normalOutline);
}
float GetDepthOutline(float topLeft, float bottomRight, float topRight, float bottomLeft)
{
float result = abs(topLeft - bottomRight) + abs(topRight - bottomLeft);
result /= max(topLeft, max(bottomRight, max(topRight, bottomLeft)));
return smoothstep(_DepthEdge.x, _DepthEdge.y, saturate(result));
}
inline float InverseLerp(float a, float b, float t)
{
return saturate((t-a)/(b-a));
}
float LuminancePowerContrast(float3 color, float power, float contrast)
{
float luminance = pow(saturate(Luminance(color)), power);
float midpoint = pow(0.5, 2.2);
return saturate((luminance - midpoint) * contrast + midpoint);
}
float4 OutlineDepthOnly (Varyings input) : SV_Target
{
float2 offset = _OutlineThickness * _BlitTexture_TexelSize.xy*_ScreenParams.y/_ReferenceHeight;
float2 centerUV = input.texcoord;
// Sample color and depth of the current pixel
float3 centerColor = SampleColor(centerUV);
float centerDepth = SampleSceneDepth(centerUV);
float distance = LinearEyeDepth(centerDepth,_ZBufferParams);
centerDepth = Linear01Depth(centerDepth,_ZBufferParams);
float cornerDepths[4];
float2 cornerUVs[4];
// Create corner UVs
cornerUVs[0] = centerUV + float2(-offset.x, offset.y);
cornerUVs[1] = centerUV - float2(-offset.x, offset.y);
cornerUVs[2] = centerUV + offset;
cornerUVs[3] = centerUV - offset;
[unroll]
for(int i=0; i<4; i++)
{
// depth
cornerDepths[i] = SampleDepthLinear01(cornerUVs[i]);
// Discard values with a lower depth
cornerDepths[i] = (cornerDepths[i]>centerDepth) ? cornerDepths[i] : centerDepth;
}
// Compute outline
float outline = GetDepthOutline(cornerDepths[0], cornerDepths[1], cornerDepths[2], cornerDepths[3]);
// Apply distance fade
outline *= 1.0 - InverseLerp(_FadeStart, _FadeEnd, distance) * _IsFadeEnabled;
// Apply background color fill
float3 color = LuminancePowerContrast(centerColor, _LuminancePower, _LuminanceContrast) * _BackgroundColor.rgb;
color = lerp(centerColor, color, _BackgroundColorOpacity);
// Apply outline
color = lerp(color, _OutlineColor.rgb, outline*_OutlineColor.a);
return float4(color, 1.0);
}
float4 OutlineDepthNormal (Varyings input) : SV_Target
{
float2 offset = _OutlineThickness * _BlitTexture_TexelSize.xy*_ScreenParams.y/_ReferenceHeight;
float2 centerUV = input.texcoord;
// Sample color, depth and normal of the current pixel
float3 centerNormal = SampleNormal(centerUV);
float3 centerColor = SampleColor(centerUV);
float centerDepth = SampleSceneDepth(centerUV);
float distance = LinearEyeDepth(centerDepth,_ZBufferParams);
centerDepth = Linear01Depth(centerDepth,_ZBufferParams);
float3 cornerNormals[4];
float cornerDepths[4];
float2 cornerUVs[4];
// Create corner UVs
cornerUVs[0] = centerUV + float2(-offset.x, offset.y);
cornerUVs[1] = centerUV - float2(-offset.x, offset.y);
cornerUVs[2] = centerUV + offset;
cornerUVs[3] = centerUV - offset;
[unroll]
for(int i=0; i<4; i++)
{
// sample normal and depth
cornerNormals[i] = SampleNormal(cornerUVs[i]);
cornerDepths[i] = SampleDepthLinear01(cornerUVs[i]);
// Discard values with a lower depth
cornerNormals[i] = (cornerDepths[i]>centerDepth) ? cornerNormals[i] : centerNormal;
cornerDepths[i] = (cornerDepths[i]>centerDepth) ? cornerDepths[i] : centerDepth;
}
// Compute outline
float normalOutline = GetNormalOutline(cornerNormals[0], cornerNormals[1], cornerNormals[2], cornerNormals[3]);
float depthOutline = GetDepthOutline(cornerDepths[0], cornerDepths[1], cornerDepths[2], cornerDepths[3]);
float outline = max(normalOutline, depthOutline);
// Apply distance fade
outline *= 1.0 - InverseLerp(_FadeStart, _FadeEnd, distance) * _IsFadeEnabled;
// Apply background color fill
float3 color = LuminancePowerContrast(centerColor, _LuminancePower, _LuminanceContrast) * _BackgroundColor.rgb;
color = lerp(centerColor, color, _BackgroundColorOpacity);
// Apply outline
color = lerp(color, _OutlineColor.rgb, outline*_OutlineColor.a);
return float4(color, 1.0);
}
ENDHLSL
SubShader
{
Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"}
LOD 100
ZWrite Off Cull Off
Pass
{
Name "OutlineDepthOnlyPass"
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment OutlineDepthOnly
ENDHLSL
}
Pass
{
Name "OutlineDepthNormalPass"
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment OutlineDepthNormal
ENDHLSL
}
}
}

View File

@@ -0,0 +1,16 @@
fileFormatVersion: 2
guid: e345fb186ff59814ea62283f99352b37
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 327778
packageName: Outline Plus - Post Processing Edge Detection for URP
packageVersion: 1.0
assetPath: Assets/Ilumisoft/Outline Plus/Shaders/OutlineShader.shader
uploadId: 782589