您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
365 行
14 KiB
365 行
14 KiB
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine.Experimental.Rendering.Universal.LibTessDotNet;
|
|
|
|
namespace UnityEngine.Experimental.Rendering.Universal
|
|
{
|
|
internal static class LightUtility
|
|
{
|
|
public static bool CheckForChange<T>(T a, ref T b)
|
|
{
|
|
bool changed = !Equals(a,b);
|
|
b = a;
|
|
return changed;
|
|
}
|
|
|
|
public static Bounds CalculateBoundingSphere(ref Vector3[] vertices, ref Color[] colors, float falloffDistance)
|
|
{
|
|
Bounds localBounds = new Bounds();
|
|
|
|
Vector3 minimum = new Vector3(float.MaxValue, float.MaxValue);
|
|
Vector3 maximum = new Vector3(float.MinValue, float.MinValue);
|
|
for (int i = 0; i < vertices.Length; i++)
|
|
{
|
|
Vector3 vertex = vertices[i];
|
|
vertex.x += falloffDistance * colors[i].r;
|
|
vertex.y += falloffDistance * colors[i].g;
|
|
|
|
minimum.x = vertex.x < minimum.x ? vertex.x : minimum.x;
|
|
minimum.y = vertex.y < minimum.y ? vertex.y : minimum.y;
|
|
maximum.x = vertex.x > maximum.x ? vertex.x : maximum.x;
|
|
maximum.y = vertex.y > maximum.y ? vertex.y : maximum.y;
|
|
}
|
|
|
|
localBounds.max = maximum;
|
|
localBounds.min = minimum;
|
|
|
|
return localBounds;
|
|
}
|
|
|
|
// Takes in a mesh that
|
|
public static Bounds GenerateParametricMesh(ref Mesh mesh, float radius, float falloffDistance, float angle, int sides)
|
|
{
|
|
if (mesh == null)
|
|
mesh = new Mesh();
|
|
|
|
float angleOffset = Mathf.PI / 2.0f + Mathf.Deg2Rad * angle;
|
|
if (sides < 3)
|
|
{
|
|
radius = 0.70710678118654752440084436210485f * radius;
|
|
sides = 4;
|
|
}
|
|
|
|
if(sides == 4)
|
|
{
|
|
angleOffset = Mathf.PI / 4.0f + Mathf.Deg2Rad * angle;
|
|
}
|
|
|
|
// Return a shape with radius = 1
|
|
Vector3[] vertices;
|
|
int[] triangles;
|
|
Color[] colors;
|
|
|
|
int centerIndex;
|
|
vertices = new Vector3[1 + 2 * sides];
|
|
colors = new Color[1 + 2 * sides];
|
|
triangles = new int[3 * 3 * sides];
|
|
centerIndex = 2 * sides;
|
|
|
|
// Color will contain r,g = x,y extrusion direction, a = alpha. b is unused at the moment. The inner shape should not be extruded
|
|
Color color = new Color(0, 0, 0, 1);
|
|
vertices[centerIndex] = Vector3.zero;
|
|
colors[centerIndex] = color;
|
|
float radiansPerSide = 2 * Mathf.PI / sides;
|
|
|
|
for (int i = 0; i < sides; i++)
|
|
{
|
|
float endAngle = (i + 1) * radiansPerSide;
|
|
|
|
Vector3 extrudeDir = new Vector3(Mathf.Cos(endAngle + angleOffset), Mathf.Sin(endAngle + angleOffset), 0);
|
|
Vector3 endPoint = radius * extrudeDir;
|
|
|
|
int vertexIndex;
|
|
vertexIndex = (2 * i + 2) % (2 * sides);
|
|
|
|
vertices[vertexIndex] = endPoint; // This is the extruded endpoint
|
|
vertices[vertexIndex + 1] = endPoint;
|
|
|
|
colors[vertexIndex] = new Color(extrudeDir.x, extrudeDir.y, 0, 0);
|
|
colors[vertexIndex + 1] = color;
|
|
|
|
// Triangle 1 (Tip)
|
|
int triangleIndex = 9 * i;
|
|
triangles[triangleIndex] = vertexIndex + 1;
|
|
triangles[triangleIndex + 1] = 2 * i + 1;
|
|
triangles[triangleIndex + 2] = centerIndex;
|
|
|
|
// Triangle 2 (Upper Top Left)
|
|
triangles[triangleIndex + 3] = vertexIndex;
|
|
triangles[triangleIndex + 4] = 2 * i;
|
|
triangles[triangleIndex + 5] = 2 * i + 1;
|
|
|
|
// Triangle 2 (Bottom Top Left)
|
|
triangles[triangleIndex + 6] = vertexIndex + 1;
|
|
triangles[triangleIndex + 7] = vertexIndex;
|
|
triangles[triangleIndex + 8] = 2 * i + 1;
|
|
}
|
|
|
|
mesh.Clear();
|
|
mesh.vertices = vertices;
|
|
mesh.colors = colors;
|
|
mesh.triangles = triangles;
|
|
|
|
return CalculateBoundingSphere(ref vertices, ref colors, falloffDistance);
|
|
}
|
|
|
|
public static Bounds GenerateSpriteMesh(ref Mesh mesh, Sprite sprite, float scale)
|
|
{
|
|
if (mesh == null)
|
|
mesh = new Mesh();
|
|
|
|
if (sprite != null)
|
|
{
|
|
Vector2[] vertices2d = sprite.vertices;
|
|
Vector3[] vertices3d = new Vector3[vertices2d.Length];
|
|
Color[] colors = new Color[vertices2d.Length];
|
|
Vector4[] volumeColor = new Vector4[vertices2d.Length];
|
|
|
|
ushort[] triangles2d = sprite.triangles;
|
|
int[] triangles3d = new int[triangles2d.Length];
|
|
|
|
|
|
Vector3 center = 0.5f * scale * (sprite.bounds.min + sprite.bounds.max);
|
|
for (int vertexIdx = 0; vertexIdx < vertices2d.Length; vertexIdx++)
|
|
{
|
|
Vector3 pos = new Vector3(vertices2d[vertexIdx].x, vertices2d[vertexIdx].y) - center;
|
|
vertices3d[vertexIdx] = scale * pos;
|
|
colors[vertexIdx] = new Color(0,0,0,1); // This will not have any extrusion available. Alpha will be 1 * the pixel alpha
|
|
}
|
|
|
|
for (int triangleIdx = 0; triangleIdx < triangles2d.Length; triangleIdx++)
|
|
{
|
|
triangles3d[triangleIdx] = (int)triangles2d[triangleIdx];
|
|
}
|
|
|
|
mesh.Clear();
|
|
mesh.vertices = vertices3d;
|
|
mesh.uv = sprite.uv;
|
|
mesh.triangles = triangles3d;
|
|
mesh.colors = colors;
|
|
|
|
return CalculateBoundingSphere(ref vertices3d, ref colors, 0);
|
|
}
|
|
|
|
return new Bounds(Vector3.zero, Vector3.zero);
|
|
}
|
|
|
|
static void GetFalloffExtrusion(ContourVertex[] contourPoints, int contourPointCount, ref List<Vector2> extrusionDir)
|
|
{
|
|
for (int i = 0; i < contourPointCount; ++i)
|
|
{
|
|
int h = (i == 0) ? (contourPointCount - 1) : (i - 1);
|
|
int j = (i + 1) % contourPointCount;
|
|
|
|
Vector2 pp = new Vector2(contourPoints[h].Position.X, contourPoints[h].Position.Y);
|
|
Vector2 cp = new Vector2(contourPoints[i].Position.X, contourPoints[i].Position.Y);
|
|
Vector2 np = new Vector2(contourPoints[j].Position.X, contourPoints[j].Position.Y);
|
|
|
|
Vector2 cpd = cp - pp;
|
|
Vector2 npd = np - cp;
|
|
if (cpd.magnitude < 0.001f || npd.magnitude < 0.001f)
|
|
continue;
|
|
|
|
Vector2 vl = cpd.normalized;
|
|
Vector2 vr = npd.normalized;
|
|
|
|
vl = new Vector2(-vl.y, vl.x);
|
|
vr = new Vector2(-vr.y, vr.x);
|
|
|
|
Vector2 va = vl.normalized + vr.normalized;
|
|
Vector2 vn = -va.normalized;
|
|
|
|
if (va.magnitude > 0 && vn.magnitude > 0)
|
|
{
|
|
Vector2 dir = new Vector2(vn.x, vn.y);
|
|
extrusionDir.Add(dir);
|
|
}
|
|
}
|
|
}
|
|
|
|
static object InterpCustomVertexData(Vec3 position, object[] data, float[] weights)
|
|
{
|
|
return data[0];
|
|
}
|
|
|
|
|
|
public static void GetFalloffShape(Vector3[] shapePath, ref List<Vector2> extrusionDir)
|
|
{
|
|
int pointCount = shapePath.Length;
|
|
var inputs = new ContourVertex[pointCount];
|
|
for (int i = 0; i < pointCount; ++i)
|
|
inputs[i] = new ContourVertex() { Position = new Vec3() { X = shapePath[i].x, Y = shapePath[i].y }, Data = null };
|
|
|
|
GetFalloffExtrusion(inputs, pointCount, ref extrusionDir);
|
|
}
|
|
|
|
public static Bounds GenerateShapeMesh(ref Mesh mesh, Vector3[] shapePath, float falloffDistance)
|
|
{
|
|
Bounds localBounds;
|
|
Color meshInteriorColor = new Color(0,0,0,1);
|
|
List<Vector3> finalVertices = new List<Vector3>();
|
|
List<int> finalIndices = new List<int>();
|
|
List<Color> finalColors = new List<Color>();
|
|
|
|
// Create interior geometry
|
|
int pointCount = shapePath.Length;
|
|
var inputs = new ContourVertex[pointCount];
|
|
for (int i = 0; i < pointCount; ++i)
|
|
inputs[i] = new ContourVertex() { Position = new Vec3() { X = shapePath[i].x, Y = shapePath[i].y }, Data = meshInteriorColor };
|
|
|
|
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 colorsI = tessI.Vertices.Select(v => new Color(((Color)v.Data).r, ((Color)v.Data).g, ((Color)v.Data).b, ((Color)v.Data).a)).ToArray();
|
|
|
|
finalVertices.AddRange(verticesI);
|
|
finalIndices.AddRange(indicesI);
|
|
finalColors.AddRange(colorsI);
|
|
|
|
// Create falloff geometry
|
|
List<Vector2> extrusionDirs = new List<Vector2>();
|
|
GetFalloffShape(shapePath, ref extrusionDirs);
|
|
|
|
pointCount = finalVertices.Count;
|
|
int falloffPointCount = 2 * shapePath.Length;
|
|
for (int i = 0; i < shapePath.Length; i++)
|
|
{
|
|
// Making triangles ABD and DCA
|
|
int triangleIndex = 2 * i;
|
|
int aIndex = pointCount + triangleIndex;
|
|
int bIndex = pointCount + triangleIndex + 1;
|
|
int cIndex = pointCount + (triangleIndex + 2) % falloffPointCount;
|
|
int dIndex = pointCount + (triangleIndex + 3) % falloffPointCount;
|
|
|
|
Vector3 point = shapePath[i];
|
|
|
|
// We are making degenerate triangles which will be extruded by the shader
|
|
finalVertices.Add(point);
|
|
finalVertices.Add(point);
|
|
|
|
finalIndices.Add(aIndex);
|
|
finalIndices.Add(bIndex);
|
|
finalIndices.Add(dIndex);
|
|
|
|
finalIndices.Add(dIndex);
|
|
finalIndices.Add(cIndex);
|
|
finalIndices.Add(aIndex);
|
|
|
|
Color aColor = new Color(0, 0, 0, 1);
|
|
Color bColor = new Color(extrusionDirs[i].x, extrusionDirs[i].y, 0, 0);
|
|
|
|
finalColors.Add(aColor);
|
|
finalColors.Add(bColor);
|
|
}
|
|
|
|
Color[] colors = finalColors.ToArray();
|
|
Vector3[] vertices = finalVertices.ToArray();
|
|
mesh.Clear();
|
|
mesh.vertices = vertices;
|
|
mesh.colors = colors;
|
|
mesh.SetIndices(finalIndices.ToArray(), MeshTopology.Triangles, 0);
|
|
|
|
localBounds = CalculateBoundingSphere(ref vertices, ref colors, falloffDistance);
|
|
|
|
return localBounds;
|
|
}
|
|
|
|
|
|
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 = transformToCheck.GetComponent<CompositeShadowCaster2D>();
|
|
if (currentGroup != null)
|
|
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);
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
public static int GetShapePathHash(Vector3[] path)
|
|
{
|
|
unchecked
|
|
{
|
|
int hashCode = (int)2166136261;
|
|
|
|
if (path != null)
|
|
{
|
|
foreach (var point in path)
|
|
hashCode = hashCode * 16777619 ^ point.GetHashCode();
|
|
}
|
|
else
|
|
{
|
|
hashCode = 0;
|
|
}
|
|
|
|
return hashCode;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|