testss
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
[AddComponentMenu("Rendering/2D/Composite Shadow Caster 2D (Experimental)")]
|
||||
[ExecuteInEditMode]
|
||||
public class CompositeShadowCaster2D : ShadowCasterGroup2D
|
||||
{
|
||||
protected void OnEnable()
|
||||
{
|
||||
ShadowCasterGroup2DManager.AddGroup(this);
|
||||
}
|
||||
|
||||
protected void OnDisable()
|
||||
{
|
||||
ShadowCasterGroup2DManager.RemoveGroup(this);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
/// <summary>
|
||||
/// Class <c>ShadowCaster2D</c> contains properties used for shadow casting
|
||||
/// </summary>
|
||||
[ExecuteInEditMode]
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Rendering/2D/Shadow Caster 2D (Experimental)")]
|
||||
public class ShadowCaster2D : ShadowCasterGroup2D
|
||||
{
|
||||
[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;
|
||||
|
||||
internal Mesh mesh => m_Mesh;
|
||||
internal 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;
|
||||
|
||||
|
||||
/// <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 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();
|
||||
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)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void Reset()
|
||||
{
|
||||
Awake();
|
||||
OnEnable();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
public abstract class ShadowCasterGroup2D : MonoBehaviour
|
||||
{
|
||||
[SerializeField] internal int m_ShadowGroup = 0;
|
||||
List<ShadowCaster2D> m_ShadowCasters;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
internal class ShadowCasterGroup2DManager
|
||||
{
|
||||
static List<ShadowCasterGroup2D> s_ShadowCasterGroups = null;
|
||||
|
||||
public static List<ShadowCasterGroup2D> shadowCasterGroups { get { return s_ShadowCasterGroups; } }
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,181 @@
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace UnityEngine.Experimental.Rendering.Universal
|
||||
{
|
||||
internal static class ShadowRendering
|
||||
{
|
||||
private static readonly int k_LightPosID = Shader.PropertyToID("_LightPos");
|
||||
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 RenderTargetHandle[] m_RenderTargets = null;
|
||||
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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void CreateShadowRenderTexture(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int shadowIndex)
|
||||
{
|
||||
CreateShadowRenderTexture(pass, m_RenderTargets[shadowIndex], renderingData, cmdBuffer);
|
||||
}
|
||||
|
||||
public static void PrerenderShadows(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int layerToRender, Light2D light, int shadowIndex, float shadowIntensity)
|
||||
{
|
||||
// Render the shadows for this light
|
||||
RenderShadows(pass, renderingData, cmdBuffer, layerToRender, light, shadowIntensity, m_RenderTargets[shadowIndex].Identifier());
|
||||
}
|
||||
|
||||
public static void SetGlobalShadowTexture(CommandBuffer cmdBuffer, Light2D light, int shadowIndex)
|
||||
{
|
||||
cmdBuffer.SetGlobalTexture("_ShadowTex", m_RenderTargets[shadowIndex].Identifier());
|
||||
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)
|
||||
{
|
||||
cmdBuffer.ReleaseTemporaryRT(m_RenderTargets[shadowIndex].id);
|
||||
}
|
||||
|
||||
private static Material GetShadowMaterial(this Renderer2DData rendererData, int index)
|
||||
{
|
||||
var shadowMaterialIndex = index % 255;
|
||||
if (rendererData.shadowMaterials[shadowMaterialIndex] == null)
|
||||
{
|
||||
rendererData.shadowMaterials[shadowMaterialIndex] = CoreUtils.CreateEngineMaterial(rendererData.shadowGroupShader);
|
||||
rendererData.shadowMaterials[shadowMaterialIndex].SetFloat(k_ShadowStencilGroupID, index);
|
||||
}
|
||||
|
||||
return rendererData.shadowMaterials[shadowMaterialIndex];
|
||||
}
|
||||
|
||||
private static Material GetRemoveSelfShadowMaterial(this Renderer2DData rendererData, int index)
|
||||
{
|
||||
var shadowMaterialIndex = index % 255;
|
||||
if (rendererData.removeSelfShadowMaterials[shadowMaterialIndex] == null)
|
||||
{
|
||||
rendererData.removeSelfShadowMaterials[shadowMaterialIndex] = CoreUtils.CreateEngineMaterial(rendererData.removeSelfShadowShader);
|
||||
rendererData.removeSelfShadowMaterials[shadowMaterialIndex].SetFloat(k_ShadowStencilGroupID, index);
|
||||
}
|
||||
|
||||
return rendererData.removeSelfShadowMaterials[shadowMaterialIndex];
|
||||
}
|
||||
|
||||
public static void RenderShadows(IRenderPass2D pass, RenderingData renderingData, CommandBuffer cmdBuffer, int layerToRender, Light2D light, float shadowIntensity, RenderTargetIdentifier renderTexture)
|
||||
{
|
||||
cmdBuffer.SetRenderTarget(renderTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
|
||||
cmdBuffer.ClearRenderTarget(true, true, Color.black); // clear stencil
|
||||
|
||||
var shadowRadius = 1.42f * light.boundingSphere.radius;
|
||||
|
||||
cmdBuffer.SetGlobalVector(k_LightPosID, light.transform.position);
|
||||
cmdBuffer.SetGlobalFloat(k_ShadowRadiusID, shadowRadius);
|
||||
|
||||
var shadowMaterial = pass.rendererData.GetShadowMaterial(1);
|
||||
var removeSelfShadowMaterial = pass.rendererData.GetRemoveSelfShadowMaterial(1);
|
||||
var shadowCasterGroups = ShadowCasterGroup2DManager.shadowCasterGroups;
|
||||
if (shadowCasterGroups != null && shadowCasterGroups.Count > 0)
|
||||
{
|
||||
var previousShadowGroupIndex = -1;
|
||||
var incrementingGroupIndex = 0;
|
||||
for (var group = 0; group < shadowCasterGroups.Count; group++)
|
||||
{
|
||||
var shadowCasterGroup = shadowCasterGroups[group];
|
||||
var shadowCasters = shadowCasterGroup.GetShadowCasters();
|
||||
|
||||
var shadowGroupIndex = shadowCasterGroup.GetShadowGroup();
|
||||
if (LightUtility.CheckForChange(shadowGroupIndex, ref previousShadowGroupIndex) || shadowGroupIndex == 0)
|
||||
{
|
||||
incrementingGroupIndex++;
|
||||
shadowMaterial = pass.rendererData.GetShadowMaterial(incrementingGroupIndex);
|
||||
removeSelfShadowMaterial = pass.rendererData.GetRemoveSelfShadowMaterial(incrementingGroupIndex);
|
||||
}
|
||||
|
||||
if (shadowCasters != null)
|
||||
{
|
||||
// Draw the shadow casting group first, then draw the silhouettes..
|
||||
for (var i = 0; i < shadowCasters.Count; i++)
|
||||
{
|
||||
var shadowCaster = shadowCasters[i];
|
||||
|
||||
if (shadowCaster != null && shadowMaterial != null && shadowCaster.IsShadowedLayer(layerToRender))
|
||||
{
|
||||
if (shadowCaster.castsShadows)
|
||||
cmdBuffer.DrawMesh(shadowCaster.mesh, shadowCaster.transform.localToWorldMatrix, shadowMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < shadowCasters.Count; i++)
|
||||
{
|
||||
var shadowCaster = shadowCasters[i];
|
||||
|
||||
if (shadowCaster != null && shadowMaterial != null && shadowCaster.IsShadowedLayer(layerToRender))
|
||||
{
|
||||
if (shadowCaster.useRendererSilhouette)
|
||||
{
|
||||
var renderer = shadowCaster.GetComponent<Renderer>();
|
||||
if (renderer != null)
|
||||
{
|
||||
if (!shadowCaster.selfShadows)
|
||||
cmdBuffer.DrawRenderer(renderer, removeSelfShadowMaterial);
|
||||
else
|
||||
cmdBuffer.DrawRenderer(renderer, shadowMaterial, 0, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!shadowCaster.selfShadows)
|
||||
{
|
||||
var meshMat = shadowCaster.transform.localToWorldMatrix;
|
||||
cmdBuffer.DrawMesh(shadowCaster.mesh, meshMat, removeSelfShadowMaterial);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,178 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using System.Linq;
|
||||
using UnityEngine.Experimental.Rendering.Universal.LibTessDotNet;
|
||||
|
||||
|
||||
namespace UnityEngine.Experimental.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);
|
||||
}
|
||||
|
||||
public static void 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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user