511 lines
24 KiB
C#
511 lines
24 KiB
C#
using System;
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
using System.Runtime.CompilerServices; // AggressiveInlining
|
|
|
|
namespace UnityEngine.Rendering.Universal
|
|
{
|
|
internal sealed class BloomPostProcessPass : PostProcessPass
|
|
{
|
|
public const int k_MaxPyramidSize = 16;
|
|
|
|
Material m_Material;
|
|
Material[] m_MaterialPyramid;
|
|
|
|
// Cached bloom params from previous frame to avoid unnecessary material updates
|
|
MaterialParams m_PrevParams;
|
|
|
|
BloomMipPyramid m_MipPyramid;
|
|
|
|
bool m_IsValid;
|
|
|
|
public BloomMipPyramid mipPyramid => m_MipPyramid;
|
|
|
|
public BloomPostProcessPass(Shader shader)
|
|
{
|
|
this.renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing - 1;
|
|
this.profilingSampler = null;
|
|
|
|
m_Material = PostProcessUtils.LoadShader(shader, passName);
|
|
|
|
// Array for bloom pyramid materials.
|
|
// Materials are references in the command buffer, so we need a separate material for each mip level.
|
|
m_MaterialPyramid = new Material[k_MaxPyramidSize];
|
|
for (uint i = 0; i < k_MaxPyramidSize; ++i)
|
|
m_MaterialPyramid[i] = PostProcessUtils.LoadShader(shader, passName);
|
|
|
|
// Check if the pass init was successful.
|
|
m_IsValid = m_Material != null;
|
|
for(int i = 0; i < k_MaxPyramidSize; i++)
|
|
m_IsValid &= m_MaterialPyramid[i] != null;
|
|
|
|
m_MipPyramid = new BloomMipPyramid(k_MaxPyramidSize);
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
CoreUtils.Destroy(m_Material);
|
|
for(int i = 0; i < k_MaxPyramidSize; i++)
|
|
CoreUtils.Destroy(m_MaterialPyramid[i]);
|
|
}
|
|
|
|
private class BloomPassData
|
|
{
|
|
internal Material material;
|
|
internal Material[] mipMaterials;
|
|
|
|
internal TextureHandle sourceTexture;
|
|
|
|
internal BloomMipPyramid mipPyramid;
|
|
}
|
|
|
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
|
|
{
|
|
if (!m_IsValid)
|
|
return;
|
|
|
|
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
|
|
var sourceTexture = resourceData.cameraColor;
|
|
var sourceDesc = sourceTexture.GetDescriptor(renderGraph);
|
|
|
|
var bloom = volumeStack.GetComponent<Bloom>();
|
|
|
|
// Setup
|
|
// Materials are set up beforehand.
|
|
// We rely on the fact that they're private and separate for each blit.
|
|
// They should remain unchanged between graph build and execution.
|
|
using(new ProfilingScope(ProfilingSampler.Get(URPProfileId.RG_BloomSetup)))
|
|
{
|
|
m_MipPyramid.Update(renderGraph, bloom, in sourceDesc);
|
|
int mipCount = m_MipPyramid.mipCount;
|
|
|
|
// Pre-filtering parameters
|
|
float clamp = bloom.clamp.value;
|
|
float threshold = Mathf.GammaToLinearSpace(bloom.threshold.value);
|
|
float thresholdKnee = threshold * 0.5f; // Hardcoded soft knee
|
|
|
|
// Material setup
|
|
float scatter = Mathf.Lerp(0.05f, 0.95f, bloom.scatter.value); // Blend factor between low/hi mip on upsample.
|
|
float kawaseScatter = Mathf.Clamp01(bloom.scatter.value); // Blend factor between linear and blurred sample. 1.0 for strict Kawase blur.
|
|
float dualScatter = Mathf.Lerp(0.3f, 1.3f, bloom.scatter.value); // Dual upsample filter scale. Scatter default == 0.7 --> 1.0 filter scale.
|
|
|
|
MaterialParams newParams = new MaterialParams();
|
|
newParams.parameters = new Vector4(scatter, clamp, threshold, thresholdKnee);
|
|
newParams.parameters2 = new Vector4(0.5f, kawaseScatter, dualScatter, 0.5f * dualScatter);
|
|
newParams.bloomFilter = bloom.filter.value;
|
|
newParams.highQualityFiltering = bloom.highQualityFiltering.value;
|
|
newParams.enableAlphaOutput = cameraData.isAlphaOutputEnabled;
|
|
|
|
// Setting keywords can be somewhat expensive on low-end platforms.
|
|
// Previous params are cached to avoid setting the same keywords every frame.
|
|
bool paramsDirty = !m_PrevParams.Equals(ref newParams);
|
|
bool isParamsPropertySet = m_Material.HasProperty(ShaderConstants._Params);
|
|
if (paramsDirty || !isParamsPropertySet)
|
|
{
|
|
m_Material.SetVector(ShaderConstants._Params, newParams.parameters);
|
|
m_Material.SetVector(ShaderConstants._Params2, newParams.parameters2);
|
|
CoreUtils.SetKeyword(m_Material, ShaderKeywordStrings.BloomHQ, newParams.highQualityFiltering);
|
|
CoreUtils.SetKeyword(m_Material, ShaderKeywordStrings._ENABLE_ALPHA_OUTPUT, newParams.enableAlphaOutput);
|
|
|
|
// These materials are duplicate just to allow different bloom blits to use different textures.
|
|
for (uint i = 0; i < k_MaxPyramidSize; ++i)
|
|
{
|
|
var materialPyramid = m_MaterialPyramid[i];
|
|
materialPyramid.SetVector(ShaderConstants._Params, newParams.parameters);
|
|
CoreUtils.SetKeyword(materialPyramid, ShaderKeywordStrings.BloomHQ, newParams.highQualityFiltering);
|
|
CoreUtils.SetKeyword(materialPyramid, ShaderKeywordStrings._ENABLE_ALPHA_OUTPUT, newParams.enableAlphaOutput);
|
|
|
|
// TODO: investigate suggested quality improvement trick in more detail:
|
|
// Kawase5: 0, 1, 2, 2, 3
|
|
// Kawase9: 0, 1, 2, 3, 4, 4, 5, 6, 7
|
|
// ? -> KawaseN: duplicate pass at N/2 (See, Bandwidth-Efficient Rendering, siggraph2015)
|
|
float kawaseDist = 0.5f + ((i > mipCount / 2) ? (i - 1) : i);
|
|
|
|
Vector4 params2 = newParams.parameters2;
|
|
params2.x = kawaseDist;
|
|
materialPyramid.SetVector(ShaderConstants._Params2, params2);
|
|
}
|
|
|
|
m_PrevParams = newParams;
|
|
}
|
|
}
|
|
|
|
switch (bloom.filter.value)
|
|
{
|
|
case BloomFilterMode.Dual:
|
|
resourceData.bloom = BloomDual(renderGraph, sourceTexture);
|
|
break;
|
|
case BloomFilterMode.Kawase:
|
|
resourceData.bloom = BloomKawase(renderGraph, sourceTexture);
|
|
break;
|
|
case BloomFilterMode.Gaussian: goto default;
|
|
default:
|
|
resourceData.bloom = BloomGaussian(renderGraph, sourceTexture);
|
|
break;
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
static public Vector2Int CalcBloomResolution(Bloom bloom, in TextureDesc bloomSourceDesc)
|
|
{
|
|
// Start at half-res
|
|
int downres = 1;
|
|
switch (bloom.downscale.value)
|
|
{
|
|
case BloomDownscaleMode.Half:
|
|
downres = 1;
|
|
break;
|
|
case BloomDownscaleMode.Quarter:
|
|
downres = 2;
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
//We should set the limit the downres result to ensure we dont turn 1x1 textures, which should technically be valid
|
|
//into 0x0 textures which will be invalid
|
|
int tw = Mathf.Max(1, bloomSourceDesc.width >> downres);
|
|
int th = Mathf.Max(1, bloomSourceDesc.height >> downres);
|
|
|
|
return new Vector2Int(tw, th);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
static public int CalcBloomMipCount(Bloom bloom, in Vector2Int bloomResolution)
|
|
{
|
|
// Determine the iteration count
|
|
int maxSize = Mathf.Max(bloomResolution.x, bloomResolution.y);
|
|
int iterations = Mathf.FloorToInt(Mathf.Log(maxSize, 2f) - 1);
|
|
int mipCount = Mathf.Clamp(iterations, 1, bloom.maxIterations.value);
|
|
return mipCount;
|
|
}
|
|
|
|
TextureHandle BloomGaussian(RenderGraph renderGraph, in TextureHandle source)
|
|
{
|
|
using (var builder = renderGraph.AddUnsafePass<BloomPassData>("Blit Bloom Mipmaps", out var passData, ProfilingSampler.Get(URPProfileId.Bloom)))
|
|
{
|
|
passData.sourceTexture = source;
|
|
passData.material = m_Material;
|
|
passData.mipMaterials = m_MaterialPyramid;
|
|
passData.mipPyramid = m_MipPyramid;
|
|
|
|
int mipCount = m_MipPyramid.mipCount;
|
|
|
|
builder.UseTexture(source, AccessFlags.Read);
|
|
for (int i = 0; i < mipCount; i++)
|
|
{
|
|
builder.UseTexture(m_MipPyramid.mipDownTextures[i], AccessFlags.ReadWrite);
|
|
builder.UseTexture(m_MipPyramid.mipUpTextures[i], AccessFlags.ReadWrite);
|
|
}
|
|
|
|
builder.SetRenderFunc(static (BloomPassData data, UnsafeGraphContext context) =>
|
|
{
|
|
// TODO: can't call BlitTexture with unsafe command buffer
|
|
var cmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd);
|
|
var material = data.material;
|
|
int mipCount = data.mipPyramid.mipCount;
|
|
TextureHandle[] mipDownTextures = data.mipPyramid.mipDownTextures;
|
|
TextureHandle[] mipUpTextures = data.mipPyramid.mipUpTextures;
|
|
|
|
var loadAction = RenderBufferLoadAction.DontCare; // Blit - always write all pixels
|
|
var storeAction = RenderBufferStoreAction.Store; // Blit - always read by then next Blit
|
|
|
|
// Prefilter
|
|
using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.RG_BloomPrefilter)))
|
|
{
|
|
Blitter.BlitCameraTexture(cmd, data.sourceTexture, mipDownTextures[0], loadAction,
|
|
storeAction, material, ShaderPass.k_Prefilter);
|
|
}
|
|
|
|
// Downsample - gaussian pyramid
|
|
// Classic two pass gaussian blur - use mipUp as a temporary target
|
|
// First pass does 2x downsampling + 9-tap gaussian
|
|
// Second pass does 9-tap gaussian using a 5-tap filter + bilinear filtering
|
|
using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.RG_BloomDownsample)))
|
|
{
|
|
TextureHandle lastDown = mipDownTextures[0];
|
|
for (int i = 1; i < mipCount; i++)
|
|
{
|
|
TextureHandle mipDown = mipDownTextures[i];
|
|
TextureHandle mipUp = mipUpTextures[i];
|
|
|
|
Blitter.BlitCameraTexture(cmd, lastDown, mipUp, loadAction, storeAction, material, ShaderPass.k_BlurHorizontal);
|
|
Blitter.BlitCameraTexture(cmd, mipUp, mipDown, loadAction, storeAction, material, ShaderPass.k_BlurVertical);
|
|
|
|
lastDown = mipDown;
|
|
}
|
|
}
|
|
|
|
using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.RG_BloomUpsample)))
|
|
{
|
|
// Upsample (bilinear by default, HQ filtering does bicubic instead
|
|
for (int i = mipCount - 2; i >= 0; i--)
|
|
{
|
|
TextureHandle lowMip =
|
|
(i == mipCount - 2) ? mipDownTextures[i + 1] : mipUpTextures[i + 1];
|
|
TextureHandle highMip = mipDownTextures[i];
|
|
TextureHandle dst = mipUpTextures[i];
|
|
|
|
// We need a separate material for each upsample pass because setting the low texture mip source
|
|
// gets overriden by the time the render func is executed.
|
|
// Material is a reference, so all the blits would share the same material state in the cmdbuf.
|
|
// NOTE: another option would be to use cmd.SetGlobalTexture().
|
|
var upMaterial = data.mipMaterials[i];
|
|
upMaterial.SetTexture(ShaderConstants._SourceTexLowMip, lowMip);
|
|
|
|
Blitter.BlitCameraTexture(cmd, highMip, dst, loadAction, storeAction, upMaterial, ShaderPass.k_Upsample);
|
|
}
|
|
}
|
|
});
|
|
|
|
// 1st mip is the prefilter.
|
|
m_MipPyramid.resultTexture = mipCount == 1 ? m_MipPyramid.mipDownTextures[0] : m_MipPyramid.mipUpTextures[0];
|
|
return m_MipPyramid.resultTexture;
|
|
}
|
|
}
|
|
|
|
TextureHandle BloomKawase(RenderGraph renderGraph, in TextureHandle source)
|
|
{
|
|
using (var builder = renderGraph.AddUnsafePass<BloomPassData>("Blit Bloom Mipmaps (Kawase)", out var passData, ProfilingSampler.Get(URPProfileId.Bloom)))
|
|
{
|
|
passData.sourceTexture = source;
|
|
passData.material = m_Material;
|
|
passData.mipMaterials = m_MaterialPyramid;
|
|
passData.mipPyramid = m_MipPyramid;
|
|
|
|
int mipCount = m_MipPyramid.mipCount;
|
|
|
|
builder.UseTexture(source, AccessFlags.Read);
|
|
builder.UseTexture(m_MipPyramid.mipDownTextures[0], AccessFlags.ReadWrite);
|
|
builder.UseTexture(m_MipPyramid.mipUpTextures[0], AccessFlags.ReadWrite);
|
|
|
|
builder.SetRenderFunc(static (BloomPassData data, UnsafeGraphContext context) =>
|
|
{
|
|
// TODO: can't call BlitTexture with unsafe command buffer
|
|
var cmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd);
|
|
var material = data.material;
|
|
int mipCount = data.mipPyramid.mipCount;
|
|
TextureHandle[] mipDownTextures = data.mipPyramid.mipDownTextures;
|
|
TextureHandle[] mipUpTextures = data.mipPyramid.mipUpTextures;
|
|
|
|
var loadAction = RenderBufferLoadAction.DontCare; // Blit - always write all pixels
|
|
var storeAction = RenderBufferStoreAction.Store; // Blit - always read by then next Blit
|
|
|
|
// Prefilter
|
|
using(new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.RG_BloomPrefilter)))
|
|
{
|
|
Blitter.BlitCameraTexture(cmd, data.sourceTexture, mipDownTextures[0], loadAction, storeAction, material, ShaderPass.k_Prefilter);
|
|
}
|
|
|
|
// Kawase blur passes
|
|
using(new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.RG_BloomDownsample)))
|
|
{
|
|
for (int i = 0; i < mipCount; i++)
|
|
{
|
|
TextureHandle src = ((i & 1) == 0) ? mipDownTextures[0] : mipUpTextures[0];
|
|
TextureHandle dst = ((i & 1) == 0) ? mipUpTextures[0] : mipDownTextures[0];
|
|
Material mat = data.mipMaterials[i];
|
|
|
|
Blitter.BlitCameraTexture(cmd, src, dst, loadAction, storeAction, mat, ShaderPass.k_Kawase);
|
|
}
|
|
}
|
|
});
|
|
|
|
m_MipPyramid.resultTexture = (((mipCount - 1) & 1) == 0) ? m_MipPyramid.mipUpTextures[0] : m_MipPyramid.mipDownTextures[0];
|
|
return m_MipPyramid.resultTexture;
|
|
}
|
|
}
|
|
|
|
|
|
// Dual Filter, Bandwidth-Efficient Rendering, siggraph2015
|
|
TextureHandle BloomDual(RenderGraph renderGraph, in TextureHandle source)
|
|
{
|
|
using (var builder = renderGraph.AddUnsafePass<BloomPassData>("Blit Bloom Mipmaps (Dual)", out var passData, ProfilingSampler.Get(URPProfileId.Bloom)))
|
|
{
|
|
passData.sourceTexture = source;
|
|
passData.material = m_Material;
|
|
passData.mipMaterials = m_MaterialPyramid;
|
|
passData.mipPyramid = m_MipPyramid;
|
|
|
|
int mipCount = m_MipPyramid.mipCount;
|
|
|
|
builder.UseTexture(source, AccessFlags.Read);
|
|
for (int i = 0; i < mipCount; i++)
|
|
{
|
|
builder.UseTexture(m_MipPyramid.mipDownTextures[i], AccessFlags.ReadWrite);
|
|
builder.UseTexture(m_MipPyramid.mipUpTextures[i], AccessFlags.ReadWrite);
|
|
}
|
|
|
|
builder.SetRenderFunc(static (BloomPassData data, UnsafeGraphContext context) =>
|
|
{
|
|
// TODO: can't call BlitTexture with unsafe command buffer
|
|
var cmd = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd);
|
|
var material = data.material;
|
|
int mipCount = data.mipPyramid.mipCount;
|
|
TextureHandle[] mipDownTextures = data.mipPyramid.mipDownTextures;
|
|
TextureHandle[] mipUpTextures = data.mipPyramid.mipUpTextures;
|
|
|
|
var loadAction = RenderBufferLoadAction.DontCare; // Blit - always write all pixels
|
|
var storeAction = RenderBufferStoreAction.Store; // Blit - always read by then next Blit
|
|
|
|
// Prefilter
|
|
using(new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.RG_BloomPrefilter)))
|
|
{
|
|
Blitter.BlitCameraTexture(cmd, data.sourceTexture, mipDownTextures[0], loadAction, storeAction, material, ShaderPass.k_Prefilter);
|
|
}
|
|
|
|
// ARM: Bandwidth-Efficient Rendering, siggraph2015
|
|
// Downsample - dual pyramid, fixed Kawase0 blur on shrinking targets.
|
|
using(new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.RG_BloomDownsample)))
|
|
{
|
|
TextureHandle lastDown = mipDownTextures[0];
|
|
for (int i = 1; i < mipCount; i++)
|
|
{
|
|
TextureHandle src = mipDownTextures[i - 1];
|
|
TextureHandle dst = mipDownTextures[i];
|
|
|
|
Blitter.BlitCameraTexture(cmd, src, dst, loadAction, storeAction, material, ShaderPass.k_DualDownsample);
|
|
}
|
|
}
|
|
|
|
using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.RG_BloomUpsample)))
|
|
{
|
|
for (int i = mipCount - 2; i >= 0; i--)
|
|
{
|
|
TextureHandle src = (i == mipCount - 2) ? mipDownTextures[i + 1] : mipUpTextures[i + 1];
|
|
TextureHandle dst = mipUpTextures[i];
|
|
|
|
Blitter.BlitCameraTexture(cmd, src, dst, loadAction, storeAction, material, ShaderPass.k_DualUpsample);
|
|
}
|
|
}
|
|
});
|
|
// 1st mip is the prefilter.
|
|
m_MipPyramid.resultTexture = mipCount == 1 ? m_MipPyramid.mipDownTextures[0] : m_MipPyramid.mipUpTextures[0];
|
|
return m_MipPyramid.resultTexture;
|
|
}
|
|
}
|
|
|
|
// Helper class to communicate bloom mip results with external passes in a consistent way.
|
|
public class BloomMipPyramid
|
|
{
|
|
int m_MipCount;
|
|
|
|
TextureHandle[] m_MipDownPyramidTextures;
|
|
TextureHandle[] m_MipUpPyramidTextures;
|
|
|
|
string[] m_MipDownPyramidNames;
|
|
string[] m_MipUpPyramidNames;
|
|
|
|
BloomFilterMode m_BloomFilterMode;
|
|
|
|
public int mipCapacity => m_MipDownPyramidTextures.Length;
|
|
public int mipCount => m_MipCount;
|
|
|
|
public TextureHandle resultTexture { get; internal set; }
|
|
|
|
public TextureHandle GetResultMip(int index)
|
|
{
|
|
if (m_BloomFilterMode == BloomFilterMode.Kawase)
|
|
return resultTexture; // No mips.
|
|
|
|
if (mipCount == 1)
|
|
return mipDownTextures[0]; // Prefilter only.
|
|
|
|
int i = Mathf.Clamp(index, 0, mipCount - 1);
|
|
return mipUpTextures[i]; // Upsampled results.
|
|
}
|
|
|
|
internal TextureHandle[] mipDownTextures => m_MipDownPyramidTextures;
|
|
internal TextureHandle[] mipUpTextures => m_MipUpPyramidTextures;
|
|
|
|
internal BloomMipPyramid(int size = k_MaxPyramidSize)
|
|
{
|
|
// Arrays for Bloom pyramid TextureHandle names.
|
|
m_MipDownPyramidNames = new string[size];
|
|
m_MipUpPyramidNames = new string[size];
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
m_MipDownPyramidNames[i] = "_BloomMipDown" + i;
|
|
m_MipUpPyramidNames[i] = "_BloomMipUp" + i;
|
|
}
|
|
|
|
// Arrays for Bloom pyramid TextureHandles.
|
|
m_MipDownPyramidTextures = new TextureHandle[size];
|
|
m_MipUpPyramidTextures = new TextureHandle[size];
|
|
}
|
|
|
|
// Create bloom mip pyramid textures
|
|
internal void Update(RenderGraph renderGraph, Bloom bloom, in TextureDesc bloomSourceDesc)
|
|
{
|
|
Vector2Int bloomResolution = CalcBloomResolution(bloom, in bloomSourceDesc);
|
|
m_MipCount = CalcBloomMipCount(bloom, in bloomResolution);
|
|
int tw = bloomResolution.x;
|
|
int th = bloomResolution.y;
|
|
|
|
var desc = PostProcessUtils.GetCompatibleDescriptor(bloomSourceDesc, tw, th, bloomSourceDesc.colorFormat);
|
|
m_MipDownPyramidTextures[0] = PostProcessUtils.CreateCompatibleTexture(renderGraph, desc, m_MipDownPyramidNames[0], false, FilterMode.Bilinear);
|
|
m_MipUpPyramidTextures[0] = PostProcessUtils.CreateCompatibleTexture(renderGraph, desc, m_MipUpPyramidNames[0], false, FilterMode.Bilinear);
|
|
|
|
m_BloomFilterMode = bloom.filter.value;
|
|
if (m_BloomFilterMode != BloomFilterMode.Kawase)
|
|
{
|
|
for (int i = 1; i < mipCount; i++)
|
|
{
|
|
tw = Mathf.Max(1, tw >> 1);
|
|
th = Mathf.Max(1, th >> 1);
|
|
ref TextureHandle mipDown = ref m_MipDownPyramidTextures[i];
|
|
ref TextureHandle mipUp = ref m_MipUpPyramidTextures[i];
|
|
|
|
desc.width = tw;
|
|
desc.height = th;
|
|
|
|
mipDown = PostProcessUtils.CreateCompatibleTexture(renderGraph, desc, m_MipDownPyramidNames[i], false, FilterMode.Bilinear);
|
|
mipUp = PostProcessUtils.CreateCompatibleTexture(renderGraph, desc, m_MipUpPyramidNames[i], false, FilterMode.Bilinear);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cache params to avoid setting each property in each material every frame.
|
|
internal struct MaterialParams
|
|
{
|
|
internal Vector4 parameters;
|
|
internal Vector4 parameters2;
|
|
internal BloomFilterMode bloomFilter;
|
|
internal bool highQualityFiltering;
|
|
internal bool enableAlphaOutput;
|
|
|
|
internal bool Equals(ref MaterialParams other)
|
|
{
|
|
return parameters == other.parameters &&
|
|
parameters2 == other.parameters2 &&
|
|
highQualityFiltering == other.highQualityFiltering &&
|
|
enableAlphaOutput == other.enableAlphaOutput &&
|
|
bloomFilter == other.bloomFilter;
|
|
}
|
|
}
|
|
|
|
// Precomputed shader ids to same some CPU cycles (mostly affects mobile)
|
|
public static class ShaderConstants
|
|
{
|
|
public static readonly int _Params = Shader.PropertyToID("_Params");
|
|
public static readonly int _Params2 = Shader.PropertyToID("_Params2");
|
|
|
|
public static readonly int _SourceTexLowMip = Shader.PropertyToID("_SourceTexLowMip");
|
|
}
|
|
|
|
public static class ShaderPass
|
|
{
|
|
public const int k_Prefilter = 0;
|
|
public const int k_BlurHorizontal = 1;
|
|
public const int k_BlurVertical = 2;
|
|
public const int k_Upsample = 3;
|
|
public const int k_Kawase = 4;
|
|
public const int k_DualDownsample = 5;
|
|
public const int k_DualUpsample = 6;
|
|
}
|
|
}
|
|
}
|