SilhouetteRenderer.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Runtime.InteropServices; 4 using DefaultNamespace; 5 using UnityEngine; 6 using Unity.Profiling; 7 using UnityEngine.Rendering; 8 9 10 [RequireComponent(typeof(IGreasePencilEdgeCalculator))] 11 public class SilhouetteRenderer : MonoBehaviour 12 { 13 14 static readonly ProfilerMarker debugMarker = new ProfilerMarker("SilhouetteRender"); 15 16 [StructLayout(LayoutKind.Sequential)] 17 public struct VertexData 18 { 19 public Vector3 position; 20 public Vector3 normal; 21 } 22 23 IGreasePencilEdgeCalculator _edgeCalculator; 24 25 GraphicsBuffer _indices; 26 ComputeBuffer _materialBuffer; 27 28 public Material material; 29 30 31 public List<GreasePencilMaterial> greasePencilMaterials; 32 33 [Range(0.0f, 1.0f)] public float opacity = 1.0f; 34 public Color colorTint = new(1, 1, 1, 0); 35 36 37 void Start() 38 { 39 _edgeCalculator = GetComponent<IGreasePencilEdgeCalculator>(); 40 InitBuffers(); 41 } 42 43 private void Update() 44 { 45 _edgeCalculator.CalculateEdges(); 46 // Create the MaterialPropertyBlock to hold our per-draw data. 47 var matProps = new MaterialPropertyBlock(); 48 49 // Set your custom data buffers 50 matProps.SetBuffer("_Pos", _edgeCalculator.GetStrokeBuffer()); 51 matProps.SetBuffer("_Color", _edgeCalculator.GetColorBuffer()); 52 matProps.SetBuffer("gp_materials", _materialBuffer); 53 54 // Strokes are already in world coordinates 55 matProps.SetMatrix("_ObjectToWorld", Matrix4x4.identity); 56 matProps.SetFloat("gp_layer_opacity", opacity); 57 matProps.SetColor("gp_layer_tint", colorTint); 58 // matProps.SetFloat("gp_layer_opacity", opacity); 59 // matProps.SetColor("gp_layer_tint", colorTint); 60 61 62 RenderParams rp = new RenderParams(material); 63 rp.worldBounds = new Bounds(Vector3.zero, 1000*Vector3.one); // use tighter bounds 64 rp.matProps = matProps; 65 66 Graphics.RenderPrimitivesIndexed(rp, MeshTopology.Triangles, _indices, _indices.count); 67 } 68 69 void OnDestroy() 70 { 71 ReleaseBuffers(); 72 } 73 74 void ReleaseBuffers() 75 { 76 _indices?.Dispose(); 77 _indices = null; 78 } 79 80 void InitBuffers() 81 { 82 ReleaseBuffers(); 83 84 85 var bufferLength = _edgeCalculator.GetMaximumBufferLength(); 86 var indices = new int[bufferLength*6]; // 6 indices per triangle 87 int triangleIboIndex = 0; 88 for (int i = 0; i < bufferLength; i++) 89 { 90 int vertIdxMarkedStroke = ((i) << 2) | GreasePencilRenderer.GP_IS_STROKE_VERTEX_BIT; 91 indices[triangleIboIndex + 0] = vertIdxMarkedStroke + 0; 92 indices[triangleIboIndex + 1] = vertIdxMarkedStroke + 1; 93 indices[triangleIboIndex + 2] = vertIdxMarkedStroke + 2; 94 triangleIboIndex += 3; 95 indices[triangleIboIndex + 0] = vertIdxMarkedStroke + 2; 96 indices[triangleIboIndex + 1] = vertIdxMarkedStroke + 1; 97 indices[triangleIboIndex + 2] = vertIdxMarkedStroke + 3; 98 triangleIboIndex += 3; 99 } 100 101 _indices = new GraphicsBuffer(GraphicsBuffer.Target.Structured | GraphicsBuffer.Target.Index, indices.Length, sizeof(int)); 102 _indices.SetData(indices); 103 104 CreateMaterialBuffer(); 105 } 106 107 private void CreateMaterialBuffer() 108 { 109 110 var materialDataList = new List<GreasePencilRenderer.GpMaterialData>(); 111 foreach (var mat in greasePencilMaterials) 112 { 113 var gpuMat = new GreasePencilRenderer.GpMaterialData 114 { 115 // Populate the C# struct from your GreasePencilSO data. 116 stroke_color = new Vector4(mat.stroke_color[0], mat.stroke_color[1], mat.stroke_color[2], 1.0f), 117 fill_color = new Vector4(mat.fill_color[0], mat.fill_color[1], mat.fill_color[2], 1.0f), 118 fill_mix_color = new Vector4(mat.fill_mix_color[0], mat.fill_mix_color[1], mat.fill_mix_color[2], 1.0f), 119 fill_uv_rot_scale = new Vector4(mat.fill_uv_rot_scale[0], mat.fill_uv_rot_scale[1], mat.fill_uv_rot_scale[2], mat.fill_uv_rot_scale[3]), 120 // Pack fill_uv_offset and alignment_rot into a single Vector4 121 fill_uv_offset_alignment_rot = new Vector4(mat.fill_uv_offset[0], mat.fill_uv_offset[1], mat.alignment_rot[0], mat.alignment_rot[1]), 122 stroke_texture_mix = mat.stroke_texture_mix, 123 stroke_u_scale = mat.stroke_u_scale, 124 fill_texture_mix = mat.fill_texture_mix, 125 flag = mat.flag 126 }; 127 128 materialDataList.Add(gpuMat); 129 } 130 131 // Create the ComputeBuffer and upload the data. 132 _materialBuffer = new ComputeBuffer(materialDataList.Count, GreasePencilRenderer.GpMaterialData.SizeOf); 133 _materialBuffer.SetData(materialDataList); 134 } 135 }