您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
458 行
16 KiB
458 行
16 KiB
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Unity.DemoTeam.DigitalHuman
|
|
{
|
|
using MeshInfo = SkinAttachmentTarget.MeshInfo;
|
|
|
|
public static class SkinAttachmentDataBuilder
|
|
{
|
|
public static unsafe int BuildPosesTriangle(SkinAttachmentPose* pose, in MeshInfo meshInfo, ref Vector3 target, int triangle)
|
|
{
|
|
var meshPositions = meshInfo.meshBuffers.vertexPositions;
|
|
var meshTriangles = meshInfo.meshBuffers.triangles;
|
|
|
|
int _0 = triangle * 3;
|
|
var v0 = meshTriangles[_0];
|
|
var v1 = meshTriangles[_0 + 1];
|
|
var v2 = meshTriangles[_0 + 2];
|
|
|
|
var p0 = meshPositions[v0];
|
|
var p1 = meshPositions[v1];
|
|
var p2 = meshPositions[v2];
|
|
|
|
var v0v1 = p1 - p0;
|
|
var v0v2 = p2 - p0;
|
|
|
|
var triangleNormal = Vector3.Cross(v0v1, v0v2);
|
|
var triangleArea = Vector3.Magnitude(triangleNormal);
|
|
|
|
triangleNormal /= triangleArea;
|
|
triangleArea *= 0.5f;
|
|
|
|
if (triangleArea < float.Epsilon)
|
|
return 0;// no pose
|
|
|
|
var targetDist = Vector3.Dot(triangleNormal, target - p0);
|
|
var targetProjected = target - targetDist * triangleNormal;
|
|
var targetCoord = new Barycentric(ref targetProjected, ref p0, ref p1, ref p2);
|
|
|
|
pose->v0 = v0;
|
|
pose->v1 = v1;
|
|
pose->v2 = v2;
|
|
pose->area = triangleArea;
|
|
pose->targetDist = targetDist;
|
|
pose->targetCoord = targetCoord;
|
|
return 1;
|
|
}
|
|
|
|
public static unsafe int BuildPosesVertex(SkinAttachmentPose* pose, in MeshInfo meshInfo, ref Vector3 target, int vertex)
|
|
{
|
|
int poseCount = 0;
|
|
foreach (int triangle in meshInfo.meshAdjacency.vertexTriangles[vertex])
|
|
{
|
|
poseCount += BuildPosesTriangle(pose + poseCount, meshInfo, ref target, triangle);
|
|
}
|
|
return poseCount;
|
|
}
|
|
|
|
// note: unused -- remove?
|
|
public static unsafe void BuildDataAttachToTriangle(SkinAttachmentData attachData, int* attachmentIndex, int* attachmentCount, in MeshInfo meshInfo, Vector3* targetPositions, int* targetTriangles, int targetCount)
|
|
{
|
|
var poseIndex = attachData.poseCount;
|
|
var itemIndex = attachData.itemCount;
|
|
|
|
fixed (SkinAttachmentPose* pose = attachData.pose)
|
|
fixed (SkinAttachmentItem* item = attachData.item)
|
|
{
|
|
for (int i = 0; i != targetCount; i++)
|
|
{
|
|
var poseCount = BuildPosesTriangle(pose + poseIndex, meshInfo, ref targetPositions[i], targetTriangles[i]);
|
|
if (poseCount == 0)
|
|
{
|
|
Debug.LogError("no valid poses for target triangle " + i + ", aborting");
|
|
poseIndex = attachData.poseCount;
|
|
itemIndex = attachData.itemCount;
|
|
break;
|
|
}
|
|
|
|
item[itemIndex].poseIndex = poseIndex;
|
|
item[itemIndex].poseCount = poseCount;
|
|
item[itemIndex].baseVertex = meshInfo.meshBuffers.triangles[3 * targetTriangles[i]];
|
|
item[itemIndex].baseNormal = meshInfo.meshBuffers.vertexNormals[item[itemIndex].baseVertex];
|
|
item[itemIndex].targetNormal = item[itemIndex].baseNormal;
|
|
item[itemIndex].targetOffset = Vector3.zero;
|
|
|
|
poseIndex += poseCount;
|
|
itemIndex += 1;
|
|
}
|
|
}
|
|
|
|
*attachmentIndex = itemIndex > attachData.itemCount ? attachData.itemCount : -1;
|
|
*attachmentCount = itemIndex - attachData.itemCount;
|
|
|
|
attachData.poseCount = poseIndex;
|
|
attachData.itemCount = itemIndex;
|
|
}
|
|
|
|
public static unsafe void BuildDataAttachToVertex(SkinAttachmentData attachData, int* attachmentIndex, int* attachmentCount, in MeshInfo meshInfo, Vector3* targetPositions, Vector3* targetOffsets, Vector3* targetNormals, int* targetVertices, int targetCount)
|
|
{
|
|
var poseIndex = attachData.poseCount;
|
|
var itemIndex = attachData.itemCount;
|
|
|
|
fixed (SkinAttachmentPose* pose = attachData.pose)
|
|
fixed (SkinAttachmentItem* item = attachData.item)
|
|
{
|
|
for (int i = 0; i != targetCount; i++)
|
|
{
|
|
var poseCount = BuildPosesVertex(pose + poseIndex, meshInfo, ref targetPositions[i], targetVertices[i]);
|
|
if (poseCount == 0)
|
|
{
|
|
Debug.LogError("no valid poses for target vertex " + i + ", aborting");
|
|
poseIndex = attachData.poseCount;
|
|
itemIndex = attachData.itemCount;
|
|
break;
|
|
}
|
|
|
|
item[itemIndex].poseIndex = poseIndex;
|
|
item[itemIndex].poseCount = poseCount;
|
|
item[itemIndex].baseVertex = targetVertices[i];
|
|
item[itemIndex].baseNormal = meshInfo.meshBuffers.vertexNormals[targetVertices[i]];
|
|
item[itemIndex].targetNormal = targetNormals[i];
|
|
item[itemIndex].targetOffset = targetOffsets[i];
|
|
|
|
poseIndex += poseCount;
|
|
itemIndex += 1;
|
|
}
|
|
}
|
|
|
|
*attachmentIndex = itemIndex > attachData.itemCount ? attachData.itemCount : -1;
|
|
*attachmentCount = itemIndex - attachData.itemCount;
|
|
|
|
attachData.poseCount = poseIndex;
|
|
attachData.itemCount = itemIndex;
|
|
}
|
|
|
|
public static unsafe void BuildDataAttachToClosestVertex(SkinAttachmentData attachData, int* attachmentIndex, int* attachmentCount, in MeshInfo meshInfo, Vector3* targetPositions, Vector3* targetNormals, int targetCount)
|
|
{
|
|
using (var targetOffsets = new UnsafeArrayVector3(targetCount))
|
|
using (var targetVertices = new UnsafeArrayInt(targetCount))
|
|
{
|
|
for (int i = 0; i != targetCount; i++)
|
|
{
|
|
targetOffsets.val[i] = Vector3.zero;
|
|
targetVertices.val[i] = meshInfo.meshVertexBSP.FindNearest(ref targetPositions[i]);
|
|
}
|
|
BuildDataAttachToVertex(attachData, attachmentIndex, attachmentCount, meshInfo, targetPositions, targetOffsets.val, targetNormals, targetVertices.val, targetCount);
|
|
}
|
|
}
|
|
|
|
public static unsafe int CountPosesTriangle(in MeshInfo meshInfo, ref Vector3 target, int triangle)
|
|
{
|
|
SkinAttachmentPose dummyPose;
|
|
return BuildPosesTriangle(&dummyPose, meshInfo, ref target, triangle);
|
|
}
|
|
|
|
public static unsafe int CountPosesVertex(in MeshInfo meshInfo, ref Vector3 target, int vertex)
|
|
{
|
|
int poseCount = 0;
|
|
foreach (int triangle in meshInfo.meshAdjacency.vertexTriangles[vertex])
|
|
{
|
|
poseCount += CountPosesTriangle(meshInfo, ref target, triangle);
|
|
}
|
|
return poseCount;
|
|
}
|
|
|
|
public static unsafe void CountDataAttachToTriangle(ref int poseCount, ref int itemCount, in MeshInfo meshInfo, Vector3* targetPositions, int* targetTriangles, int targetCount)
|
|
{
|
|
for (int i = 0; i != targetCount; i++)
|
|
{
|
|
poseCount += CountPosesTriangle(meshInfo, ref targetPositions[i], targetTriangles[i]);
|
|
itemCount += 1;
|
|
}
|
|
}
|
|
|
|
public static unsafe void CountDataAttachToVertex(ref int poseCount, ref int itemCount, in MeshInfo meshInfo, Vector3* targetPositions, Vector3* targetOffsets, Vector3* targetNormals, int* targetVertices, int targetCount)
|
|
{
|
|
for (int i = 0; i != targetCount; i++)
|
|
{
|
|
poseCount += CountPosesVertex(meshInfo, ref targetPositions[i], targetVertices[i]);
|
|
itemCount += 1;
|
|
}
|
|
}
|
|
|
|
public static unsafe void CountDataAttachToClosestVertex(ref int poseCount, ref int itemCount, in MeshInfo meshInfo, Vector3* targetPositions, Vector3* targetNormals, int targetCount)
|
|
{
|
|
using (var targetOffsets = new UnsafeArrayVector3(targetCount))
|
|
using (var targetVertices = new UnsafeArrayInt(targetCount))
|
|
{
|
|
for (int i = 0; i != targetCount; i++)
|
|
{
|
|
targetVertices.val[i] = meshInfo.meshVertexBSP.FindNearest(ref targetPositions[i]);
|
|
}
|
|
CountDataAttachToVertex(ref poseCount, ref itemCount, meshInfo, targetPositions, targetOffsets.val, targetNormals, targetVertices.val, targetCount);
|
|
}
|
|
}
|
|
|
|
public static unsafe void BuildDataAttachSubject(ref SkinAttachmentData attachData, int* attachmentIndex, int* attachmentCount, Transform target, in MeshInfo meshInfo, SkinAttachment subject, bool dryRun, ref int dryRunPoseCount, ref int dryRunItemCount)
|
|
{
|
|
Matrix4x4 subjectToTarget;
|
|
{
|
|
if (subject.skinningBone != null)
|
|
subjectToTarget = target.transform.worldToLocalMatrix * (subject.skinningBone.localToWorldMatrix * subject.skinningBoneBindPose);
|
|
else
|
|
subjectToTarget = target.transform.worldToLocalMatrix * subject.transform.localToWorldMatrix;
|
|
}
|
|
|
|
switch (subject.attachmentType)
|
|
{
|
|
case SkinAttachment.AttachmentType.Transform:
|
|
{
|
|
var targetPosition = subjectToTarget.MultiplyPoint3x4(Vector3.zero);
|
|
var targetNormal = subjectToTarget.MultiplyVector(Vector3.up);
|
|
|
|
if (dryRun)
|
|
CountDataAttachToClosestVertex(ref dryRunPoseCount, ref dryRunItemCount, meshInfo, &targetPosition, &targetNormal, 1);
|
|
else
|
|
BuildDataAttachToClosestVertex(attachData, attachmentIndex, attachmentCount, meshInfo, &targetPosition, &targetNormal, 1);
|
|
}
|
|
break;
|
|
|
|
case SkinAttachment.AttachmentType.Mesh:
|
|
{
|
|
if (subject.meshInstance == null)
|
|
break;
|
|
|
|
var subjectVertexCount = subject.meshBuffers.vertexCount;
|
|
var subjectPositions = subject.meshBuffers.vertexPositions;
|
|
var subjectNormals = subject.meshBuffers.vertexNormals;
|
|
|
|
using (var targetPositions = new UnsafeArrayVector3(subjectVertexCount))
|
|
using (var targetNormals = new UnsafeArrayVector3(subjectVertexCount))
|
|
{
|
|
for (int i = 0; i != subjectVertexCount; i++)
|
|
{
|
|
targetPositions.val[i] = subjectToTarget.MultiplyPoint3x4(subjectPositions[i]);
|
|
targetNormals.val[i] = subjectToTarget.MultiplyVector(subjectNormals[i]);
|
|
}
|
|
|
|
if (dryRun)
|
|
CountDataAttachToClosestVertex(ref dryRunPoseCount, ref dryRunItemCount, meshInfo, targetPositions.val, targetNormals.val, subjectVertexCount);
|
|
else
|
|
BuildDataAttachToClosestVertex(attachData, attachmentIndex, attachmentCount, meshInfo, targetPositions.val, targetNormals.val, subjectVertexCount);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SkinAttachment.AttachmentType.MeshRoots:
|
|
{
|
|
if (subject.meshInstance == null)
|
|
break;
|
|
|
|
var subjectVertexCount = subject.meshBuffers.vertexCount;
|
|
var subjectPositions = subject.meshBuffers.vertexPositions;
|
|
var subjectNormals = subject.meshBuffers.vertexPositions;
|
|
|
|
using (var targetPositions = new UnsafeArrayVector3(subjectVertexCount))
|
|
using (var targetNormals = new UnsafeArrayVector3(subjectVertexCount))
|
|
using (var targetOffsets = new UnsafeArrayVector3(subjectVertexCount))
|
|
using (var targetVertices = new UnsafeArrayInt(subjectVertexCount))
|
|
using (var rootIdx = new UnsafeArrayInt(subjectVertexCount))
|
|
using (var rootDir = new UnsafeArrayVector3(subjectVertexCount))
|
|
using (var rootGen = new UnsafeArrayInt(subjectVertexCount))
|
|
using (var visitor = new UnsafeBFS(subjectVertexCount))
|
|
{
|
|
for (int i = 0; i != subjectVertexCount; i++)
|
|
{
|
|
targetPositions.val[i] = subjectToTarget.MultiplyPoint3x4(subjectPositions[i]);
|
|
targetNormals.val[i] = subjectToTarget.MultiplyVector(subjectNormals[i]);
|
|
targetOffsets.val[i] = Vector3.zero;
|
|
}
|
|
|
|
visitor.Clear();
|
|
|
|
// find island roots
|
|
for (int island = 0; island != subject.meshIslands.islandCount; island++)
|
|
{
|
|
int rootCount = 0;
|
|
|
|
var bestDist0 = float.PositiveInfinity;
|
|
var bestNode0 = -1;
|
|
var bestVert0 = -1;
|
|
|
|
var bestDist1 = float.PositiveInfinity;
|
|
var bestNode1 = -1;
|
|
var bestVert1 = -1;
|
|
|
|
foreach (var i in subject.meshIslands.islandVertices[island])
|
|
{
|
|
var targetDist = float.PositiveInfinity;
|
|
var targetNode = -1;
|
|
|
|
if (meshInfo.meshVertexBSP.FindNearest(ref targetDist, ref targetNode, ref targetPositions.val[i]))
|
|
{
|
|
// found a root if one or more neighbouring vertices are below
|
|
var bestDist = float.PositiveInfinity;
|
|
var bestNode = -1;
|
|
|
|
foreach (var j in subject.meshAdjacency.vertexVertices[i])
|
|
{
|
|
var targetDelta = targetPositions.val[j] - meshInfo.meshBuffers.vertexPositions[targetNode];
|
|
var targetNormalDist = Vector3.Dot(targetDelta, meshInfo.meshBuffers.vertexNormals[targetNode]);
|
|
if (targetNormalDist < 0.0f)
|
|
{
|
|
var d = Vector3.SqrMagnitude(targetDelta);
|
|
if (d < bestDist)
|
|
{
|
|
bestDist = d;
|
|
bestNode = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bestNode != -1)
|
|
{
|
|
visitor.Ignore(i);
|
|
rootIdx.val[i] = targetNode;
|
|
rootDir.val[i] = Vector3.Normalize(targetPositions.val[bestNode] - targetPositions.val[i]);
|
|
rootGen.val[i] = 0;
|
|
rootCount++;
|
|
}
|
|
else
|
|
{
|
|
rootIdx.val[i] = -1;
|
|
rootGen.val[i] = -1;
|
|
|
|
// see if node qualifies as second choice root
|
|
var targetDelta = targetPositions.val[i] - meshInfo.meshBuffers.vertexPositions[targetNode];
|
|
var targetNormalDist = Mathf.Abs(Vector3.Dot(targetDelta, meshInfo.meshBuffers.vertexNormals[targetNode]));
|
|
if (targetNormalDist < bestDist0)
|
|
{
|
|
bestDist1 = bestDist0;
|
|
bestNode1 = bestNode0;
|
|
bestVert1 = bestVert0;
|
|
|
|
bestDist0 = targetNormalDist;
|
|
bestNode0 = targetNode;
|
|
bestVert0 = i;
|
|
}
|
|
else if (targetNormalDist < bestDist1)
|
|
{
|
|
bestDist1 = targetNormalDist;
|
|
bestNode1 = targetNode;
|
|
bestVert1 = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rootCount < 2 && bestVert0 != -1)
|
|
{
|
|
visitor.Ignore(bestVert0);
|
|
rootIdx.val[bestVert0] = bestNode0;
|
|
rootDir.val[bestVert0] = Vector3.Normalize(meshInfo.meshBuffers.vertexPositions[bestNode0] - targetPositions.val[bestVert0]);
|
|
rootGen.val[bestVert0] = 0;
|
|
rootCount++;
|
|
|
|
if (rootCount < 2 && bestVert1 != -1)
|
|
{
|
|
visitor.Ignore(bestVert1);
|
|
rootIdx.val[bestVert1] = bestNode1;
|
|
rootDir.val[bestVert1] = Vector3.Normalize(meshInfo.meshBuffers.vertexPositions[bestNode1] - targetPositions.val[bestVert1]);
|
|
rootGen.val[bestVert1] = 0;
|
|
rootCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// find boundaries
|
|
for (int i = 0; i != subjectVertexCount; i++)
|
|
{
|
|
if (rootIdx.val[i] != -1)
|
|
continue;
|
|
|
|
foreach (var j in subject.meshAdjacency.vertexVertices[i])
|
|
{
|
|
if (rootIdx.val[j] != -1)
|
|
{
|
|
visitor.Insert(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// propagate roots
|
|
while (visitor.MoveNext())
|
|
{
|
|
var i = visitor.position;
|
|
|
|
var bestDist = float.PositiveInfinity;
|
|
var bestNode = -1;
|
|
|
|
foreach (var j in subject.meshAdjacency.vertexVertices[i])
|
|
{
|
|
if (rootIdx.val[j] != -1)
|
|
{
|
|
var d = -Vector3.Dot(rootDir.val[j], Vector3.Normalize(targetPositions.val[j] - targetPositions.val[i]));
|
|
if (d < bestDist)
|
|
{
|
|
bestDist = d;
|
|
bestNode = j;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
visitor.Insert(j);
|
|
}
|
|
}
|
|
|
|
rootIdx.val[i] = rootIdx.val[bestNode];
|
|
rootDir.val[i] = Vector3.Normalize(targetPositions.val[bestNode] - targetPositions.val[i]);
|
|
rootGen.val[i] = rootGen.val[bestNode] + 1;
|
|
|
|
targetOffsets.val[i] = targetPositions.val[i] - targetPositions.val[bestNode];
|
|
targetPositions.val[i] = targetPositions.val[bestNode];
|
|
}
|
|
|
|
// copy to target vertices
|
|
for (int i = 0; i != subjectVertexCount; i++)
|
|
{
|
|
targetVertices.val[i] = rootIdx.val[i];
|
|
}
|
|
|
|
if (dryRun)
|
|
CountDataAttachToVertex(ref dryRunPoseCount, ref dryRunItemCount, meshInfo, targetPositions.val, targetOffsets.val, targetNormals.val, targetVertices.val, subjectVertexCount);
|
|
else
|
|
BuildDataAttachToVertex(attachData, attachmentIndex, attachmentCount, meshInfo, targetPositions.val, targetOffsets.val, targetNormals.val, targetVertices.val, subjectVertexCount);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
public static void BuildDataAttachSubject(ref SkinAttachmentData attachData, Transform target, in MeshInfo meshInfo, SkinAttachment subject, bool dryRun, ref int dryRunPoseCount, ref int dryRunItemCount)
|
|
{
|
|
unsafe
|
|
{
|
|
fixed (int* attachmentIndex = &subject.attachmentIndex)
|
|
fixed (int* attachmentCount = &subject.attachmentCount)
|
|
{
|
|
BuildDataAttachSubject(ref attachData, attachmentIndex, attachmentCount, target, meshInfo, subject, dryRun, ref dryRunPoseCount, ref dryRunItemCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void BuildDataAttachSubjectReadOnly(ref SkinAttachmentData attachData, Transform target, in MeshInfo meshInfo, SkinAttachment subject, bool dryRun, ref int dryRunPoseCount, ref int dryRunItemCount)
|
|
{
|
|
unsafe
|
|
{
|
|
int attachmentIndex = 0;
|
|
int attachmentCount = 0;
|
|
{
|
|
BuildDataAttachSubject(ref attachData, &attachmentIndex, &attachmentCount, target, meshInfo, subject, dryRun, ref dryRunPoseCount, ref dryRunItemCount);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|