像素化

This commit is contained in:
SoulliesOfficial
2025-06-30 09:25:29 -04:00
parent f31d77197b
commit e91f378989
19 changed files with 16279 additions and 17232 deletions

View File

@@ -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
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 272e7eef87baea8408e583d2670e66dd
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 6d1fa92947bbef246a8a112b2a6b96c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8be62d4e6aca4494caf6095e90160cd9
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: