implementation of drecon in unity 2022 lts forked from: https://github.com/joanllobera/marathon-envs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

480 lines
15 KiB

7 months ago
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using System.Linq;
public class ROMparserSwingTwist : MonoBehaviour
{
//we assume a decomposition where the twist is in the X axis.
//This seems consistent with how ArticulationBody works (see constraints in the inspector and definition of ReducedCoordinates)
public
Animator theAnimator;
public
Transform skeletonRoot;
Transform[] joints;
float duration;
[SerializeField]
//public ROMinfoCollector info2store;
public RangeOfMotionValues info2store;
//those are to generate a prefab from a bunch of articulated bodies and the constraints parsed
//[SerializeField]
public ArticulationBody targetRagdollRoot;
[Tooltip("Learning Environment where to integrate the constrained ragdoll. Leave blanc if you do not want to generate any training environment")]
public
ManyWorlds.SpawnableEnv trainingEnv;
[Tooltip("Leave blanc if you want to apply on all the children of targetRoot")]
[SerializeField]
ArticulationBody[] targetJoints;
string animationEndMessage = "First animation played.If there are no more animations, the constraints have been stored.If there are, wait until the ROM info collector file does not update anymore";
// [SerializeField]
// public RangeOfMotionValue[] RangeOfMotionPreview;
MapAnim2Ragdoll _mocapControllerArtanim;
Vector3 _rootStartPosition;
Quaternion _rootStartRotation;
public bool MimicMocap;
[Range(0, 359)]
public int MaxROM = 180;
[Range(0, 500)]
public int MimicSkipPhysicsSteps = 50;
int _physicsStepsToNextMimic = 0;
public float stiffness = 40000f;
public float damping = 0f;
public float forceLimit = float.MaxValue;
// Start is called before the first frame update
void Start()
{
joints = skeletonRoot.GetComponentsInChildren<Transform>();
foreach (Transform j in joints) {
info2store.addJoint(j);
}
try
{
AnimatorClipInfo[] info = theAnimator.GetCurrentAnimatorClipInfo(0);
AnimationClip theClip = info[0].clip;
duration = theClip.length;
Debug.Log("The animation " + theClip.name + " has a duration of: " + duration);
}
catch {
Debug.Log("the character does not seem to have an animator. Make sure it is moving in some way to extract the Range of Motion");
}
_mocapControllerArtanim = theAnimator.GetComponent<MapAnim2Ragdoll>();
// get root start position and rotation
var articulationBodies = targetRagdollRoot.GetComponentsInChildren<ArticulationBody>(true);
if (articulationBodies.Length == 0)
return;
var root = articulationBodies.First(x => x.isRoot);
_rootStartPosition = root.transform.position;
_rootStartRotation = root.transform.rotation;
// if no joints specified get joints using
// not root (is static), begins with 'articulation:'
if (targetJoints.Length == 0)
{
targetJoints = targetRagdollRoot
.GetComponentsInChildren<ArticulationBody>(true)
.Where(x => x.isRoot == false)
.Where(x => x.name.StartsWith("articulation:"))
.ToArray();
SetJointsToMaxROM();
}
}
void CopyMocap()
{
if (_mocapControllerArtanim != null &&
targetRagdollRoot != null &&
_mocapControllerArtanim.enabled)
{
var atriculationBodies = targetRagdollRoot.GetComponentsInChildren<ArticulationBody>();
if (atriculationBodies.Length == 0)
return;
var root = atriculationBodies.First(x => x.isRoot);
CopyMocapStatesTo(root.gameObject, _rootStartPosition);
// teleport back to start position
// var curRotation = root.transform.rotation;
// root.TeleportRoot(_rootStartPosition, curRotation);
// Vector3 offset = _rootStartPosition - root.transform.position;
// root.gameObject.SetActive(false);
// foreach (var t in root.GetComponentsInChildren<Transform>())
// {
// t.position = t.position + offset;
// }
// root.transform.position = _rootStartPosition;
// root.gameObject.SetActive(true);
// foreach (var body in atriculationBodies)
// {
// if (body.twistLock == ArticulationDofLock.LimitedMotion)
// {
// var xDrive = body.xDrive;
// List<float> targets = new List<float>();
// var bb = body.GetDriveTargets(targets);
// var cc = 22;
// }
// }
}
}
void CopyMocapStatesTo(GameObject target, Vector3 rootPosition)
{
var targets = target.GetComponentsInChildren<ArticulationBody>().ToList();
if (targets?.Count == 0)
return;
var root = targets.First(x => x.isRoot);
root.gameObject.SetActive(false);
var mocapRoot = _mocapControllerArtanim.GetComponentsInChildren<Rigidbody>().First(x => x.name == root.name);
Vector3 offset = rootPosition - mocapRoot.transform.position;
foreach (var body in targets)
{
var stat = _mocapControllerArtanim.GetComponentsInChildren<Rigidbody>().First(x => x.name == body.name);
body.transform.position = stat.position + offset;
body.transform.rotation = stat.rotation;
if (body.isRoot)
{
body.TeleportRoot(stat.position + offset, stat.rotation);
}
}
root.gameObject.SetActive(true);
foreach (var body in targets)
{
// body.AddForce(new Vector3(0.1f, -200f, 3f));
// body.AddTorque(new Vector3(0.1f, 200f, 3f));
body.velocity = (new Vector3(0.1f, 4f, .3f));
body.angularVelocity = (new Vector3(0.1f, 20f, 3f));
}
}
void FixedUpdate()
{
for (int i = 0; i < joints.Length; i++)
{
Quaternion localRotation = joints[i].localRotation;
Vector3 candidates4storage = Utils.GetSwingTwist(localRotation);
if (info2store.Values[i].upper.x < candidates4storage.x)
info2store.Values[i].upper.x = candidates4storage.x;
if (info2store.Values[i].upper.y < candidates4storage.y)
info2store.Values[i].upper.y = candidates4storage.y;
if (info2store.Values[i].upper.z < candidates4storage.z)
info2store.Values[i].upper.z = candidates4storage.z;
if (info2store.Values[i].lower.x > candidates4storage.x)
info2store.Values[i].lower.x = candidates4storage.x;
if (info2store.Values[i].lower.y > candidates4storage.y)
info2store.Values[i].lower.y = candidates4storage.y;
if (info2store.Values[i].lower.z > candidates4storage.z)
info2store.Values[i].lower.z = candidates4storage.z;
}
if (duration < Time.time)
{
if(animationEndMessage.Length > 0) {
Debug.Log(animationEndMessage);
animationEndMessage = "";
}
}
// CalcPreview();//this only stores the ROM value?
CalculateOscillatorParameters();
}
// void FixedUpdate()
void OnRenderObject()
{
if (MimicMocap)
{
if (_physicsStepsToNextMimic-- < 1)
{
CopyMocap();
_physicsStepsToNextMimic = MimicSkipPhysicsSteps;
}
}
}
// preview range of motion
/*
void CalcPreview()
{
ArticulationBody[] articulationBodies = targetJoints;
//we want them all:
if (articulationBodies.Length == 0)
articulationBodies = targetRagdollRoot.GetComponentsInChildren<ArticulationBody>(true);
List<RangeOfMotionValue> preview = new List<RangeOfMotionValue>();
//List<string> jNames = new List<string>(info2store.jointNames);
List<string> jNames = new List<string>(info2store.getNames());
for (int i = 0; i < articulationBodies.Length; i++)
{
string s = articulationBodies[i].name;
string[] parts = s.Split(':');
//we assume the articulationBodies have a name structure of hte form ANYNAME:something-in-the-targeted-joint
int index = -1;
index = jNames.FindIndex(x => x.Contains(parts[1]));
if (index < 0)
Debug.Log("Could not find a joint name matching " + s + " and specifically: " + parts[1]);
else
{
preview.Add(info2store.Values[index]);
}
}
// RangeOfMotionPreview = preview.ToArray();
}
*/
//Not needed, the previous function already does that
//public void WriteRangeOfMotion()
//{
// if (RangeOfMotion2Store == null)
// RangeOfMotion2Store = RangeOfMotion004.CreateInstance<RangeOfMotion004>();
// RangeOfMotion2Store.Values = RangeOfMotionPreview;
//}
// Make all joints use Max Range of Motion
public void SetJointsToMaxROM()
{
//these are the articulationBodies that we want to parse and apply the constraints to
ArticulationBody[] articulationBodies;
ArticulationBody[] joints = targetJoints;
//we want them all:
if (joints.Length == 0)
joints = targetRagdollRoot.GetComponentsInChildren<ArticulationBody>();
articulationBodies = joints.ToArray();
foreach (var body in articulationBodies)
{
// root has no DOF
if (body.isRoot)
continue;
body.jointType = ArticulationJointType.SphericalJoint;
body.twistLock = ArticulationDofLock.LimitedMotion;
body.swingYLock = ArticulationDofLock.LimitedMotion;
body.swingZLock = ArticulationDofLock.LimitedMotion;
var drive = new ArticulationDrive();
drive.lowerLimit = -(float)MaxROM;
drive.upperLimit = (float)MaxROM;
drive.stiffness = stiffness;
drive.damping = damping;
drive.forceLimit = forceLimit;
body.xDrive = drive;
drive = new ArticulationDrive();
drive.lowerLimit = -(float)MaxROM;
drive.upperLimit = (float)MaxROM;
drive.stiffness = stiffness;
drive.damping = damping;
drive.forceLimit = forceLimit;
body.yDrive = drive;
drive = new ArticulationDrive();
drive.lowerLimit = -(float)MaxROM;
drive.upperLimit = (float)MaxROM;
drive.stiffness = stiffness;
drive.damping = damping;
drive.forceLimit = forceLimit;
body.zDrive = drive;
// body.useGravity = false;
}
}
public void CalculateOscillatorParameters() {
}
//we assume the constraints have been well applied
//This function is called from an Editor Script
public void Prepare4PrefabStorage(out ProcRagdollAgent rda, out ManyWorlds.SpawnableEnv envPrefab)
{
ArticulationBody targetRagdollPrefab = GameObject.Instantiate(targetRagdollRoot);
//if there is a spawnableEnv, there is a ragdollAgent:
rda = targetRagdollPrefab.GetComponent<ProcRagdollAgent>();
if (rda != null)
Debug.Log("Setting up the ragdoll agent");
envPrefab = null;
//these are all the articulationBodies in the ragdoll prefab
ArticulationBody[] articulationBodies;
Transform[] joints = targetRagdollPrefab.GetComponentsInChildren<Transform>();
List<ArticulationBody> temp = new List<ArticulationBody>();
for (int i = 0; i < joints.Length; i++)
{
ArticulationBody a = joints[i].GetComponent<ArticulationBody>();
if (a != null)
temp.Add(a);
}
articulationBodies = temp.ToArray();
//We also prepare everything inside the ragdoll agent :
for (int i = 0; i < articulationBodies.Length; i++)
{
articulationBodies[i].transform.localRotation = Quaternion.identity;
if (articulationBodies[i].isRoot)
{
articulationBodies[i].immovable = false;
if (rda != null)
rda.CameraTarget = articulationBodies[i].transform;
if (trainingEnv)
{
envPrefab = GameObject.Instantiate(trainingEnv);
Animator target = envPrefab.transform.GetComponentInChildren<Animator>();
//we assume the environment has an animated character, and in this there is a son which is the root of a bunch of rigidBodies forming a humanoid.
//TODO: replace this function with something that creates the rigidBody humanoid such a thing procedurally
activateMarathonManTarget(target);
//we also need our target animation to have this:
TrackBodyStatesInWorldSpace tracker = target.GetComponent<TrackBodyStatesInWorldSpace>();
if (tracker == null)
target.gameObject.AddComponent<TrackBodyStatesInWorldSpace>();
if (rda != null)
{
rda.transform.parent = envPrefab.transform;
rda.name = targetRagdollRoot.name;
rda.enabled = true;//this should already be the case, but just ot be cautious
}
MapRagdoll2Anim agentOutcome = envPrefab.GetComponentInChildren<MapRagdoll2Anim>(true);
if (agentOutcome != null)
{
agentOutcome.gameObject.SetActive(true);
//agentOutcome.enabled = true;
agentOutcome.ArticulationBodyRoot = articulationBodies[i];
}
}
}
}
}
static void activateMarathonManTarget(Animator target)
{
Transform[] rbs = target.GetComponentsInChildren<Transform>(true);
//Rigidbody[] rbs = target.GetComponentsInChildren<Rigidbody>(true);
for (int i = 0; i < rbs.Length; i++)
{
rbs[i].gameObject.SetActive(true);
}
//the animation source is a son of the SpawnableEnv, or it does not find the MocapControllerArtanim when it initializes
MapAnim2Ragdoll mca = target.GetComponent<MapAnim2Ragdoll>();
mca.enabled = true;
}
}