parent
1e5428816d
commit
bbb6cd59e6
9 changed files with 284 additions and 2 deletions
@ -0,0 +1,8 @@ |
||||
fileFormatVersion: 2 |
||||
guid: 2c68054ffd8fd3345bea8887a0f038e2 |
||||
folderAsset: yes |
||||
DefaultImporter: |
||||
externalObjects: {} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
||||
@ -0,0 +1,8 @@ |
||||
fileFormatVersion: 2 |
||||
guid: df079c0fdb908c94c9f648fdda464782 |
||||
folderAsset: yes |
||||
DefaultImporter: |
||||
externalObjects: {} |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
||||
@ -0,0 +1,101 @@ |
||||
Shader "Custom/TiltShift" |
||||
{ |
||||
SubShader |
||||
{ |
||||
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" } |
||||
ZTest Always ZWrite Off Cull Off Blend Off |
||||
|
||||
HLSLINCLUDE |
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" |
||||
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl" |
||||
|
||||
float _TiltShift_CenterOffset; |
||||
float _TiltShift_FocusWidth; |
||||
float _TiltShift_FalloffRange; |
||||
float _TiltShift_MaxBlurRadius; |
||||
int _TiltShift_SampleCount; |
||||
|
||||
// _BlitTexture and _BlitTexture_TexelSize are provided by Blit.hlsl |
||||
// _BlitTexture_TexelSize: (1/w, 1/h, w, h) |
||||
// sampler_LinearClamp is provided by GlobalSamplers.hlsl (included via Blit.hlsl) |
||||
|
||||
// Returns blur radius in pixels for a given vertical UV coordinate. |
||||
float ComputeBlurRadius(float uvY) |
||||
{ |
||||
float dist = abs(uvY - 0.5 + _TiltShift_CenterOffset); |
||||
float halfFocus = _TiltShift_FocusWidth * 0.5; |
||||
float range = max(_TiltShift_FalloffRange, 0.001); |
||||
return smoothstep(halfFocus, halfFocus + range, dist) * _TiltShift_MaxBlurRadius; |
||||
} |
||||
|
||||
// Gaussian blur in an arbitrary direction. |
||||
// direction: offset per sample step in UV space (already multiplied by texelSize) |
||||
float4 GaussianBlur(float2 uv, float2 stepUV) |
||||
{ |
||||
int n = max(1, _TiltShift_SampleCount); |
||||
float4 color = 0; |
||||
float totalWeight = 0; |
||||
|
||||
[loop] |
||||
for (int i = -n; i <= n; i++) |
||||
{ |
||||
// t in [-1, 1]; weight peaks at centre and falls near edges. |
||||
float t = float(i) / float(n); |
||||
float weight = exp(-4.5 * t * t); |
||||
float2 sampleUV = uv + stepUV * float(i); |
||||
color += SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, sampleUV, 0) * weight; |
||||
totalWeight += weight; |
||||
} |
||||
|
||||
return color / totalWeight; |
||||
} |
||||
|
||||
float4 HorizontalBlur(Varyings input) : SV_Target |
||||
{ |
||||
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); |
||||
float2 uv = input.texcoord; |
||||
float radius = ComputeBlurRadius(uv.y); |
||||
if (radius < 0.5) |
||||
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, uv, 0); |
||||
|
||||
// stepUV: one step in the horizontal direction, spread over [−radius, +radius] pixels |
||||
int n = max(1, _TiltShift_SampleCount); |
||||
float2 stepUV = float2((radius / float(n)) * _BlitTexture_TexelSize.x, 0.0); |
||||
return GaussianBlur(uv, stepUV); |
||||
} |
||||
|
||||
float4 VerticalBlur(Varyings input) : SV_Target |
||||
{ |
||||
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); |
||||
float2 uv = input.texcoord; |
||||
float radius = ComputeBlurRadius(uv.y); |
||||
if (radius < 0.5) |
||||
return SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearClamp, uv, 0); |
||||
|
||||
int n = max(1, _TiltShift_SampleCount); |
||||
float2 stepUV = float2(0.0, (radius / float(n)) * _BlitTexture_TexelSize.y); |
||||
return GaussianBlur(uv, stepUV); |
||||
} |
||||
ENDHLSL |
||||
|
||||
// Pass 0 — Horizontal blur |
||||
Pass |
||||
{ |
||||
Name "TiltShift_H" |
||||
HLSLPROGRAM |
||||
#pragma vertex Vert |
||||
#pragma fragment HorizontalBlur |
||||
ENDHLSL |
||||
} |
||||
|
||||
// Pass 1 — Vertical blur |
||||
Pass |
||||
{ |
||||
Name "TiltShift_V" |
||||
HLSLPROGRAM |
||||
#pragma vertex Vert |
||||
#pragma fragment VerticalBlur |
||||
ENDHLSL |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,9 @@ |
||||
fileFormatVersion: 2 |
||||
guid: 73dea10312786894ea13fd32ffab89b3 |
||||
ShaderImporter: |
||||
externalObjects: {} |
||||
defaultTextures: [] |
||||
nonModifiableTextures: [] |
||||
userData: |
||||
assetBundleName: |
||||
assetBundleVariant: |
||||
@ -0,0 +1,132 @@ |
||||
using UnityEngine; |
||||
using UnityEngine.Rendering; |
||||
using UnityEngine.Rendering.Universal; |
||||
using UnityEngine.Rendering.RenderGraphModule; |
||||
using UnityEngine.Rendering.RenderGraphModule.Util; |
||||
|
||||
public class TiltShiftFeature : ScriptableRendererFeature |
||||
{ |
||||
[System.Serializable] |
||||
public class Settings |
||||
{ |
||||
[Tooltip("Vertical offset of the sharp focus band from screen centre. Positive = up.")] |
||||
[Range(-0.4f, 0.4f)] |
||||
public float centerOffset = 0f; |
||||
|
||||
[Tooltip("Height of the fully-sharp band as a fraction of screen height.")] |
||||
[Range(0.01f, 0.8f)] |
||||
public float focusWidth = 0.2f; |
||||
|
||||
[Tooltip("Distance over which blur fades in at each edge of the focus band.")] |
||||
[Range(0.01f, 0.4f)] |
||||
public float falloffRange = 0.15f; |
||||
|
||||
[Tooltip("Maximum blur radius in pixels at the extreme top and bottom.")] |
||||
[Range(1f, 64f)] |
||||
public float maxBlurRadius = 20f; |
||||
|
||||
[Tooltip("Samples per side per pass (higher = smoother blur, higher cost).")] |
||||
[Range(2, 20)] |
||||
public int sampleCount = 8; |
||||
|
||||
public RenderPassEvent injectionPoint = RenderPassEvent.AfterRenderingPostProcessing; |
||||
} |
||||
|
||||
public Settings settings = new Settings(); |
||||
|
||||
TiltShiftPass _pass; |
||||
Material _material; |
||||
|
||||
public override void Create() |
||||
{ |
||||
var shader = Shader.Find("Custom/TiltShift"); |
||||
if (shader == null) |
||||
{ |
||||
Debug.LogWarning("[TiltShift] Shader 'Custom/TiltShift' not found. " + |
||||
"Make sure TiltShift.shader is in the project."); |
||||
return; |
||||
} |
||||
|
||||
_material = CoreUtils.CreateEngineMaterial(shader); |
||||
_pass = new TiltShiftPass(_material, settings); |
||||
_pass.renderPassEvent = settings.injectionPoint; |
||||
} |
||||
|
||||
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) |
||||
{ |
||||
if (_material == null || _pass == null) return; |
||||
|
||||
// Skip scene view and preview cameras to avoid visual noise. |
||||
var camType = renderingData.cameraData.cameraType; |
||||
if (camType == CameraType.Preview || camType == CameraType.Reflection) return; |
||||
|
||||
_pass.UpdateSettings(settings); |
||||
renderer.EnqueuePass(_pass); |
||||
} |
||||
|
||||
protected override void Dispose(bool disposing) |
||||
{ |
||||
CoreUtils.Destroy(_material); |
||||
} |
||||
|
||||
// ------------------------------------------------------------------------- |
||||
|
||||
class TiltShiftPass : ScriptableRenderPass |
||||
{ |
||||
static readonly int s_CenterOffset = Shader.PropertyToID("_TiltShift_CenterOffset"); |
||||
static readonly int s_FocusWidth = Shader.PropertyToID("_TiltShift_FocusWidth"); |
||||
static readonly int s_FalloffRange = Shader.PropertyToID("_TiltShift_FalloffRange"); |
||||
static readonly int s_MaxBlurRadius = Shader.PropertyToID("_TiltShift_MaxBlurRadius"); |
||||
static readonly int s_SampleCount = Shader.PropertyToID("_TiltShift_SampleCount"); |
||||
|
||||
readonly Material _material; |
||||
Settings _settings; |
||||
|
||||
public TiltShiftPass(Material material, Settings settings) |
||||
{ |
||||
_material = material; |
||||
_settings = settings; |
||||
requiresIntermediateTexture = true; |
||||
} |
||||
|
||||
public void UpdateSettings(Settings settings) => _settings = settings; |
||||
|
||||
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData) |
||||
{ |
||||
var resourceData = frameData.Get<UniversalResourceData>(); |
||||
|
||||
if (resourceData.isActiveTargetBackBuffer) |
||||
return; |
||||
|
||||
// Push current settings to the material. |
||||
_material.SetFloat(s_CenterOffset, _settings.centerOffset); |
||||
_material.SetFloat(s_FocusWidth, _settings.focusWidth); |
||||
_material.SetFloat(s_FalloffRange, _settings.falloffRange); |
||||
_material.SetFloat(s_MaxBlurRadius, _settings.maxBlurRadius); |
||||
_material.SetInt(s_SampleCount, _settings.sampleCount); |
||||
|
||||
var source = resourceData.activeColorTexture; |
||||
|
||||
// Intermediate texture for horizontal-blur result. |
||||
var desc = renderGraph.GetTextureDesc(source); |
||||
desc.clearBuffer = false; |
||||
desc.name = "TiltShift_Temp"; |
||||
TextureHandle temp = renderGraph.CreateTexture(desc); |
||||
|
||||
// Final texture for vertical-blur result. |
||||
desc.name = "TiltShift_Final"; |
||||
TextureHandle final = renderGraph.CreateTexture(desc); |
||||
|
||||
// Pass 0 — horizontal blur: source → temp |
||||
var paraH = new RenderGraphUtils.BlitMaterialParameters(source, temp, _material, 0); |
||||
renderGraph.AddBlitPass(paraH, passName: "TiltShift_H"); |
||||
|
||||
// Pass 1 — vertical blur: temp → final |
||||
var paraV = new RenderGraphUtils.BlitMaterialParameters(temp, final, _material, 1); |
||||
renderGraph.AddBlitPass(paraV, passName: "TiltShift_V"); |
||||
|
||||
// Redirect the camera colour so subsequent passes see our result. |
||||
resourceData.cameraColor = final; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,2 @@ |
||||
fileFormatVersion: 2 |
||||
guid: aff85384491b2c84fb68adcd676beaca |
||||
Loading…
Reference in new issue