initial commit

This commit is contained in:
Jo 2025-01-07 02:06:59 +01:00
parent 6715289efe
commit 788c3389af
37645 changed files with 2526849 additions and 80 deletions

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f68d0654b5ceb4a4b92e324b3d1a373c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,42 @@
Shader "Hidden/Universal Render Pipeline/DBufferClear"
{
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
LOD 100
Pass
{
Name "DBufferClear"
ZTest Always
ZWrite Off
Cull Off
HLSLPROGRAM
#pragma vertex FullscreenVert
#pragma fragment Fragment
#pragma multi_compile_fragment _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3
#pragma multi_compile _ _USE_DRAW_PROCEDURAL
#include "Packages/com.unity.render-pipelines.universal/Shaders/Utils/Fullscreen.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
void Fragment(
Varyings input,
OUTPUT_DBUFFER(outDBuffer))
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
outDBuffer0 = half4(0, 0, 0, 1);
#if defined(_DBUFFER_MRT3) || defined(_DBUFFER_MRT2)
outDBuffer1 = half4(0.5f, 0.5f, 0.5f, 1);
#endif
#if defined(_DBUFFER_MRT3)
outDBuffer2 = half4(0, 0, 0, 1);
#endif
}
ENDHLSL
}
}
}

View file

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f056d8bd2a1c7e44e9729144b4c70395
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,190 @@
using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering.Universal.Internal;
namespace UnityEngine.Rendering.Universal
{
internal class DecalDrawDBufferSystem : DecalDrawSystem
{
public DecalDrawDBufferSystem(DecalEntityManager entityManager) : base("DecalDrawIntoDBufferSystem.Execute", entityManager) { }
protected override int GetPassIndex(DecalCachedChunk decalCachedChunk) => decalCachedChunk.passIndexDBuffer;
}
internal class DBufferRenderPass : ScriptableRenderPass
{
private static string[] s_DBufferNames = { "_DBufferTexture0", "_DBufferTexture1", "_DBufferTexture2", "_DBufferTexture3" };
private static string s_DBufferDepthName = "DBufferDepth";
private DecalDrawDBufferSystem m_DrawSystem;
private DBufferSettings m_Settings;
private Material m_DBufferClear;
private FilteringSettings m_FilteringSettings;
private List<ShaderTagId> m_ShaderTagIdList;
private int m_DBufferCount;
private ProfilingSampler m_ProfilingSampler;
internal DeferredLights deferredLights { get; set; }
private bool isDeferred => deferredLights != null;
internal RenderTargetIdentifier[] dBufferColorIndentifiers { get; private set; }
internal RenderTargetIdentifier dBufferDepthIndentifier { get; private set; }
internal RenderTargetIdentifier cameraDepthTextureIndentifier { get; private set; }
internal RenderTargetIdentifier cameraDepthAttachmentIndentifier { get; private set; }
public DBufferRenderPass(Material dBufferClear, DBufferSettings settings, DecalDrawDBufferSystem drawSystem)
{
renderPassEvent = RenderPassEvent.AfterRenderingPrePasses + 1;
ConfigureInput(ScriptableRenderPassInput.Normal); // Require depth
m_DrawSystem = drawSystem;
m_Settings = settings;
m_DBufferClear = dBufferClear;
m_ProfilingSampler = new ProfilingSampler("DBuffer Render");
m_FilteringSettings = new FilteringSettings(RenderQueueRange.opaque, -1);
m_ShaderTagIdList = new List<ShaderTagId>();
m_ShaderTagIdList.Add(new ShaderTagId(DecalShaderPassNames.DBufferMesh));
int dBufferCount = (int)settings.surfaceData + 1;
dBufferColorIndentifiers = new RenderTargetIdentifier[dBufferCount];
for (int dbufferIndex = 0; dbufferIndex < dBufferCount; ++dbufferIndex)
dBufferColorIndentifiers[dbufferIndex] = new RenderTargetIdentifier(s_DBufferNames[dbufferIndex]);
m_DBufferCount = dBufferCount;
dBufferDepthIndentifier = new RenderTargetIdentifier(s_DBufferDepthName);
cameraDepthTextureIndentifier = new RenderTargetIdentifier("_CameraDepthTexture");
cameraDepthAttachmentIndentifier = new RenderTargetIdentifier("_CameraDepthAttachment");
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
// base
{
var desc = renderingData.cameraData.cameraTargetDescriptor;
desc.graphicsFormat = QualitySettings.activeColorSpace == ColorSpace.Linear ? GraphicsFormat.R8G8B8A8_SRGB : GraphicsFormat.R8G8B8A8_UNorm;
desc.depthBufferBits = 0;
desc.msaaSamples = 1;
cmd.GetTemporaryRT(Shader.PropertyToID(s_DBufferNames[0]), desc);
}
if (m_Settings.surfaceData == DecalSurfaceData.AlbedoNormal || m_Settings.surfaceData == DecalSurfaceData.AlbedoNormalMAOS)
{
var desc = renderingData.cameraData.cameraTargetDescriptor;
desc.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm;
desc.depthBufferBits = 0;
desc.msaaSamples = 1;
cmd.GetTemporaryRT(Shader.PropertyToID(s_DBufferNames[1]), desc);
}
if (m_Settings.surfaceData == DecalSurfaceData.AlbedoNormalMAOS)
{
var desc = renderingData.cameraData.cameraTargetDescriptor;
desc.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm;
desc.depthBufferBits = 0;
desc.msaaSamples = 1;
cmd.GetTemporaryRT(Shader.PropertyToID(s_DBufferNames[2]), desc);
}
// depth
RenderTargetIdentifier depthIdentifier;
if (!isDeferred)
{
var depthDesc = renderingData.cameraData.cameraTargetDescriptor;
depthDesc.graphicsFormat = GraphicsFormat.None; //Depth only rendering
depthDesc.depthStencilFormat = renderingData.cameraData.cameraTargetDescriptor.depthStencilFormat;
depthDesc.msaaSamples = 1;
cmd.GetTemporaryRT(Shader.PropertyToID(s_DBufferDepthName), depthDesc);
depthIdentifier = dBufferDepthIndentifier;
}
else
{
depthIdentifier = deferredLights.DepthAttachmentIdentifier;
}
ConfigureTarget(dBufferColorIndentifiers, depthIdentifier);
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
SortingCriteria sortingCriteria = renderingData.cameraData.defaultOpaqueSortFlags;
DrawingSettings drawingSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, sortingCriteria);
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, m_ProfilingSampler))
{
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
if (isDeferred)
{
cmd.SetGlobalTexture("_CameraNormalsTexture", deferredLights.GbufferAttachmentIdentifiers[deferredLights.GBufferNormalSmoothnessIndex]);
}
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DBufferMRT1, m_Settings.surfaceData == DecalSurfaceData.Albedo);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DBufferMRT2, m_Settings.surfaceData == DecalSurfaceData.AlbedoNormal);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DBufferMRT3, m_Settings.surfaceData == DecalSurfaceData.AlbedoNormalMAOS);
// TODO: This should be replace with mrt clear once we support it
// Clear render targets
ClearDBuffers(cmd, renderingData.cameraData);
// Split here allows clear to be executed before DrawRenderers
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
m_DrawSystem.Execute(cmd);
context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref m_FilteringSettings);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
private void ClearDBuffers(CommandBuffer cmd, in CameraData cameraData)
{
// for alpha compositing, color is cleared to 0, alpha to 1
// https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch23.html
var clearSampleName = "Clear";
cmd.BeginSample(clearSampleName);
Vector4 scaleBias = new Vector4(1, 1, 0, 0);
cmd.SetGlobalVector(ShaderPropertyId.scaleBias, scaleBias);
if (cameraData.xr.enabled)
{
cmd.DrawProcedural(Matrix4x4.identity, m_DBufferClear, 0, MeshTopology.Quads, 4, 1, null);
}
else
{
cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity); // Prepare for manual blit
cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_DBufferClear, 0, 0);
cmd.SetViewProjectionMatrices(cameraData.camera.worldToCameraMatrix, cameraData.camera.projectionMatrix);
}
cmd.EndSample(clearSampleName);
}
public override void OnCameraCleanup(CommandBuffer cmd)
{
if (cmd == null)
{
throw new System.ArgumentNullException("cmd");
}
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DBufferMRT1, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DBufferMRT2, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DBufferMRT3, false);
for (int dbufferIndex = 0; dbufferIndex < m_DBufferCount; ++dbufferIndex)
{
cmd.ReleaseTemporaryRT(Shader.PropertyToID(s_DBufferNames[dbufferIndex]));
}
if (!isDeferred)
cmd.ReleaseTemporaryRT(Shader.PropertyToID(s_DBufferDepthName));
}
}
}

View file

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

View file

@ -0,0 +1,50 @@
using System.Collections.Generic;
namespace UnityEngine.Rendering.Universal
{
internal class DecalDrawFowardEmissiveSystem : DecalDrawSystem
{
public DecalDrawFowardEmissiveSystem(DecalEntityManager entityManager) : base("DecalDrawFowardEmissiveSystem.Execute", entityManager) { }
protected override int GetPassIndex(DecalCachedChunk decalCachedChunk) => decalCachedChunk.passIndexEmissive;
}
internal class DecalForwardEmissivePass : ScriptableRenderPass
{
private FilteringSettings m_FilteringSettings;
private ProfilingSampler m_ProfilingSampler;
private List<ShaderTagId> m_ShaderTagIdList;
private DecalDrawFowardEmissiveSystem m_DrawSystem;
public DecalForwardEmissivePass(DecalDrawFowardEmissiveSystem drawSystem)
{
renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
ConfigureInput(ScriptableRenderPassInput.Depth); // Require depth
m_DrawSystem = drawSystem;
m_ProfilingSampler = new ProfilingSampler("Decal Forward Emissive Render");
m_FilteringSettings = new FilteringSettings(RenderQueueRange.opaque, -1);
m_ShaderTagIdList = new List<ShaderTagId>();
m_ShaderTagIdList.Add(new ShaderTagId(DecalShaderPassNames.DecalMeshForwardEmissive));
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
SortingCriteria sortingCriteria = renderingData.cameraData.defaultOpaqueSortFlags;
DrawingSettings drawingSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, sortingCriteria);
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, m_ProfilingSampler))
{
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
m_DrawSystem.Execute(cmd);
context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref m_FilteringSettings);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
}

View file

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

View file

@ -0,0 +1,35 @@
using System.Collections.Generic;
using Unity.Collections;
using Unity.Mathematics;
namespace UnityEngine.Rendering.Universal
{
internal class DecalDrawErrorSystem : DecalDrawSystem
{
private DecalTechnique m_Technique;
public DecalDrawErrorSystem(DecalEntityManager entityManager, DecalTechnique technique) : base("DecalDrawErrorSystem.Execute", entityManager)
{
m_Technique = technique;
}
protected override int GetPassIndex(DecalCachedChunk decalCachedChunk)
{
switch (m_Technique)
{
case DecalTechnique.DBuffer:
return ((decalCachedChunk.passIndexDBuffer == -1) && (decalCachedChunk.passIndexEmissive == -1)) ? 0 : -1;
case DecalTechnique.ScreenSpace:
return decalCachedChunk.passIndexScreenSpace == -1 ? 0 : -1;
case DecalTechnique.GBuffer:
return decalCachedChunk.passIndexGBuffer == -1 ? 0 : -1;
case DecalTechnique.Invalid:
return 0;
default:
return 0;
}
}
protected override Material GetMaterial(DecalEntityChunk decalEntityChunk) => m_EntityManager.errorMaterial;
}
}

View file

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

View file

@ -0,0 +1,40 @@
using System.Collections.Generic;
namespace UnityEngine.Rendering.Universal
{
internal class DecalPreviewPass : ScriptableRenderPass
{
private FilteringSettings m_FilteringSettings;
private List<ShaderTagId> m_ShaderTagIdList;
private ProfilingSampler m_ProfilingSampler;
public DecalPreviewPass()
{
renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
ConfigureInput(ScriptableRenderPassInput.Depth); // Require depth
m_ProfilingSampler = new ProfilingSampler("Decal Preview Render");
m_FilteringSettings = new FilteringSettings(RenderQueueRange.opaque, -1);
m_ShaderTagIdList = new List<ShaderTagId>();
m_ShaderTagIdList.Add(new ShaderTagId(DecalShaderPassNames.DecalScreenSpaceMesh));
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
SortingCriteria sortingCriteria = renderingData.cameraData.defaultOpaqueSortFlags;
DrawingSettings drawingSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, sortingCriteria);
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, m_ProfilingSampler))
{
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref m_FilteringSettings);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
}

View file

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

View file

@ -0,0 +1,331 @@
using System;
using UnityEditor;
namespace UnityEngine.Rendering.Universal
{
/// <summary>The scaling mode to apply to decals that use the Decal Projector.</summary>
public enum DecalScaleMode
{
/// <summary>Ignores the transformation hierarchy and uses the scale values in the Decal Projector component directly.</summary>
ScaleInvariant,
/// <summary>Multiplies the lossy scale of the Transform with the Decal Projector's own scale then applies this to the decal.</summary>
[InspectorName("Inherit from Hierarchy")]
InheritFromHierarchy,
}
/// <summary>
/// Decal Projector component.
/// </summary>
[ExecuteAlways]
#if UNITY_EDITOR
[CanEditMultipleObjects]
#endif
[AddComponentMenu("Rendering/URP Decal Projector")]
public class DecalProjector : MonoBehaviour
{
internal delegate void DecalProjectorAction(DecalProjector decalProjector);
internal static event DecalProjectorAction onDecalAdd;
internal static event DecalProjectorAction onDecalRemove;
internal static event DecalProjectorAction onDecalPropertyChange;
internal static event DecalProjectorAction onDecalMaterialChange;
internal static Material defaultMaterial { get; set; }
internal static bool isSupported => onDecalAdd != null;
internal DecalEntity decalEntity { get; set; }
[SerializeField]
private Material m_Material = null;
/// <summary>
/// The material used by the decal.
/// </summary>
public Material material
{
get
{
return m_Material;
}
set
{
m_Material = value;
OnValidate();
}
}
[SerializeField]
private float m_DrawDistance = 1000.0f;
/// <summary>
/// Distance from camera at which the Decal is not rendered anymore.
/// </summary>
public float drawDistance
{
get
{
return m_DrawDistance;
}
set
{
m_DrawDistance = Mathf.Max(0f, value);
OnValidate();
}
}
[SerializeField]
[Range(0, 1)]
private float m_FadeScale = 0.9f;
/// <summary>
/// Percent of the distance from the camera at which this Decal start to fade off.
/// </summary>
public float fadeScale
{
get
{
return m_FadeScale;
}
set
{
m_FadeScale = Mathf.Clamp01(value);
OnValidate();
}
}
[SerializeField]
[Range(0, 180)]
private float m_StartAngleFade = 180.0f;
/// <summary>
/// Angle between decal backward orientation and vertex normal of receiving surface at which the Decal start to fade off.
/// </summary>
public float startAngleFade
{
get
{
return m_StartAngleFade;
}
set
{
m_StartAngleFade = Mathf.Clamp(value, 0.0f, 180.0f);
OnValidate();
}
}
[SerializeField]
[Range(0, 180)]
private float m_EndAngleFade = 180.0f;
/// <summary>
/// Angle between decal backward orientation and vertex normal of receiving surface at which the Decal end to fade off.
/// </summary>
public float endAngleFade
{
get
{
return m_EndAngleFade;
}
set
{
m_EndAngleFade = Mathf.Clamp(value, m_StartAngleFade, 180.0f);
OnValidate();
}
}
[SerializeField]
private Vector2 m_UVScale = new Vector2(1, 1);
/// <summary>
/// Tilling of the UV of the projected texture.
/// </summary>
public Vector2 uvScale
{
get
{
return m_UVScale;
}
set
{
m_UVScale = value;
OnValidate();
}
}
[SerializeField]
private Vector2 m_UVBias = new Vector2(0, 0);
/// <summary>
/// Offset of the UV of the projected texture.
/// </summary>
public Vector2 uvBias
{
get
{
return m_UVBias;
}
set
{
m_UVBias = value;
OnValidate();
}
}
[SerializeField]
private DecalScaleMode m_ScaleMode = DecalScaleMode.ScaleInvariant;
/// <summary>
/// The scaling mode to apply to decals that use this Decal Projector.
/// </summary>
public DecalScaleMode scaleMode
{
get => m_ScaleMode;
set
{
m_ScaleMode = value;
OnValidate();
}
}
[SerializeField]
internal Vector3 m_Offset = new Vector3(0, 0, 0.5f);
/// <summary>
/// Change the offset position.
/// Do not expose: Could be changed by the inspector when manipulating the gizmo.
/// </summary>
public Vector3 pivot
{
get
{
return m_Offset;
}
set
{
m_Offset = value;
OnValidate();
}
}
[SerializeField]
internal Vector3 m_Size = new Vector3(1, 1, 1);
/// <summary>
/// The size of the projection volume.
/// </summary>
public Vector3 size
{
get
{
return m_Size;
}
set
{
m_Size = value;
OnValidate();
}
}
[SerializeField]
[Range(0, 1)]
private float m_FadeFactor = 1.0f;
/// <summary>
/// Controls the transparency of the decal.
/// </summary>
public float fadeFactor
{
get
{
return m_FadeFactor;
}
set
{
m_FadeFactor = Mathf.Clamp01(value);
OnValidate();
}
}
private Material m_OldMaterial = null;
/// <summary>A scale that should be used for rendering and handles.</summary>
internal Vector3 effectiveScale => m_ScaleMode == DecalScaleMode.InheritFromHierarchy ? transform.lossyScale : Vector3.one;
/// <summary>current size in a way the DecalSystem will be able to use it</summary>
internal Vector3 decalSize => new Vector3(m_Size.x, m_Size.z, m_Size.y);
/// <summary>current size in a way the DecalSystem will be able to use it</summary>
internal Vector3 decalOffset => new Vector3(m_Offset.x, -m_Offset.z, m_Offset.y);
/// <summary>current uv parameters in a way the DecalSystem will be able to use it</summary>
internal Vector4 uvScaleBias => new Vector4(m_UVScale.x, m_UVScale.y, m_UVBias.x, m_UVBias.y);
void InitMaterial()
{
if (m_Material == null)
{
#if UNITY_EDITOR
m_Material = defaultMaterial;
#endif
}
}
void OnEnable()
{
InitMaterial();
m_OldMaterial = m_Material;
onDecalAdd?.Invoke(this);
#if UNITY_EDITOR
// Handle scene visibility
UnityEditor.SceneVisibilityManager.visibilityChanged += UpdateDecalVisibility;
#endif
}
#if UNITY_EDITOR
void UpdateDecalVisibility()
{
// Fade out the decal when it is hidden by the scene visibility
if (UnityEditor.SceneVisibilityManager.instance.IsHidden(gameObject))
{
onDecalRemove?.Invoke(this);
}
else
{
onDecalAdd?.Invoke(this);
onDecalPropertyChange?.Invoke(this); // Scene culling mask may have changed.
}
}
#endif
void OnDisable()
{
onDecalRemove?.Invoke(this);
#if UNITY_EDITOR
UnityEditor.SceneVisibilityManager.visibilityChanged -= UpdateDecalVisibility;
#endif
}
internal void OnValidate()
{
if (!isActiveAndEnabled)
return;
if (m_Material != m_OldMaterial)
{
onDecalMaterialChange?.Invoke(this);
m_OldMaterial = m_Material;
}
else
onDecalPropertyChange?.Invoke(this);
}
public bool IsValid()
{
if (material == null)
return false;
if (material.FindPass(DecalShaderPassNames.DBufferProjector) != -1)
return true;
if (material.FindPass(DecalShaderPassNames.DecalProjectorForwardEmissive) != -1)
return true;
if (material.FindPass(DecalShaderPassNames.DecalScreenSpaceProjector) != -1)
return true;
if (material.FindPass(DecalShaderPassNames.DecalGBufferProjector) != -1)
return true;
return false;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0777d029ed3dffa4692f417d4aba19ca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 9ba98ca4f0fc0754caca09e38af0cc0a, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,17 @@
namespace UnityEngine.Rendering.Universal
{
internal static class DecalShaderPassNames
{
public const string DecalPreview = "DecalPreview";
public const string DBufferProjector = "DBufferProjector";
public const string DecalProjectorForwardEmissive = "DecalProjectorForwardEmissive";
public const string DecalScreenSpaceProjector = "DecalScreenSpaceProjector";
public const string DecalGBufferProjector = "DecalGBufferProjector";
public const string DBufferMesh = "DBufferMesh";
public const string DecalMeshForwardEmissive = "DecalMeshForwardEmissive";
public const string DecalScreenSpaceMesh = "DecalScreenSpaceMesh";
public const string DecalGBufferMesh = "DecalGBufferMesh";
}
}

View file

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

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6b3e7dae1e82a6b448b739d1331813f0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,44 @@
using System;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine.Jobs;
using UnityEngine.Rendering;
namespace UnityEngine.Rendering.Universal
{
internal abstract class DecalChunk : IDisposable
{
public int count { get; protected set; }
public int capacity { get; protected set; }
public JobHandle currentJobHandle { get; set; }
public virtual void Push() { count++; }
public abstract void RemoveAtSwapBack(int index);
public abstract void SetCapacity(int capacity);
public virtual void Dispose() { }
protected void ResizeNativeArray(ref TransformAccessArray array, DecalProjector[] decalProjectors, int capacity)
{
var newArray = new TransformAccessArray(capacity);
if (array.isCreated)
{
for (int i = 0; i < array.length; ++i)
newArray.Add(decalProjectors[i].transform);
array.Dispose();
}
array = newArray;
}
protected void RemoveAtSwapBack<T>(ref NativeArray<T> array, int index, int count) where T : struct
{
array[index] = array[count - 1];
}
protected void RemoveAtSwapBack<T>(ref T[] array, int index, int count)
{
array[index] = array[count - 1];
}
}
}

View file

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

View file

@ -0,0 +1,217 @@
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
namespace UnityEngine.Rendering.Universal
{
internal struct DecalSubDrawCall
{
public int start;
public int end;
public int count { get => end - start; }
}
/// <summary>
/// Contains information about <see cref="DecalEntity"/> draw calls.
/// </summary>
internal class DecalDrawCallChunk : DecalChunk
{
public NativeArray<float4x4> decalToWorlds;
public NativeArray<float4x4> normalToDecals;
public NativeArray<DecalSubDrawCall> subCalls;
public NativeArray<int> subCallCounts;
public int subCallCount { set { subCallCounts[0] = value; } get => subCallCounts[0]; }
public override void RemoveAtSwapBack(int entityIndex)
{
RemoveAtSwapBack(ref decalToWorlds, entityIndex, count);
RemoveAtSwapBack(ref normalToDecals, entityIndex, count);
RemoveAtSwapBack(ref subCalls, entityIndex, count);
count--;
}
public override void SetCapacity(int newCapacity)
{
decalToWorlds.ResizeArray(newCapacity);
normalToDecals.ResizeArray(newCapacity);
subCalls.ResizeArray(newCapacity);
capacity = newCapacity;
}
public override void Dispose()
{
subCallCounts.Dispose();
if (capacity == 0)
return;
decalToWorlds.Dispose();
normalToDecals.Dispose();
subCalls.Dispose();
count = 0;
capacity = 0;
}
}
/// <summary>
/// Outputs draw calls into <see cref="DecalDrawCallChunk"/>.
/// </summary>
internal class DecalCreateDrawCallSystem
{
private DecalEntityManager m_EntityManager;
private ProfilingSampler m_Sampler;
private float m_MaxDrawDistance;
/// <summary>
/// Provides acces to the maximum draw distance.
/// </summary>
public float maxDrawDistance
{
get { return m_MaxDrawDistance; }
set { m_MaxDrawDistance = value; }
}
public DecalCreateDrawCallSystem(DecalEntityManager entityManager, float maxDrawDistance)
{
m_EntityManager = entityManager;
m_Sampler = new ProfilingSampler("DecalCreateDrawCallSystem.Execute");
m_MaxDrawDistance = maxDrawDistance;
}
public void Execute()
{
using (new ProfilingScope(null, m_Sampler))
{
for (int i = 0; i < m_EntityManager.chunkCount; ++i)
Execute(m_EntityManager.cachedChunks[i], m_EntityManager.culledChunks[i], m_EntityManager.drawCallChunks[i], m_EntityManager.cachedChunks[i].count);
}
}
private void Execute(DecalCachedChunk cachedChunk, DecalCulledChunk culledChunk, DecalDrawCallChunk drawCallChunk, int count)
{
if (count == 0)
return;
DrawCallJob drawCallJob = new DrawCallJob()
{
decalToWorlds = cachedChunk.decalToWorlds,
normalToWorlds = cachedChunk.normalToWorlds,
sizeOffsets = cachedChunk.sizeOffsets,
drawDistances = cachedChunk.drawDistances,
angleFades = cachedChunk.angleFades,
uvScaleBiases = cachedChunk.uvScaleBias,
layerMasks = cachedChunk.layerMasks,
sceneLayerMasks = cachedChunk.sceneLayerMasks,
fadeFactors = cachedChunk.fadeFactors,
boundingSpheres = cachedChunk.boundingSpheres,
cameraPosition = culledChunk.cameraPosition,
sceneCullingMask = culledChunk.sceneCullingMask,
cullingMask = culledChunk.cullingMask,
visibleDecalIndices = culledChunk.visibleDecalIndices,
visibleDecalCount = culledChunk.visibleDecalCount,
maxDrawDistance = m_MaxDrawDistance,
decalToWorldsDraw = drawCallChunk.decalToWorlds,
normalToDecalsDraw = drawCallChunk.normalToDecals,
subCalls = drawCallChunk.subCalls,
subCallCount = drawCallChunk.subCallCounts,
};
var handle = drawCallJob.Schedule(cachedChunk.currentJobHandle);
drawCallChunk.currentJobHandle = handle;
cachedChunk.currentJobHandle = handle;
}
#if ENABLE_BURST_1_0_0_OR_NEWER
[Unity.Burst.BurstCompile]
#endif
struct DrawCallJob : IJob
{
[ReadOnly] public NativeArray<float4x4> decalToWorlds;
[ReadOnly] public NativeArray<float4x4> normalToWorlds;
[ReadOnly] public NativeArray<float4x4> sizeOffsets;
[ReadOnly] public NativeArray<float2> drawDistances;
[ReadOnly] public NativeArray<float2> angleFades;
[ReadOnly] public NativeArray<float4> uvScaleBiases;
[ReadOnly] public NativeArray<int> layerMasks;
[ReadOnly] public NativeArray<ulong> sceneLayerMasks;
[ReadOnly] public NativeArray<float> fadeFactors;
[ReadOnly] public NativeArray<BoundingSphere> boundingSpheres;
public Vector3 cameraPosition;
public ulong sceneCullingMask;
public int cullingMask;
[ReadOnly] public NativeArray<int> visibleDecalIndices;
public int visibleDecalCount;
public float maxDrawDistance;
[WriteOnly] public NativeArray<float4x4> decalToWorldsDraw;
[WriteOnly] public NativeArray<float4x4> normalToDecalsDraw;
[WriteOnly] public NativeArray<DecalSubDrawCall> subCalls;
[WriteOnly] public NativeArray<int> subCallCount;
public void Execute()
{
int subCallIndex = 0;
int instanceIndex = 0;
int instanceStart = 0;
for (int i = 0; i < visibleDecalCount; ++i)
{
int decalIndex = visibleDecalIndices[i];
#if UNITY_EDITOR
ulong decalSceneCullingMask = sceneLayerMasks[decalIndex];
if ((sceneCullingMask & decalSceneCullingMask) == 0)
continue;
#endif
int decalMask = 1 << layerMasks[decalIndex];
if ((cullingMask & decalMask) == 0)
continue;
BoundingSphere boundingSphere = boundingSpheres[decalIndex];
float2 drawDistance = drawDistances[decalIndex];
float distanceToDecal = (cameraPosition - boundingSphere.position).magnitude;
float cullDistance = math.min(drawDistance.x, maxDrawDistance) + boundingSphere.radius;
if (distanceToDecal > cullDistance)
continue;
decalToWorldsDraw[instanceIndex] = decalToWorlds[decalIndex];
float fadeFactorScaler = fadeFactors[decalIndex];
float2 angleFade = angleFades[decalIndex];
float4 uvScaleBias = uvScaleBiases[decalIndex];
float4x4 normalToDecals = normalToWorlds[decalIndex];
// NormalToWorldBatchis a Matrix4x4x but is a Rotation matrix so bottom row and last column can be used for other data to save space
float fadeFactor = fadeFactorScaler * math.clamp((cullDistance - distanceToDecal) / (cullDistance * (1.0f - drawDistance.y)), 0.0f, 1.0f);
normalToDecals.c0.w = uvScaleBias.x;
normalToDecals.c1.w = uvScaleBias.y;
normalToDecals.c2.w = uvScaleBias.z;
normalToDecals.c3 = new float4(fadeFactor * 1.0f, angleFade.x, angleFade.y, uvScaleBias.w);
normalToDecalsDraw[instanceIndex] = normalToDecals;
instanceIndex++;
int instanceCount = instanceIndex - instanceStart;
bool isReachedMaximumBatchSize = instanceCount >= 250;
bool isLastDecal = i == visibleDecalCount - 1;
if (isReachedMaximumBatchSize || isLastDecal)
{
subCalls[subCallIndex++] = new DecalSubDrawCall()
{
start = instanceStart,
end = instanceIndex,
};
instanceStart = instanceIndex;
}
}
subCallCount[0] = subCallIndex;
}
}
}
}

View file

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

View file

@ -0,0 +1,187 @@
using Unity.Collections;
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// Abstract class that render decals using <see cref="DecalDrawCallChunk"/>.
/// Supports rendering with <see cref="CommandBuffer"/> and graphics draw calls.
/// </summary>
internal abstract class DecalDrawSystem
{
protected DecalEntityManager m_EntityManager;
private Matrix4x4[] m_WorldToDecals;
private Matrix4x4[] m_NormalToDecals;
private ProfilingSampler m_Sampler;
public Material overrideMaterial { get; set; }
public DecalDrawSystem(string sampler, DecalEntityManager entityManager)
{
m_EntityManager = entityManager;
m_WorldToDecals = new Matrix4x4[250];
m_NormalToDecals = new Matrix4x4[250];
m_Sampler = new ProfilingSampler(sampler);
}
public void Execute(CommandBuffer cmd)
{
using (new ProfilingScope(cmd, m_Sampler))
{
for (int i = 0; i < m_EntityManager.chunkCount; ++i)
{
Execute(
cmd,
m_EntityManager.entityChunks[i],
m_EntityManager.cachedChunks[i],
m_EntityManager.drawCallChunks[i],
m_EntityManager.entityChunks[i].count);
}
}
}
protected virtual Material GetMaterial(DecalEntityChunk decalEntityChunk) => decalEntityChunk.material;
protected abstract int GetPassIndex(DecalCachedChunk decalCachedChunk);
private void Execute(CommandBuffer cmd, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk, int count)
{
decalCachedChunk.currentJobHandle.Complete();
decalDrawCallChunk.currentJobHandle.Complete();
Material material = GetMaterial(decalEntityChunk);
int passIndex = GetPassIndex(decalCachedChunk);
if (count == 0 || passIndex == -1 || material == null)
return;
if (SystemInfo.supportsInstancing && material.enableInstancing)
{
DrawInstanced(cmd, decalEntityChunk, decalCachedChunk, decalDrawCallChunk, passIndex);
}
else
{
Draw(cmd, decalEntityChunk, decalCachedChunk, decalDrawCallChunk, passIndex);
}
}
private void Draw(CommandBuffer cmd, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk, int passIndex)
{
var mesh = m_EntityManager.decalProjectorMesh;
var material = GetMaterial(decalEntityChunk);
decalCachedChunk.propertyBlock.SetVector("unity_LightData", new Vector4(1, 1, 1, 0)); // GetMainLight requires z component to be set
int subCallCount = decalDrawCallChunk.subCallCount;
for (int i = 0; i < subCallCount; ++i)
{
var subCall = decalDrawCallChunk.subCalls[i];
for (int j = subCall.start; j < subCall.end; ++j)
{
decalCachedChunk.propertyBlock.SetMatrix("_NormalToWorld", decalDrawCallChunk.normalToDecals[j]);
cmd.DrawMesh(mesh, decalDrawCallChunk.decalToWorlds[j], material, 0, passIndex, decalCachedChunk.propertyBlock);
}
}
}
private void DrawInstanced(CommandBuffer cmd, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk, int passIndex)
{
var mesh = m_EntityManager.decalProjectorMesh;
var material = GetMaterial(decalEntityChunk);
decalCachedChunk.propertyBlock.SetVector("unity_LightData", new Vector4(1, 1, 1, 0)); // GetMainLight requires z component to be set
int subCallCount = decalDrawCallChunk.subCallCount;
for (int i = 0; i < subCallCount; ++i)
{
var subCall = decalDrawCallChunk.subCalls[i];
var decalToWorldSlice = decalDrawCallChunk.decalToWorlds.Reinterpret<Matrix4x4>();
NativeArray<Matrix4x4>.Copy(decalToWorldSlice, subCall.start, m_WorldToDecals, 0, subCall.count);
var normalToWorldSlice = decalDrawCallChunk.normalToDecals.Reinterpret<Matrix4x4>();
NativeArray<Matrix4x4>.Copy(normalToWorldSlice, subCall.start, m_NormalToDecals, 0, subCall.count);
decalCachedChunk.propertyBlock.SetMatrixArray("_NormalToWorld", m_NormalToDecals);
cmd.DrawMeshInstanced(mesh, 0, material, passIndex, m_WorldToDecals, subCall.end - subCall.start, decalCachedChunk.propertyBlock);
}
}
public void Execute(in CameraData cameraData)
{
using (new ProfilingScope(null, m_Sampler))
{
for (int i = 0; i < m_EntityManager.chunkCount; ++i)
{
Execute(
cameraData,
m_EntityManager.entityChunks[i],
m_EntityManager.cachedChunks[i],
m_EntityManager.drawCallChunks[i],
m_EntityManager.entityChunks[i].count);
}
}
}
private void Execute(in CameraData cameraData, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk, int count)
{
decalCachedChunk.currentJobHandle.Complete();
decalDrawCallChunk.currentJobHandle.Complete();
Material material = GetMaterial(decalEntityChunk);
int passIndex = GetPassIndex(decalCachedChunk);
if (count == 0 || passIndex == -1 || material == null)
return;
if (SystemInfo.supportsInstancing && material.enableInstancing)
{
DrawInstanced(cameraData, decalEntityChunk, decalCachedChunk, decalDrawCallChunk);
}
else
{
Draw(cameraData, decalEntityChunk, decalCachedChunk, decalDrawCallChunk);
}
}
private void Draw(in CameraData cameraData, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk)
{
var mesh = m_EntityManager.decalProjectorMesh;
var material = GetMaterial(decalEntityChunk);
int subCallCount = decalDrawCallChunk.subCallCount;
for (int i = 0; i < subCallCount; ++i)
{
var subCall = decalDrawCallChunk.subCalls[i];
for (int j = subCall.start; j < subCall.end; ++j)
{
decalCachedChunk.propertyBlock.SetMatrix("_NormalToWorld", decalDrawCallChunk.normalToDecals[j]);
Graphics.DrawMesh(mesh, decalCachedChunk.decalToWorlds[j], material, decalCachedChunk.layerMasks[j], cameraData.camera, 0, decalCachedChunk.propertyBlock);
}
}
}
private void DrawInstanced(in CameraData cameraData, DecalEntityChunk decalEntityChunk, DecalCachedChunk decalCachedChunk, DecalDrawCallChunk decalDrawCallChunk)
{
var mesh = m_EntityManager.decalProjectorMesh;
var material = GetMaterial(decalEntityChunk);
decalCachedChunk.propertyBlock.SetVector("unity_LightData", new Vector4(1, 1, 1, 0)); // GetMainLight requires z component to be set
int subCallCount = decalDrawCallChunk.subCallCount;
for (int i = 0; i < subCallCount; ++i)
{
var subCall = decalDrawCallChunk.subCalls[i];
var decalToWorldSlice = decalDrawCallChunk.decalToWorlds.Reinterpret<Matrix4x4>();
NativeArray<Matrix4x4>.Copy(decalToWorldSlice, subCall.start, m_WorldToDecals, 0, subCall.count);
var normalToWorldSlice = decalDrawCallChunk.normalToDecals.Reinterpret<Matrix4x4>();
NativeArray<Matrix4x4>.Copy(normalToWorldSlice, subCall.start, m_NormalToDecals, 0, subCall.count);
decalCachedChunk.propertyBlock.SetMatrixArray("_NormalToWorld", m_NormalToDecals);
Graphics.DrawMeshInstanced(mesh, 0, material,
m_WorldToDecals, subCall.count, decalCachedChunk.propertyBlock, ShadowCastingMode.On, true, 0, cameraData.camera);
}
}
}
}

View file

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

View file

@ -0,0 +1,520 @@
using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine.Assertions;
using UnityEngine.Jobs;
namespace UnityEngine.Rendering.Universal
{
internal class DecalEntityIndexer
{
public struct DecalEntityItem
{
public int chunkIndex;
public int arrayIndex;
public int version;
}
private List<DecalEntityItem> m_Entities = new List<DecalEntityItem>();
private Queue<int> m_FreeIndices = new Queue<int>();
public bool IsValid(DecalEntity decalEntity)
{
if (m_Entities.Count <= decalEntity.index)
return false;
return m_Entities[decalEntity.index].version == decalEntity.version;
}
public DecalEntity CreateDecalEntity(int arrayIndex, int chunkIndex)
{
// Reuse
if (m_FreeIndices.Count != 0)
{
int entityIndex = m_FreeIndices.Dequeue();
int newVersion = m_Entities[entityIndex].version + 1;
m_Entities[entityIndex] = new DecalEntityItem()
{
arrayIndex = arrayIndex,
chunkIndex = chunkIndex,
version = newVersion,
};
return new DecalEntity()
{
index = entityIndex,
version = newVersion,
};
}
// Create new one
{
int entityIndex = m_Entities.Count;
int version = 1;
m_Entities.Add(new DecalEntityItem()
{
arrayIndex = arrayIndex,
chunkIndex = chunkIndex,
version = version,
});
return new DecalEntity()
{
index = entityIndex,
version = version,
};
}
}
public void DestroyDecalEntity(DecalEntity decalEntity)
{
Assert.IsTrue(IsValid(decalEntity));
m_FreeIndices.Enqueue(decalEntity.index);
// Update version that everything that points to it will have outdated version
var item = m_Entities[decalEntity.index];
item.version++;
m_Entities[decalEntity.index] = item;
}
public DecalEntityItem GetItem(DecalEntity decalEntity)
{
Assert.IsTrue(IsValid(decalEntity));
return m_Entities[decalEntity.index];
}
public void UpdateIndex(DecalEntity decalEntity, int newArrayIndex)
{
Assert.IsTrue(IsValid(decalEntity));
var item = m_Entities[decalEntity.index];
item.arrayIndex = newArrayIndex;
item.version = decalEntity.version;
m_Entities[decalEntity.index] = item;
}
public void RemapChunkIndices(List<int> remaper)
{
for (int i = 0; i < m_Entities.Count; ++i)
{
int newChunkIndex = remaper[m_Entities[i].chunkIndex];
var item = m_Entities[i];
item.chunkIndex = newChunkIndex;
m_Entities[i] = item;
}
}
public void Clear()
{
m_Entities.Clear();
m_FreeIndices.Clear();
}
}
internal struct DecalEntity
{
public int index;
public int version;
}
/// <summary>
/// Contains <see cref="DecalEntity"/> and shared material.
/// </summary>
internal class DecalEntityChunk : DecalChunk
{
public Material material;
public NativeArray<DecalEntity> decalEntities;
public DecalProjector[] decalProjectors;
public TransformAccessArray transformAccessArray;
public override void Push()
{
count++;
}
public override void RemoveAtSwapBack(int entityIndex)
{
RemoveAtSwapBack(ref decalEntities, entityIndex, count);
RemoveAtSwapBack(ref decalProjectors, entityIndex, count);
transformAccessArray.RemoveAtSwapBack(entityIndex);
count--;
}
public override void SetCapacity(int newCapacity)
{
decalEntities.ResizeArray(newCapacity);
ResizeNativeArray(ref transformAccessArray, decalProjectors, newCapacity);
ArrayExtensions.ResizeArray(ref decalProjectors, newCapacity);
capacity = newCapacity;
}
public override void Dispose()
{
if (capacity == 0)
return;
decalEntities.Dispose();
transformAccessArray.Dispose();
decalProjectors = null;
count = 0;
capacity = 0;
}
}
/// <summary>
/// Manages lifetime between <see cref="DecalProjector"></see> and <see cref="DecalEntity"/>.
/// Contains all <see cref="DecalChunk"/>.
/// </summary>
internal class DecalEntityManager : IDisposable
{
public List<DecalEntityChunk> entityChunks = new List<DecalEntityChunk>();
public List<DecalCachedChunk> cachedChunks = new List<DecalCachedChunk>();
public List<DecalCulledChunk> culledChunks = new List<DecalCulledChunk>();
public List<DecalDrawCallChunk> drawCallChunks = new List<DecalDrawCallChunk>();
public int chunkCount;
private ProfilingSampler m_AddDecalSampler;
private ProfilingSampler m_ResizeChunks;
private ProfilingSampler m_SortChunks;
private DecalEntityIndexer m_DecalEntityIndexer = new DecalEntityIndexer();
private Dictionary<Material, int> m_MaterialToChunkIndex = new Dictionary<Material, int>();
private struct CombinedChunks
{
public DecalEntityChunk entityChunk;
public DecalCachedChunk cachedChunk;
public DecalCulledChunk culledChunk;
public DecalDrawCallChunk drawCallChunk;
public int previousChunkIndex;
public bool valid;
}
private List<CombinedChunks> m_CombinedChunks = new List<CombinedChunks>();
private List<int> m_CombinedChunkRemmap = new List<int>();
private Material m_ErrorMaterial;
public Material errorMaterial
{
get
{
if (m_ErrorMaterial == null)
m_ErrorMaterial = CoreUtils.CreateEngineMaterial(Shader.Find("Hidden/InternalErrorShader"));
return m_ErrorMaterial;
}
}
private Mesh m_DecalProjectorMesh;
public Mesh decalProjectorMesh
{
get
{
if (m_DecalProjectorMesh == null)
m_DecalProjectorMesh = CoreUtils.CreateCubeMesh(new Vector4(-0.5f, -0.5f, -0.5f, 1.0f), new Vector4(0.5f, 0.5f, 0.5f, 1.0f));
return m_DecalProjectorMesh;
}
}
public DecalEntityManager()
{
m_AddDecalSampler = new ProfilingSampler("DecalEntityManager.CreateDecalEntity");
m_ResizeChunks = new ProfilingSampler("DecalEntityManager.ResizeChunks");
m_SortChunks = new ProfilingSampler("DecalEntityManager.SortChunks");
}
public bool IsValid(DecalEntity decalEntity)
{
return m_DecalEntityIndexer.IsValid(decalEntity);
}
public DecalEntity CreateDecalEntity(DecalProjector decalProjector)
{
var material = decalProjector.material;
if (material == null)
material = errorMaterial;
using (new ProfilingScope(null, m_AddDecalSampler))
{
int chunkIndex = CreateChunkIndex(material);
int entityIndex = entityChunks[chunkIndex].count;
DecalEntity entity = m_DecalEntityIndexer.CreateDecalEntity(entityIndex, chunkIndex);
DecalEntityChunk entityChunk = entityChunks[chunkIndex];
DecalCachedChunk cachedChunk = cachedChunks[chunkIndex];
DecalCulledChunk culledChunk = culledChunks[chunkIndex];
DecalDrawCallChunk drawCallChunk = drawCallChunks[chunkIndex];
// Make sure we have space to add new entity
if (entityChunks[chunkIndex].capacity == entityChunks[chunkIndex].count)
{
using (new ProfilingScope(null, m_ResizeChunks))
{
int newCapacity = entityChunks[chunkIndex].capacity + entityChunks[chunkIndex].capacity;
newCapacity = math.max(8, newCapacity);
entityChunk.SetCapacity(newCapacity);
cachedChunk.SetCapacity(newCapacity);
culledChunk.SetCapacity(newCapacity);
drawCallChunk.SetCapacity(newCapacity);
}
}
entityChunk.Push();
cachedChunk.Push();
culledChunk.Push();
drawCallChunk.Push();
entityChunk.decalProjectors[entityIndex] = decalProjector;
entityChunk.decalEntities[entityIndex] = entity;
entityChunk.transformAccessArray.Add(decalProjector.transform);
UpdateDecalEntityData(entity, decalProjector);
return entity;
}
}
private int CreateChunkIndex(Material material)
{
if (!m_MaterialToChunkIndex.TryGetValue(material, out int chunkIndex))
{
var propertyBlock = new MaterialPropertyBlock();
// In order instanced and non instanced rendering to work with _NormalToWorld
// We need to make sure array is created with maximum size
propertyBlock.SetMatrixArray("_NormalToWorld", new Matrix4x4[250]);
entityChunks.Add(new DecalEntityChunk() { material = material });
cachedChunks.Add(new DecalCachedChunk()
{
propertyBlock = propertyBlock,
});
culledChunks.Add(new DecalCulledChunk());
drawCallChunks.Add(new DecalDrawCallChunk() { subCallCounts = new NativeArray<int>(1, Allocator.Persistent) });
m_CombinedChunks.Add(new CombinedChunks());
m_CombinedChunkRemmap.Add(0);
m_MaterialToChunkIndex.Add(material, chunkCount);
return chunkCount++;
}
return chunkIndex;
}
public void UpdateDecalEntityData(DecalEntity decalEntity, DecalProjector decalProjector)
{
var decalItem = m_DecalEntityIndexer.GetItem(decalEntity);
int chunkIndex = decalItem.chunkIndex;
int arrayIndex = decalItem.arrayIndex;
DecalCachedChunk cachedChunk = cachedChunks[chunkIndex];
cachedChunk.sizeOffsets[arrayIndex] = Matrix4x4.Translate(decalProjector.decalOffset) * Matrix4x4.Scale(decalProjector.decalSize);
float drawDistance = decalProjector.drawDistance;
float fadeScale = decalProjector.fadeScale;
float startAngleFade = decalProjector.startAngleFade;
float endAngleFade = decalProjector.endAngleFade;
Vector4 uvScaleBias = decalProjector.uvScaleBias;
int layerMask = decalProjector.gameObject.layer;
ulong sceneLayerMask = decalProjector.gameObject.sceneCullingMask;
float fadeFactor = decalProjector.fadeFactor;
cachedChunk.drawDistances[arrayIndex] = new Vector2(drawDistance, fadeScale);
// In the shader to remap from cosine -1 to 1 to new range 0..1 (with 0 - 0 degree and 1 - 180 degree)
// we do 1.0 - (dot() * 0.5 + 0.5) => 0.5 * (1 - dot())
// we actually square that to get smoother result => x = (0.5 - 0.5 * dot())^2
// Do a remap in the shader. 1.0 - saturate((x - start) / (end - start))
// After simplification => saturate(a + b * dot() * (dot() - 2.0))
// a = 1.0 - (0.25 - start) / (end - start), y = - 0.25 / (end - start)
if (startAngleFade == 180.0f) // angle fade is disabled
{
cachedChunk.angleFades[arrayIndex] = new Vector2(0.0f, 0.0f);
}
else
{
float angleStart = startAngleFade / 180.0f;
float angleEnd = endAngleFade / 180.0f;
var range = Mathf.Max(0.0001f, angleEnd - angleStart);
cachedChunk.angleFades[arrayIndex] = new Vector2(1.0f - (0.25f - angleStart) / range, -0.25f / range);
}
cachedChunk.uvScaleBias[arrayIndex] = uvScaleBias;
cachedChunk.layerMasks[arrayIndex] = layerMask;
cachedChunk.sceneLayerMasks[arrayIndex] = sceneLayerMask;
cachedChunk.fadeFactors[arrayIndex] = fadeFactor;
cachedChunk.scaleModes[arrayIndex] = decalProjector.scaleMode;
cachedChunk.positions[arrayIndex] = decalProjector.transform.position;
cachedChunk.rotation[arrayIndex] = decalProjector.transform.rotation;
cachedChunk.scales[arrayIndex] = decalProjector.transform.lossyScale;
cachedChunk.dirty[arrayIndex] = true;
}
public void DestroyDecalEntity(DecalEntity decalEntity)
{
if (!m_DecalEntityIndexer.IsValid(decalEntity))
return;
var decalItem = m_DecalEntityIndexer.GetItem(decalEntity);
m_DecalEntityIndexer.DestroyDecalEntity(decalEntity);
int chunkIndex = decalItem.chunkIndex;
int arrayIndex = decalItem.arrayIndex;
DecalEntityChunk entityChunk = entityChunks[chunkIndex];
DecalCachedChunk cachedChunk = cachedChunks[chunkIndex];
DecalCulledChunk culledChunk = culledChunks[chunkIndex];
DecalDrawCallChunk drawCallChunk = drawCallChunks[chunkIndex];
int lastArrayIndex = entityChunk.count - 1;
if (arrayIndex != lastArrayIndex)
m_DecalEntityIndexer.UpdateIndex(entityChunk.decalEntities[lastArrayIndex], arrayIndex);
entityChunk.RemoveAtSwapBack(arrayIndex);
cachedChunk.RemoveAtSwapBack(arrayIndex);
culledChunk.RemoveAtSwapBack(arrayIndex);
drawCallChunk.RemoveAtSwapBack(arrayIndex);
}
public void Update()
{
using (new ProfilingScope(null, m_SortChunks))
{
for (int i = 0; i < chunkCount; ++i)
{
if (entityChunks[i].material == null)
entityChunks[i].material = errorMaterial;
}
// Combine chunks into single array
for (int i = 0; i < chunkCount; ++i)
{
m_CombinedChunks[i] = new CombinedChunks()
{
entityChunk = entityChunks[i],
cachedChunk = cachedChunks[i],
culledChunk = culledChunks[i],
drawCallChunk = drawCallChunks[i],
previousChunkIndex = i,
valid = entityChunks[i].count != 0,
};
}
// Sort
m_CombinedChunks.Sort((a, b) =>
{
if (a.valid && !b.valid)
return -1;
if (!a.valid && b.valid)
return 1;
if (a.cachedChunk.drawOrder < b.cachedChunk.drawOrder)
return -1;
if (a.cachedChunk.drawOrder > b.cachedChunk.drawOrder)
return 1;
return a.entityChunk.material.GetHashCode().CompareTo(b.entityChunk.material.GetHashCode());
});
// Early out if nothing changed
bool dirty = false;
for (int i = 0; i < chunkCount; ++i)
{
if (m_CombinedChunks[i].previousChunkIndex != i || !m_CombinedChunks[i].valid)
{
dirty = true;
break;
}
}
if (!dirty)
return;
// Update chunks
int count = 0;
m_MaterialToChunkIndex.Clear();
for (int i = 0; i < chunkCount; ++i)
{
var combinedChunk = m_CombinedChunks[i];
// Destroy invalid chunk
if (!m_CombinedChunks[i].valid)
{
combinedChunk.entityChunk.currentJobHandle.Complete();
combinedChunk.cachedChunk.currentJobHandle.Complete();
combinedChunk.culledChunk.currentJobHandle.Complete();
combinedChunk.drawCallChunk.currentJobHandle.Complete();
combinedChunk.entityChunk.Dispose();
combinedChunk.cachedChunk.Dispose();
combinedChunk.culledChunk.Dispose();
combinedChunk.drawCallChunk.Dispose();
continue;
}
entityChunks[i] = combinedChunk.entityChunk;
cachedChunks[i] = combinedChunk.cachedChunk;
culledChunks[i] = combinedChunk.culledChunk;
drawCallChunks[i] = combinedChunk.drawCallChunk;
if (!m_MaterialToChunkIndex.ContainsKey(entityChunks[i].material))
m_MaterialToChunkIndex.Add(entityChunks[i].material, i);
m_CombinedChunkRemmap[combinedChunk.previousChunkIndex] = i;
count++;
}
// In case some chunks where destroyed resize the arrays
if (chunkCount > count)
{
entityChunks.RemoveRange(count, chunkCount - count);
cachedChunks.RemoveRange(count, chunkCount - count);
culledChunks.RemoveRange(count, chunkCount - count);
drawCallChunks.RemoveRange(count, chunkCount - count);
m_CombinedChunks.RemoveRange(count, chunkCount - count);
chunkCount = count;
}
// Remap entities chunk index with new sorted ones
m_DecalEntityIndexer.RemapChunkIndices(m_CombinedChunkRemmap);
}
}
public void Dispose()
{
CoreUtils.Destroy(m_ErrorMaterial);
CoreUtils.Destroy(m_DecalProjectorMesh);
foreach (var entityChunk in entityChunks)
entityChunk.currentJobHandle.Complete();
foreach (var cachedChunk in cachedChunks)
cachedChunk.currentJobHandle.Complete();
foreach (var culledChunk in culledChunks)
culledChunk.currentJobHandle.Complete();
foreach (var drawCallChunk in drawCallChunks)
drawCallChunk.currentJobHandle.Complete();
foreach (var entityChunk in entityChunks)
entityChunk.Dispose();
foreach (var cachedChunk in cachedChunks)
cachedChunk.Dispose();
foreach (var culledChunk in culledChunks)
culledChunk.Dispose();
foreach (var drawCallChunk in drawCallChunks)
drawCallChunk.Dispose();
m_DecalEntityIndexer.Clear();
m_MaterialToChunkIndex.Clear();
entityChunks.Clear();
cachedChunks.Clear();
culledChunks.Clear();
drawCallChunks.Clear();
m_CombinedChunks.Clear();
chunkCount = 0;
}
}
}

View file

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

View file

@ -0,0 +1,69 @@
using System;
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// System used for skipping culling. It is used with <see cref="Graphics.DrawMesh"/> as it already handles culling.
/// </summary>
internal class DecalSkipCulledSystem
{
private DecalEntityManager m_EntityManager;
private ProfilingSampler m_Sampler;
private Camera m_Camera;
public DecalSkipCulledSystem(DecalEntityManager entityManager)
{
m_EntityManager = entityManager;
m_Sampler = new ProfilingSampler("DecalSkipCulledSystem.Execute");
}
public void Execute(Camera camera)
{
using (new ProfilingScope(null, m_Sampler))
{
m_Camera = camera;
for (int i = 0; i < m_EntityManager.chunkCount; ++i)
Execute(m_EntityManager.culledChunks[i], m_EntityManager.culledChunks[i].count);
}
}
private void Execute(DecalCulledChunk culledChunk, int count)
{
if (count == 0)
return;
culledChunk.currentJobHandle.Complete();
for (int i = 0; i < count; ++i)
culledChunk.visibleDecalIndices[i] = i;
culledChunk.visibleDecalCount = count;
culledChunk.cameraPosition = m_Camera.transform.position;
culledChunk.cullingMask = m_Camera.cullingMask;
#if UNITY_EDITOR
culledChunk.sceneCullingMask = GetSceneCullingMaskFromCamera(m_Camera);
#endif
}
internal static UInt64 GetSceneCullingMaskFromCamera(Camera camera)
{
#if UNITY_EDITOR
if (camera.overrideSceneCullingMask != 0)
return camera.overrideSceneCullingMask;
if (camera.scene.IsValid())
return UnityEditor.SceneManagement.EditorSceneManager.GetSceneCullingMask(camera.scene);
switch (camera.cameraType)
{
case CameraType.SceneView:
return UnityEditor.SceneManagement.SceneCullingMasks.MainStageSceneViewObjects;
default:
return UnityEditor.SceneManagement.SceneCullingMasks.GameViewObjects;
}
#else
return 0;
#endif
}
}
}

View file

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

View file

@ -0,0 +1,271 @@
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine.Jobs;
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// Contains <see cref="DecalProjector"/> cached properties needed for rendering.
/// </summary>
internal class DecalCachedChunk : DecalChunk
{
public MaterialPropertyBlock propertyBlock;
public int passIndexDBuffer;
public int passIndexEmissive;
public int passIndexScreenSpace;
public int passIndexGBuffer;
public int drawOrder;
public bool isCreated;
public NativeArray<float4x4> decalToWorlds;
public NativeArray<float4x4> normalToWorlds;
public NativeArray<float4x4> sizeOffsets;
public NativeArray<float2> drawDistances;
public NativeArray<float2> angleFades;
public NativeArray<float4> uvScaleBias;
public NativeArray<int> layerMasks;
public NativeArray<ulong> sceneLayerMasks;
public NativeArray<float> fadeFactors;
public NativeArray<BoundingSphere> boundingSpheres;
public NativeArray<DecalScaleMode> scaleModes;
public NativeArray<float3> positions;
public NativeArray<quaternion> rotation;
public NativeArray<float3> scales;
public NativeArray<bool> dirty;
public BoundingSphere[] boundingSphereArray;
public override void RemoveAtSwapBack(int entityIndex)
{
RemoveAtSwapBack(ref decalToWorlds, entityIndex, count);
RemoveAtSwapBack(ref normalToWorlds, entityIndex, count);
RemoveAtSwapBack(ref sizeOffsets, entityIndex, count);
RemoveAtSwapBack(ref drawDistances, entityIndex, count);
RemoveAtSwapBack(ref angleFades, entityIndex, count);
RemoveAtSwapBack(ref uvScaleBias, entityIndex, count);
RemoveAtSwapBack(ref layerMasks, entityIndex, count);
RemoveAtSwapBack(ref sceneLayerMasks, entityIndex, count);
RemoveAtSwapBack(ref fadeFactors, entityIndex, count);
RemoveAtSwapBack(ref boundingSphereArray, entityIndex, count);
RemoveAtSwapBack(ref boundingSpheres, entityIndex, count);
RemoveAtSwapBack(ref scaleModes, entityIndex, count);
RemoveAtSwapBack(ref positions, entityIndex, count);
RemoveAtSwapBack(ref rotation, entityIndex, count);
RemoveAtSwapBack(ref scales, entityIndex, count);
RemoveAtSwapBack(ref dirty, entityIndex, count);
count--;
}
public override void SetCapacity(int newCapacity)
{
decalToWorlds.ResizeArray(newCapacity);
normalToWorlds.ResizeArray(newCapacity);
sizeOffsets.ResizeArray(newCapacity);
drawDistances.ResizeArray(newCapacity);
angleFades.ResizeArray(newCapacity);
uvScaleBias.ResizeArray(newCapacity);
layerMasks.ResizeArray(newCapacity);
sceneLayerMasks.ResizeArray(newCapacity);
fadeFactors.ResizeArray(newCapacity);
boundingSpheres.ResizeArray(newCapacity);
scaleModes.ResizeArray(newCapacity);
positions.ResizeArray(newCapacity);
rotation.ResizeArray(newCapacity);
scales.ResizeArray(newCapacity);
dirty.ResizeArray(newCapacity);
ArrayExtensions.ResizeArray(ref boundingSphereArray, newCapacity);
capacity = newCapacity;
}
public override void Dispose()
{
if (capacity == 0)
return;
decalToWorlds.Dispose();
normalToWorlds.Dispose();
sizeOffsets.Dispose();
drawDistances.Dispose();
angleFades.Dispose();
uvScaleBias.Dispose();
layerMasks.Dispose();
sceneLayerMasks.Dispose();
fadeFactors.Dispose();
boundingSpheres.Dispose();
scaleModes.Dispose();
positions.Dispose();
rotation.Dispose();
scales.Dispose();
dirty.Dispose();
count = 0;
capacity = 0;
}
}
/// <summary>
/// Caches <see cref="DecalProjector"/> properties into <see cref="DecalCachedChunk"/>.
/// Uses jobs with <see cref="IJobParallelForTransform"/>.
/// </summary>
internal class DecalUpdateCachedSystem
{
private DecalEntityManager m_EntityManager;
private ProfilingSampler m_Sampler;
private ProfilingSampler m_SamplerJob;
public DecalUpdateCachedSystem(DecalEntityManager entityManager)
{
m_EntityManager = entityManager;
m_Sampler = new ProfilingSampler("DecalUpdateCachedSystem.Execute");
m_SamplerJob = new ProfilingSampler("DecalUpdateCachedSystem.ExecuteJob");
}
public void Execute()
{
using (new ProfilingScope(null, m_Sampler))
{
for (int i = 0; i < m_EntityManager.chunkCount; ++i)
Execute(m_EntityManager.entityChunks[i], m_EntityManager.cachedChunks[i], m_EntityManager.entityChunks[i].count);
}
}
private void Execute(DecalEntityChunk entityChunk, DecalCachedChunk cachedChunk, int count)
{
if (count == 0)
return;
cachedChunk.currentJobHandle.Complete();
// Make sure draw order is up to date
var material = entityChunk.material;
if (material.HasProperty("_DrawOrder"))
cachedChunk.drawOrder = material.GetInt("_DrawOrder");
// Shader can change any time in editor, so we have to update passes each time
#if !UNITY_EDITOR
if (!cachedChunk.isCreated)
#endif
{
int passIndexDBuffer = material.FindPass(DecalShaderPassNames.DBufferProjector);
cachedChunk.passIndexDBuffer = passIndexDBuffer;
int passIndexEmissive = material.FindPass(DecalShaderPassNames.DecalProjectorForwardEmissive);
cachedChunk.passIndexEmissive = passIndexEmissive;
int passIndexScreenSpace = material.FindPass(DecalShaderPassNames.DecalScreenSpaceProjector);
cachedChunk.passIndexScreenSpace = passIndexScreenSpace;
int passIndexGBuffer = material.FindPass(DecalShaderPassNames.DecalGBufferProjector);
cachedChunk.passIndexGBuffer = passIndexGBuffer;
cachedChunk.isCreated = true;
}
using (new ProfilingScope(null, m_SamplerJob))
{
UpdateTransformsJob updateTransformJob = new UpdateTransformsJob()
{
positions = cachedChunk.positions,
rotations = cachedChunk.rotation,
scales = cachedChunk.scales,
dirty = cachedChunk.dirty,
scaleModes = cachedChunk.scaleModes,
sizeOffsets = cachedChunk.sizeOffsets,
decalToWorlds = cachedChunk.decalToWorlds,
normalToWorlds = cachedChunk.normalToWorlds,
boundingSpheres = cachedChunk.boundingSpheres,
minDistance = System.Single.Epsilon,
};
var handle = updateTransformJob.Schedule(entityChunk.transformAccessArray);
cachedChunk.currentJobHandle = handle;
}
}
#if ENABLE_BURST_1_0_0_OR_NEWER
[Unity.Burst.BurstCompile]
#endif
public unsafe struct UpdateTransformsJob : IJobParallelForTransform
{
private static readonly quaternion k_MinusYtoZRotation = quaternion.EulerXYZ(-math.PI / 2.0f, 0, 0);
public NativeArray<float3> positions;
public NativeArray<quaternion> rotations;
public NativeArray<float3> scales;
public NativeArray<bool> dirty;
[ReadOnly] public NativeArray<DecalScaleMode> scaleModes;
[ReadOnly] public NativeArray<float4x4> sizeOffsets;
[WriteOnly] public NativeArray<float4x4> decalToWorlds;
[WriteOnly] public NativeArray<float4x4> normalToWorlds;
[WriteOnly] public NativeArray<BoundingSphere> boundingSpheres;
public float minDistance;
private float DistanceBetweenQuaternions(quaternion a, quaternion b)
{
return math.distancesq(a.value, b.value);
}
public void Execute(int index, TransformAccess transform)
{
// Check if transform changed
bool positionChanged = math.distancesq(transform.position, positions[index]) > minDistance;
if (positionChanged)
positions[index] = transform.position;
bool rotationChanged = DistanceBetweenQuaternions(transform.rotation, rotations[index]) > minDistance;
if (rotationChanged)
rotations[index] = transform.rotation;
bool scaleChanged = math.distancesq(transform.localScale, scales[index]) > minDistance;
if (scaleChanged)
scales[index] = transform.localScale;
// Early out if transform did not changed
if (!positionChanged && !rotationChanged && !scaleChanged && !dirty[index])
return;
float4x4 localToWorld;
if (scaleModes[index] == DecalScaleMode.InheritFromHierarchy)
{
localToWorld = transform.localToWorldMatrix;
localToWorld = math.mul(localToWorld, new float4x4(k_MinusYtoZRotation, float3.zero));
}
else
{
quaternion rotation = math.mul(transform.rotation, k_MinusYtoZRotation);
localToWorld = float4x4.TRS(positions[index], rotation, new float3(1, 1, 1));
}
float4x4 decalRotation = localToWorld;
// z/y axis swap for normal to decal space, Unity is column major
float4 temp = decalRotation.c1;
decalRotation.c1 = decalRotation.c2;
decalRotation.c2 = temp;
normalToWorlds[index] = decalRotation;
float4x4 sizeOffset = sizeOffsets[index];
float4x4 decalToWorld = math.mul(localToWorld, sizeOffset);
decalToWorlds[index] = decalToWorld;
boundingSpheres[index] = GetDecalProjectBoundingSphere(decalToWorld);
dirty[index] = false;
}
private BoundingSphere GetDecalProjectBoundingSphere(Matrix4x4 decalToWorld)
{
float4 min = new float4(-0.5f, -0.5f, -0.5f, 1.0f);
float4 max = new float4(0.5f, 0.5f, 0.5f, 1.0f);
min = math.mul(decalToWorld, min);
max = math.mul(decalToWorld, max);
float3 position = ((max + min) / 2f).xyz;
float radius = math.length(max - min) / 2f;
BoundingSphere res = new BoundingSphere();
res.position = position;
res.radius = radius;
return res;
}
}
}
}

View file

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

View file

@ -0,0 +1,38 @@
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// Writes culling results into <see cref="DecalCulledChunk"/>.
/// </summary>
internal class DecalUpdateCulledSystem
{
private DecalEntityManager m_EntityManager;
private ProfilingSampler m_Sampler;
public DecalUpdateCulledSystem(DecalEntityManager entityManager)
{
m_EntityManager = entityManager;
m_Sampler = new ProfilingSampler("DecalUpdateCulledSystem.Execute");
}
public void Execute()
{
using (new ProfilingScope(null, m_Sampler))
{
for (int i = 0; i < m_EntityManager.chunkCount; ++i)
Execute(m_EntityManager.culledChunks[i], m_EntityManager.culledChunks[i].count);
}
}
private void Execute(DecalCulledChunk culledChunk, int count)
{
if (count == 0)
return;
culledChunk.currentJobHandle.Complete();
CullingGroup cullingGroup = culledChunk.cullingGroups;
culledChunk.visibleDecalCount = cullingGroup.QueryIndices(true, culledChunk.visibleDecalIndexArray, 0);
culledChunk.visibleDecalIndices.CopyFrom(culledChunk.visibleDecalIndexArray);
}
}
}

View file

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

View file

@ -0,0 +1,126 @@
using System;
using Unity.Collections;
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// Contains culling results.
/// </summary>
internal class DecalCulledChunk : DecalChunk
{
public Vector3 cameraPosition;
public ulong sceneCullingMask;
public int cullingMask;
public CullingGroup cullingGroups;
public int[] visibleDecalIndexArray;
public NativeArray<int> visibleDecalIndices;
public int visibleDecalCount;
public override void RemoveAtSwapBack(int entityIndex)
{
RemoveAtSwapBack(ref visibleDecalIndexArray, entityIndex, count);
RemoveAtSwapBack(ref visibleDecalIndices, entityIndex, count);
count--;
}
public override void SetCapacity(int newCapacity)
{
ArrayExtensions.ResizeArray(ref visibleDecalIndexArray, newCapacity);
visibleDecalIndices.ResizeArray(newCapacity);
if (cullingGroups == null)
cullingGroups = new CullingGroup();
capacity = newCapacity;
}
public override void Dispose()
{
if (capacity == 0)
return;
visibleDecalIndices.Dispose();
visibleDecalIndexArray = null;
count = 0;
capacity = 0;
cullingGroups.Dispose();
cullingGroups = null;
}
}
/// <summary>
/// Issues culling job with <see cref="CullingGroup"/>.
/// </summary>
internal class DecalUpdateCullingGroupSystem
{
/// <summary>
/// Provides acces to the bounding distance.
/// </summary>
public float boundingDistance
{
get { return m_BoundingDistance[0]; }
set { m_BoundingDistance[0] = value; }
}
private float[] m_BoundingDistance = new float[1];
private Camera m_Camera;
private DecalEntityManager m_EntityManager;
private ProfilingSampler m_Sampler;
public DecalUpdateCullingGroupSystem(DecalEntityManager entityManager, float drawDistance)
{
m_EntityManager = entityManager;
m_BoundingDistance[0] = drawDistance;
m_Sampler = new ProfilingSampler("DecalUpdateCullingGroupsSystem.Execute");
}
public void Execute(Camera camera)
{
using (new ProfilingScope(null, m_Sampler))
{
m_Camera = camera;
for (int i = 0; i < m_EntityManager.chunkCount; ++i)
Execute(m_EntityManager.cachedChunks[i], m_EntityManager.culledChunks[i], m_EntityManager.culledChunks[i].count);
}
}
public void Execute(DecalCachedChunk cachedChunk, DecalCulledChunk culledChunk, int count)
{
cachedChunk.currentJobHandle.Complete();
CullingGroup cullingGroup = culledChunk.cullingGroups;
cullingGroup.targetCamera = m_Camera;
cullingGroup.SetDistanceReferencePoint(m_Camera.transform.position);
cullingGroup.SetBoundingDistances(m_BoundingDistance);
cachedChunk.boundingSpheres.CopyTo(cachedChunk.boundingSphereArray);
cullingGroup.SetBoundingSpheres(cachedChunk.boundingSphereArray);
cullingGroup.SetBoundingSphereCount(count);
culledChunk.cameraPosition = m_Camera.transform.position;
culledChunk.cullingMask = m_Camera.cullingMask;
#if UNITY_EDITOR
culledChunk.sceneCullingMask = GetSceneCullingMaskFromCamera(m_Camera);
#endif
}
internal static UInt64 GetSceneCullingMaskFromCamera(Camera camera)
{
#if UNITY_EDITOR
if (camera.overrideSceneCullingMask != 0)
return camera.overrideSceneCullingMask;
if (camera.scene.IsValid())
return UnityEditor.SceneManagement.EditorSceneManager.GetSceneCullingMask(camera.scene);
switch (camera.cameraType)
{
case CameraType.SceneView:
return UnityEditor.SceneManagement.SceneCullingMasks.MainStageSceneViewObjects;
default:
return UnityEditor.SceneManagement.SceneCullingMasks.GameViewObjects;
}
#else
return 0;
#endif
}
}
}

View file

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

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5818a14fd27827e48951a0d2ee539d75
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,100 @@
using System.Collections.Generic;
using UnityEngine.Rendering.Universal.Internal;
namespace UnityEngine.Rendering.Universal
{
internal class DecalDrawGBufferSystem : DecalDrawSystem
{
public DecalDrawGBufferSystem(DecalEntityManager entityManager) : base("DecalDrawGBufferSystem.Execute", entityManager) { }
protected override int GetPassIndex(DecalCachedChunk decalCachedChunk) => decalCachedChunk.passIndexGBuffer;
}
internal class DecalGBufferRenderPass : ScriptableRenderPass
{
private FilteringSettings m_FilteringSettings;
private ProfilingSampler m_ProfilingSampler;
private List<ShaderTagId> m_ShaderTagIdList;
private DecalDrawGBufferSystem m_DrawSystem;
private DecalScreenSpaceSettings m_Settings;
private DeferredLights m_DeferredLights;
private RenderTargetIdentifier[] m_GbufferAttachments;
public DecalGBufferRenderPass(DecalScreenSpaceSettings settings, DecalDrawGBufferSystem drawSystem)
{
renderPassEvent = RenderPassEvent.AfterRenderingGbuffer;
m_DrawSystem = drawSystem;
m_Settings = settings;
m_ProfilingSampler = new ProfilingSampler("Decal GBuffer Render");
m_FilteringSettings = new FilteringSettings(RenderQueueRange.opaque, -1);
m_ShaderTagIdList = new List<ShaderTagId>();
if (drawSystem == null)
m_ShaderTagIdList.Add(new ShaderTagId(DecalShaderPassNames.DecalGBufferProjector));
else
m_ShaderTagIdList.Add(new ShaderTagId(DecalShaderPassNames.DecalGBufferMesh));
}
internal void Setup(DeferredLights deferredLights)
{
m_DeferredLights = deferredLights;
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
if (m_DeferredLights != null && m_DeferredLights.UseRenderPass)
{
if (m_GbufferAttachments == null)
m_GbufferAttachments = new RenderTargetIdentifier[]
{
m_DeferredLights.GbufferAttachmentIdentifiers[0], m_DeferredLights.GbufferAttachmentIdentifiers[1],
m_DeferredLights.GbufferAttachmentIdentifiers[2], m_DeferredLights.GbufferAttachmentIdentifiers[3]
};
}
else
m_GbufferAttachments = m_DeferredLights.GbufferAttachmentIdentifiers;
ConfigureTarget(m_GbufferAttachments, m_DeferredLights.DepthAttachmentIdentifier);
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
SortingCriteria sortingCriteria = renderingData.cameraData.defaultOpaqueSortFlags;
DrawingSettings drawingSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, sortingCriteria);
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, m_ProfilingSampler))
{
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
NormalReconstruction.SetupProperties(cmd, renderingData.cameraData);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendLow, m_Settings.normalBlend == DecalNormalBlend.Low);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendMedium, m_Settings.normalBlend == DecalNormalBlend.Medium);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendHigh, m_Settings.normalBlend == DecalNormalBlend.High);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
m_DrawSystem?.Execute(cmd);
context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref m_FilteringSettings);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public override void OnCameraCleanup(CommandBuffer cmd)
{
if (cmd == null)
{
throw new System.ArgumentNullException("cmd");
}
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendLow, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendMedium, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendHigh, false);
}
}
}

