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,21 @@
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.Rendering.Universal
{
[AddComponentMenu("Rendering/2D/Composite Shadow Caster 2D")]
[MovedFrom("UnityEngine.Experimental.Rendering.Universal")]
[ExecuteInEditMode]
public class CompositeShadowCaster2D : ShadowCasterGroup2D
{
protected void OnEnable()
{
ShadowCasterGroup2DManager.AddGroup(this);
}
protected void OnDisable()
{
ShadowCasterGroup2DManager.RemoveGroup(this);
}
}
}

View file

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

View file

@ -0,0 +1,249 @@
using System;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.Rendering.Universal
{
/// <summary>
/// Class <c>ShadowCaster2D</c> contains properties used for shadow casting
/// </summary>
[ExecuteInEditMode]
[DisallowMultipleComponent]
[AddComponentMenu("Rendering/2D/Shadow Caster 2D")]
[MovedFrom("UnityEngine.Experimental.Rendering.Universal")]
public class ShadowCaster2D : ShadowCasterGroup2D, ISerializationCallbackReceiver
{
public enum ComponentVersions
{
Version_Unserialized = 0,
Version_1 = 1
}
const ComponentVersions k_CurrentComponentVersion = ComponentVersions.Version_1;
[SerializeField] ComponentVersions m_ComponentVersion = ComponentVersions.Version_Unserialized;
[SerializeField] bool m_HasRenderer = false;
[SerializeField] bool m_UseRendererSilhouette = true;
[SerializeField] bool m_CastsShadows = true;
[SerializeField] bool m_SelfShadows = false;
[SerializeField] int[] m_ApplyToSortingLayers = null;
[SerializeField] Vector3[] m_ShapePath = null;
[SerializeField] int m_ShapePathHash = 0;
[SerializeField] Mesh m_Mesh;
[SerializeField] int m_InstanceId;
internal ShadowCasterGroup2D m_ShadowCasterGroup = null;
internal ShadowCasterGroup2D m_PreviousShadowCasterGroup = null;
[SerializeField]
internal BoundingSphere m_ProjectedBoundingSphere;
public Mesh mesh => m_Mesh;
public Vector3[] shapePath => m_ShapePath;
internal int shapePathHash { get { return m_ShapePathHash; } set { m_ShapePathHash = value; } }
int m_PreviousShadowGroup = 0;
bool m_PreviousCastsShadows = true;
int m_PreviousPathHash = 0;
internal Vector3 m_CachedPosition;
internal Vector3 m_CachedLossyScale;
internal Quaternion m_CachedRotation;
internal Matrix4x4 m_CachedShadowMatrix;
internal Matrix4x4 m_CachedInverseShadowMatrix;
internal Matrix4x4 m_CachedLocalToWorldMatrix;
internal override void CacheValues()
{
m_CachedPosition = transform.position;
m_CachedLossyScale = transform.lossyScale;
m_CachedRotation = transform.rotation;
m_CachedShadowMatrix = Matrix4x4.TRS(m_CachedPosition, m_CachedRotation, Vector3.one);
m_CachedInverseShadowMatrix = m_CachedShadowMatrix.inverse;
m_CachedLocalToWorldMatrix = transform.localToWorldMatrix;
}
/// <summary>
/// If selfShadows is true, useRendererSilhoutte specifies that the renderer's sihouette should be considered part of the shadow. If selfShadows is false, useRendererSilhoutte specifies that the renderer's sihouette should be excluded from the shadow
/// </summary>
public bool useRendererSilhouette
{
set { m_UseRendererSilhouette = value; }
get { return m_UseRendererSilhouette && m_HasRenderer; }
}
/// <summary>
/// If true, the shadow casting shape is included as part of the shadow. If false, the shadow casting shape is excluded from the shadow.
/// </summary>
public bool selfShadows
{
set { m_SelfShadows = value; }
get { return m_SelfShadows; }
}
/// <summary>
/// Specifies if shadows will be cast.
/// </summary>
public bool castsShadows
{
set { m_CastsShadows = value; }
get { return m_CastsShadows; }
}
static int[] SetDefaultSortingLayers()
{
int layerCount = SortingLayer.layers.Length;
int[] allLayers = new int[layerCount];
for (int layerIndex = 0; layerIndex < layerCount; layerIndex++)
{
allLayers[layerIndex] = SortingLayer.layers[layerIndex].id;
}
return allLayers;
}
internal bool IsLit(Light2D light)
{
// Oddly adding and subtracting vectors is expensive here because of the new structures created...
Vector3 deltaPos;
deltaPos.x = m_ProjectedBoundingSphere.position.x + m_CachedPosition.x;
deltaPos.y = m_ProjectedBoundingSphere.position.y + m_CachedPosition.y;
deltaPos.z = m_ProjectedBoundingSphere.position.z + m_CachedPosition.z;
deltaPos.x = light.m_CachedPosition.x - deltaPos.x;
deltaPos.y = light.m_CachedPosition.y - deltaPos.y;
deltaPos.z = light.m_CachedPosition.z - deltaPos.z;
float distanceSq = Vector3.SqrMagnitude(deltaPos);
float radiiLength = light.boundingSphere.radius + m_ProjectedBoundingSphere.radius;
return distanceSq <= (radiiLength * radiiLength);
}
internal bool IsShadowedLayer(int layer)
{
return m_ApplyToSortingLayers != null ? Array.IndexOf(m_ApplyToSortingLayers, layer) >= 0 : false;
}
private void Awake()
{
if (m_ApplyToSortingLayers == null)
m_ApplyToSortingLayers = SetDefaultSortingLayers();
Bounds bounds = new Bounds(transform.position, Vector3.one);
Renderer renderer = GetComponent<Renderer>();
if (renderer != null)
{
bounds = renderer.bounds;
}
#if USING_PHYSICS2D_MODULE
else
{
Collider2D collider = GetComponent<Collider2D>();
if (collider != null)
bounds = collider.bounds;
}
#endif
Vector3 inverseScale = Vector3.zero;
Vector3 relOffset = transform.position;
if (transform.lossyScale.x != 0 && transform.lossyScale.y != 0)
{
inverseScale = new Vector3(1 / transform.lossyScale.x, 1 / transform.lossyScale.y);
relOffset = new Vector3(inverseScale.x * -transform.position.x, inverseScale.y * -transform.position.y);
}
if (m_ShapePath == null || m_ShapePath.Length == 0)
{
m_ShapePath = new Vector3[]
{
relOffset + new Vector3(inverseScale.x * bounds.min.x, inverseScale.y * bounds.min.y),
relOffset + new Vector3(inverseScale.x * bounds.min.x, inverseScale.y * bounds.max.y),
relOffset + new Vector3(inverseScale.x * bounds.max.x, inverseScale.y * bounds.max.y),
relOffset + new Vector3(inverseScale.x * bounds.max.x, inverseScale.y * bounds.min.y),
};
}
}
protected void OnEnable()
{
if (m_Mesh == null || m_InstanceId != GetInstanceID())
{
m_Mesh = new Mesh();
m_ProjectedBoundingSphere = ShadowUtility.GenerateShadowMesh(m_Mesh, m_ShapePath);
m_InstanceId = GetInstanceID();
}
m_ShadowCasterGroup = null;
}
protected void OnDisable()
{
ShadowCasterGroup2DManager.RemoveFromShadowCasterGroup(this, m_ShadowCasterGroup);
}
public void Update()
{
Renderer renderer;
m_HasRenderer = TryGetComponent<Renderer>(out renderer);
bool rebuildMesh = LightUtility.CheckForChange(m_ShapePathHash, ref m_PreviousPathHash);
if (rebuildMesh)
{
m_ProjectedBoundingSphere = ShadowUtility.GenerateShadowMesh(m_Mesh, m_ShapePath);
}
m_PreviousShadowCasterGroup = m_ShadowCasterGroup;
bool addedToNewGroup = ShadowCasterGroup2DManager.AddToShadowCasterGroup(this, ref m_ShadowCasterGroup);
if (addedToNewGroup && m_ShadowCasterGroup != null)
{
if (m_PreviousShadowCasterGroup == this)
ShadowCasterGroup2DManager.RemoveGroup(this);
ShadowCasterGroup2DManager.RemoveFromShadowCasterGroup(this, m_PreviousShadowCasterGroup);
if (m_ShadowCasterGroup == this)
ShadowCasterGroup2DManager.AddGroup(this);
}
if (LightUtility.CheckForChange(m_ShadowGroup, ref m_PreviousShadowGroup))
{
ShadowCasterGroup2DManager.RemoveGroup(this);
ShadowCasterGroup2DManager.AddGroup(this);
}
if (LightUtility.CheckForChange(m_CastsShadows, ref m_PreviousCastsShadows))
{
if (m_CastsShadows)
ShadowCasterGroup2DManager.AddGroup(this);
else
ShadowCasterGroup2DManager.RemoveGroup(this);
}
}
public void OnBeforeSerialize()
{
m_ComponentVersion = k_CurrentComponentVersion;
}
public void OnAfterDeserialize()
{
// Upgrade from no serialized version
if (m_ComponentVersion == ComponentVersions.Version_Unserialized)
{
ShadowUtility.ComputeBoundingSphere(m_ShapePath, out m_ProjectedBoundingSphere);
m_ComponentVersion = ComponentVersions.Version_1;
}
}
#if UNITY_EDITOR
void Reset()
{
Awake();
OnEnable();
}
#endif
}
}

View file

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

View file

@ -0,0 +1,37 @@
using System.Collections.Generic;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.Rendering.Universal
{
[MovedFrom("UnityEngine.Experimental.Rendering.Universal")]
public abstract class ShadowCasterGroup2D : MonoBehaviour
{
[SerializeField] internal int m_ShadowGroup = 0;
List<ShadowCaster2D> m_ShadowCasters;
internal virtual void CacheValues()
{
for (int i = 0; i < m_ShadowCasters.Count; i++)
m_ShadowCasters[i].CacheValues();
}
public List<ShadowCaster2D> GetShadowCasters() { return m_ShadowCasters; }
public int GetShadowGroup() { return m_ShadowGroup; }
public void RegisterShadowCaster2D(ShadowCaster2D shadowCaster2D)
{
if (m_ShadowCasters == null)
m_ShadowCasters = new List<ShadowCaster2D>();
m_ShadowCasters.Add(shadowCaster2D);
}
public void UnregisterShadowCaster2D(ShadowCaster2D shadowCaster2D)
{
if (m_ShadowCasters != null)
m_ShadowCasters.Remove(shadowCaster2D);
}
}
}

View file

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

View file

@ -0,0 +1,121 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngine.Rendering.Universal
{
#if UNITY_EDITOR
[InitializeOnLoadAttribute]
#endif
internal class ShadowCasterGroup2DManager
{
static List<ShadowCasterGroup2D> s_ShadowCasterGroups = null;
public static List<ShadowCasterGroup2D> shadowCasterGroups { get { return s_ShadowCasterGroups; } }
#if UNITY_EDITOR
static ShadowCasterGroup2DManager()
{
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
private static void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (s_ShadowCasterGroups != null && (state == PlayModeStateChange.ExitingEditMode || state == PlayModeStateChange.ExitingPlayMode))
s_ShadowCasterGroups.Clear();
}
#endif
public static void CacheValues()
{
if (shadowCasterGroups != null)
{
for (int i = 0; i < shadowCasterGroups.Count; i++)
{
if (shadowCasterGroups[i] != null)
shadowCasterGroups[i].CacheValues();
}
}
}
public static void AddShadowCasterGroupToList(ShadowCasterGroup2D shadowCaster, List<ShadowCasterGroup2D> list)
{
int positionToInsert = 0;
for (positionToInsert = 0; positionToInsert < list.Count; positionToInsert++)
{
if (shadowCaster.GetShadowGroup() == list[positionToInsert].GetShadowGroup())
break;
}
list.Insert(positionToInsert, shadowCaster);
}
public static void RemoveShadowCasterGroupFromList(ShadowCasterGroup2D shadowCaster, List<ShadowCasterGroup2D> list)
{
list.Remove(shadowCaster);
}
static CompositeShadowCaster2D FindTopMostCompositeShadowCaster(ShadowCaster2D shadowCaster)
{
CompositeShadowCaster2D retGroup = null;
Transform transformToCheck = shadowCaster.transform.parent;
while (transformToCheck != null)
{
CompositeShadowCaster2D currentGroup;
if (transformToCheck.TryGetComponent<CompositeShadowCaster2D>(out currentGroup))
retGroup = currentGroup;
transformToCheck = transformToCheck.parent;
}
return retGroup;
}
public static bool AddToShadowCasterGroup(ShadowCaster2D shadowCaster, ref ShadowCasterGroup2D shadowCasterGroup)
{
ShadowCasterGroup2D newShadowCasterGroup = FindTopMostCompositeShadowCaster(shadowCaster) as ShadowCasterGroup2D;
if (newShadowCasterGroup == null)
newShadowCasterGroup = shadowCaster.GetComponent<ShadowCaster2D>();
if (newShadowCasterGroup != null && shadowCasterGroup != newShadowCasterGroup)
{
newShadowCasterGroup.RegisterShadowCaster2D(shadowCaster);
shadowCasterGroup = newShadowCasterGroup;
return true;
}
return false;
}
public static void RemoveFromShadowCasterGroup(ShadowCaster2D shadowCaster, ShadowCasterGroup2D shadowCasterGroup)
{
if (shadowCasterGroup != null)
shadowCasterGroup.UnregisterShadowCaster2D(shadowCaster);
}
public static void AddGroup(ShadowCasterGroup2D group)
{
if (group == null)
return;
if (s_ShadowCasterGroups == null)
s_ShadowCasterGroups = new List<ShadowCasterGroup2D>();
AddShadowCasterGroupToList(group, s_ShadowCasterGroups);
}
public static void RemoveGroup(ShadowCasterGroup2D group)
{
if (group != null && s_ShadowCasterGroups != null)
RemoveShadowCasterGroupFromList(group, s_ShadowCasterGroups);
}
}
}

