/// <summary> /// Refit mesh against mesh variant originally used /// </summary> /// <param name="baseVariant">Original variant</param> /// <param name="targetVariant">Target variant</param> /// <param name="sourceMesh">Mesh to recreate</param> /// <param name="malleable">Optional pre-allocated mesh to modify</param> /// <returns>Newly allocated refit mesh</returns> public static LiveMesh Refit(LiveMesh baseVariant, LiveMesh targetVariant, LiveMesh sourceMesh, LiveMesh malleable = null) { if (baseVariant == null) { throw new ArgumentNullException(nameof(baseVariant)); } if (targetVariant == null) { throw new ArgumentNullException(nameof(targetVariant)); } if (sourceMesh == null) { throw new ArgumentNullException(nameof(sourceMesh)); } var res = malleable ?? (LiveMesh)sourceMesh.Clone(); res.FitUniqueName = baseVariant.UniqueName; Span <float> delta = stackalloc float[3]; foreach (var sub in res.SubMeshes) { for (var iSubMesh = 0; iSubMesh < sub.VertexCount; iSubMesh++) { var closestBaseIdx = 0; var closestBaseVert = 0; var closestLenSq = float.MaxValue; for (var iBaseIdx = 0; iBaseIdx < baseVariant.SubMeshes.Length; iBaseIdx++) { var baseSubMesh = baseVariant.SubMeshes[iBaseIdx]; for (var iBaseVert = 0; iBaseVert < baseSubMesh.VertexCount; iBaseVert++) { var curLenSq = SqDist(sub.Vertices, iSubMesh, baseSubMesh.Vertices, iBaseVert, 3); if (!(curLenSq < closestLenSq)) { continue; } closestBaseIdx = iBaseIdx; closestBaseVert = iBaseVert; closestLenSq = curLenSq; } } // Placeholder basic single-vertex delta Sub(baseVariant.SubMeshes[closestBaseIdx].Vertices, closestBaseVert, targetVariant.SubMeshes[closestBaseIdx].Vertices, closestBaseVert, delta, 0, 3); Add(sub.Vertices, iSubMesh, delta, 0, sub.Vertices, iSubMesh, 3); // Determine face // Procedural transformation } } return(res); }
/// <summary> /// Synchronize bones of a mesh with a prototype mesh /// </summary> /// <param name="protoMesh">Prototype to match bones against</param> /// <param name="sourceMesh">Mesh to recreate</param> /// <param name="res">Newly allocated bone synchronized mesh</param> /// <param name="malleable">Optional pre-allocated mesh to modify</param> /// <returns>True if success (all source mesh bones had matching prototype mesh bones)</returns> public static bool BoneSync(LiveMesh protoMesh, LiveMesh sourceMesh, out LiveMesh res, LiveMesh malleable = null) { if (protoMesh == null) { throw new ArgumentNullException(nameof(protoMesh)); } if (sourceMesh == null) { throw new ArgumentNullException(nameof(sourceMesh)); } res = malleable ?? (LiveMesh)sourceMesh.Clone(); var boneMap = MapBones(protoMesh.Bones); foreach (var sub in res.SubMeshes) { for (var i = 0; i < sub.VertexCount; i++) { for (var j = 0; j < 4; j++) { // Ignore zero weights if (Math.Abs(sub.BoneWeights[4 * i + j]) < float.Epsilon) { continue; } if (boneMap.TryGetValue(sourceMesh.Bones[sub.BoneIds[4 * i + j]].Type, out var newIdx)) { sub.BoneIds[4 * i + j] = newIdx; } else { return(false); } } } } res.Bones = new Bone[protoMesh.Bones.Length]; Array.Copy(protoMesh.Bones, res.Bones, protoMesh.Bones.Length); return(true); }
public object Clone() { var res = new LiveMesh { Bones = new Bone[Bones.Length], SubMeshes = new LiveSubMesh[SubMeshes.Length], DefaultAttachPoints = new AttachPoint[DefaultAttachPoints.Length], UniqueName = UniqueName, VariantTypeName = VariantTypeName, FitUniqueName = FitUniqueName }; Array.Copy(Bones, res.Bones, Bones.Length); for (var i = 0; i < DefaultAttachPoints.Length; i++) { res.SubMeshes[i] = (LiveSubMesh)SubMeshes[i].Clone(); } for (var i = 0; i < DefaultAttachPoints.Length; i++) { res.DefaultAttachPoints[i] = (AttachPoint)DefaultAttachPoints[i].Clone(); } return(res); }