private static void DrawTetra(FinalData final, int tetraIndex, List <Vector3> wposList, float tetraSize) { // サイズチェック if (final.tetraSizes[tetraIndex] > tetraSize) { return; } int index = tetraIndex * 4; int vi0 = final.tetras[index]; int vi1 = final.tetras[index + 1]; int vi2 = final.tetras[index + 2]; int vi3 = final.tetras[index + 3]; var v0 = wposList[vi0]; var v1 = wposList[vi1]; var v2 = wposList[vi2]; var v3 = wposList[vi3]; Gizmos.DrawLine(v0, v1); Gizmos.DrawLine(v0, v2); Gizmos.DrawLine(v0, v3); Gizmos.DrawLine(v1, v2); Gizmos.DrawLine(v2, v3); Gizmos.DrawLine(v3, v1); }
//========================================================================================= /// <summary> /// FinalDataの共有頂点デバッグ表示 /// (OnDrawGizmos内で呼び出してください) /// </summary> /// <param name="final"></param> /// <param name="drawNormal"></param> public static void DebugDrawShared( FinalData final, bool drawTriangle = true, bool drawLine = true, bool drawTetra = true, bool drawVertexNormal = true, bool drawVertexTangent = true, bool drawNumber = false, int maxPolygonCount = int.MaxValue, int layer = -1, int tetraIndex = -1, float tetraSize = 1.0f, List <int> drawNumberList = null, float axisSize = 0.01f ) { if (final == null) { return; } List <Vector3> wposList; List <Vector3> wnorList; List <Vector4> wtanList; Utility.CalcFinalDataWorldPositionNormalTangent(final, out wposList, out wnorList, out wtanList); // triangle if (drawTriangle) { int tcnt = final.TriangleCount; for (int i = 0; i < tcnt && i < maxPolygonCount; i++) { int index = i * 3; int vi0 = final.triangles[index]; int vi1 = final.triangles[index + 1]; int vi2 = final.triangles[index + 2]; if (drawNumberList != null && drawNumberList.Count > 0) { if (drawNumberList.Contains(vi0) == false && drawNumberList.Contains(vi1) == false && drawNumberList.Contains(vi2) == false) { continue; } } var v0 = wposList[vi0]; var v1 = wposList[vi1]; var v2 = wposList[vi2]; Gizmos.color = Color.magenta; Gizmos.DrawLine(v0, v1); Gizmos.DrawLine(v1, v2); Gizmos.DrawLine(v0, v2); } } // line if (drawLine) { Gizmos.color = Color.cyan; int lcnt = final.LineCount; for (int i = 0; i < lcnt; i++) { int index = i * 2; int vi0 = final.lines[index]; int vi1 = final.lines[index + 1]; Gizmos.DrawLine(wposList[vi0], wposList[vi1]); } } // tetra if (drawTetra) { Gizmos.color = Color.green; int tetracnt = final.TetraCount; for (int i = 0; i < tetracnt; i++) { DrawTetra(final, i, wposList, tetraSize); } } if (tetraIndex >= 0 && tetraIndex < final.TetraCount) { Gizmos.color = Color.red; DrawTetra(final, tetraIndex, wposList, tetraSize); } // normal if (drawVertexNormal) { Gizmos.color = Color.blue; if (drawNumberList != null && drawNumberList.Count > 0) { foreach (var i in drawNumberList) { var wpos = wposList[i]; Gizmos.DrawLine(wpos, wpos + wnorList[i] * axisSize); } } else { for (int i = 0; i < final.VertexCount; i++) { var wpos = wposList[i]; Gizmos.DrawLine(wpos, wpos + wnorList[i] * axisSize); } } } // tangent if (drawVertexTangent) { Gizmos.color = Color.red; if (drawNumberList != null && drawNumberList.Count > 0) { foreach (var i in drawNumberList) { var wpos = wposList[i]; Vector3 wtan = wtanList[i]; Gizmos.DrawLine(wpos, wpos + wtan * axisSize); } } else { for (int i = 0; i < final.VertexCount; i++) { var wpos = wposList[i]; Vector3 wtan = wtanList[i]; Gizmos.DrawLine(wpos, wpos + wtan * axisSize); } } } // number #if UNITY_EDITOR if (drawNumber) { if (drawNumberList != null && drawNumberList.Count > 0) { foreach (var i in drawNumberList) { var wpos = wposList[i]; Handles.Label(wpos, "(" + i.ToString() + ")"); } } else { for (int i = 0; i < final.VertexCount; i++) { var wpos = wposList[i]; Handles.Label(wpos, "(" + i.ToString() + ")"); } } } #endif }
/// <summary> /// FinalDataの子頂点デバッグ表示 /// (OnDrawGizmos内で呼び出してください) /// </summary> /// <param name="final"></param> /// <param name="drawNormal"></param> public static void DebugDrawChild( FinalData final, bool drawPosition = false, bool drawNormal = false, bool drawTriangle = false, bool drawNumber = false, int maxVertexCount = int.MaxValue, float positionSize = 0.001f, float axisSize = 0.01f ) { if (final == null) { return; } if (drawPosition == false && drawNormal == false && drawTriangle == false && drawNumber == false) { return; } List <Vector3> swposList; List <Vector3> swnorList; List <Vector4> swtanList; Utility.CalcFinalDataWorldPositionNormalTangent(final, out swposList, out swnorList, out swtanList); for (int mindex = 0; mindex < final.MeshCount; mindex++) { List <Vector3> wposList; List <Vector3> wnorList; List <Vector4> wtanList; Utility.CalcFinalDataChildWorldPositionNormalTangent( final, mindex, swposList, swnorList, swtanList, out wposList, out wnorList, out wtanList ); for (int i = 0; i < wposList.Count && i < maxVertexCount; i++) { var wpos = wposList[i]; // position if (drawPosition) { Gizmos.color = Color.red; Gizmos.DrawSphere(wpos, positionSize); } // normal if (drawNormal) { Gizmos.color = Color.blue; Gizmos.DrawLine(wpos, wpos + wnorList[i] * axisSize); } #if UNITY_EDITOR // number if (drawNumber) { Handles.Label(wpos, i.ToString()); } #endif } // triangle if (drawTriangle) { Gizmos.color = Color.magenta; var triangles = final.meshList[mindex].mesh.triangles; for (int i = 0; i < triangles.Length / 3; i++) { int v0 = triangles[i * 3]; int v1 = triangles[i * 3 + 1]; int v2 = triangles[i * 3 + 2]; var wpos0 = wposList[v0]; var wpos1 = wposList[v1]; var wpos2 = wposList[v2]; Gizmos.DrawLine(wpos0, wpos1); Gizmos.DrawLine(wpos1, wpos2); Gizmos.DrawLine(wpos2, wpos0); } } } }
/// <summary> /// FinalDataの子頂点座標/法線/接線をワールド座標変換して返す /// </summary> /// <param name="wposList"></param> /// <param name="wnorList"></param> /// <param name="wtanList"></param> /// <returns></returns> public static void CalcFinalDataChildWorldPositionNormalTangent( FinalData final, int meshIndex, List <Vector3> sposList, List <Vector3> snorList, List <Vector4> stanList, out List <Vector3> wposList, out List <Vector3> wnorList, out List <Vector4> wtanList ) { wposList = new List <Vector3>(); wnorList = new List <Vector3>(); wtanList = new List <Vector4>(); // 回転を求める List <Quaternion> quatList = new List <Quaternion>(); for (int i = 0; i < sposList.Count; i++) { var q = Quaternion.LookRotation(snorList[i], stanList[i]); quatList.Add(q); } // 共有頂点からさらにスキニングする var minfo = final.meshList[meshIndex]; float[] weights = new float[4]; int[] boneIndexs = new int[4]; for (int i = 0; i < minfo.VertexCount; i++) { Vector3 wpos = Vector3.zero; Vector3 wnor = Vector3.zero; Vector3 wtan = Vector3.zero; // 頂点スキニング weights[0] = minfo.boneWeights[i].weight0; weights[1] = minfo.boneWeights[i].weight1; weights[2] = minfo.boneWeights[i].weight2; weights[3] = minfo.boneWeights[i].weight3; boneIndexs[0] = minfo.boneWeights[i].boneIndex0; boneIndexs[1] = minfo.boneWeights[i].boneIndex1; boneIndexs[2] = minfo.boneWeights[i].boneIndex2; boneIndexs[3] = minfo.boneWeights[i].boneIndex3; for (int j = 0; j < 4; j++) { float w = weights[j]; if (w > 0.0f) { int bindex = boneIndexs[j]; var rot = quatList[bindex]; // position Vector3 v = final.vertexBindPoses[bindex].MultiplyPoint3x4(minfo.vertices[i]); v = rot * v + sposList[bindex]; v *= w; wpos += v; // normal v = final.vertexBindPoses[bindex].MultiplyVector(minfo.normals[i]); v = rot * v; wnor += v.normalized * w; // tangent v = final.vertexBindPoses[bindex].MultiplyVector(minfo.tangents[i]); v = rot * v; wtan += v.normalized * w; } } wposList.Add(wpos); wnorList.Add(wnor); wtanList.Add(new Vector4(wtan.x, wtan.y, wtan.z, -1)); } }
//========================================================================================= /// <summary> /// FinalDataの共有頂点座標/法線/接線をワールド座標変換して返す /// </summary> /// <param name="wposList"></param> /// <param name="wnorList"></param> /// <param name="wtanList"></param> /// <returns></returns> public static void CalcFinalDataWorldPositionNormalTangent(FinalData final, out List <Vector3> wposList, out List <Vector3> wnorList, out List <Vector4> wtanList) { wposList = new List <Vector3>(); wnorList = new List <Vector3>(); wtanList = new List <Vector4>(); if (final.VertexCount == 0) { return; } if (final.BoneCount == 0) { return; } int vcnt = final.VertexCount; if (final.IsSkinning == false) { // 通常メッシュ Transform t = final.bones[0]; for (int i = 0; i < vcnt; i++) { Vector3 wpos = t.TransformPoint(final.vertices[i]); wposList.Add(wpos); Vector3 wnor = t.TransformDirection(final.normals[i]); wnor.Normalize(); wnorList.Add(wnor); Vector3 wtan = t.TransformDirection(final.tangents[i]); wtan.Normalize(); wtanList.Add(new Vector4(wtan.x, wtan.y, wtan.z, final.tangents[i].w)); } } else { // スキンメッシュ float[] weights = new float[4]; int[] boneIndexs = new int[4]; for (int i = 0; i < vcnt; i++) { Vector3 wpos = Vector3.zero; Vector3 wnor = Vector3.zero; Vector3 wtan = Vector3.zero; // 頂点スキニング weights[0] = final.boneWeights[i].weight0; weights[1] = final.boneWeights[i].weight1; weights[2] = final.boneWeights[i].weight2; weights[3] = final.boneWeights[i].weight3; boneIndexs[0] = final.boneWeights[i].boneIndex0; boneIndexs[1] = final.boneWeights[i].boneIndex1; boneIndexs[2] = final.boneWeights[i].boneIndex2; boneIndexs[3] = final.boneWeights[i].boneIndex3; for (int j = 0; j < 4; j++) { float w = weights[j]; if (w > 0.0f) { int bindex = boneIndexs[j]; Transform t = final.bones[bindex]; // position Vector3 v = final.bindPoses[bindex].MultiplyPoint3x4(final.vertices[i]); v = t.TransformPoint(v); v *= w; wpos += v; // normal v = final.bindPoses[bindex].MultiplyVector(final.normals[i]); v = t.TransformVector(v); wnor += v.normalized * w; // tangent v = final.bindPoses[bindex].MultiplyVector(final.tangents[i]); v = t.TransformVector(v); wtan += v.normalized * w; } } wposList.Add(wpos); wnorList.Add(wnor); wtanList.Add(new Vector4(wtan.x, wtan.y, wtan.z, final.tangents[i].w)); } } }