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); } }
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; }
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); }
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); }
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"); }
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"); }
public void CannotCreateRemapTableWhenSourceRigIsInvalid() { var rigRemapQuery = new RigRemapQuery { }; Assert.Throws <ArgumentNullException>(() => rigRemapQuery.ToRigRemapTable(default, m_DestinationRig));