497 lines
20 KiB
C#
497 lines
20 KiB
C#
// 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<Vector3> positionBuffer0 = new List<Vector3>(1024);
|
||
static List<Vector3> positionBuffer1 = new List<Vector3>(1024);
|
||
static List<Vector3> positionBuffer2 = new List<Vector3>(1024);
|
||
static List<int> segmentBuffer0 = new List<int>(2048);
|
||
static List<int> segmentBuffer1 = new List<int>(2048);
|
||
static List<int> segmentBuffer2 = new List<int>(2048);
|
||
|
||
//=========================================================================================
|
||
|
||
/// <summary>
|
||
/// VirtualMeshのデバッグ表示(編集用)
|
||
/// </summary>
|
||
/// <param name="vmesh"></param>
|
||
/// <param name="debugSettings"></param>
|
||
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<quaternion> dummyRotations = new NativeArray<quaternion>(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()
|
||
);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Proxy/Mappingメッシュのデバッグ表示(ランタイム用)
|
||
/// </summary>
|
||
/// <param name="cprocess"></param>
|
||
/// <param name="vmesh"></param>
|
||
/// <param name="debugSettings"></param>
|
||
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<VertexAttribute> attributes,
|
||
NativeArray<float3> positions,
|
||
NativeArray<quaternion> rotations,
|
||
NativeArray<float3> normals,
|
||
NativeArray<float3> tangents,
|
||
NativeArray<VirtualMeshBoneWeight> 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
|
||
}
|