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