using T3.Core.Rendering; using T3.Core.Utils; using T3.Core.Utils.Geometry; namespace Lib.mesh.generate; [Guid("1b9977be-70cf-4dbd-8af1-1459596b6527")] internal sealed class NGonMesh : Instance { [Output(Guid = "9c949c29-9dc1-4ded-94ce-1e86317a5233")] public readonly Slot Data = new(); public enum TextureModes { Planar, Circular, CircularScaled } public NGonMesh() { Data.UpdateAction += Update; } private void Update(EvaluationContext context) { try { var radius = Radius.GetValue(context); var stretch = Stretch.GetValue(context); var rotation = Rotation.GetValue(context); var yaw = rotation.Y.ToRadians(); var pitch = rotation.X.ToRadians(); var roll = rotation.Z.ToRadians(); var textureMode = (TextureModes)(int)TextureMode.GetValue(context).Clamp(0, Enum.GetValues(typeof(TextureModes)).Length); var rotationMatrix = Matrix4x4.CreateFromYawPitchRoll(yaw, pitch, roll); var center = Center.GetValue(context); var center2 = new Vector3(center.X, center.Y, center.Z); var segments = Segments.GetValue(context).Clamp(1, 10000); var verticesCount = segments + 1; // +1 for center // Create buffers if (_vertexBufferData.Length != verticesCount) _vertexBufferData = new PbrVertex[verticesCount]; if (_indexBufferData.Length != segments) _indexBufferData = new Int3[segments]; var normal = Vector3.TransformNormal(VectorT3.ForwardLH, rotationMatrix); var tangent = Vector3.TransformNormal(VectorT3.Right, rotationMatrix); var binormal = Vector3.TransformNormal(VectorT3.Up, rotationMatrix); // center { float uCenter = 0; float vCenter = 0; switch (textureMode) { case TextureModes.Planar: uCenter = 0.5f; vCenter = 0.5f; break; } _vertexBufferData[0] = new PbrVertex { Position = center2, Normal = normal, Tangent = tangent, Bitangent = binormal, Texcoord = new Vector2(uCenter, vCenter), Selection = 1, ColorRgb = Vector3.One }; } // the other points are on a circle for (var segmentIndex = 0; segmentIndex < segments; ++segmentIndex) { var phi = 2 * MathF.PI * segmentIndex / segments; var p = new Vector3(radius * MathF.Sin(phi) * stretch.X, // starts at top radius * MathF.Cos(phi) * stretch.Y, 0); float u0 = 0f, v0 = 0f; switch (textureMode) { case TextureModes.Planar: u0 = MathF.Sin(phi) / 2 + 0.5f; v0 = MathF.Cos(phi) / 2 + 0.5f; break; case TextureModes.Circular: u0 = phi / (2 * MathF.PI); v0 = 1; break; case TextureModes.CircularScaled: u0 = phi / (2 * MathF.PI); v0 = radius; break; } var uv0 = new Vector2(u0, v0); var posRotated = Vector3.TransformNormal(p, rotationMatrix); _vertexBufferData[segmentIndex + 1] = new PbrVertex { Position = posRotated + center2, Normal = normal, Tangent = tangent, Bitangent = binormal, Texcoord = uv0, Selection = 1, ColorRgb = Vector3.One }; _indexBufferData[segmentIndex] = new Int3(0, (segmentIndex + 2) > segments ? 1 : segmentIndex + 2, segmentIndex + 1); } // Write Data ResourceManager.SetupStructuredBuffer(_vertexBufferData, PbrVertex.Stride * verticesCount, PbrVertex.Stride, ref _vertexBuffer); ResourceManager.CreateStructuredBufferSrv(_vertexBuffer, ref _vertexBufferWithViews.Srv); ResourceManager.CreateStructuredBufferUav(_vertexBuffer, UnorderedAccessViewBufferFlags.None, ref _vertexBufferWithViews.Uav); _vertexBufferWithViews.Buffer = _vertexBuffer; const int stride = 3 * 4; ResourceManager.SetupStructuredBuffer(_indexBufferData, stride * segments, stride, ref _indexBuffer); ResourceManager.CreateStructuredBufferSrv(_indexBuffer, ref _indexBufferWithViews.Srv); ResourceManager.CreateStructuredBufferUav(_indexBuffer, UnorderedAccessViewBufferFlags.None, ref _indexBufferWithViews.Uav); _indexBufferWithViews.Buffer = _indexBuffer; _data.VertexBuffer = _vertexBufferWithViews; _data.IndicesBuffer = _indexBufferWithViews; Data.Value = _data; Data.DirtyFlag.Clear(); } catch (Exception e) { Log.Error("Failed to create mesh:" + e.Message); } } private Buffer _vertexBuffer; private PbrVertex[] _vertexBufferData = new PbrVertex[0]; private readonly BufferWithViews _vertexBufferWithViews = new(); private Buffer _indexBuffer; private Int3[] _indexBufferData = new Int3[0]; private readonly BufferWithViews _indexBufferWithViews = new(); private readonly MeshBuffers _data = new(); [Input(Guid = "33921c65-61bc-4229-af8c-c89db9a874bf")] public readonly InputSlot Segments = new(); [Input(Guid = "9dbf0c3d-4762-41f6-94b8-26acbd1531c1")] public readonly InputSlot Radius = new(); [Input(Guid = "deee0efc-949e-41da-bdb1-d80dbb6ac6e2")] public readonly InputSlot Stretch = new(); [Input(Guid = "69a2e8c2-2c88-4969-8beb-66fe8ff4af18")] public readonly InputSlot Center = new(); [Input(Guid = "b819ad07-6229-4b8d-b8b6-a2a89b7c81d8")] public readonly InputSlot Rotation = new(); [Input(Guid = "d85761fb-3c82-4785-a2a2-4b111230e4ee", MappedType = typeof(TextureModes))] public readonly InputSlot TextureMode = new(); }