コード例 #1
0
 public override void PreProcessData<T>(T data)
 {
     if (data is RigComponent)
     {
         var dstRig = data as RigComponent;
         var srcRig = SourceRigPrefab.GetComponent<RigComponent>();
         m_RemapQuery = CreateRemapQuery(srcRig, dstRig, RetargetMap);
     }
 }
コード例 #2
0
    public RigRemapQuery CreateRemapQuery(RigComponent srcRig, RigComponent dstRig, List<string> retargetMap)
    {
        string status = "";

        List<ChannelMap> translationChannels = new List<ChannelMap>();
        List<ChannelMap> rotationChannels = new List<ChannelMap>();
        List<RigTranslationOffset> translationOffsets = new List<RigTranslationOffset>();
        List<RigRotationOffset> rotationOffsets = new List<RigRotationOffset>();

        for (var mapIter = 0; mapIter < retargetMap.Count; mapIter++)
        {
            bool success = false;

            string[] splitMap = retargetMap[mapIter].Split(new char[] { ' ' }, 3);

            for (var srcBoneIter = 0; srcBoneIter < srcRig.Bones.Length; srcBoneIter++)
            {
                if (splitMap.Length > 0 && splitMap[0] == srcRig.Bones[srcBoneIter].name)
                {
                    for (var dstBoneIter = 0; dstBoneIter < dstRig.Bones.Length; dstBoneIter++)
                    {
                        if (splitMap.Length > 1 && splitMap[1] == dstRig.Bones[dstBoneIter].name)
                        {
                            if (splitMap.Length > 2)
                            {
                                var srcPath = RigGenerator.ComputeRelativePath(srcRig.Bones[srcBoneIter], srcRig.transform);
                                var dstPath = RigGenerator.ComputeRelativePath(dstRig.Bones[dstBoneIter], dstRig.transform);

                                if (splitMap[2] == "TR" || splitMap[2] == "T")
                                {
                                    var translationOffset = new RigTranslationOffset();

                                    // heuristic that computes retarget scale based on translation node (ex: hips) height (assumed to be y)
                                    translationOffset.Scale = dstRig.Bones[dstBoneIter].position.y / srcRig.Bones[srcBoneIter].position.y;
                                    
                                    translationOffset.Rotation = mathex.mul(math.conjugate(dstRig.Bones[dstBoneIter].parent.rotation), srcRig.Bones[srcBoneIter].parent.rotation);

                                    translationOffsets.Add(translationOffset);
                                    translationChannels.Add(new ChannelMap() { SourceId = srcPath, DestinationId = dstPath, OffsetIndex = translationOffsets.Count });
                                }

                                if (splitMap[2] == "TR" || splitMap[2] == "R")
                                {
                                    var rotationOffset = new RigRotationOffset();

                                    rotationOffset.PreRotation = mathex.mul(math.conjugate(dstRig.Bones[dstBoneIter].parent.rotation), srcRig.Bones[srcBoneIter].parent.rotation);
                                    rotationOffset.PostRotation = mathex.mul(math.conjugate(srcRig.Bones[srcBoneIter].rotation), dstRig.Bones[dstBoneIter].rotation);

                                    rotationOffsets.Add(rotationOffset);
                                    rotationChannels.Add(new ChannelMap() { SourceId = srcPath, DestinationId = dstPath, OffsetIndex = rotationOffsets.Count });
                                }

                                success = true;
                            }
                        }
                    }
                }
            }

            if (!success)
            {
                status = status + mapIter + " ";
            }
        }

        RigRemapQuery rigRemapQuery = new RigRemapQuery();

        rigRemapQuery.TranslationChannels = new ChannelMap[translationChannels.Count];

        for (var iter = 0; iter < translationChannels.Count; iter++)
        {
            rigRemapQuery.TranslationChannels[iter] = translationChannels[iter];
        }

        rigRemapQuery.TranslationOffsets = new RigTranslationOffset[translationOffsets.Count + 1];
        rigRemapQuery.TranslationOffsets[0] = new RigTranslationOffset();

        for (var iter = 0; iter < translationOffsets.Count; iter++)
        {
            rigRemapQuery.TranslationOffsets[iter + 1] = translationOffsets[iter];
        }

        rigRemapQuery.RotationChannels = new ChannelMap[rotationChannels.Count];

        for (var iter = 0; iter < rotationChannels.Count; iter++)
        {
            rigRemapQuery.RotationChannels[iter] = rotationChannels[iter];
        }

        rigRemapQuery.RotationOffsets = new RigRotationOffset[rotationOffsets.Count + 1];
        rigRemapQuery.RotationOffsets[0] = new RigRotationOffset();

        for (var iter = 0; iter < rotationOffsets.Count; iter++)
        {
            rigRemapQuery.RotationOffsets[iter + 1] = rotationOffsets[iter];
        }

        if (!string.IsNullOrEmpty(status))
        {
            UnityEngine.Debug.LogError("Faulty Entries : " + status);
        }

        return rigRemapQuery;
    }
コード例 #3
0
    private RigRemapQuery CreateRemapQuery(RigComponent srcRig, RigComponent dstRig, List <string> retargetMap)
    {
        var status = "";

        var translationChannels = new List <ChannelMap>();
        var rotationChannels    = new List <ChannelMap>();
        var translationOffsets  = new List <RigTranslationOffset>();
        var rotationOffsets     = new List <RigRotationOffset>();

        //Inverse Quaternion = (x * -1, y * -1, z * -1, w)
        var srcRootRotInv = math.inverse(srcRig.transform.rotation);
        var dstRootRotInv = math.inverse(dstRig.transform.rotation);

        //We are iterating through the retargetMap collection..
        for (var mapIter = 0; mapIter < retargetMap.Count; mapIter++)
        {
            var successFlag = false;

            //Splitting the element in each array when there a space. Three element
            //ex. "First Second Third" = ["First", "Second", "Third"]
            var splitMap = retargetMap[mapIter].Split(new[] { ' ' }, 3);

            //We are iterating through the for loop on the number of bones the srcPrefab.
            for (var srcBoneIter = 0; srcBoneIter < srcRig.Bones.Length; srcBoneIter++)
            {
                //We are checking if the splitMap element has atleast one element and if the first element matches any bone name of the srcRig prefab bone
                if (splitMap.Length > 0 && splitMap[0] == srcRig.Bones[srcBoneIter].name)
                {
                    //We are iterating through the for loop on the number of bones we have on the gameObject attached to this script.
                    for (var dstBoneIter = 0; dstBoneIter < dstRig.Bones.Length; dstBoneIter++)
                    {
                        //We are checking if the splitMap element has atleast two element and if the second element matches any bone name of this gameObject
                        if (splitMap.Length > 1 && splitMap[1] == dstRig.Bones[dstBoneIter].name)
                        {
                            //We are checking if the splitMap has atleast three element
                            if (splitMap.Length > 2)
                            {
                                //We are getting all the parent gameObject name of the current srcRig bone at srcBoneIter up until and excluding the srcRig.transform
                                //Ex.
                                // if srcRig.Bones[srcBoneIter] = Chest
                                // then the srcPath = Skeleton/Root/Spine/Chest (it traverse the hierarchy and get the parent up until the srcRig.transform)
                                var srcPath =
                                    RigGenerator.ComputeRelativePath(srcRig.Bones[srcBoneIter], srcRig.transform);
                                var dstPath
                                    = RigGenerator.ComputeRelativePath(dstRig.Bones[dstBoneIter], dstRig.transform);

                                if (splitMap[2] == "TR" || splitMap[2] == "T")
                                {
                                    var translationOffset = new RigTranslationOffset();

                                    //self bone position.y / target bone position.y to get the average height of the bone (assumed to be y/ standing up right)
                                    translationOffset.Scale = dstRig.Bones[dstBoneIter].position.y /
                                                              srcRig.Bones[srcBoneIter].position.y;

                                    var dstParentRot =
                                        math.mul(dstRootRotInv, dstRig.Bones[dstBoneIter].parent.rotation);
                                    var srcParentRot =
                                        math.mul(srcRootRotInv, srcRig.Bones[srcBoneIter].parent.rotation);

                                    translationOffset.Rotation = mathex.mul(math.inverse(dstParentRot), srcParentRot);

                                    translationOffsets.Add(translationOffset);
                                    translationChannels.Add(new ChannelMap
                                    {
                                        SourceId    = srcPath, DestinationId = dstPath,
                                        OffsetIndex = translationOffsets.Count
                                    });
                                }

                                if (splitMap[2] == "TR" || splitMap[2] == "R")
                                {
                                    var rotationOffset = new RigRotationOffset();

                                    var dstParentRot = math.mul(dstRootRotInv,
                                                                dstRig.Bones[dstBoneIter].parent.transform.rotation);
                                    var srcParentRot = math.mul(srcRootRotInv,
                                                                srcRig.Bones[srcBoneIter].parent.transform.rotation);

                                    var dstRot = math.mul(dstRootRotInv,
                                                          dstRig.Bones[dstBoneIter].transform.rotation);
                                    var srcRot = math.mul(srcRootRotInv,
                                                          srcRig.Bones[srcBoneIter].transform.rotation);

                                    rotationOffset.PreRotation  = mathex.mul(math.inverse(dstParentRot), srcParentRot);
                                    rotationOffset.PostRotation = mathex.mul(math.inverse(srcRot), dstRot);

                                    rotationOffsets.Add(rotationOffset);
                                    rotationChannels.Add(new ChannelMap
                                    {
                                        SourceId = srcPath, DestinationId = dstPath, OffsetIndex = rotationOffsets.Count
                                    });
                                }

                                successFlag = true;
                            }
                        }
                    }
                }
            }

            if (!successFlag)
            {
                status = status + mapIter + " ";
            }
        }

        var rigRemapQuery = new RigRemapQuery();

        rigRemapQuery.TranslationChannels = new ChannelMap[translationChannels.Count];

        for (var iter = 0; iter < translationChannels.Count; iter++)
        {
            rigRemapQuery.TranslationChannels[iter] = translationChannels[iter];
        }

        rigRemapQuery.TranslationOffsets    = new RigTranslationOffset[translationOffsets.Count + 1];
        rigRemapQuery.TranslationOffsets[0] = new RigTranslationOffset();

        for (var iter = 0; iter < translationOffsets.Count; iter++)
        {
            rigRemapQuery.TranslationOffsets[iter + 1] = translationOffsets[iter];
        }

        rigRemapQuery.RotationChannels = new ChannelMap[rotationChannels.Count];

        for (var iter = 0; iter < rotationChannels.Count; iter++)
        {
            rigRemapQuery.RotationChannels[iter] = rotationChannels[iter];
        }

        rigRemapQuery.RotationOffsets    = new RigRotationOffset[rotationOffsets.Count + 1];
        rigRemapQuery.RotationOffsets[0] = new RigRotationOffset();

        for (var iter = 0; iter < rotationOffsets.Count; iter++)
        {
            rigRemapQuery.RotationOffsets[iter + 1] = rotationOffsets[iter];
        }

        if (!string.IsNullOrEmpty(status))
        {
            Debug.LogError("Faulty Entries : " + status);
        }

        return(rigRemapQuery);
    }
