Пример #1
0
        public void Initialize(Skeleton skeleton)
        {
            var newNodes = skeleton?.Nodes;

            if (this.nodes == newNodes && this.nodes != null)
            {
                return;
            }

            this.nodes = newNodes ?? GetDefaultNodeDefinitions();

            if (nodeTransformations == null || nodeTransformations.Length < this.nodes.Length)
                nodeTransformations = new ModelNodeTransformation[this.nodes.Length];

            for (int index = 0; index < nodes.Length; index++)
            {
                nodeTransformations[index].ParentIndex = nodes[index].ParentIndex;
                nodeTransformations[index].Transform = nodes[index].Transform;
                nodeTransformations[index].Flags = nodes[index].Flags;
                nodeTransformations[index].RenderingEnabledRecursive = true;
                UpdateLocalMatrix(ref nodeTransformations[index]);
            }

            nodeTransformations[0].Flags &= ~ModelNodeFlags.EnableTransform;
        }
            public SkeletonMapping(Skeleton targetSkeleton, Skeleton sourceSkeleton)
            {
                SourceToTarget = new int[sourceSkeleton.Nodes.Length]; // model => skeleton mapping
                SourceToSource = new int[sourceSkeleton.Nodes.Length]; // model => model mapping

                if (targetSkeleton == null)
                {
                    // No skeleton, we can compact everything
                    for (int i = 0; i < sourceSkeleton.Nodes.Length; ++i)
                    {
                        // Map everything to root node
                        SourceToTarget[i] = 0;
                        SourceToSource[i] = 0;
                    }
                    return;
                }

                var targetToSource = new int[targetSkeleton.Nodes.Length]; // skeleton => model mapping
                for (int i = 0; i < targetToSource.Length; ++i)
                    targetToSource[i] = -1;

                // Build mapping from model to actual skeleton
                for (int modelIndex = 0; modelIndex < sourceSkeleton.Nodes.Length; ++modelIndex)
                {
                    var node = sourceSkeleton.Nodes[modelIndex];
                    var parentModelIndex = node.ParentIndex;

                    // Find matching node in skeleton (or map to best parent)
                    var skeletonIndex = targetSkeleton.Nodes.IndexOf(x => x.Name == node.Name);

                    if (skeletonIndex == -1)
                    {
                        // Nothing match, remap to parent node
                        SourceToTarget[modelIndex] = parentModelIndex != -1 ? SourceToTarget[parentModelIndex] : 0;
                        continue;
                    }

                    // TODO: Check hierarchy for inconsistencies

                    // Name match
                    SourceToTarget[modelIndex] = skeletonIndex;
                    targetToSource[skeletonIndex] = modelIndex;
                }

                for (int modelIndex = 0; modelIndex < sourceSkeleton.Nodes.Length; ++modelIndex)
                {
                    SourceToSource[modelIndex] = targetToSource[SourceToTarget[modelIndex]];
                }
            }
        private object ExportSkeleton(ICommandContext commandContext, AssetManager assetManager)
        {
            var skeleton = LoadSkeleton(commandContext, assetManager);

            var modelNodes = new HashSet<string>(skeleton.Nodes.Select(x => x.Name));
            var skeletonNodes = new HashSet<string>(SkeletonNodesWithPreserveInfo.Select(x => x.Key));

            // List missing nodes on both sides, to display warnings
            var missingNodesInModel = new HashSet<string>(skeletonNodes);
            missingNodesInModel.ExceptWith(modelNodes);

            var missingNodesInAsset = new HashSet<string>(modelNodes);
            missingNodesInAsset.ExceptWith(skeletonNodes);

            // Output warnings if skeleton was not properly reimported from latest FBX
            if (missingNodesInAsset.Count > 0)
                commandContext.Logger.Warning($"{missingNodesInAsset.Count} node(s) were present in model [{SourcePath}] but not in asset [{Location}], please reimport: {string.Join(", ", missingNodesInAsset)}");

            if (missingNodesInModel.Count > 0)
                commandContext.Logger.Warning($"{missingNodesInModel.Count} node(s) were present in asset [{Location}] but not in model [{SourcePath}], please reimport: {string.Join(", ", missingNodesInModel)}");

            // Build node mapping to expected structure
            var optimizedNodes = new HashSet<string>(SkeletonNodesWithPreserveInfo.Where(x => !x.Value).Select(x => x.Key));

            // Refresh skeleton updater with loaded skeleton (to be able to compute matrices)
            var hierarchyUpdater = new SkeletonUpdater(skeleton);
            hierarchyUpdater.UpdateMatrices();

            // Removed optimized nodes
            var filteredSkeleton = new Skeleton { Nodes = skeleton.Nodes.Where(x => !optimizedNodes.Contains(x.Name)).ToArray() };

            // Fix parent indices (since we removed some nodes)
            for (int i = 0; i < filteredSkeleton.Nodes.Length; ++i)
            {
                var parentIndex = filteredSkeleton.Nodes[i].ParentIndex;
                if (parentIndex != -1)
                {
                    // Find appropriate parent to map to
                    var newParentIndex = -1;
                    while (newParentIndex == -1 && parentIndex != -1)
                    {
                        var nodeName = skeleton.Nodes[parentIndex].Name;
                        parentIndex = skeleton.Nodes[parentIndex].ParentIndex;
                        newParentIndex = filteredSkeleton.Nodes.IndexOf(x => x.Name == nodeName);
                    }
                    filteredSkeleton.Nodes[i].ParentIndex = newParentIndex;
                }
            }

            // Generate mapping
            var skeletonMapping = new SkeletonMapping(filteredSkeleton, skeleton);

            // Children of remapped nodes need to have their matrices updated
            for (int i = 0; i < skeleton.Nodes.Length; ++i)
            {
                // Skip node if it doesn't exist in source skeleton
                if (skeletonMapping.SourceToSource[i] != i)
                    continue;

                var node = skeleton.Nodes[i];
                var filteredIndex = skeletonMapping.SourceToTarget[i];
                var oldParentIndex = node.ParentIndex;

                if (oldParentIndex != -1 && skeletonMapping.SourceToSource[oldParentIndex] != oldParentIndex)
                {
                    // Compute matrix for intermediate missing nodes
                    var transformMatrix = CombineMatricesFromNodeIndices(hierarchyUpdater.NodeTransformations, skeletonMapping.SourceToSource[oldParentIndex], oldParentIndex);
                    var localMatrix = hierarchyUpdater.NodeTransformations[i].LocalMatrix;

                    // Combine it with local matrix, and use that instead in the new skeleton; resulting node should be same position as before optimized nodes were removed
                    localMatrix = Matrix.Multiply(localMatrix, transformMatrix);
                    localMatrix.Decompose(out filteredSkeleton.Nodes[filteredIndex].Transform.Scale, out filteredSkeleton.Nodes[filteredIndex].Transform.Rotation, out filteredSkeleton.Nodes[filteredIndex].Transform.Position);
                }
            }

            return filteredSkeleton;
        }
        private void AdjustSkeleton(Skeleton skeleton)
        {
            // Translate node with parent 0 using PivotPosition
            for (int i = 0; i < skeleton.Nodes.Length; ++i)
            {
                if (skeleton.Nodes[i].ParentIndex == 0)
                    skeleton.Nodes[i].Transform.Position -= PivotPosition;

                skeleton.Nodes[i].Transform.Position *= ScaleImport;
            }
        }
Пример #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SkeletonUpdater" /> class.
 /// </summary>
 /// <param name="skeleton">The skeleton.</param>
 public SkeletonUpdater(Skeleton skeleton)
 {
     Initialize(skeleton);
 }