Advertisement
noradninja

StencilVolumeGenerator

May 11th, 2025
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 3.45 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3.  
  4. [RequireComponent(typeof(MeshFilter))]
  5. public class StencilShadowCaster : MonoBehaviour
  6. {
  7.     [Header("Assign Your Lights")]
  8.     public Light directionalLight;         // your main sun‐like light
  9.     public Light spotLight;                // your local spotlight
  10.     public float extrusionDistance = 50f;  // “infinite” extrusion length
  11.  
  12.     // original mesh data
  13.     Mesh       origMesh;
  14.     Vector3[]  verts;
  15.     int[]      tris;
  16.     List<(int a, int b)> boundaryEdges;
  17.  
  18.     // dynamic volume mesh
  19.     Mesh       volumeMesh;
  20.  
  21.     void Awake()
  22.     {
  23.         // cache original mesh & silhouette edges
  24.         var mf = GetComponent<MeshFilter>();
  25.         origMesh = mf.sharedMesh;
  26.         verts    = origMesh.vertices;
  27.         tris     = origMesh.triangles;
  28.         boundaryEdges = new List<(int,int)>();
  29.         BuildBoundaryEdges();
  30.  
  31.         volumeMesh = new Mesh();
  32.         volumeMesh.MarkDynamic();
  33.  
  34.         ShadowVolumeManager.Instance.Register(this);
  35.     }
  36.  
  37.     void BuildBoundaryEdges()
  38.     {
  39.         // count undirected edges: boundary edges appear exactly once
  40.         var edgeCount = new Dictionary<(int,int),int>();
  41.         for(int i = 0; i < tris.Length; i += 3)
  42.         {
  43.             TryEdge(tris[i],   tris[i+1], edgeCount);
  44.             TryEdge(tris[i+1], tris[i+2], edgeCount);
  45.             TryEdge(tris[i+2], tris[i],   edgeCount);
  46.         }
  47.         foreach(var kv in edgeCount)
  48.             if (kv.Value == 1)
  49.                 boundaryEdges.Add(kv.Key);
  50.     }
  51.  
  52.     void TryEdge(int u, int v, Dictionary<(int,int),int> dict)
  53.     {
  54.         var key = u < v ? (u,v) : (v,u);
  55.         dict[key] = dict.TryGetValue(key, out var c) ? c + 1 : 1;
  56.     }
  57.  
  58.     /// <summary>
  59.     /// Builds a single volume mesh that contains both the directional‐light
  60.     /// volumes and the spotlight volumes.
  61.     /// </summary>
  62.     public Mesh BuildVolumeMesh()
  63.     {
  64.         var allVerts = new List<Vector3>();
  65.         var allIdx   = new List<int>();
  66.         int idx = 0;
  67.  
  68.         // helper to extrude for any given light
  69.         void ExtrudeForLight(Light L)
  70.         {
  71.             if (L == null) return;
  72.             bool isDir = L.type == LightType.Directional;
  73.             Vector3 Ldir = isDir ? -L.transform.forward : Vector3.zero;
  74.             Vector3 Lpos = L.transform.position;
  75.  
  76.             foreach(var (a,b) in boundaryEdges)
  77.             {
  78.                 // original world positions
  79.                 Vector3 v0 = transform.TransformPoint(verts[a]);
  80.                 Vector3 v1 = transform.TransformPoint(verts[b]);
  81.  
  82.                 // extruded positions
  83.                 Vector3 e0 = isDir
  84.                     ? v0 + Ldir * extrusionDistance
  85.                     : (v0 - Lpos).normalized * extrusionDistance + Lpos;
  86.                 Vector3 e1 = isDir
  87.                     ? v1 + Ldir * extrusionDistance
  88.                     : (v1 - Lpos).normalized * extrusionDistance + Lpos;
  89.  
  90.                 // add quad: v0, v1, e1, e0
  91.                 allVerts.AddRange(new[]{ v0, v1, e1, e0 });
  92.                 allIdx.AddRange(new[]{ idx, idx+1, idx+2, idx, idx+2, idx+3 });
  93.                 idx += 4;
  94.             }
  95.         }
  96.  
  97.         // Extrude for both lights
  98.         ExtrudeForLight(directionalLight);
  99.         ExtrudeForLight(spotLight);
  100.  
  101.         volumeMesh.Clear();
  102.         volumeMesh.SetVertices(allVerts);
  103.         volumeMesh.SetTriangles(allIdx, 0);
  104.         return volumeMesh;
  105.     }
  106. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement