// Magica Cloth 2. // Copyright (c) 2023 MagicaSoft. // https://magicasoft.jp #if MC2_DEBUG using System.Collections.Generic; using Unity.Collections; using Unity.Mathematics; using UnityEditor; using UnityEngine; #endif namespace MagicaCloth2 { #if MC2_DEBUG public static partial class VirtualMeshEditorUtility { //========================================================================================= static List positionBuffer0 = new List(1024); static List positionBuffer1 = new List(1024); static List positionBuffer2 = new List(1024); static List segmentBuffer0 = new List(2048); static List segmentBuffer1 = new List(2048); static List segmentBuffer2 = new List(2048); //========================================================================================= /// /// VirtualMeshのデバッグ表示(編集用) /// /// /// public static void DrawGizmos(VirtualMesh vmesh, VirtualMeshDebugSettings debugSettings, bool selected, bool useHandles) { if (debugSettings.enable == false) return; if (vmesh == null || vmesh.IsSuccess == false || vmesh.VertexCount == 0) return; var t = vmesh.GetCenterTransform(); if (t == null) return; using NativeArray dummyRotations = new NativeArray(0, Allocator.TempJob); DrawGizmosInternal( useHandles, true, selected, vmesh, debugSettings, t, 0, vmesh.attributes.GetNativeArray(), vmesh.localPositions.GetNativeArray(), dummyRotations, vmesh.localNormals.GetNativeArray(), vmesh.localTangents.GetNativeArray(), vmesh.boneWeights.GetNativeArray() ); } /// /// Proxy/Mappingメッシュのデバッグ表示(ランタイム用) /// /// /// /// public static void DrawRuntimeGizmos(ClothProcess cprocess, bool isMapping, VirtualMesh vmesh, VirtualMeshDebugSettings debugSettings, bool selected, bool useHandles) { if (cprocess == null || cprocess.IsValid() == false) return; if (debugSettings.enable == false) return; if (MagicaManager.Team == null) return; if (MagicaManager.Team.ContainsTeamData(cprocess.TeamId) == false) return; if (vmesh == null || vmesh.IsSuccess == false) return; // チームデータ var tdata = MagicaManager.Team.GetTeamData(cprocess.TeamId); var tm = MagicaManager.Team; var vm = MagicaManager.VMesh; // メッシュタイプにより参照するデータを切り替える var attributes = vmesh.IsMapping ? vm.mappingAttributes : vm.attributes; var positions = vmesh.IsMapping ? vm.mappingPositions : vm.positions; var rotations = vmesh.IsMapping ? vm.mappingRotations : vm.rotations; var boneWeights = vmesh.IsMapping ? vm.mappingBoneWeights : vm.boneWeights; int vstart = vmesh.IsMapping ? tm.mappingDataArray[vmesh.mappingId].mappingCommonChunk.startIndex : tdata.proxyCommonChunk.startIndex; // 座標空間に合わせる var t = vmesh.GetCenterTransform(); if (t == null) return; DrawGizmosInternal( useHandles, isMapping ? true : false, selected, vmesh, debugSettings, t, vstart, attributes.GetNativeArray(), positions.GetNativeArray(), rotations.GetNativeArray(), vmesh.localNormals.GetNativeArray(), vmesh.localTangents.GetNativeArray(), boneWeights.GetNativeArray() ); } static void DrawGizmosInternal( bool useHandles, bool isLocal, bool selected, VirtualMesh vmesh, VirtualMeshDebugSettings debugSettings, Transform center, int vstart, NativeArray attributes, NativeArray positions, NativeArray rotations, NativeArray normals, NativeArray tangents, NativeArray boneWeights ) { // 座標空間に合わせる if (isLocal) { Handles.matrix = center.localToWorldMatrix; if (useHandles == false) Gizmos.matrix = center.localToWorldMatrix; } else { Handles.matrix = Matrix4x4.identity; Gizmos.matrix = Matrix4x4.identity; } // シーンカメラ var scam = SceneView.currentDrawingSceneView?.camera; if (scam == null) return; quaternion camRot = scam.transform.rotation; quaternion invCamRot = math.inverse(camRot); int vcnt = vmesh.VertexCount; // 表示スケール調整 var scl = isLocal ? 1.0f / (center.lossyScale.magnitude / 1.7305f) : 1.0f; var drawPointSize = debugSettings.pointSize * scl; float drawAxisSize = debugSettings.lineSize * scl; bool hasRotation = rotations.IsCreated && rotations.Length > 0; float colorScale = selected ? 1 : 0.5f; // position if (debugSettings.position) { for (int i = 0; i < vcnt; i++) { if (i < debugSettings.vertexMinIndex || i > debugSettings.vertexMaxIndex) continue; var pos = positions[vstart + i]; var attr = attributes[vstart + i]; var col = Color.black; if (attr.IsFixed()) col = Color.red; if (attr.IsMove()) col = Color.green; GizmoUtility.SetColor(col * colorScale, useHandles); GizmoUtility.DrawSphere(pos, drawPointSize, useHandles); } } // rotation axis if (debugSettings.axis) { positionBuffer0.Clear(); positionBuffer1.Clear(); positionBuffer2.Clear(); segmentBuffer0.Clear(); segmentBuffer1.Clear(); segmentBuffer2.Clear(); for (int i = 0; i < vcnt; i++) { if (i < debugSettings.vertexMinIndex || i > debugSettings.vertexMaxIndex) continue; var pos = positions[vstart + i]; var y = hasRotation ? MathUtility.ToNormal(rotations[vstart + i]) : normals[vstart + i]; var z = hasRotation ? MathUtility.ToTangent(rotations[vstart + i]) : tangents[vstart + i]; var x = math.cross(y, z); positionBuffer0.Add(pos); positionBuffer0.Add(pos + x * drawAxisSize); segmentBuffer0.Add(i * 2); segmentBuffer0.Add(i * 2 + 1); positionBuffer1.Add(pos); positionBuffer1.Add(pos + y * drawAxisSize); segmentBuffer1.Add(i * 2); segmentBuffer1.Add(i * 2 + 1); positionBuffer2.Add(pos); positionBuffer2.Add(pos + z * drawAxisSize); segmentBuffer2.Add(i * 2); segmentBuffer2.Add(i * 2 + 1); } // x Handles.color = Color.red * colorScale; Handles.DrawLines(positionBuffer0.ToArray(), segmentBuffer0.ToArray()); // y Handles.color = Color.green * colorScale; Handles.DrawLines(positionBuffer1.ToArray(), segmentBuffer1.ToArray()); // z Handles.color = Color.blue * colorScale; Handles.DrawLines(positionBuffer2.ToArray(), segmentBuffer2.ToArray()); } // bone weight if (debugSettings.boneWeight) { for (int i = 0; i < vcnt; i++) { if (i < debugSettings.vertexMinIndex || i > debugSettings.vertexMaxIndex) continue; var pos = positions[vstart + i]; var bw = boneWeights[vstart + i]; Handles.Label(pos, $"[{bw.boneIndices.x},{bw.boneIndices.y},{bw.boneIndices.z},{bw.boneIndices.w}] w({bw.weights.x:0.###}, {bw.weights.y:0.###}, {bw.weights.z:0.###}, {bw.weights.w:0.###})"); } } // number else if (debugSettings.indexNumber) { for (int i = 0; i < vcnt; i++) { if (i < debugSettings.vertexMinIndex || i > debugSettings.vertexMaxIndex) continue; var pos = positions[vstart + i]; Handles.Label(pos, i.ToString()); } } // uv else if (debugSettings.uv) { if (vmesh.IsProxy) { // プロキシのみ for (int i = 0; i < vcnt; i++) { if (i < debugSettings.vertexMinIndex || i > debugSettings.vertexMaxIndex) continue; var pos = positions[vstart + i]; var uv = vmesh.uv[i]; Handles.Label(pos, $"({uv.x:0.####}, {uv.y:0.####})"); } } } // depth else if (debugSettings.depth) { if (vmesh.IsProxy) { if (vmesh.vertexDepths.IsCreated) { for (int i = 0; i < vcnt; i++) { if (i < debugSettings.vertexMinIndex || i > debugSettings.vertexMaxIndex) continue; var pos = positions[vstart + i]; var depth = vmesh.vertexDepths[i]; Handles.Label(pos, $"{depth:0.##}"); } } } } // root index else if (debugSettings.rootIndex) { if (vmesh.IsProxy) { if (vmesh.vertexRootIndices.IsCreated) { for (int i = 0; i < vcnt; i++) { if (i < debugSettings.vertexMinIndex || i > debugSettings.vertexMaxIndex) continue; var pos = positions[vstart + i]; int rootIndex = vmesh.vertexRootIndices[i]; if (rootIndex >= 0) Handles.Label(pos, $"{rootIndex}"); } } } } // parent index else if (debugSettings.parentIndex) { if (vmesh.IsProxy) { if (vmesh.vertexParentIndices.IsCreated) { for (int i = 0; i < vcnt; i++) { if (i < debugSettings.vertexMinIndex || i > debugSettings.vertexMaxIndex) continue; var pos = positions[vstart + i]; int parentIndex = vmesh.vertexParentIndices[i]; //if (parentIndex < 0) Handles.Label(pos, $"{parentIndex}"); } } } } // triangls if (debugSettings.triangle) { positionBuffer0.Clear(); segmentBuffer0.Clear(); switch (vmesh.meshType) { case VirtualMesh.MeshType.NormalMesh: GizmoUtility.SetColor(Color.magenta * colorScale, useHandles); break; case VirtualMesh.MeshType.NormalBoneMesh: GizmoUtility.SetColor(Color.magenta * colorScale, useHandles); break; case VirtualMesh.MeshType.ProxyMesh: GizmoUtility.SetColor(new Color(0.8666f, 0.627f, 0.8666f) * colorScale, useHandles); break; case VirtualMesh.MeshType.ProxyBoneMesh: GizmoUtility.SetColor(new Color(0.8666f, 0.627f, 0.8666f) * colorScale, useHandles); break; case VirtualMesh.MeshType.Mapping: GizmoUtility.SetColor(new Color(0.851f, 0.644f, 0.125f) * colorScale, useHandles); break; } for (int i = 0; i < vmesh.TriangleCount; i++) { if (i < debugSettings.triangleMinIndex || i > debugSettings.triangleMaxIndex) continue; int3 tri = vmesh.triangles[i]; var pos1 = positions[vstart + tri.x]; var pos2 = positions[vstart + tri.y]; var pos3 = positions[vstart + tri.z]; int index = positionBuffer0.Count; positionBuffer0.Add(pos1); positionBuffer0.Add(pos2); positionBuffer0.Add(pos3); segmentBuffer0.Add(index); segmentBuffer0.Add(index + 1); segmentBuffer0.Add(index + 1); segmentBuffer0.Add(index + 2); segmentBuffer0.Add(index + 2); segmentBuffer0.Add(index); } Handles.DrawLines(positionBuffer0.ToArray(), segmentBuffer0.ToArray()); } // line if (debugSettings.line) { positionBuffer0.Clear(); segmentBuffer0.Clear(); GizmoUtility.SetColor(Color.cyan * colorScale, useHandles); for (int i = 0; i < vmesh.LineCount; i++) { int2 line = vmesh.lines[i]; var pos1 = positions[vstart + line.x]; var pos2 = positions[vstart + line.y]; positionBuffer0.Add(pos1); positionBuffer0.Add(pos2); segmentBuffer0.Add(i * 2); segmentBuffer0.Add(i * 2 + 1); } Handles.DrawLines(positionBuffer0.ToArray(), segmentBuffer0.ToArray()); } // edge number if (debugSettings.edgeNumber) { int ecnt = vmesh.EdgeCount; for (int i = 0; i < ecnt; i++) { if (i < debugSettings.edgeMinIndex || i > debugSettings.edgeMaxIndex) continue; int2 edge = vmesh.edges[i]; var pos1 = positions[vstart + edge.x]; var pos2 = positions[vstart + edge.y]; var c = (pos1 + pos2) * 0.5f; Handles.Label(c, i.ToString()); } } // triangle normal if (debugSettings.triangleNormal || debugSettings.triangleNumber) { positionBuffer0.Clear(); segmentBuffer0.Clear(); Color colF = Color.yellow; //Color colB = new Color(1.0f, 0.3f, 0.3f, 1.0f); for (int i = 0; i < vmesh.TriangleCount; i++) { if (i < debugSettings.triangleMinIndex || i > debugSettings.triangleMaxIndex) continue; int3 tri = vmesh.triangles[i]; var pos1 = positions[vstart + tri.x]; var pos2 = positions[vstart + tri.y]; var pos3 = positions[vstart + tri.z]; var n = MathUtility.TriangleNormal(pos1, pos2, pos3); var c = MathUtility.TriangleCenter(pos1, pos2, pos3); if (debugSettings.triangleNormal) { var dir = math.mul(invCamRot, n); //GizmoUtility.SetColor((dir.z < 0.0f ? colF : colB) * colorScale, useHandles); //GizmoUtility.DrawLine(c, c + n * drawAxisSize, useHandles); positionBuffer0.Add(c); positionBuffer0.Add(c + n * drawAxisSize); segmentBuffer0.Add(i * 2); segmentBuffer0.Add(i * 2 + 1); } if (debugSettings.triangleNumber) Handles.Label(c, i.ToString()); } if (debugSettings.triangleNormal) { GizmoUtility.SetColor(colF * colorScale, useHandles); Handles.DrawLines(positionBuffer0.ToArray(), segmentBuffer0.ToArray()); } } // base line if (vmesh.IsProxy) { // プロキシのみ if (debugSettings.baseLine && vmesh.BaseLineCount > 0) { GizmoUtility.SetColor(new Color(1.0f, 0.27f, 0.0f) * colorScale, useHandles); positionBuffer0.Clear(); segmentBuffer0.Clear(); for (int i = 0; i < vcnt; i++) { int pindex = vmesh.vertexParentIndices[i]; if (pindex >= 0) { var pos = positions[vstart + i]; var ppos = positions[vstart + pindex]; //GizmoUtility.DrawLine(pos, ppos, useHandles); positionBuffer0.Add(pos); positionBuffer0.Add(ppos); segmentBuffer0.Add(i * 2); segmentBuffer0.Add(i * 2 + 1); } } Handles.DrawLines(positionBuffer0.ToArray(), segmentBuffer0.ToArray()); } } // 空間を戻す Handles.matrix = Matrix4x4.identity; if (useHandles == false) Gizmos.matrix = Matrix4x4.identity; // bone name if (debugSettings.boneName) { int cnt = vmesh.transformData.Count; for (int i = 0; i < cnt; i++) { var t = vmesh.transformData.GetTransformFromIndex(i); if (t) { var pos = t.position; Handles.Label(pos, $"[{i}] {t.name}"); } } } } } #endif // MC_DEBUG }