124 lines
3.8 KiB
C#
124 lines
3.8 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
|
|||
|
|
public class ShadowColliderGenerator : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
public Camera shadowCamera; // ר<><D7A8><EFBFBD><EFBFBD>Ⱦ<EFBFBD><C8BE>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
public RenderTexture shadowRT; // <20><>Ⱦ<EFBFBD><C8BE><EFBFBD><EFBFBD>
|
|||
|
|
public LayerMask shadowCasterLayer; // Ͷ<><CDB6><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
public float colliderPrecision = 0.1f; // <20><>ײ<EFBFBD>徫<EFBFBD><E5BEAB>
|
|||
|
|
|
|||
|
|
private Texture2D processedTexture;
|
|||
|
|
private PolygonCollider2D polygonCollider;
|
|||
|
|
|
|||
|
|
void Start()
|
|||
|
|
{
|
|||
|
|
// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>Ⱦ<EFBFBD><C8BE><EFBFBD><EFBFBD>
|
|||
|
|
shadowRT = new RenderTexture(512, 512, 24);
|
|||
|
|
shadowCamera.targetTexture = shadowRT;
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
processedTexture = new Texture2D(512, 512, TextureFormat.RGB24, false);
|
|||
|
|
|
|||
|
|
polygonCollider = GetComponent<PolygonCollider2D>();
|
|||
|
|
if (polygonCollider == null)
|
|||
|
|
polygonCollider = gameObject.AddComponent<PolygonCollider2D>();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Update()
|
|||
|
|
{
|
|||
|
|
GenerateShadowCollider();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void GenerateShadowCollider()
|
|||
|
|
{
|
|||
|
|
// 1. <20><>Ⱦ<EFBFBD><C8BE>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
shadowCamera.Render();
|
|||
|
|
|
|||
|
|
// 2. <20><>GPU<50><55>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>CPU
|
|||
|
|
RenderTexture.active = shadowRT;
|
|||
|
|
processedTexture.ReadPixels(new Rect(0, 0, shadowRT.width, shadowRT.height), 0, 0);
|
|||
|
|
processedTexture.Apply();
|
|||
|
|
RenderTexture.active = null;
|
|||
|
|
|
|||
|
|
// 3. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0>Ե
|
|||
|
|
List<Vector2> edgePoints = DetectEdges(processedTexture);
|
|||
|
|
|
|||
|
|
// 4. ת<><D7AA>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>겢<EFBFBD><EAB2A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ײ<EFBFBD><D7B2>
|
|||
|
|
if (edgePoints.Count > 2)
|
|||
|
|
{
|
|||
|
|
List<Vector2> worldPoints = ConvertToWorldCoordinates(edgePoints);
|
|||
|
|
polygonCollider.SetPath(0, worldPoints);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
List<Vector2> DetectEdges(Texture2D texture)
|
|||
|
|
{
|
|||
|
|
List<Vector2> edges = new List<Vector2>();
|
|||
|
|
Color[] pixels = texture.GetPixels();
|
|||
|
|
|
|||
|
|
int width = texture.width;
|
|||
|
|
int height = texture.height;
|
|||
|
|
|
|||
|
|
// <20>ı<F2B5A5B5>Ե<EFBFBD><D4B5><EFBFBD><EFBFBD><EFBFBD>㷨
|
|||
|
|
for (int y = 1; y < height - 1; y += (int)(1f / colliderPrecision))
|
|||
|
|
{
|
|||
|
|
for (int x = 1; x < width - 1; x += (int)(1f / colliderPrecision))
|
|||
|
|
{
|
|||
|
|
int index = y * width + x;
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD>鵱ǰ<E9B5B1><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Χ<EFBFBD><CEA7><EFBFBD>صIJ<D8B5><C4B2><EFBFBD>
|
|||
|
|
if (IsEdgePixel(pixels, index, width))
|
|||
|
|
{
|
|||
|
|
edges.Add(new Vector2(x, y));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return edges;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool IsEdgePixel(Color[] pixels, int index, int width)
|
|||
|
|
{
|
|||
|
|
Color current = pixels[index];
|
|||
|
|
float currentBrightness = current.r + current.g + current.b;
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
float[] neighborBrightness = new float[4]
|
|||
|
|
{
|
|||
|
|
pixels[index - 1].r + pixels[index - 1].g + pixels[index - 1].b, // <20><>
|
|||
|
|
pixels[index + 1].r + pixels[index + 1].g + pixels[index + 1].b, // <20><>
|
|||
|
|
pixels[index - width].r + pixels[index - width].g + pixels[index - width].b, // <20><>
|
|||
|
|
pixels[index + width].r + pixels[index + width].g + pixels[index + width].b // <20><>
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ھӲ<DABE><D3B2><EFBFBD><EFBFBD>ϴ<EFBFBD><CFB4><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>DZ<EFBFBD>Ե
|
|||
|
|
float threshold = 0.3f;
|
|||
|
|
for (int i = 0; i < 4; i++)
|
|||
|
|
{
|
|||
|
|
if (Mathf.Abs(currentBrightness - neighborBrightness[i]) > threshold)
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
List<Vector2> ConvertToWorldCoordinates(List<Vector2> texturePoints)
|
|||
|
|
{
|
|||
|
|
List<Vector2> worldPoints = new List<Vector2>();
|
|||
|
|
Bounds wallBounds = GetComponent<Collider2D>().bounds;
|
|||
|
|
|
|||
|
|
foreach (Vector2 point in texturePoints)
|
|||
|
|
{
|
|||
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>Ϊǽ<CEAA><C7BD><EFBFBD>ֲ<EFBFBD><D6B2><EFBFBD><EFBFBD><EFBFBD>
|
|||
|
|
Vector2 localPoint = new Vector2(
|
|||
|
|
point.x / shadowRT.width * wallBounds.size.x - wallBounds.size.x * 0.5f,
|
|||
|
|
point.y / shadowRT.height * wallBounds.size.y - wallBounds.size.y * 0.5f
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
worldPoints.Add(localPoint);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return worldPoints;
|
|||
|
|
}
|
|||
|
|
}
|