浏览代码

fixed issue with attachments referencing bad data after undo

/main
Lasse Jon Fuglsang Pedersen 5 年前
当前提交
fa6e3cf5
共有 7 个文件被更改,包括 426 次插入259 次删除
  1. 45
      Editor/SkinAttachmentEditor.cs
  2. 57
      Editor/SkinAttachmentTargetEditor.cs
  3. 95
      Runtime/SkinAttachment.cs
  4. 33
      Runtime/SkinAttachmentData.cs
  5. 293
      Runtime/SkinAttachmentTarget.cs
  6. 151
      Runtime/SkinAttachmentDataBuilder.cs
  7. 11
      Runtime/SkinAttachmentDataBuilder.cs.meta

45
Editor/SkinAttachmentEditor.cs


public class SkinAttachmentEditor : Editor
{
private Editor attachmentTargetEditor;
private HashSet<SkinAttachmentTarget> attachmentTargetSet = new HashSet<SkinAttachmentTarget>();
attachmentTargetSet.Clear();
if (target == null)
return;

if (attachment == null)
return;
EditorGUILayout.HelpBox(attachment.attached ? "Attached to " + attachment.target : "Detached", MessageType.Info);
DrawGUIAttachDetach(attachment);
EditorGUILayout.HelpBox(attachment.attached ? "Currently attached to " + attachment.target : "Currently detached.", MessageType.Info);
DrawGUIAttachDetach(attachment, attachmentTargetSet);
CommitTargetChanges(attachmentTargetSet);
EditorGUILayout.Separator();
base.OnInspectorGUI();

{
EditorGUILayout.Separator();
Editor.CreateCachedEditor(attachmentTarget, null, ref attachmentTargetEditor);
attachmentTargetEditor.DrawHeader();
attachmentTargetEditor.OnInspectorGUI();

{
EditorGUILayout.HelpBox("Multiple attachments selected", MessageType.Warning);
EditorGUILayout.HelpBox("Multiple attachments selected.", MessageType.Warning);
foreach (var target in targets)
{

EditorGUILayout.BeginHorizontal();
EditorGUILayout.ObjectField(attachment, typeof(SkinAttachment), false);
DrawGUIAttachDetach(attachment);
DrawGUIAttachDetach(attachment, attachmentTargetSet);
CommitTargetChanges(attachmentTargetSet);
public static void DrawGUIAttachDetach(SkinAttachment attachment)
public static void CommitTargetChanges(HashSet<SkinAttachmentTarget> attachmentTargetSet)
{
foreach (var attachmentTarget in attachmentTargetSet)
{
if (attachmentTarget != null)
attachmentTarget.CommitSubjectsIfRequired();
}
}
public static void DrawGUIAttachDetach(SkinAttachment attachment, HashSet<SkinAttachmentTarget> attachmentTargetSet)
DrawGUIAttach(attachment);
DrawGUIDetach(attachment);
DrawGUIAttach(attachment, attachmentTargetSet);
DrawGUIDetach(attachment, attachmentTargetSet);
public static void DrawGUIAttach(SkinAttachment attachment)
public static void DrawGUIAttach(SkinAttachment attachment, HashSet<SkinAttachmentTarget> attachmentTargetSet)
attachment.attached = true;
attachmentTargetSet.Add(attachment.targetActive);
attachment.Attach(storePositionRotation: true);
attachmentTargetSet.Add(attachment.targetActive);
public static void DrawGUIDetach(SkinAttachment attachment)
public static void DrawGUIDetach(SkinAttachment attachment, HashSet<SkinAttachmentTarget> attachmentTargetSet)
{
EditorGUI.BeginDisabledGroup(!attachment.attached);
{

attachment.attached = false;
attachment.preserveResolved = false;
attachmentTargetSet.Add(attachment.targetActive);
attachment.Detach(revertPositionRotation: true);
attachment.attached = false;
attachment.preserveResolved = true;
attachmentTargetSet.Add(attachment.targetActive);
attachment.Detach(revertPositionRotation: false);
}
EditorGUILayout.EndHorizontal();
}

57
Editor/SkinAttachmentTargetEditor.cs


using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
namespace Unity.DemoTeam.DigitalHuman
{

bool showAttachments;
private HashSet<SkinAttachmentTarget> attachmentTargetSet = new HashSet<SkinAttachmentTarget>();
attachmentTargetSet.Clear();
if (target == null)
return;

return;
}
EditorGUILayout.HelpBox("Bound to " + driver.attachData, MessageType.Info);
EditorGUILayout.HelpBox("Currently bound to " + driver.attachData + "\nChecksum: " + driver.attachData.Checksum(), MessageType.Info);
DrawGUIAttachmentDataValidation(driver);
GUILayout.Label("Attachments", EditorStyles.boldLabel);
GUILayout.Label(string.Format("Attachments ({0})", driver.subjects.Count), EditorStyles.boldLabel);
var checksum = driver.attachData.Checksum();
var checksumFailed = driver.CommitRequired();
SkinAttachmentEditor.DrawGUIDetach(attachment);
SkinAttachmentEditor.DrawGUIDetach(attachment, attachmentTargetSet);
if (checksumFailed)
{
if (checksum != attachment.Checksum())
{
Color color = GUI.color;
GUI.color = Color.red;
GUILayout.Label("Checksum FAILED: " + attachment.Checksum(), EditorStyles.helpBox);
GUI.color = color;
}
else
{
GUILayout.Label("Checksum passed: " + attachment.Checksum(), EditorStyles.helpBox);
}
}
SkinAttachmentEditor.CommitTargetChanges(attachmentTargetSet);
}
void DrawGUIAttachmentData(SkinAttachmentData attachData)

attachData.Persist();
}
}
}
void DrawGUIAttachmentDataValidation(SkinAttachmentTarget driver)
{
var checksum = driver.attachData.Checksum();
var checksumFailed = driver.CommitRequired();
if (checksumFailed)
{
EditorGUILayout.HelpBox("Rebuild required: Checksum of one or more subjects does not match checksum of data.", MessageType.Warning);
}
else if (driver.attachData.subjectCount != driver.subjects.Count)
{
EditorGUILayout.HelpBox("Rebuild suggested: Data contains poses that are no longer referenced.", MessageType.Warning);
}
if (GUILayout.Button("Rebuild"))
{
driver.CommitSubjects();
}
}

}
}
}
//var vertexPosition = meshInfo.meshBuffers.vertexPositions[vertex];
//var vertexNormal = meshInfo.meshBuffers.vertexNormals[vertex];
//Handles.DrawWireDisc(vertexPosition, vertexNormal, 0.005f);
//Handles.DrawLine(vertexPosition, vertexPosition + 0.0025f * vertexNormal);
}
}
}

95
Runtime/SkinAttachment.cs


}
[HideInInspector] public bool attached;
[HideInInspector] public bool preserveResolved;
[HideInInspector] public Vector3 attachedLocalPosition;
[HideInInspector] public Quaternion attachedLocalRotation;

[EditableIf("attached", false)]
public AttachmentType attachmentType = AttachmentType.Transform;
[EditableIf("attached", false)]
public AttachmentMode attachmentMode = AttachmentMode.BuildPoses;
[EditableIf("attached", false)]

[EditableIf("attachmentMode", AttachmentMode.LinkPosesBySpecificIndex)]
public int attachmentCount = 0;
[HideInInspector]
public ulong checksum0 = 0;
[HideInInspector]
public ulong checksum1 = 0;
[Header("Debug options")]
[Range(0, 6)]

// do nothing
}
void EnsureRegistration()
public Hash128 Checksum()
if (attached)
return new Hash128(checksum0, checksum1);
}
public void RevertVertexData()
{
if (meshAsset != null)
if (target == targetActive)
return;
if (meshBuffers == null)
meshBuffers = new MeshBuffers(meshAsset);
else
meshBuffers.LoadFrom(meshAsset);
}
}
RemoveRegistration();
public void Attach(bool storePositionRotation = true)
{
EnsureMeshInstance();
if (target)
target.Attach(this);
}
else
if (targetActive != null)
targetActive.RemoveSubject(this);
targetActive = target;
targetActive.AddSubject(this);
if (storePositionRotation)
RemoveRegistration();
attachedLocalPosition = transform.localPosition;
attachedLocalRotation = transform.localRotation;
attached = true;
void RemoveRegistration()
public void Detach(bool revertPositionRotation = true)
if (targetActive)
targetActive.Detach(this);
}
RemoveMeshInstance();
void OnEnable()
{
EnsureMeshInstance();
EnsureRegistration();
if (targetActive != null)
targetActive.RemoveSubject(this);
if (revertPositionRotation)
{
transform.localPosition = attachedLocalPosition;
transform.localRotation = attachedLocalRotation;
}
attached = false;
void Update()
void ValidateAttachedState()
EnsureMeshInstance();
EnsureRegistration();
if (targetActive != null && targetActive == target)
{
EnsureMeshInstance();
}
else
{
Detach();
}
RemoveRegistration();
void OnEnable()
{
ValidateAttachedState();
}
void Update()
{
ValidateAttachedState();
}
void LateUpdate()
{
var forceRecalculateAny = forceRecalculateBounds || forceRecalculateNormals || forceRecalculateTangents;

meshInstance.RecalculateNormals();
if (forceRecalculateTangents)
meshInstance.RecalculateTangents();
if (forceRecalculateBounds)
meshInstance.RecalculateBounds();
if (forceRecalculateBounds)
meshInstance.RecalculateBounds();
}
}

var targetMeshInfo = target.GetCachedMeshInfo();
if (targetMeshInfo.valid == false)
return;
//TODO get rid of duplicate code
if (attached)
{

33
Runtime/SkinAttachmentData.cs


using System;
using UnityEngine;
using Unity.Collections.LowLevel.Unsafe;
namespace Unity.DemoTeam.DigitalHuman
{

{
[HideInInspector]
public ulong checksum0 = 0;
[HideInInspector]
public ulong checksum1 = 0;
[HideInInspector]
public SkinAttachmentPose[] pose = new SkinAttachmentPose[131072];
public int poseCount = 0;

[HideInInspector]
public int subjectCount = 0;
public Hash128 Checksum()
{
return new Hash128(checksum0, checksum1);
}
checksum0 = 0;
checksum1 = 0;
subjectCount = 0;
unsafe
{
fixed (SkinAttachmentPose* ptrPose = pose)
fixed (SkinAttachmentItem* ptrItem = item)
fixed (ulong* ptrChecksum0 = &checksum0)
fixed (ulong* ptrChecksum1 = &checksum1)
{
HashUnsafeUtilities.ComputeHash128(ptrPose, (ulong)(sizeof(SkinAttachmentPose) * poseCount), ptrChecksum0, ptrChecksum1);
HashUnsafeUtilities.ComputeHash128(ptrItem, (ulong)(sizeof(SkinAttachmentItem) * itemCount), ptrChecksum0, ptrChecksum1);
Debug.LogFormat("SkinAttachmentData changed, new checksum = '{0}' ({1} poses, {2} items)", Checksum(), poseCount, itemCount);
}
}
UnityEditor.Undo.ClearUndo(this);
#endif
}
}

public Vector3 targetNormal;
public Vector3 targetOffset;// TODO split this into leaf type item that doesn't perform full resolve
}
}
}

293
Runtime/SkinAttachmentTarget.cs