コード例 #4
0
    private RigRemapQuery CreateAutoRemapQuery([NotNull] RigComponent srcRig, [NotNull] RigComponent dstRig)
    {
        var translationChannels = new List <ChannelMap>();
        var rotationChannels    = new List <ChannelMap>();

        var translationOffsets = new List <RigTranslationOffset>();
        var rotationOffsets    = new List <RigRotationOffset>();

        var srcRootRotInv = math.inverse(srcRig.transform.rotation);
        var dstRootRotInv = math.inverse(dstRig.transform.rotation);

        for (var boneIter = 0; boneIter < srcRig.Bones.Length; boneIter++)
        {
            if (srcRig.Bones[boneIter].parent != null)
            {
                if (srcRig.Bones[boneIter].name == dstRig.Bones[boneIter].name)
                {
                    var srcPath = RigGenerator.ComputeRelativePath(srcRig.Bones[boneIter], srcRig.transform);
                    var dstPath = RigGenerator.ComputeRelativePath(dstRig.Bones[boneIter], dstRig.transform);

                    var dstParentRot = math.mul(dstRootRotInv, dstRig.Bones[boneIter].parent.transform.rotation);
                    var srcParentRot = math.mul(srcRootRotInv, srcRig.Bones[boneIter].parent.transform.rotation);
                    var rotation     = mathex.mul(math.inverse(dstParentRot), srcParentRot);

                    //Got to calculate the translation.
                    //Only applying translationOffset to the first bone (most cases the hips)
                    if (boneIter == 1)
                    {
                        var translationOffset = new RigTranslationOffset
                        {
                            Scale    = dstRig.Bones[boneIter].position.y / srcRig.Bones[boneIter].position.y,
                            Rotation = rotation
                        };

                        translationOffsets.Add(translationOffset);
                        translationChannels.Add(new ChannelMap
                        {
                            DestinationId = dstPath, SourceId = srcPath, OffsetIndex = translationOffsets.Count
                        });
                    }

                    //Got to calculate the rotation.
                    var dstRot = math.mul(dstRootRotInv, dstRig.Bones[boneIter].transform.rotation);
                    var srcRot = math.mul(srcRootRotInv, srcRig.Bones[boneIter].transform.rotation);

                    var rotationOffset = new RigRotationOffset
                    {
                        PreRotation  = rotation,
                        PostRotation = mathex.mul(math.inverse(srcRot), dstRot)
                    };

                    rotationOffsets.Add(rotationOffset);
                    rotationChannels.Add(new ChannelMap
                    {
                        SourceId = srcPath, DestinationId = dstPath, OffsetIndex = rotationOffsets.Count
                    });
                }
            }
        }

        var rigRemapQuery = new RigRemapQuery
        {
            TranslationChannels = new ChannelMap[translationChannels.Count],
            RotationChannels    = new ChannelMap[rotationChannels.Count],
            TranslationOffsets  = new RigTranslationOffset[translationChannels.Count + 1],
            RotationOffsets     = new RigRotationOffset[rotationChannels.Count + 1]
        };

        rigRemapQuery.TranslationOffsets[0] = new RigTranslationOffset();
        rigRemapQuery.RotationOffsets[0]    = new RigRotationOffset();

        for (var iter = 0; iter < translationChannels.Count; iter++)
        {
            rigRemapQuery.TranslationChannels[iter]    = translationChannels[iter];
            rigRemapQuery.TranslationOffsets[iter + 1] = translationOffsets[iter];
        }

        for (var iter = 0; iter < rotationChannels.Count; iter++)
        {
            rigRemapQuery.RotationChannels[iter]    = rotationChannels[iter];
            rigRemapQuery.RotationOffsets[iter + 1] = rotationOffsets[iter];
        }

        return(rigRemapQuery);
    }
