using System.Collections.Generic; using Unity.Collections; using Unity.Mathematics; using UnityEngine; using UnityEngine.Profiling; namespace RealityReboot.jelycho { [ExecuteInEditMode] public class GutRenderer : MonoBehaviour { static readonly List s_worldPositions = new(1024); [SerializeField] Rope m_Rope; [SerializeField] Material m_Material; [SerializeField] float3[] m_Positions; [SerializeField] float m_Radius = 0.2f; [SerializeField, Range(3, 128)] int m_Resolution = 16; [SerializeField] Mesh m_Mesh; [SerializeField, Header("Debug")] bool m_ShowPositions = false; void Update() { Profiler.BeginSample("GutRenderer.GenerateMesh"); GenerateMesh(); Profiler.EndSample(); Graphics.DrawMesh(m_Mesh, Matrix4x4.identity, m_Material, 0); } void OnDrawGizmos() { Gizmos.color = Color.white; for (int i = 0; i < m_Resolution; ++i) { float angle = (float)i / m_Resolution * math.PI * 2.0f; float3 pos = new(math.cos(angle), 0, math.sin(angle)); Gizmos.DrawSphere(pos, 0.1f); } if (m_ShowPositions) { if (m_Positions.Length < 2) { return; } for (int i = 0; i < m_Positions.Length - 1; i++) { Gizmos.color = Color.white; Gizmos.DrawLine(m_Positions[i], m_Positions[i + 1]); Gizmos.color = Color.yellow; Gizmos.DrawSphere(m_Positions[i], m_Radius); } Gizmos.DrawSphere(m_Positions[m_Positions.Length - 1], 0.1f); } } void GenerateMesh() { if (m_Mesh is null) { m_Mesh = new Mesh { name = "GutMesh", indexFormat = UnityEngine.Rendering.IndexFormat.UInt32 }; m_Mesh.MarkDynamic(); } if (m_Positions.Length < 2) { return; } int segmentCount = m_Positions.Length - 1; int vertexCount = m_Resolution * segmentCount; int triangleCount = (segmentCount - 1) * m_Resolution * 2; NativeList positions = new(vertexCount, Allocator.Temp); NativeList normals = new(vertexCount, Allocator.Temp); NativeList uvs = new(vertexCount, Allocator.Temp); NativeList indices = new(triangleCount * 3, Allocator.Temp); for (int i = 0; i < m_Positions.Length - 1; i++) { float3 pos0 = m_Positions[i]; float3 pos1 = m_Positions[i + 1]; float startV0 = (float)i / (m_Positions.Length - 1); float startV1 = (float)(i + 1) / (m_Positions.Length - 1); for (int j = 0; j < m_Resolution - 1; j++) { float t0 = (float)j / m_Resolution; float t1 = (float)(j + 1) / m_Resolution; float angle0 = (float)j / m_Resolution * math.PI * 2.0f; float angle1 = (float)(j + 1) / m_Resolution * math.PI * 2.0f; float3 offset0 = new float3(math.cos(angle0), 0.0f, math.sin(angle0)) * m_Radius; float3 offset1 = new float3(math.cos(angle1), 0.0f, math.sin(angle1)) * m_Radius; int startIndex = positions.Length; positions.Add(pos0 + offset0); positions.Add(pos0 + offset1); positions.Add(pos1 + offset0); positions.Add(pos1 + offset1); uvs.Add(new float2(t0, startV0)); uvs.Add(new float2(t0, startV1)); uvs.Add(new float2(t1, startV0)); uvs.Add(new float2(t1, startV1)); normals.Add(math.normalize(offset0)); normals.Add(math.normalize(offset1)); normals.Add(math.normalize(offset0)); normals.Add(math.normalize(offset1)); indices.Add(startIndex + 0); indices.Add(startIndex + 1); indices.Add(startIndex + 2); indices.Add(startIndex + 3); indices.Add(startIndex + 2); indices.Add(startIndex + 1); } } m_Mesh.Clear(); m_Mesh.SetVertices(positions.AsArray()); m_Mesh.SetNormals(normals.AsArray()); m_Mesh.SetUVs(0, uvs.AsArray()); m_Mesh.SetIndices(indices.AsArray(), MeshTopology.Triangles, 0, false); } } }