View file

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

View file

@ -0,0 +1,78 @@
using System.Collections.Generic;
using UnityEngine.Rendering.Universal.Internal;
namespace UnityEngine.Rendering.Universal
{
internal class DecalDrawScreenSpaceSystem : DecalDrawSystem
{
public DecalDrawScreenSpaceSystem(DecalEntityManager entityManager) : base("DecalDrawScreenSpaceSystem.Execute", entityManager) { }
protected override int GetPassIndex(DecalCachedChunk decalCachedChunk) => decalCachedChunk.passIndexScreenSpace;
}
internal class DecalScreenSpaceRenderPass : ScriptableRenderPass
{
private FilteringSettings m_FilteringSettings;
private ProfilingSampler m_ProfilingSampler;
private List<ShaderTagId> m_ShaderTagIdList;
private DecalDrawScreenSpaceSystem m_DrawSystem;
private DecalScreenSpaceSettings m_Settings;
public DecalScreenSpaceRenderPass(DecalScreenSpaceSettings settings, DecalDrawScreenSpaceSystem drawSystem)
{
renderPassEvent = RenderPassEvent.AfterRenderingSkybox;
ConfigureInput(ScriptableRenderPassInput.Depth); // Require depth
m_DrawSystem = drawSystem;
m_Settings = settings;
m_ProfilingSampler = new ProfilingSampler("Decal Screen Space Render");
m_FilteringSettings = new FilteringSettings(RenderQueueRange.opaque, -1);
m_ShaderTagIdList = new List<ShaderTagId>();
if (m_DrawSystem == null)
m_ShaderTagIdList.Add(new ShaderTagId(DecalShaderPassNames.DecalScreenSpaceProjector));
else
m_ShaderTagIdList.Add(new ShaderTagId(DecalShaderPassNames.DecalScreenSpaceMesh));
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
SortingCriteria sortingCriteria = SortingCriteria.CommonTransparent;
DrawingSettings drawingSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, sortingCriteria);
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, m_ProfilingSampler))
{
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
NormalReconstruction.SetupProperties(cmd, renderingData.cameraData);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendLow, m_Settings.normalBlend == DecalNormalBlend.Low);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendMedium, m_Settings.normalBlend == DecalNormalBlend.Medium);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendHigh, m_Settings.normalBlend == DecalNormalBlend.High);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
m_DrawSystem?.Execute(cmd);
context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref m_FilteringSettings);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public override void OnCameraCleanup(CommandBuffer cmd)
{
if (cmd == null)
{
throw new System.ArgumentNullException("cmd");
}
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendLow, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendMedium, false);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.DecalNormalBlendHigh, false);
}
}
}

View file

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