像素化
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
Shader "Hidden/Custom/Pixelate"
|
||||
{
|
||||
SubShader
|
||||
{
|
||||
Tags { "RenderPipeline" = "UniversalPipeline" }
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "Pixelate Pass"
|
||||
ZTest Always
|
||||
Cull Off
|
||||
ZWrite Off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma vertex PixelatePassVert
|
||||
#pragma fragment PixelatePassFrag
|
||||
#include "PixelatePass.hlsl"
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 272e7eef87baea8408e583d2670e66dd
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,47 +1,100 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
public class PixelateFeature : ScriptableRendererFeature
|
||||
{
|
||||
[System.Serializable]
|
||||
public class Settings
|
||||
public class PixelatePass : ScriptableRenderPass
|
||||
{
|
||||
public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;
|
||||
[Tooltip("用于像素化的材质")]
|
||||
public Material pixelateMaterial = null;
|
||||
private static readonly string ProfilerTag = "PixelateEffect";
|
||||
|
||||
private static readonly int PixelateStrengthXID = Shader.PropertyToID("_PixelateStrengthX");
|
||||
private static readonly int PixelateStrengthYID = Shader.PropertyToID("_PixelateStrengthY");
|
||||
private static readonly int SourceTextureID = Shader.PropertyToID("_SourceTexture");
|
||||
|
||||
public Material pixelateMaterial;
|
||||
public float pixelateX = 64f;
|
||||
public float pixelateY = 64f;
|
||||
|
||||
private RTHandle sourceRT;
|
||||
private RTHandle transientRT;
|
||||
|
||||
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
|
||||
{
|
||||
sourceRT = renderingData.cameraData.renderer.cameraColorTargetHandle;
|
||||
RenderTextureDescriptor descriptor = renderingData.cameraData.cameraTargetDescriptor;
|
||||
descriptor.depthBufferBits = 0;
|
||||
RenderingUtils.ReAllocateIfNeeded(ref transientRT, descriptor, name: "_PixelateTransientRT");
|
||||
}
|
||||
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||
{
|
||||
if (pixelateMaterial == null) return;
|
||||
|
||||
CommandBuffer cmd = CommandBufferPool.Get(ProfilerTag);
|
||||
|
||||
pixelateMaterial.SetFloat(PixelateStrengthXID, pixelateX);
|
||||
pixelateMaterial.SetFloat(PixelateStrengthYID, pixelateY);
|
||||
|
||||
cmd.SetGlobalTexture(SourceTextureID, sourceRT);
|
||||
cmd.SetRenderTarget(transientRT, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
|
||||
cmd.DrawProcedural(Matrix4x4.identity, pixelateMaterial, 0, MeshTopology.Triangles, 3);
|
||||
|
||||
cmd.SetGlobalTexture(SourceTextureID, transientRT);
|
||||
cmd.SetRenderTarget(sourceRT, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
|
||||
cmd.DrawProcedural(Matrix4x4.identity, pixelateMaterial, 0, MeshTopology.Triangles, 3);
|
||||
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
CommandBufferPool.Release(cmd);
|
||||
}
|
||||
|
||||
public void UpdateConfig(float x, float y)
|
||||
{
|
||||
pixelateX = x;
|
||||
pixelateY = y;
|
||||
}
|
||||
}
|
||||
|
||||
public Settings settings = new Settings();
|
||||
private PixelatePass m_PixelatePass;
|
||||
[System.Serializable]
|
||||
public class PixelateSettings
|
||||
{
|
||||
[SerializeField] private Shader pixelateShader;
|
||||
private Material pixelateMaterial;
|
||||
public Material PixelateMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pixelateMaterial == null && pixelateShader != null)
|
||||
{
|
||||
pixelateMaterial = new Material(pixelateShader)
|
||||
{
|
||||
hideFlags = HideFlags.HideAndDontSave
|
||||
};
|
||||
}
|
||||
return pixelateMaterial;
|
||||
}
|
||||
}
|
||||
[Min(2)] public float pixelateStrengthX = 64f;
|
||||
[Min(2)] public float pixelateStrengthY = 64f;
|
||||
public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingTransparents;
|
||||
}
|
||||
|
||||
public PixelateSettings settings = new();
|
||||
public PixelatePass pixelatePass;
|
||||
|
||||
// 当Feature被创建或Inspector中的值被改变时调用
|
||||
public override void Create()
|
||||
{
|
||||
// 检查材质是否存在
|
||||
if (settings.pixelateMaterial != null)
|
||||
pixelatePass = new PixelatePass
|
||||
{
|
||||
m_PixelatePass = new PixelatePass(settings.pixelateMaterial);
|
||||
// 将Inspector中设置的事件赋值给Pass
|
||||
m_PixelatePass.renderPassEvent = settings.renderPassEvent;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果材质为空,则不创建Pass,避免后续报错
|
||||
m_PixelatePass = null;
|
||||
}
|
||||
renderPassEvent = settings.passEvent,
|
||||
pixelateMaterial = settings.PixelateMaterial,
|
||||
pixelateX = settings.pixelateStrengthX,
|
||||
pixelateY = settings.pixelateStrengthY
|
||||
};
|
||||
}
|
||||
|
||||
// 【核心修正】这个方法现在非常干净,只负责将创建好的Pass入队
|
||||
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
|
||||
{
|
||||
if (m_PixelatePass == null)
|
||||
{
|
||||
// 如果Pass没有被成功创建(因为没材质),就直接返回
|
||||
return;
|
||||
}
|
||||
|
||||
// 将我们的Pass添加到渲染队列中,URP会在正确的时间执行它
|
||||
renderer.EnqueuePass(m_PixelatePass);
|
||||
renderer.EnqueuePass(pixelatePass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
public class PixelatePass : ScriptableRenderPass
|
||||
{
|
||||
private Material m_PixelateMaterial;
|
||||
|
||||
// 构造函数,接收材质
|
||||
public PixelatePass(Material pixelateMaterial)
|
||||
{
|
||||
this.m_PixelateMaterial = pixelateMaterial;
|
||||
}
|
||||
|
||||
// 这个方法在每一帧渲染该Pass之前被调用
|
||||
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||
{
|
||||
// 1. 安全检查
|
||||
if (m_PixelateMaterial == null)
|
||||
{
|
||||
Debug.LogError("Pixelate Material not assigned to the pass.");
|
||||
return;
|
||||
}
|
||||
// 如果渲染的不是游戏主相机(例如Scene视图的相机),则直接返回,避免在编辑器里也显示效果
|
||||
if (renderingData.cameraData.cameraType != CameraType.Game)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 获取命令缓冲区
|
||||
CommandBuffer cmd = CommandBufferPool.Get("PixelatePass");
|
||||
|
||||
// 3. 【核心修正】在Execute方法内部,安全地获取当前摄像机的渲染目标
|
||||
// URP 12+ 使用 renderingData.cameraData.renderer.cameraColorTargetHandle
|
||||
RTHandle source = renderingData.cameraData.renderer.cameraColorTargetHandle;
|
||||
|
||||
// 4. 执行Blit操作
|
||||
// 将源纹理(source)通过我们的材质处理后,再写回源纹理(source)
|
||||
Blit(cmd, source, source, m_PixelateMaterial, 0);
|
||||
|
||||
// 5. 执行并释放命令缓冲区
|
||||
context.ExecuteCommandBuffer(cmd);
|
||||
CommandBufferPool.Release(cmd);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d1fa92947bbef246a8a112b2a6b96c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef PIXELATE_PASS_INCLUDED
|
||||
#define PIXELATE_PASS_INCLUDED
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||
|
||||
TEXTURE2D(_SourceTexture);
|
||||
SAMPLER(sampler_SourceTexture);
|
||||
float4 _SourceTexture_TexelSize;
|
||||
|
||||
float _PixelateStrengthX;
|
||||
float _PixelateStrengthY;
|
||||
|
||||
struct Varyings
|
||||
{
|
||||
float4 positionCS_SS : SV_POSITION;
|
||||
float2 screenUV : VAR_SCREEN_UV;
|
||||
};
|
||||
|
||||
Varyings PixelatePassVert(uint vertexID : SV_VertexID)
|
||||
{
|
||||
Varyings output;
|
||||
output.positionCS_SS = float4(
|
||||
vertexID <= 1 ? -1.0 : 3.0,
|
||||
vertexID == 1 ? 3.0 : -1.0,
|
||||
0.0, 1.0
|
||||
);
|
||||
output.screenUV = float2(
|
||||
vertexID <= 1 ? 0.0 : 2.0,
|
||||
vertexID == 1 ? 2.0 : 0.0
|
||||
);
|
||||
if (_ProjectionParams.x < 0.0)
|
||||
{
|
||||
output.screenUV.y = 1.0 - output.screenUV.y;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
half4 PixelatePassFrag(Varyings input) : SV_Target
|
||||
{
|
||||
float2 screenUV = input.screenUV;
|
||||
float2 strength = float2(_PixelateStrengthX, _PixelateStrengthY);
|
||||
float2 uvScaled = screenUV * strength;
|
||||
float2 uvFloor = floor(uvScaled);
|
||||
float2 uvCenter = uvFloor + 0.5;
|
||||
float2 uvPixelated = uvCenter / strength;
|
||||
|
||||
return SAMPLE_TEXTURE2D(_SourceTexture, sampler_SourceTexture, uvPixelated);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8be62d4e6aca4494caf6095e90160cd9
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user