View file

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

View file

@ -0,0 +1,343 @@
using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
namespace UnityEngine.Rendering.Universal
{
// TODO: Culling of shadow casters, rotate color channels for shadow casting, check get material functions.
internal static class ShadowRendering
{
private static readonly int k_LightPosID = Shader.PropertyToID("_LightPos");
private static readonly int k_SelfShadowingID = Shader.PropertyToID("_SelfShadowing");
private static readonly int k_ShadowStencilGroupID = Shader.PropertyToID("_ShadowStencilGroup");
private static readonly int k_ShadowIntensityID = Shader.PropertyToID("_ShadowIntensity");
private static readonly int k_ShadowVolumeIntensityID = Shader.PropertyToID("_ShadowVolumeIntensity");
private static readonly int k_ShadowRadiusID = Shader.PropertyToID("_ShadowRadius");
private static readonly int k_ShadowColorMaskID = Shader.PropertyToID("_ShadowColorMask");
private static readonly int k_ShadowModelMatrixID = Shader.PropertyToID("_ShadowModelMatrix");
private static readonly int k_ShadowModelInvMatrixID = Shader.PropertyToID("_ShadowModelInvMatrix");
private static readonly int k_ShadowModelScaleID = Shader.PropertyToID("_ShadowModelScale");
private static readonly ProfilingSampler m_ProfilingSamplerShadows = new ProfilingSampler("Draw 2D Shadow Texture");
private static readonly ProfilingSampler m_ProfilingSamplerShadowsA = new ProfilingSampler("Draw 2D Shadows (A)");
private static readonly ProfilingSampler m_ProfilingSamplerShadowsR = new ProfilingSampler("Draw 2D Shadows (R)");
private static readonly ProfilingSampler m_ProfilingSamplerShadowsG = new ProfilingSampler("Draw 2D Shadows (G)");
private static readonly ProfilingSampler m_ProfilingSamplerShadowsB = new ProfilingSampler("Draw 2D Shadows (B)");
private static RenderTargetHandle[] m_RenderTargets = null;
private static RenderTargetIdentifier[] m_LightInputTextures = null;
private static readonly Color[] k_ColorLookup = new Color[4] { new Color(0, 0, 0, 1), new Color(0, 0, 1, 0), new Color(0, 1, 0, 0), new Color(1, 0, 0, 0) };
private static readonly ProfilingSampler[] m_ProfilingSamplerShadowColorsLookup = new ProfilingSampler[4] { m_ProfilingSamplerShadowsA, m_ProfilingSamplerShadowsB, m_ProfilingSamplerShadowsG, m_ProfilingSamplerShadowsR };
public static uint maxTextureCount { get; private set; }
public static void InitializeBudget(uint maxTextureCount)
{
if (m_RenderTargets == null || m_RenderTargets.Length != maxTextureCount)
{
m_RenderTargets = new RenderTargetHandle[maxTextureCount];
ShadowRendering.maxTextureCount = maxTextureCount;
for (int i = 0; i < maxTextureCount; i++)
{
unsafe
{
m_RenderTargets[i].id = Shader.PropertyToID($"ShadowTex_{i}");
}
}
}
if (m_LightInputTextures == null || m_LightInputTextures.Length != maxTextureCount)
{
m_LightInputTextures = new RenderTargetIdentifier[maxTextureCount];
}
}
private static Material[] CreateMaterials(Shader shader, int pass = 0)
{
const int k_ColorChannels = 4;
Material[] materials = new Material[k_ColorChannels];
for (int i = 0; i < k_ColorChannels; i++)
{
materials[i] = CoreUtils.CreateEngineMaterial(shader);
materials[i].SetInt(k_ShadowColorMaskID, 1 << i);
materials[i].SetPass(pass);
}
return materials;
}
private static Material GetProjectedShadowMaterial(this Renderer2DData rendererData, int colorIndex)
{
//rendererData.projectedShadowMaterial = null;
if (rendererData.projectedShadowMaterial == null || rendererData.projectedShadowMaterial.Length == 0 || rendererData.projectedShadowShader != rendererData.projectedShadowMaterial[0].shader)
{
rendererData.projectedShadowMaterial = CreateMaterials(rendererData.projectedShadowShader);
}
return rendererData.projectedShadowMaterial[colorIndex];
}
private static Material GetStencilOnlyShadowMaterial(this Renderer2DData rendererData, int colorIndex)
{
//rendererData.stencilOnlyShadowMaterial = null;
if (rendererData.stencilOnlyShadowMaterial == null || rendererData.stencilOnlyShadowMaterial.Length == 0 || rendererData.projectedShadowShader != rendererData.stencilOnlyShadowMaterial[0].shader)
{
rendererData.stencilOnlyShadowMaterial = CreateMaterials(rendererData.projectedShadowShader, 1);
}
return rendererData.stencilOnlyShadowMaterial[colorIndex];
}
private static Material GetSpriteSelfShadowMaterial(this Renderer2DData rendererData, int colorIndex)
{
//rendererData.spriteSelfShadowMaterial = null;
if (rendererData.spriteSelfShadowMaterial == null || rendererData.spriteSelfShadowMaterial.Length == 0 || rendererData.spriteShadowShader != rendererData.spriteSelfShadowMaterial[0].shader)
{
rendererData.spriteSelfShadowMaterial = CreateMaterials(rendererData.spriteShadowShader);
}
return rendererData.spriteSelfShadowMaterial[colorIndex];
}
private static Material GetSpriteUnshadowMaterial(this Renderer2DData rendererData, int colorIndex)
{
//rendererData.spriteUnshadowMaterial = null;
if (rendererData.spriteUnshadowMaterial == null || rendererData.spriteUnshadowMaterial.Length == 0 || rendererData.spriteUnshadowShader != rendererData.spriteUnshadowMaterial[0].shader)
{
rendererData.spriteUnshadowMaterial = CreateMaterials(rendererData.spriteUnshadowShader);
}
return rendererData.spriteUnshadowMaterial[colorIndex];
}
private static Material GetGeometryUnshadowMaterial(this Renderer2DData rendererData, int colorIndex)
{
//rendererData.geometryUnshadowMaterial = null;
if (rendererData.geometryUnshadowMaterial == null || rendererData.geometryUnshadowMaterial.Length == 0 || rendererData.geometryUnshadowShader != rendererData.geometryUnshadowMaterial[0].shader)
{
rendererData.geometryUnshadowMaterial = CreateMaterials(rendererData.geometryUnshadowShader);
}
return rendererData.geometryUnshadowMaterial[colorIndex];
}
public static void CreateShadowRenderTexture(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int shadowIndex)
{
CreateShadowRenderTexture(pass, m_RenderTargets[shadowIndex], renderingData, cmdBuffer);
}
public static bool PrerenderShadows(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int layerToRender, Light2D light, int shadowIndex, float shadowIntensity)
{
var colorChannel = shadowIndex % 4;
var textureIndex = shadowIndex / 4;
if (colorChannel == 0)
ShadowRendering.CreateShadowRenderTexture(pass, renderingData, cmdBuffer, textureIndex);
bool hadShadowsToRender = RenderShadows(pass, renderingData, cmdBuffer, layerToRender, light, shadowIntensity, m_RenderTargets[textureIndex].Identifier(), colorChannel);
// Render the shadows for this light
if (RenderShadows(pass, renderingData, cmdBuffer, layerToRender, light, shadowIntensity, m_RenderTargets[textureIndex].Identifier(), colorChannel))
m_LightInputTextures[textureIndex] = m_RenderTargets[textureIndex].Identifier();
else
m_LightInputTextures[textureIndex] = Texture2D.blackTexture;
return hadShadowsToRender;
}
public static void SetGlobalShadowTexture(CommandBuffer cmdBuffer, Light2D light, int shadowIndex)
{
var colorChannel = shadowIndex % 4;
var textureIndex = shadowIndex / 4;
cmdBuffer.SetGlobalTexture("_ShadowTex", m_LightInputTextures[textureIndex]);
cmdBuffer.SetGlobalColor(k_ShadowColorMaskID, k_ColorLookup[colorChannel]);
cmdBuffer.SetGlobalFloat(k_ShadowIntensityID, 1 - light.shadowIntensity);
cmdBuffer.SetGlobalFloat(k_ShadowVolumeIntensityID, 1 - light.shadowVolumeIntensity);
}
public static void DisableGlobalShadowTexture(CommandBuffer cmdBuffer)
{
cmdBuffer.SetGlobalFloat(k_ShadowIntensityID, 1);
cmdBuffer.SetGlobalFloat(k_ShadowVolumeIntensityID, 1);
}
private static void CreateShadowRenderTexture(IRenderPass2D pass, RenderTargetHandle rtHandle, RenderingData renderingData, CommandBuffer cmdBuffer)
{
var renderTextureScale = Mathf.Clamp(pass.rendererData.lightRenderTextureScale, 0.01f, 1.0f);
var width = (int)(renderingData.cameraData.cameraTargetDescriptor.width * renderTextureScale);
var height = (int)(renderingData.cameraData.cameraTargetDescriptor.height * renderTextureScale);
var descriptor = new RenderTextureDescriptor(width, height);
descriptor.useMipMap = false;
descriptor.autoGenerateMips = false;
descriptor.depthBufferBits = 24;
descriptor.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm;
descriptor.msaaSamples = 1;
descriptor.dimension = TextureDimension.Tex2D;
cmdBuffer.GetTemporaryRT(rtHandle.id, descriptor, FilterMode.Bilinear);
}
public static void ReleaseShadowRenderTexture(CommandBuffer cmdBuffer, int shadowIndex)
{
var colorChannel = shadowIndex % 4;
var textureIndex = shadowIndex / 4;
if (colorChannel == 0)
cmdBuffer.ReleaseTemporaryRT(m_RenderTargets[textureIndex].id);
}
public static void SetShadowProjectionGlobals(CommandBuffer cmdBuffer, ShadowCaster2D shadowCaster)
{
cmdBuffer.SetGlobalVector(k_ShadowModelScaleID, shadowCaster.m_CachedLossyScale);
cmdBuffer.SetGlobalMatrix(k_ShadowModelMatrixID, shadowCaster.m_CachedShadowMatrix);
cmdBuffer.SetGlobalMatrix(k_ShadowModelInvMatrixID, shadowCaster.m_CachedInverseShadowMatrix);
}
public static bool RenderShadows(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int layerToRender, Light2D light, float shadowIntensity, RenderTargetIdentifier renderTexture, int colorBit)
{
using (new ProfilingScope(cmdBuffer, m_ProfilingSamplerShadows))
{
bool hasShadow = false;
var shadowCasterGroups = ShadowCasterGroup2DManager.shadowCasterGroups;
if (shadowCasterGroups != null && shadowCasterGroups.Count > 0)
{
// Before doing anything check to see if any of the shadow casters are visible to this light
for (var group = 0; group < shadowCasterGroups.Count; group++)
{
var shadowCasterGroup = shadowCasterGroups[group];
var shadowCasters = shadowCasterGroup.GetShadowCasters();
if (shadowCasters != null)
{
// Draw the projected shadows for the shadow caster group. Writing into the group stencil buffer bit
for (var i = 0; i < shadowCasters.Count; i++)
{
var shadowCaster = shadowCasters[i];
if (shadowCaster != null && shadowCaster.IsLit(light) && shadowCaster.IsShadowedLayer(layerToRender))
{
hasShadow = true;
break;
}
}
}
}
if (hasShadow)
{
cmdBuffer.SetRenderTarget(renderTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
using (new ProfilingScope(cmdBuffer, m_ProfilingSamplerShadowColorsLookup[colorBit]))
{
if (colorBit == 0)
cmdBuffer.ClearRenderTarget(true, true, Color.clear);
else
cmdBuffer.ClearRenderTarget(true, false, Color.clear);
var shadowRadius = light.boundingSphere.radius;
cmdBuffer.SetGlobalVector(k_LightPosID, light.transform.position);
cmdBuffer.SetGlobalFloat(k_ShadowRadiusID, shadowRadius);
cmdBuffer.SetGlobalColor(k_ShadowColorMaskID, k_ColorLookup[colorBit]);
var unshadowGeometryMaterial = pass.rendererData.GetGeometryUnshadowMaterial(colorBit);
var projectedShadowsMaterial = pass.rendererData.GetProjectedShadowMaterial(colorBit);
var selfShadowMaterial = pass.rendererData.GetSpriteSelfShadowMaterial(colorBit);
var unshadowMaterial = pass.rendererData.GetSpriteUnshadowMaterial(colorBit);
var setGlobalStencilMaterial = pass.rendererData.GetStencilOnlyShadowMaterial(colorBit);
for (var group = 0; group < shadowCasterGroups.Count; group++)
{
var shadowCasterGroup = shadowCasterGroups[group];
var shadowCasters = shadowCasterGroup.GetShadowCasters();
if (shadowCasters != null)
{
for (var i = 0; i < shadowCasters.Count; i++)
{
var shadowCaster = shadowCasters[i];
if (shadowCaster.IsLit(light))
{
if (shadowCaster != null && projectedShadowsMaterial != null && shadowCaster.IsShadowedLayer(layerToRender))
{
if (shadowCaster.castsShadows)
{
SetShadowProjectionGlobals(cmdBuffer, shadowCaster);
cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.m_CachedLocalToWorldMatrix, unshadowGeometryMaterial, 0, 0);
cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.m_CachedLocalToWorldMatrix, projectedShadowsMaterial, 0, 0);
cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.m_CachedLocalToWorldMatrix, unshadowGeometryMaterial, 0, 1);
}
}
}
}
// Draw the sprites, either as self shadowing or unshadowing
for (var i = 0; i < shadowCasters.Count; i++)
{
var shadowCaster = shadowCasters[i];
if (shadowCaster.IsLit(light))
{
if (shadowCaster != null && shadowCaster.IsShadowedLayer(layerToRender))
{
if (shadowCaster.useRendererSilhouette)
{
// Draw using the sprite renderer
var renderer = (Renderer)null;
shadowCaster.TryGetComponent<Renderer>(out renderer);
if (renderer != null)
{
var material = shadowCaster.selfShadows ? selfShadowMaterial : unshadowMaterial;
if (material != null)
cmdBuffer.DrawRenderer(renderer, material);
}
}
else
{
var meshMat = shadowCaster.m_CachedLocalToWorldMatrix;
var material = shadowCaster.selfShadows ? selfShadowMaterial : unshadowMaterial;
// Draw using the shadow mesh
if (material != null)
cmdBuffer.DrawMesh(shadowCaster.mesh, meshMat, material);
}
}
}
}
// Draw the projected shadows for the shadow caster group. Writing clearing the group stencil bit, and setting the global bit
for (var i = 0; i < shadowCasters.Count; i++)
{
var shadowCaster = shadowCasters[i];
if (shadowCaster.IsLit(light))
{
if (shadowCaster != null && projectedShadowsMaterial != null && shadowCaster.IsShadowedLayer(layerToRender))
{
if (shadowCaster.castsShadows)
{
SetShadowProjectionGlobals(cmdBuffer, shadowCaster);
cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.m_CachedLocalToWorldMatrix, projectedShadowsMaterial, 0, 1);
}
}
}
}
}
}
}
}
}
return hasShadow;
}
}
}
}