namespace Unity.DemoTeam.DigitalHuman
{
using static SkinAttachmentDataBuilder;
[ExecuteAlways]
public class SkinAttachmentTarget : MonoBehaviour
{

}
[HideInInspector] public List<SkinAttachment> subjects = new List<SkinAttachment>();
[HideInInspector] private bool subjectsChanged = false;
[NonSerialized] public Mesh meshBakedSmr;
[NonSerialized] public Mesh meshBakedOrAsset;

{
if (UpdateMeshBuffers())
{
if (subjectsChanged)
{
if (AttachSubjects())
{
subjectsChanged = false;
}
}
else
{
ResolveSubjects();
}
ResolveSubjects();
}
}

info.meshBuffers = meshBuffers;
const bool weldedAdjacency = false;//TODO enable for more reliable poses along uv seams
if (info.meshAdjacency == null)
info.meshAdjacency = new MeshAdjacency(meshBuffers, weldedAdjacency);
else if (info.meshAdjacency.vertexCount != meshBuffers.vertexCount)

return ref cachedMeshInfo;
}
public void Attach(SkinAttachment subject)
public void AddSubject(SkinAttachment subject)
Debug.Assert(subject.targetActive == null);
subject.targetActive = this;
{
switch (subject.attachmentMode)
{
case SkinAttachment.AttachmentMode.BuildPoses:
subjectsChanged = true;
break;
case SkinAttachment.AttachmentMode.LinkPosesByReference:
Debug.Assert(subject.attachmentLink != null);
subject.attachmentType = subject.attachmentLink.attachmentType;
subject.attachmentIndex = subject.attachmentLink.attachmentIndex;
subject.attachmentCount = subject.attachmentLink.attachmentCount;
break;
case SkinAttachment.AttachmentMode.LinkPosesBySpecificIndex:
subject.attachmentIndex = Mathf.Clamp(subject.attachmentIndex, 0, attachData.itemCount - 1);
subject.attachmentCount = Mathf.Clamp(subject.attachmentCount, 0, attachData.itemCount - subject.attachmentIndex);
break;
}
Debug.Assert(subject.target.attachData == attachData);
subject.attachedLocalPosition = subject.transform.localPosition;
subject.attachedLocalRotation = subject.transform.localRotation;
}
public void Detach(SkinAttachment subject)
public void RemoveSubject(SkinAttachment subject)
Debug.Assert(subject.targetActive == this);
subject.targetActive = null;
{
}
if (subject.attachmentMode == SkinAttachment.AttachmentMode.BuildPoses)
subjectsChanged = true;
}
public bool CommitRequired()
{
if (attachData == null)
return false;
if (subject.attachmentMode != SkinAttachment.AttachmentMode.LinkPosesBySpecificIndex)
for (int i = 0, n = subjects.Count; i != n; i++)
subject.attachmentIndex = -1;
subject.attachmentCount = 0;
if (subjects[i].Checksum() != attachData.Checksum())
return true;
if (subject.preserveResolved == false)
{
subject.transform.localPosition = subject.attachedLocalPosition;
subject.transform.localRotation = subject.attachedLocalRotation;
}
return false;
}
public void CommitSubjectsIfRequired()
{
if (CommitRequired())
CommitSubjects();
bool AttachSubjects()
public void CommitSubjects()
return false;
return;
return false;
return;
// pass 1: build poses
AttachSubject(ref meshInfo, subjects[i]);
if (subjects[i].attachmentMode == SkinAttachment.AttachmentMode.BuildPoses)
{
subjects[i].RevertVertexData();
CommitSubject(ref meshInfo, subjects[i]);
}
}
// pass 2: reference poses
for (int i = 0, n = subjects.Count; i != n; i++)
{
switch (subjects[i].attachmentMode)
{
case SkinAttachment.AttachmentMode.LinkPosesByReference:
{
if (subjects[i].attachmentLink != null)
{
subjects[i].attachmentType = subjects[i].attachmentLink.attachmentType;
subjects[i].attachmentIndex = subjects[i].attachmentLink.attachmentIndex;
subjects[i].attachmentCount = subjects[i].attachmentLink.attachmentCount;
}
else
{
subjects[i].attachmentIndex = -1;
subjects[i].attachmentCount = 0;
}
}
break;
case SkinAttachment.AttachmentMode.LinkPosesBySpecificIndex:
{
subjects[i].attachmentIndex = Mathf.Clamp(subjects[i].attachmentIndex, 0, attachData.itemCount - 1);
subjects[i].attachmentCount = Mathf.Clamp(subjects[i].attachmentCount, 0, attachData.itemCount - subjects[i].attachmentIndex);
}
break;
}
}
}
attachData.subjectCount = subjects.Count;
return true;
for (int i = 0, n = subjects.Count; i != n; i++)
{
subjects[i].checksum0 = attachData.checksum0;
subjects[i].checksum1 = attachData.checksum1;
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(subjects[i]);
UnityEditor.Undo.ClearUndo(subjects[i]);
#endif
}
void AttachSubject(ref MeshInfo meshInfo, SkinAttachment subject)
void CommitSubject(ref MeshInfo meshInfo, SkinAttachment subject)
{
Profiler.BeginSample("attach-subj");

fixed (int* attachmentIndex = &subject.attachmentIndex)
fixed (int* attachmentCount = &subject.attachmentCount)
{
AttachToClosestVertex(ref meshInfo, &targetPosition, &targetNormal, 1, attachmentIndex, attachmentCount);
BuildDataAttachToClosestVertex(attachData, attachmentIndex, attachmentCount, meshInfo, &targetPosition, &targetNormal, 1);
case SkinAttachment.AttachmentType.Mesh:
unsafe
{

fixed (int* attachmentIndex = &subject.attachmentIndex)
fixed (int* attachmentCount = &subject.attachmentCount)
{
AttachToClosestVertex(ref meshInfo, targetPositions.val, targetNormals.val, subjectVertexCount, attachmentIndex, attachmentCount);
BuildDataAttachToClosestVertex(attachData, attachmentIndex, attachmentCount, meshInfo, targetPositions.val, targetNormals.val, subjectVertexCount);
case SkinAttachment.AttachmentType.MeshRoots:
unsafe
{

fixed (int* attachmentIndex = &subject.attachmentIndex)
fixed (int* attachmentCount = &subject.attachmentCount)
{
AttachToVertex(ref meshInfo, targetPositions.val, targetOffsets.val, targetNormals.val, targetVertices.val, subjectVertexCount, attachmentIndex, attachmentCount);
BuildDataAttachToVertex(attachData, attachmentIndex, attachmentCount, meshInfo, targetPositions.val, targetOffsets.val, targetNormals.val, targetVertices.val, subjectVertexCount);
}
}
}

//--------
// Attach
public static unsafe int BuildPosesTriangle(ref MeshInfo meshInfo, SkinAttachmentPose* pose, 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(ref MeshInfo meshInfo, SkinAttachmentPose* pose, ref Vector3 target, int vertex)
{
int poseCount = 0;
foreach (int triangle in meshInfo.meshAdjacency.vertexTriangles[vertex])
{
poseCount += BuildPosesTriangle(ref meshInfo, pose + poseCount, ref target, triangle);
}
return poseCount;
}
//TODO remove
public unsafe void AttachToTriangle(ref MeshInfo meshInfo, Vector3* targetPositions, int* targetTriangles, int targetCount, int* attachmentIndex, int* attachmentCount)
{
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(ref meshInfo, pose + poseIndex, 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 unsafe void AttachToVertex(ref MeshInfo meshInfo, Vector3* targetPositions, Vector3* targetOffsets, Vector3* targetNormals, int* targetVertices, int targetCount, int* attachmentIndex, int* attachmentCount)
{
var poseIndex = attachData.poseCount;
var descIndex = attachData.itemCount;
fixed (SkinAttachmentPose* pose = attachData.pose)
fixed (SkinAttachmentItem* desc = attachData.item)
{
for (int i = 0; i != targetCount; i++)
{
var poseCount = BuildPosesVertex(ref meshInfo, pose + poseIndex, ref targetPositions[i], targetVertices[i]);
if (poseCount == 0)
{
Debug.LogError("no valid poses for target vertex " + i + ", aborting");
poseIndex = attachData.poseCount;
descIndex = attachData.itemCount;
break;
}
desc[descIndex].poseIndex = poseIndex;
desc[descIndex].poseCount = poseCount;
desc[descIndex].baseVertex = targetVertices[i];
desc[descIndex].baseNormal = meshInfo.meshBuffers.vertexNormals[targetVertices[i]];
desc[descIndex].targetNormal = targetNormals[i];
desc[descIndex].targetOffset = targetOffsets[i];
poseIndex += poseCount;
descIndex += 1;
}
}
*attachmentIndex = descIndex > attachData.itemCount ? attachData.itemCount : -1;
*attachmentCount = descIndex - attachData.itemCount;
attachData.poseCount = poseIndex;
attachData.itemCount = descIndex;
}
public unsafe void AttachToClosestVertex(ref MeshInfo meshInfo, Vector3* targetPositions, Vector3* targetNormals, int targetCount, int* attachmentIndex, int* attachmentCount)
{
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]);
}
AttachToVertex(ref meshInfo, targetPositions, targetOffsets.val, targetNormals, targetVertices.val, targetCount, attachmentIndex, attachmentCount);
}
}
// moved to SkinAttachmentDataBuilder
//---------
// Resolve

if (attachData == null)
return;
Profiler.BeginSample("resolve-subj-all");
subjects.RemoveAll(p => p == null);

for (int i = 0, n = subjects.Count; i != n; i++)
{
var subject = subjects[i];
if (subject.Checksum() != attachData.Checksum())
continue;
int attachmentIndex = subject.attachmentIndex;
int attachmentCount = subject.attachmentCount;

for (int i = 0, n = subjects.Count; i != n; i++)
{
var subject = subjects[i];
if (subject.Checksum() != attachData.Checksum())
continue;
var stillRunning = (stagingJobs[i].IsCompleted == false);
if (stillRunning)

151
Runtime/SkinAttachmentDataBuilder.cs


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 descIndex = attachData.itemCount;
fixed (SkinAttachmentPose* pose = attachData.pose)
fixed (SkinAttachmentItem* desc = 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;
descIndex = attachData.itemCount;
break;
}
desc[descIndex].poseIndex = poseIndex;
desc[descIndex].poseCount = poseCount;
desc[descIndex].baseVertex = targetVertices[i];
desc[descIndex].baseNormal = meshInfo.meshBuffers.vertexNormals[targetVertices[i]];
desc[descIndex].targetNormal = targetNormals[i];
desc[descIndex].targetOffset = targetOffsets[i];
poseIndex += poseCount;
descIndex += 1;
}
}
*attachmentIndex = descIndex > attachData.itemCount ? attachData.itemCount : -1;
*attachmentCount = descIndex - attachData.itemCount;
attachData.poseCount = poseIndex;
attachData.itemCount = descIndex;
}
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);
}
}
}
}

11
Runtime/SkinAttachmentDataBuilder.cs.meta


fileFormatVersion: 2
guid: 5f72a6e5bf4698e4f8663184ccf84034
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存