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.
479 lines
15 KiB
479 lines
15 KiB
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;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|