Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System.Collections.Generic;
- using UnityEngine;
- [RequireComponent(typeof(MeshFilter))]
- public class StencilShadowCaster : MonoBehaviour
- {
- [Header("Assign Your Lights")]
- public Light directionalLight; // your main sun‐like light
- public Light spotLight; // your local spotlight
- public float extrusionDistance = 50f; // “infinite” extrusion length
- // original mesh data
- Mesh origMesh;
- Vector3[] verts;
- int[] tris;
- List<(int a, int b)> boundaryEdges;
- // dynamic volume mesh
- Mesh volumeMesh;
- void Awake()
- {
- // cache original mesh & silhouette edges
- var mf = GetComponent<MeshFilter>();
- origMesh = mf.sharedMesh;
- verts = origMesh.vertices;
- tris = origMesh.triangles;
- boundaryEdges = new List<(int,int)>();
- BuildBoundaryEdges();
- volumeMesh = new Mesh();
- volumeMesh.MarkDynamic();
- ShadowVolumeManager.Instance.Register(this);
- }
- void BuildBoundaryEdges()
- {
- // count undirected edges: boundary edges appear exactly once
- var edgeCount = new Dictionary<(int,int),int>();
- for(int i = 0; i < tris.Length; i += 3)
- {
- TryEdge(tris[i], tris[i+1], edgeCount);
- TryEdge(tris[i+1], tris[i+2], edgeCount);
- TryEdge(tris[i+2], tris[i], edgeCount);
- }
- foreach(var kv in edgeCount)
- if (kv.Value == 1)
- boundaryEdges.Add(kv.Key);
- }
- void TryEdge(int u, int v, Dictionary<(int,int),int> dict)
- {
- var key = u < v ? (u,v) : (v,u);
- dict[key] = dict.TryGetValue(key, out var c) ? c + 1 : 1;
- }
- /// <summary>
- /// Builds a single volume mesh that contains both the directional‐light
- /// volumes and the spotlight volumes.
- /// </summary>
- public Mesh BuildVolumeMesh()
- {
- var allVerts = new List<Vector3>();
- var allIdx = new List<int>();
- int idx = 0;
- // helper to extrude for any given light
- void ExtrudeForLight(Light L)
- {
- if (L == null) return;
- bool isDir = L.type == LightType.Directional;
- Vector3 Ldir = isDir ? -L.transform.forward : Vector3.zero;
- Vector3 Lpos = L.transform.position;
- foreach(var (a,b) in boundaryEdges)
- {
- // original world positions
- Vector3 v0 = transform.TransformPoint(verts[a]);
- Vector3 v1 = transform.TransformPoint(verts[b]);
- // extruded positions
- Vector3 e0 = isDir
- ? v0 + Ldir * extrusionDistance
- : (v0 - Lpos).normalized * extrusionDistance + Lpos;
- Vector3 e1 = isDir
- ? v1 + Ldir * extrusionDistance
- : (v1 - Lpos).normalized * extrusionDistance + Lpos;
- // add quad: v0, v1, e1, e0
- allVerts.AddRange(new[]{ v0, v1, e1, e0 });
- allIdx.AddRange(new[]{ idx, idx+1, idx+2, idx, idx+2, idx+3 });
- idx += 4;
- }
- }
- // Extrude for both lights
- ExtrudeForLight(directionalLight);
- ExtrudeForLight(spotLight);
- volumeMesh.Clear();
- volumeMesh.SetVertices(allVerts);
- volumeMesh.SetTriangles(allIdx, 0);
- return volumeMesh;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement