public static UvSetRecipe Merge(FigureRecipeMerger.Reindexer reindexer, UvSetRecipe parentUvSet, UvSetRecipe[] childUvSets) { List <Vector2> mergedUvs = new List <Vector2>(); List <Quad> mergedFaces = new List <Quad>(); mergedUvs.AddRange(parentUvSet.Uvs); Quad[] parentFaces = parentUvSet.Faces; for (int faceIdx = 0; faceIdx < parentFaces.Length; ++faceIdx) { if (reindexer.IsParentFaceHidden(faceIdx)) { continue; } mergedFaces.Add(parentFaces[faceIdx]); } for (int childIdx = 0; childIdx < childUvSets.Length; ++childIdx) { UvSetRecipe childUvSet = childUvSets[childIdx]; int uvOffset = mergedUvs.Count; mergedUvs.AddRange(childUvSet.Uvs); mergedFaces.AddRange(childUvSet.Faces.Select(face => face.Reindex(uvOffset))); } return(new UvSetRecipe( parentUvSet.Name, mergedUvs.ToArray(), mergedFaces.ToArray())); }
public static SkinBindingRecipe Merge(FigureRecipeMerger.Reindexer reindexer, SkinBindingRecipe parentSkinBinding, SkinBindingRecipe[] childSkinBindings) { List <string> mergedBones = new List <string>(parentSkinBinding.BoneNames); Dictionary <string, int> mergedBonesIndicesByName = Enumerable.Range(0, mergedBones.Count) .ToDictionary(idx => mergedBones[idx], idx => idx); PackedLists <BoneWeight> mergedBoneWeights = parentSkinBinding.BoneWeights; foreach (SkinBindingRecipe childSkinBinding in childSkinBindings) { var remappedChildBoneWeights = childSkinBinding.BoneWeights .Map(boneWeight => { string boneName = childSkinBinding.BoneNames[boneWeight.Index]; if (!mergedBonesIndicesByName.TryGetValue(boneName, out int mergedBoneIdx)) { mergedBoneIdx = mergedBones.Count; mergedBonesIndicesByName[boneName] = mergedBoneIdx; mergedBones.Add(boneName); } return(new BoneWeight(mergedBoneIdx, boneWeight.Weight)); }); mergedBoneWeights = PackedLists <BoneWeight> .Concat(mergedBoneWeights, remappedChildBoneWeights); } return(new SkinBindingRecipe { BoneNames = mergedBones.ToArray(), BoneWeights = mergedBoneWeights, FaceGroupToNodeMap = parentSkinBinding.FaceGroupToNodeMap }); }
public static MorphRecipe Merge(string channelName, FigureRecipeMerger.Reindexer reindexer, MorphRecipe parentMorph, MorphRecipe[] childMorphs, AutomorpherRecipe[] childAutomorphers) { List <MorphDelta> morphDeltas = new List <MorphDelta>(); Vector3[] flatPositionOffsets; if (parentMorph != null) { morphDeltas.AddRange(parentMorph.Deltas); flatPositionOffsets = new Vector3[reindexer.GetParentVertexCount()]; foreach (MorphDelta parentDelta in parentMorph.Deltas) { flatPositionOffsets[parentDelta.VertexIdx] = parentDelta.PositionOffset; } } else { flatPositionOffsets = null; } for (int childIdx = 0; childIdx < reindexer.ChildOffsets.Length; ++childIdx) { int childVertexOffset = reindexer.ChildOffsets[childIdx].Vertex; var childMorph = childMorphs[childIdx]; if (childMorph != null) { morphDeltas.AddRange(childMorph.Deltas .Select(delta => new MorphDelta(delta.VertexIdx + childVertexOffset, delta.PositionOffset))); } else { if (flatPositionOffsets == null) { continue; } //generate the deltas using the automorpher var automorpher = childAutomorphers[childIdx]; for (int childVertexIdx = 0; childVertexIdx < automorpher.BaseDeltaWeights.Count; ++childVertexIdx) { Vector3 childPositionOffset = Vector3.Zero; foreach (var baseDeltaWeight in automorpher.BaseDeltaWeights.GetElements(childVertexIdx)) { childPositionOffset += baseDeltaWeight.Weight * flatPositionOffsets[baseDeltaWeight.Index]; } if (!childPositionOffset.IsZero) { morphDeltas.Add(new MorphDelta(childVertexIdx + childVertexOffset, childPositionOffset)); } } } } return(new MorphRecipe { Channel = channelName, Deltas = morphDeltas.ToArray() }); }
public static GeometryRecipe Merge(FigureRecipeMerger.Reindexer reindexer, GeometryRecipe parent, GeometryRecipe[] children, AutomorpherRecipe[] childAutomorphers) { List <Quad> mergedFaces = new List <Quad>(); List <int> mergedFaceGroupMap = new List <int>(); List <int> mergedSurfaceMap = new List <int>(); List <Vector3> mergedVertexPositions = new List <Vector3>(); List <string> mergedSurfaceNames = new List <string>(); for (int faceIdx = 0; faceIdx < parent.Faces.Length; faceIdx++) { if (reindexer.IsParentFaceHidden(faceIdx)) { continue; } mergedFaces.Add(parent.Faces[faceIdx]); mergedFaceGroupMap.Add(parent.FaceGroupMap[faceIdx]); mergedSurfaceMap.Add(parent.SurfaceMap[faceIdx]); } mergedVertexPositions.AddRange(parent.VertexPositions); mergedSurfaceNames.AddRange(parent.SurfaceNames); for (int childIdx = 0; childIdx < children.Length; ++childIdx) { GeometryRecipe child = children[childIdx]; AutomorpherRecipe automorpher = childAutomorphers[childIdx]; Dictionary <int, int> graftVertexMap = new Dictionary <int, int>(); if (child.Graft != null) { foreach (var pair in child.Graft.VertexPairs) { graftVertexMap[pair.Source] = pair.Target; } } FigureRecipeMerger.Offset offset = reindexer.ChildOffsets[childIdx]; if (child.Type != parent.Type) { throw new InvalidOperationException("children must have same geometry type as parent"); } mergedSurfaceNames.AddRange(child.SurfaceNames); /* * Children start "turned off" so instead of adding the child's base vertex positions here, I add the * nearest positions on the parent's surface. Later I'll add a morph that moves the child vertices * into place. */ mergedVertexPositions.AddRange(automorpher.ParentSurfacePositions); foreach (Quad face in child.Faces) { mergedFaces.Add(face.Map(idx => { if (graftVertexMap.TryGetValue(idx, out int graftIdx)) { return(graftIdx); } else { return(idx + offset.Vertex); } })); } int[] childToParentFaceGroupIdx = new int[child.FaceGroupNames.Length]; for (int childFaceGroupIdx = 0; childFaceGroupIdx < child.FaceGroupNames.Length; ++childFaceGroupIdx) { string faceGroupName = child.FaceGroupNames[childFaceGroupIdx]; int parentFaceGroupIdx = Array.FindIndex(parent.FaceGroupNames, name => name == faceGroupName); childToParentFaceGroupIdx[childFaceGroupIdx] = parentFaceGroupIdx; } foreach (int childFaceGroupIdx in child.FaceGroupMap) { int parentFaceGroupIdx = childToParentFaceGroupIdx[0]; mergedFaceGroupMap.Add(parentFaceGroupIdx); } foreach (int surfaceIdx in child.SurfaceMap) { mergedSurfaceMap.Add(surfaceIdx + offset.Surface); } } return(new GeometryRecipe( parent.Type, mergedFaces.ToArray(), mergedFaceGroupMap.ToArray(), mergedSurfaceMap.ToArray(), mergedVertexPositions.ToArray(), parent.FaceGroupNames, mergedSurfaceNames.ToArray(), parent.DefaultUvSet, null)); }