コード例 #5
0
        public void CanRemapAllIntChannel()
        {
            var sourceChannels = new IAnimationChannel[]
            {
                new IntChannel {
                    Id = "Root", DefaultValue = m_ExpectedSourceInt
                },
                new IntChannel {
                    Id = "Child1", DefaultValue = m_ExpectedSourceInt
                },
                new IntChannel {
                    Id = "Child2", DefaultValue = m_ExpectedSourceInt
                },
            };

            var sourceRig = new Rig {
                Value = RigBuilder.CreateRigDefinition(sourceChannels)
            };

            var destinationChannels = new IAnimationChannel[]
            {
                new IntChannel {
                    Id = "AnotherRoot", DefaultValue = 0
                },
                new IntChannel {
                    Id = "AnotherChild1", DefaultValue = 0
                },
                new IntChannel {
                    Id = "AnotherChild2", DefaultValue = 0
                },
            };
            var destinationRig = new Rig {
                Value = RigBuilder.CreateRigDefinition(destinationChannels)
            };
            var rigEntity = m_Manager.CreateEntity();

            RigEntityBuilder.SetupRigEntity(rigEntity, m_Manager, destinationRig);

            var rigRemapQuery = new RigRemapQuery
            {
                AllChannels = new [] {
                    new ChannelMap {
                        SourceId = "Root", DestinationId = "AnotherRoot"
                    },
                    new ChannelMap {
                        SourceId = "Child1", DestinationId = "AnotherChild1"
                    },
                    new ChannelMap {
                        SourceId = "Child2", DestinationId = "AnotherChild2"
                    }
                }
            };
            var remapTable = rigRemapQuery.ToRigRemapTable(sourceRig, destinationRig);

            // Here I'm using a layerMixer with no inputs connected
            // the expected result is to inject the default pose into Graph samples buffer
            var layerMixer = CreateNode <LayerMixerNode>();

            Set.SendMessage(layerMixer, LayerMixerNode.SimulationPorts.Rig, sourceRig);

            var rigRemapper = CreateNode <RigRemapperNode>();

            Set.Connect(layerMixer, LayerMixerNode.KernelPorts.Output, rigRemapper, RigRemapperNode.KernelPorts.Input);

            Set.SendMessage(rigRemapper, RigRemapperNode.SimulationPorts.SourceRig, sourceRig);
            Set.SendMessage(rigRemapper, RigRemapperNode.SimulationPorts.DestinationRig, destinationRig);
            Set.SendMessage(rigRemapper, RigRemapperNode.SimulationPorts.RemapTable, remapTable);

            var entityNode = CreateComponentNode(rigEntity);

            Set.Connect(rigRemapper, RigRemapperNode.KernelPorts.Output, entityNode);

            m_Manager.AddComponent <PreAnimationGraphTag>(rigEntity);

            m_AnimationGraphSystem.Update();

            var streamECS = AnimationStream.CreateReadOnly(
                destinationRig,
                m_Manager.GetBuffer <AnimatedData>(rigEntity).AsNativeArray()
                );

            Assert.That(streamECS.GetInt(0), Is.EqualTo(m_ExpectedSourceInt), "Channel int 0 doesn't match source rig default value");
            Assert.That(streamECS.GetInt(1), Is.EqualTo(m_ExpectedSourceInt), "Channel int 1 doesn't match source rig default value");
            Assert.That(streamECS.GetInt(2), Is.EqualTo(m_ExpectedSourceInt), "Channel int 2 doesn't match source rig default value");
        }