View file

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

View file

@ -0,0 +1,214 @@
using System.Collections.Generic;
using System;
using System.Linq;
using UnityEngine.Rendering.Universal.LibTessDotNet;
namespace UnityEngine.Rendering.Universal
{
internal class ShadowUtility
{
internal struct Edge : IComparable<Edge>
{
public int vertexIndex0;
public int vertexIndex1;
public Vector4 tangent;
private bool compareReversed; // This is done so that edge AB can equal edge BA
public void AssignVertexIndices(int vi0, int vi1)
{
vertexIndex0 = vi0;
vertexIndex1 = vi1;
compareReversed = vi0 > vi1;
}
public int Compare(Edge a, Edge b)
{
int adjustedVertexIndex0A = a.compareReversed ? a.vertexIndex1 : a.vertexIndex0;
int adjustedVertexIndex1A = a.compareReversed ? a.vertexIndex0 : a.vertexIndex1;
int adjustedVertexIndex0B = b.compareReversed ? b.vertexIndex1 : b.vertexIndex0;
int adjustedVertexIndex1B = b.compareReversed ? b.vertexIndex0 : b.vertexIndex1;
// Sort first by VI0 then by VI1
int deltaVI0 = adjustedVertexIndex0A - adjustedVertexIndex0B;
int deltaVI1 = adjustedVertexIndex1A - adjustedVertexIndex1B;
if (deltaVI0 == 0)
return deltaVI1;
else
return deltaVI0;
}
public int CompareTo(Edge edgeToCompare)
{
return Compare(this, edgeToCompare);
}
}
static Edge CreateEdge(int triangleIndexA, int triangleIndexB, List<Vector3> vertices, List<int> triangles)
{
Edge retEdge = new Edge();
retEdge.AssignVertexIndices(triangles[triangleIndexA], triangles[triangleIndexB]);
Vector3 vertex0 = vertices[retEdge.vertexIndex0];
vertex0.z = 0;
Vector3 vertex1 = vertices[retEdge.vertexIndex1];
vertex1.z = 0;
Vector3 edgeDir = Vector3.Normalize(vertex1 - vertex0);
retEdge.tangent = Vector3.Cross(-Vector3.forward, edgeDir);
return retEdge;
}
static void PopulateEdgeArray(List<Vector3> vertices, List<int> triangles, List<Edge> edges)
{
for (int triangleIndex = 0; triangleIndex < triangles.Count; triangleIndex += 3)
{
edges.Add(CreateEdge(triangleIndex, triangleIndex + 1, vertices, triangles));
edges.Add(CreateEdge(triangleIndex + 1, triangleIndex + 2, vertices, triangles));
edges.Add(CreateEdge(triangleIndex + 2, triangleIndex, vertices, triangles));
}
}
static bool IsOutsideEdge(int edgeIndex, List<Edge> edgesToProcess)
{
int previousIndex = edgeIndex - 1;
int nextIndex = edgeIndex + 1;
int numberOfEdges = edgesToProcess.Count;
Edge currentEdge = edgesToProcess[edgeIndex];
return (previousIndex < 0 || (currentEdge.CompareTo(edgesToProcess[edgeIndex - 1]) != 0)) && (nextIndex >= numberOfEdges || (currentEdge.CompareTo(edgesToProcess[edgeIndex + 1]) != 0));
}
static void SortEdges(List<Edge> edgesToProcess)
{
edgesToProcess.Sort();
}
static void CreateShadowTriangles(List<Vector3> vertices, List<Color> colors, List<int> triangles, List<Vector4> tangents, List<Edge> edges)
{
for (int edgeIndex = 0; edgeIndex < edges.Count; edgeIndex++)
{
if (IsOutsideEdge(edgeIndex, edges))
{
Edge edge = edges[edgeIndex];
tangents[edge.vertexIndex1] = -edge.tangent;
int newVertexIndex = vertices.Count;
vertices.Add(vertices[edge.vertexIndex0]);
colors.Add(colors[edge.vertexIndex0]);
tangents.Add(-edge.tangent);
triangles.Add(edge.vertexIndex0);
triangles.Add(newVertexIndex);
triangles.Add(edge.vertexIndex1);
}
}
}
static object InterpCustomVertexData(Vec3 position, object[] data, float[] weights)
{
return data[0];
}
static void InitializeTangents(int tangentsToAdd, List<Vector4> tangents)
{
for (int i = 0; i < tangentsToAdd; i++)
tangents.Add(Vector4.zero);
}
static internal void ComputeBoundingSphere(Vector3[] shapePath, out BoundingSphere boundingSphere)
{
float minX = float.MaxValue;
float maxX = float.MinValue;
float minY = float.MaxValue;
float maxY = float.MinValue;
// Add outline vertices
int pathLength = shapePath.Length;
for (int i = 0; i < pathLength; i++)
{
Vector3 vertex = shapePath[i];
if (minX > vertex.x)
minX = vertex.x;
if (maxX < vertex.x)
maxX = vertex.x;
if (minY > vertex.y)
minY = vertex.y;
if (maxY < vertex.y)
maxY = vertex.y;
}
// Calculate bounding sphere (circle)
Vector3 origin = new Vector2(0.5f * (minX + maxX), 0.5f * (minY + maxY));
float deltaX = maxX - minX;
float deltaY = maxY - minY;
float radius = 0.5f * Mathf.Sqrt(deltaX * deltaX + deltaY * deltaY);
boundingSphere.position = origin;
boundingSphere.radius = radius;
}
public static BoundingSphere GenerateShadowMesh(Mesh mesh, Vector3[] shapePath)
{
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
List<Vector4> tangents = new List<Vector4>();
List<Color> extrusion = new List<Color>();
// Create interior geometry
int pointCount = shapePath.Length;
var inputs = new ContourVertex[2 * pointCount];
for (int i = 0; i < pointCount; i++)
{
Color extrusionData = new Color(shapePath[i].x, shapePath[i].y, shapePath[i].x, shapePath[i].y);
int nextPoint = (i + 1) % pointCount;
inputs[2 * i] = new ContourVertex() { Position = new Vec3() { X = shapePath[i].x, Y = shapePath[i].y, Z = 0 }, Data = extrusionData };
extrusionData = new Color(shapePath[i].x, shapePath[i].y, shapePath[nextPoint].x, shapePath[nextPoint].y);
Vector2 midPoint = 0.5f * (shapePath[i] + shapePath[nextPoint]);
inputs[2 * i + 1] = new ContourVertex() { Position = new Vec3() { X = midPoint.x, Y = midPoint.y, Z = 0 }, Data = extrusionData };
}
Tess tessI = new Tess();
tessI.AddContour(inputs, ContourOrientation.Original);
tessI.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3, InterpCustomVertexData);
var indicesI = tessI.Elements.Select(i => i).ToArray();
var verticesI = tessI.Vertices.Select(v => new Vector3(v.Position.X, v.Position.Y, 0)).ToArray();
var extrusionI = tessI.Vertices.Select(v => new Color(((Color)v.Data).r, ((Color)v.Data).g, ((Color)v.Data).b, ((Color)v.Data).a)).ToArray();
vertices.AddRange(verticesI);
triangles.AddRange(indicesI);
extrusion.AddRange(extrusionI);
InitializeTangents(vertices.Count, tangents);
List<Edge> edges = new List<Edge>();
PopulateEdgeArray(vertices, triangles, edges);
SortEdges(edges);
CreateShadowTriangles(vertices, extrusion, triangles, tangents, edges);
Color[] finalExtrusion = extrusion.ToArray();
Vector3[] finalVertices = vertices.ToArray();
int[] finalTriangles = triangles.ToArray();
Vector4[] finalTangents = tangents.ToArray();
mesh.Clear();
mesh.vertices = finalVertices;
mesh.triangles = finalTriangles;
mesh.tangents = finalTangents;
mesh.colors = finalExtrusion;
BoundingSphere retSphere;
ComputeBoundingSphere(shapePath, out retSphere);
return retSphere;
}
}
}

View file

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