thank you. PatrickLamm
The environment is Unity2020.3.6f1 and URP14.0.6.
I’m using Volume to do a custom post process.
Write shader code and pass code below.
Shader Code:
Shader "Hidden/Custom Post Processing/Starburst"
{
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Filtering.hlsl"
#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.core/ShaderLibrary/FoveatedRendering.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Common.hlsl"
float4 _BlitTexture_TexelSize;
uniform float4 _Direction;
uniform float _Offset;
uniform float _Attenuation;
half4 FragStreak(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = UnityStereoTransformScreenSpaceTex(input.texcoord);
float2 dx = _BlitTexture_TexelSize.xy;
half4 color = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv);
float attenuationSquared = _Attenuation * _Attenuation;
float attenuationCubed = _Attenuation * _Attenuation * _Attenuation;
return color
+ _Attenuation * SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv + _Offset * _Direction.xy * dx)
+ attenuationSquared * SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv + 2 * _Offset * _Direction.xy * dx)
+ attenuationCubed * SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv + 3 * _Offset * _Direction.xy * dx);
}
half4 FragCompose(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float2 uv = UnityStereoTransformScreenSpaceTex(input.texcoord);
half4 color = SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_LinearClamp, uv);
return color;
}
ENDHLSL
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
LOD 100
ZTest Always ZWrite Off Cull Off
Pass
{
Name "Starburst Streak"
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment FragStreak;
ENDHLSL
}
Pass
{
Name "Compose"
Blend One One
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment FragCompose
ENDHLSL
}
}
}
VolumeComponent Code:
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace MyCPP
{
[Serializable, VolumeComponentMenu("MyCPP/PostProcess/Starburst")]
public sealed class StarburstVolume : VolumeComponent, IPostProcessComponent
{
public ClampedIntParameter streaks = new ClampedIntParameter(0, 0, 16);
public ClampedIntParameter power = new ClampedIntParameter(1, 1, 30);
public ClampedFloatParameter attenuation = new ClampedFloatParameter(0.95f, 0.9f, 0.98f);
public ClampedFloatParameter angle = new ClampedFloatParameter(45f, 0f, 360f);
public BoolParameter useCameraRotate = new BoolParameter(true);
public bool IsActive() => streaks.value > 0;
public bool IsTileCompatible() => false;
}
}
ScriptableRenderPass Code:
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Experimental.Rendering;
namespace MyCPP
{
public class CustomPostProcessRenderPass : ScriptableRenderPass
{
RenderTextureDescriptor m_Descriptor;
RTHandle m_Source;
RTHandle m_Destination;
RTHandle m_CameraTargetHandle;
RTHandle m_MonochromeTexture;
RTHandle m_LumaTexture;
RTHandle[] m_GlareMipDown;
RTHandle[] m_GlareMipUp;
RTHandle m_HaloTexture;
RTHandle m_StarburstTextureX;
RTHandle m_StarburstTextureY;
RTHandle m_TempTarget;
const string k_RenderPostProcessingTag = "Render PostProcessing Effects";
const string k_MonochromeTag = "Monochrome";
const string k_LumaTag = "Luma";
const string k_GlareTag = "Glare";
const string k_HaloTag = "Halo";
const string k_StarburstTag = "Starburst";
const string k_StreaksTag = "Streaks";
private static readonly ProfilingSampler m_ProfilingRenderPostProcessing = new ProfilingSampler(k_RenderPostProcessingTag);
private static readonly ProfilingSampler m_ProfilingMonochrome = new ProfilingSampler(k_MonochromeTag);
private static readonly ProfilingSampler m_ProfilingLuma = new ProfilingSampler(k_LumaTag);
private static readonly ProfilingSampler m_ProfilingGlare = new ProfilingSampler(k_GlareTag);
private static readonly ProfilingSampler m_ProfilingHalo = new ProfilingSampler(k_HaloTag);
private static readonly ProfilingSampler m_ProfilingStarburst = new ProfilingSampler(k_StarburstTag);
private static ProfilingSampler[] m_ProfilingStreaks;
ShaderResources m_Shaders;
MaterialLibrary m_Materials;
const string k_MonochromeShaderTag = "Hidden/Custom Post Processing/Monochrome";
const string k_LumaShaderTag = "Hidden/Custom Post Processing/Luma";
const string k_GlareShaderTag = "Hidden/Custom Post Processing/Glare";
const string k_HaloShaderTag = "Hidden/Custom Post Processing/Halo";
const string k_StarburstShaderTag = "Hidden/Custom Post Processing/Starburst";
MonochromeVolume m_Monochrome;
LumaVolume m_Luma;
GlareVolume m_Glare;
HaloVolume m_Halo;
StarburstVolume m_Starburst;
// Misc
const int k_MaxPyramidSize = 16;
readonly GraphicsFormat m_DefaultHDRFormat;
bool m_UseRGBM;
private float[] m_SbDirection;
bool m_UseSwapBuffer;
public CustomPostProcessRenderPass(CustomPostProcessRendererFeature.Settings settings)
{
base.profilingSampler = new ProfilingSampler(nameof(CustomPostProcessRenderPass));
renderPassEvent = settings._event;
m_Shaders = new ShaderResources();
m_Materials = new MaterialLibrary(m_Shaders);
ShaderConstants._GlareMipUp = new int[k_MaxPyramidSize];
ShaderConstants._GlareMipDown = new int[k_MaxPyramidSize];
m_GlareMipUp = new RTHandle[k_MaxPyramidSize];
m_GlareMipDown = new RTHandle[k_MaxPyramidSize];
m_SbDirection = new float[10];
m_ProfilingStreaks = new ProfilingSampler[10];
for (int i = 0; i < k_MaxPyramidSize; i++)
{
ShaderConstants._GlareMipUp[i] = Shader.PropertyToID("_GlareMipUp" + i);
ShaderConstants._GlareMipDown[i] = Shader.PropertyToID("_GlareMipDown" + i);
// 名前を取得する。後に記述子とともに割り当てられる
m_GlareMipUp[i] = RTHandles.Alloc(ShaderConstants._GlareMipUp[i], name: "_GlareMipUp" + i);
m_GlareMipDown[i] = RTHandles.Alloc(ShaderConstants._GlareMipDown[i], name: "_GlareMipDown" + i);
}
m_DefaultHDRFormat = QualitySettings.activeColorSpace == ColorSpace.Linear
? GraphicsFormat.R8G8B8A8_SRGB
: GraphicsFormat.R8G8B8A8_UNorm;
m_UseRGBM = true;
}
// パスで使用されるマテリアルライブラリをクリーンアップする
public void Cleanup() => m_Materials.Cleanup();
public void Dispose()
{
foreach (var handle in m_GlareMipDown)
handle?.Release();
foreach (var handle in m_GlareMipUp)
handle?.Release();
m_CameraTargetHandle?.Release();
m_TempTarget?.Release();
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var stack = VolumeManager.instance.stack;
m_Monochrome = stack.GetComponent<MonochromeVolume>();
m_Luma = stack.GetComponent<LumaVolume>();
m_Glare = stack.GetComponent<GlareVolume>();
m_Halo = stack.GetComponent<HaloVolume>();
m_Starburst = stack.GetComponent<StarburstVolume>();
var cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, m_ProfilingRenderPostProcessing))
{
Render(cmd, ref renderingData);
}
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
CommandBufferPool.Release(cmd);
}
RenderTextureDescriptor GetCompatibleDescriptor()
=> GetCompatibleDescriptor(m_Descriptor.width, m_Descriptor.height, m_Descriptor.graphicsFormat);
RenderTextureDescriptor GetCompatibleDescriptor(int width, int height, GraphicsFormat format, DepthBits depthBufferBits = DepthBits.None)
=> GetCompatibleDescriptor(m_Descriptor, width, height, format, depthBufferBits);
internal static RenderTextureDescriptor GetCompatibleDescriptor(RenderTextureDescriptor desc, int width, int height, GraphicsFormat format, DepthBits depthBufferBits = DepthBits.None)
{
desc.depthBufferBits = (int)depthBufferBits;
desc.msaaSamples = 1;
desc.width = width;
desc.height = height;
desc.graphicsFormat = format;
return desc;
}
void Render(CommandBuffer cmd, ref RenderingData renderingData)
{
ref CameraData cameraData = ref renderingData.cameraData;
ref ScriptableRenderer renderer = ref cameraData.renderer;
bool isSceneViewCamera = cameraData.isSceneViewCamera;
bool useMonochrome = m_Monochrome.IsActive() && !isSceneViewCamera;
bool useLuma = m_Luma.IsActive() && !isSceneViewCamera;
bool useGlare = m_Glare.IsActive() && !isSceneViewCamera;
bool useHalo = m_Halo.IsActive() && !isSceneViewCamera;
bool useStarburst = m_Starburst.IsActive() && !isSceneViewCamera;
m_Descriptor = renderingData.cameraData.cameraTargetDescriptor;
m_Descriptor.depthBufferBits = 0;
RTHandle source = renderer.cameraColorTargetHandle;
RTHandle destination = source;
RTHandle GetSource() => source;
RTHandle GetDestination() => destination;
if (useMonochrome)
{
using (new ProfilingScope(cmd, m_ProfilingMonochrome))
{
SetupMonochrome(cmd, GetSource(), GetDestination(), m_Descriptor);
}
}
if (useLuma)
{
using (new ProfilingScope(cmd, m_ProfilingLuma))
{
SetupLuma(cmd, GetSource(), GetDestination(), m_Descriptor);
}
}
if (useGlare)
{
if (!useLuma) return;
using (new ProfilingScope(cmd, m_ProfilingGlare))
{
SetupGlare(cmd, m_LumaTexture, GetDestination(), m_Descriptor);
}
}
if (useHalo)
{
if (!useLuma || !useGlare) return;
using (new ProfilingScope(cmd, m_ProfilingHalo))
{
SetupHalo(cmd, m_GlareMipDown[0], GetDestination(), m_Descriptor);
}
}
if (useStarburst)
{
if (!useLuma) return;
using (new ProfilingScope(cmd, m_ProfilingStarburst))
{
SetupStarburst(cmd, m_LumaTexture, GetDestination(), m_Descriptor);
}
}
}
void SetupMonochrome(CommandBuffer cmd, RTHandle source, RTHandle destination, RenderTextureDescriptor descriptor)
{
var material = m_Materials.monochrome;
material.SetFloat("_Weight", m_Monochrome.weight.value);
RenderingUtils.ReAllocateIfNeeded(ref m_MonochromeTexture, descriptor, name: "m_MonochromeTexture");
Blitter.BlitCameraTexture(cmd, source, m_MonochromeTexture);
Blitter.BlitCameraTexture(cmd, m_MonochromeTexture, destination, material, 0);
int boolint = m_Monochrome.boolint.value;
material.SetInt("_Boolint", boolint);
Blitter.BlitCameraTexture(cmd, source, m_MonochromeTexture, material, 0);
int boolint1 = 1;
material.SetInt("_Boolint", boolint1);
Blitter.BlitCameraTexture(cmd, source, m_MonochromeTexture, material, 0);
// やってみた結果
// boolintは最後の1がずっと出力される。
// なので、真ん中のSetInt()が意味なくなる
}
void SetupLuma(CommandBuffer cmd, RTHandle source, RTHandle destination, RenderTextureDescriptor descriptor)
{
var material = m_Materials.luma;
material.SetFloat("_Threshold", m_Luma.threshold.value);
RenderingUtils.ReAllocateIfNeeded(ref m_LumaTexture, descriptor, name: "m_LumaTexture");
Blitter.BlitCameraTexture(cmd, source, m_LumaTexture, material, 0);
//Blitter.BlitCameraTexture(cmd, m_LumaTexture, destination, material, 0);
}
void SetupGlare(CommandBuffer cmd, RTHandle source, RTHandle destination, RenderTextureDescriptor descriptor)
{
var material = m_Materials.glare;
int tw = descriptor.width >> 1;
int th = descriptor.height >> 1;
int maxSize = Mathf.Max(tw, th);
int iterations = Mathf.FloorToInt(Mathf.Log(maxSize, 2f) -1);
int mipCount = Mathf.Clamp(iterations, 1, 10);
int iteration = m_Glare.iteration.value;
// テクスチャの生成
var desc = GetCompatibleDescriptor(tw, th, m_DefaultHDRFormat);
for (int j = 0; j < iteration; j++)
{
RenderingUtils.ReAllocateIfNeeded(ref m_GlareMipUp[j], desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: m_GlareMipUp[j].name);
RenderingUtils.ReAllocateIfNeeded(ref m_GlareMipDown[j], desc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: m_GlareMipDown[j].name);
desc.width = Mathf.Max(1, desc.width >> 1);
desc.height = Mathf.Max(1, desc.height >> 1);
}
// ダウンサンプリング
var currentSource = source;
RTHandle currentDest = null;
int i = 0;
for (; i < iteration; i++)
{
currentDest = m_GlareMipDown[i];
Blitter.BlitCameraTexture(cmd, currentSource, currentDest, material, 0);
currentSource = currentDest;
}
for (i -= 2; i >= 0; i--)
{
currentDest = m_GlareMipDown[i];
Blitter.BlitCameraTexture(cmd, currentSource, currentDest, material, 1);
currentSource = currentDest;
}
Blitter.BlitCameraTexture(cmd, currentSource, destination, material, 1);
}
void SetupHalo(CommandBuffer cmd, RTHandle source, RTHandle destination, RenderTextureDescriptor descriptor)
{
var material = m_Materials.halo;
material.SetFloat("_Threshold", m_Halo.threshold.value);
RenderingUtils.ReAllocateIfNeeded(ref m_HaloTexture, descriptor, name: "m_HaloTexture");
Blitter.BlitCameraTexture(cmd, source, m_HaloTexture);
Blitter.BlitCameraTexture(cmd, m_HaloTexture, destination, material, 0);
}
void SetupStarburst(CommandBuffer cmd, RTHandle source, RTHandle destination, RenderTextureDescriptor descriptor)
{
//var material = m_Materials.starburst;
int power = m_Starburst.power.value;
float attenuation = m_Starburst.attenuation.value;
int streaks = m_Starburst.streaks.value;
float angle = m_Starburst.angle.value;
RenderingUtils.ReAllocateIfNeeded(ref m_StarburstTextureX, descriptor, name: "m_StarburstTextureX");
RenderingUtils.ReAllocateIfNeeded(ref m_StarburstTextureY, descriptor, name: "m_StarburstTextureY");
float period = (2.0f * Mathf.PI) / streaks;
for (var i = 0; i < streaks; i++)
{
m_ProfilingStreaks[i] = new ProfilingSampler(k_StreaksTag + i);
using(new ProfilingScope(cmd, m_ProfilingStreaks[i]))
{
var material = m_Materials.starburst;
float streakDirection = i * period;
int texelOffset = 1;
float streakAttenuation = Mathf.Pow(attenuation, texelOffset);
Blitter.BlitCameraTexture(cmd, source, m_StarburstTextureX);
for (var j = 0; j < power; j++)
{
if (j != 0) texelOffset *= 4;
material.SetFloat("_Offset", texelOffset);
material.SetFloat("_Attenuation", streakAttenuation);
material.SetVector("_Direction", new Vector4(Mathf.Cos(streakDirection), Mathf.Sin(streakDirection), 0, 0));
Blitter.BlitCameraTexture(cmd, m_StarburstTextureX, m_StarburstTextureY, material, 0);
RTHandle temp = m_StarburstTextureX;
m_StarburstTextureX = m_StarburstTextureY;
m_StarburstTextureY = temp;
}
Blitter.BlitCameraTexture(cmd, m_StarburstTextureX, destination, material, 1);
}
}
}
public override void OnCameraCleanup(CommandBuffer cmd)
{
}
class MaterialLibrary {
public readonly Material monochrome;
public readonly Material luma;
public readonly Material glare;
public readonly Material halo;
public readonly Material starburst;
public MaterialLibrary(ShaderResources resources)
{
monochrome = Load(resources.monochrome);
luma = Load(resources.luma);
glare = Load(resources.glare);
halo = Load(resources.halo);
starburst = Load(resources.starburst);
}
Material Load(Shader shader)
{
if (shader == null)
{
Debug.LogErrorFormat($"Missing shader. {shader}");
return null;
}
return CoreUtils.CreateEngineMaterial(shader);
}
internal void Cleanup()
{
CoreUtils.Destroy(monochrome);
CoreUtils.Destroy(luma);
CoreUtils.Destroy(glare);
CoreUtils.Destroy(halo);
CoreUtils.Destroy(starburst);
}
}
class ShaderResources {
public Shader monochrome;
public Shader luma;
public Shader glare;
public Shader halo;
public Shader starburst;
public ShaderResources()
{
monochrome = Load(k_MonochromeShaderTag);
luma = Load(k_LumaShaderTag);
glare = Load(k_GlareShaderTag);
halo = Load(k_HaloShaderTag);
starburst = Load(k_StarburstShaderTag);
}
Shader Load(string tag)
{
if (tag == null)
{
Debug.LogErrorFormat($"Missing shaderTag. {tag}");
return null;
}
return Shader.Find(tag);
}
}
static class ShaderConstants
{
public static int[] _GlareMipUp;
public static int[] _GlareMipDown;
}
}
}
ScriptableRendererFeature Code:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace MyCPP
{
public class CustomPostProcessRendererFeature : ScriptableRendererFeature
{
[System.Serializable]
public class Settings {
public bool showInSceneView = true;
public RenderPassEvent _event = RenderPassEvent.BeforeRenderingPostProcessing;
}
public Settings settings = new Settings();
private CustomPostProcessRenderPass pass;
public override void Create()
{
pass = new CustomPostProcessRenderPass(settings);
}
// このメソッドは、URPのレンダラでScriptableRenderPassesを挿入/キューに入れる役割を果たす。
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
// エディタ/インスペクターのプレビューとアセットのサムネイルの無視
if (renderingData.cameraData.isPreviewCamera) return;
// シーンビューの機能を無視する。
if (!settings.showInSceneView && renderingData.cameraData.isSceneViewCamera) return;
// メインカメラでないカメラを無視する
if (renderingData.cameraData.camera != Camera.main) return;
renderer.EnqueuePass(pass);
}
}
}
I tried to get the same value with SetupMonochrome(), but it was the same value. Both are printed as 1.
int boolint = 0;
material.SetInt("_Boolint", boolint);
Blitter.BlitCameraTexture(cmd, source, m_MonochromeTexture, material, 0);
int boolint1 = 1;
material.SetInt("_Boolint", boolint1);
Blitter.BlitCameraTexture(cmd, source, m_MonochromeTexture, material, 0);
Masaya