コード例 #6
0
        public void CanRemapRigRotationOffset()
        {
            var sourceChannels = new IAnimationChannel[]
            {
                new LocalRotationChannel {
                    Id = "Root", DefaultValue = m_ExpectedSourceRotation
                },
                new LocalRotationChannel {
                    Id = "Child", DefaultValue = m_ExpectedSourceRotation
                },
            };

            var sourceRig = new Rig {
                Value = RigBuilder.CreateRigDefinition(sourceChannels)
            };

            var destinationChannels = new IAnimationChannel[]
            {
                new LocalRotationChannel {
                    Id = "AnotherRoot", DefaultValue = quaternion.identity
                },
                new LocalRotationChannel {
                    Id = "AnotherChild", DefaultValue = quaternion.identity
                },
            };

            var destinationRig = new Rig {
                Value = RigBuilder.CreateRigDefinition(destinationChannels)
            };
            var rigEntity = m_Manager.CreateEntity();

            RigEntityBuilder.SetupRigEntity(rigEntity, m_Manager, destinationRig);

            var rigRemapQuery = new RigRemapQuery
            {
                RotationChannels = new []
                {
                    new ChannelMap {
                        SourceId = "Root", DestinationId = "AnotherRoot"
                    },
                    new ChannelMap {
                        SourceId = "Child", DestinationId = "AnotherChild", OffsetIndex = 1
                    }
                },

                RotationOffsets = new []
                {
                    new RigRotationOffset(),
                    new RigRotationOffset {
                        PreRotation = math.normalize(math.quaternion(1, 2, 3, 4)), PostRotation = math.normalize(math.quaternion(5, 6, 7, 8))
                    }
                }
            };

            var remapTable = rigRemapQuery.ToRigRemapTable(sourceRig, destinationRig);

            // Here I'm using a layerMixer with no inputs connected
            // the expected result is to inject the default pose into Graph samples buffer
            var layerMixer = CreateNode <LayerMixerNode>();

            Set.SendMessage(layerMixer, LayerMixerNode.SimulationPorts.Rig, sourceRig);

            var rigRemapper = CreateNode <RigRemapperNode>();

            Set.Connect(layerMixer, LayerMixerNode.KernelPorts.Output, rigRemapper, RigRemapperNode.KernelPorts.Input);

            Set.SendMessage(rigRemapper, RigRemapperNode.SimulationPorts.SourceRig, sourceRig);
            Set.SendMessage(rigRemapper, RigRemapperNode.SimulationPorts.DestinationRig, destinationRig);
            Set.SendMessage(rigRemapper, RigRemapperNode.SimulationPorts.RemapTable, remapTable);

            var entityNode = CreateComponentNode(rigEntity);

            Set.Connect(rigRemapper, RigRemapperNode.KernelPorts.Output, entityNode);

            m_Manager.AddComponent <PreAnimationGraphTag>(rigEntity);

            m_AnimationGraphSystem.Update();

            var streamECS = AnimationStream.CreateReadOnly(
                destinationRig,
                m_Manager.GetBuffer <AnimatedData>(rigEntity).AsNativeArray()
                );

            Assert.That(streamECS.GetLocalToParentRotation(1), Is.EqualTo(math.mul(rigRemapQuery.RotationOffsets[1].PreRotation, math.mul(m_ExpectedSourceRotation, rigRemapQuery.RotationOffsets[1].PostRotation))).Using(RotationComparer), "Channel localRotation doesn't match destination rig default value with rig rotation offset");
        }
コード例 #7
0
        public void CannotCreateRemapTableWhenSourceRigIsInvalid()
        {
            var rigRemapQuery = new RigRemapQuery {
            };

            Assert.Throws <ArgumentNullException>(() => rigRemapQuery.ToRigRemapTable(default, m_DestinationRig));