This commit is contained in:
2025-10-15 20:13:48 +08:00
parent 0fd74a1a45
commit 1b17489c11
27 changed files with 3196 additions and 302 deletions

View File

@@ -0,0 +1,136 @@
using UnityEngine;
using System.Collections.Generic;
[System.Serializable]
public class ShadowProjector
{
public Light lightSource;
public Transform projectionWall;
public LayerMask obstacleMask;
private Vector3 wallNormal;
private Vector3 wallPosition;
public ShadowProjector(Light light, Transform wall, LayerMask obstacleMask)
{
this.lightSource = light;
this.projectionWall = wall;
this.obstacleMask = obstacleMask;
CalculateWallPlane();
}
public ProjectedMesh ProjectMeshToWall(GameObject shadowCaster)
{
var meshFilter = shadowCaster.GetComponent<MeshFilter>();
if (meshFilter == null) return new ProjectedMesh();
var mesh = meshFilter.mesh;
var vertices = mesh.vertices;
var triangles = mesh.triangles;
List<Vector3> projectedVertices = new List<Vector3>();
List<int> projectedTriangles = new List<int>();
// 投影每个顶点
for (int i = 0; i < vertices.Length; i++)
{
Vector3 worldVertex = shadowCaster.transform.TransformPoint(vertices[i]);
Vector3 projectedVertex = ProjectPoint(worldVertex);
if (!IsObstructed(worldVertex, projectedVertex))
{
projectedVertices.Add(projectedVertex);
}
}
// 重新构建三角形(简化版本)
// 实际应该使用更复杂的三角化算法
for (int i = 0; i < triangles.Length; i += 3)
{
if (IsValidTriangle(projectedVertices, triangles, i))
{
projectedTriangles.Add(triangles[i]);
projectedTriangles.Add(triangles[i + 1]);
projectedTriangles.Add(triangles[i + 2]);
}
}
return new ProjectedMesh
{
vertices = projectedVertices,
triangles = projectedTriangles.ToArray(),
sourceObject = shadowCaster
};
}
Vector3 ProjectPoint(Vector3 worldPoint)
{
Vector3 lightDirection = GetLightDirection(worldPoint);
return IntersectWithWall(worldPoint, lightDirection);
}
Vector3 GetLightDirection(Vector3 targetPoint)
{
if (lightSource.type == LightType.Directional)
{
return -lightSource.transform.forward;
}
else
{
return (targetPoint - lightSource.transform.position).normalized;
}
}
Vector3 IntersectWithWall(Vector3 point, Vector3 direction)
{
float denominator = Vector3.Dot(direction, wallNormal);
if (Mathf.Abs(denominator) < 0.0001f)
return point;
float t = Vector3.Dot(wallPosition - point, wallNormal) / denominator;
return point + direction * t;
}
bool IsObstructed(Vector3 start, Vector3 end)
{
Vector3 direction = (end - start).normalized;
float distance = Vector3.Distance(start, end);
RaycastHit hit;
if (Physics.Raycast(start, direction, out hit, distance, obstacleMask))
{
return hit.collider.gameObject != projectionWall.gameObject;
}
return false;
}
bool IsValidTriangle(List<Vector3> vertices, int[] triangles, int startIndex)
{
int i1 = triangles[startIndex];
int i2 = triangles[startIndex + 1];
int i3 = triangles[startIndex + 2];
return i1 < vertices.Count && i2 < vertices.Count && i3 < vertices.Count;
}
void CalculateWallPlane()
{
if (projectionWall != null)
{
wallPosition = projectionWall.position;
wallNormal = -projectionWall.forward;
}
}
}
[System.Serializable]
public struct ProjectedMesh
{
public List<Vector3> vertices;
public int[] triangles;
public GameObject sourceObject;
public bool IsValid => vertices != null && vertices.Count >= 3;
}