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.

594 lines
18 KiB

9 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.MLAgents;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.AI;
using System.Linq.Expressions;
public class MapAnim2Ragdoll : MonoBehaviour, IOnSensorCollision
{//previously Mocap Controller Artanim
public List<float> SensorIsInTouch;
List<GameObject> _sensors;
internal Animator anim;
[Range(0f,1f)]
public float NormalizedTime;
public float Lenght;
public bool IsLoopingAnimation;
[SerializeField]
Rigidbody _rigidbodyRoot;
List<Transform> _animTransforms;
public List<Transform> _ragdollTransforms;
List<Rigidbody> _ragDollRigidbody;
// private List<Rigidbody> _rigidbodies;
// private List<Transform> _transforms;
public bool RequestCamera;
public bool CameraFollowMe;
public Transform CameraTarget;
Vector3 _resetPosition;
Quaternion _resetRotation;
[Space(20)]
[Header("Stats")]
public Vector3 CenterOfMassVelocity;
public float CenterOfMassVelocityMagnitude;
public Vector3 CenterOfMassVelocityInRootSpace;
public float CenterOfMassVelocityMagnitudeInRootSpace;
public Vector3 LastCenterOfMassInWorldSpace;
public Vector3 LastRootPositionInWorldSpace;
public Vector3 LastHeadPositionInWorldSpace;
public Vector3 HorizontalDirection;
public List<Vector3> LastPosition;
public List<Quaternion> LastRotation;
public List<Vector3> Velocities;
public List<Vector3> AngularVelocities;
//TODO: find a way to remove this dependency (otherwise, not fully procedural)
private bool _usingMocapAnimatorController = false;
IAnimationController _mocapAnimController;
// [SerializeField]
// float _debugDistance = 0.0f;
private List<MappingOffset> _offsetsSource2RB = null;
//for debugging, we disable this when setTpose in MarathonTestBedController is on
[HideInInspector]
public bool doFixedUpdate = true;
bool _hasLazyInitialized;
bool _hackyNavAgentMode;
Collider _root;
Collider _head;
public void OnAgentInitialize()
{
LazyInitialize();
}
void LazyInitialize()
{
if (_hasLazyInitialized)
return;
// check if we need to create our ragdoll
var ragdoll4Mocap = GetComponentsInChildren<Transform>()
.Where(x=>x.name == "RagdollForMocap")
.FirstOrDefault();
if (ragdoll4Mocap == null)
DynamicallyCreateRagdollForMocap();
_mocapAnimController = GetComponent<IAnimationController>();
_usingMocapAnimatorController = _mocapAnimController != null;
if (!_usingMocapAnimatorController)
{
Debug.LogWarning("Mocap Controller is working WITHOUT AnimationController");
}
var ragdollTransforms =
GetComponentsInChildren<Transform>()
.Where(x=>x.name.StartsWith("articulation"))
.ToList();
var ragdollNames = ragdollTransforms
.Select(x=>x.name)
.ToList();
var animNames = ragdollNames
.Select(x=>x.Replace("articulation:",""))
.ToList();
var animTransforms = animNames
.Select(x=>GetComponentsInChildren<Transform>().FirstOrDefault(y=>y.name == x))
.Where(x=>x!=null)
.ToList();
_animTransforms = new List<Transform>();
_ragdollTransforms = new List<Transform>();
// first time, copy position and rotation
foreach (var animTransform in animTransforms)
{
var ragdollTransform = ragdollTransforms
.First(x=>x.name == $"articulation:{animTransform.name}");
ragdollTransform.position = animTransform.position;
ragdollTransform.rotation = animTransform.rotation;
_animTransforms.Add(animTransform);
_ragdollTransforms.Add(ragdollTransform);
}
_ragDollRigidbody = _ragdollTransforms
.Select(x=>x.GetComponent<Rigidbody>())
.Where(x=> x != null)
.ToList();
SetupSensors();
if (RequestCamera && CameraTarget != null)
{
var instances = FindObjectsOfType<MapAnim2Ragdoll>().ToList();
if (instances.Count(x=>x.CameraFollowMe) < 1)
CameraFollowMe = true;
}
if (CameraFollowMe){
var camera = FindObjectOfType<Camera>();
var follow = camera.GetComponent<SmoothFollow>();
follow.target = CameraTarget;
}
var navAgent = GetComponent<NavMeshAgent>();
if (navAgent)
{
var radius = 16f;
Vector3 randomDirection = UnityEngine.Random.insideUnitSphere * radius;
NavMeshHit hit;
Vector3 finalPosition = Vector3.zero;
if (NavMesh.SamplePosition(randomDirection, out hit, radius, 1))
{
finalPosition = hit.position;
}
transform.position = finalPosition;
_hackyNavAgentMode = true;
}
_resetPosition = transform.position;
_resetRotation = transform.rotation;
_hasLazyInitialized = true;
// NOTE: do after setting _hasLazyInitialized as can trigger infinate loop
anim = GetComponent<Animator>();
if (_usingMocapAnimatorController)
{
anim.Update(0f);
}
var colliders = GetComponentsInChildren<Collider>().ToList();
_root = colliders.FirstOrDefault();
_head = colliders.FirstOrDefault(x=>x.name.ToLower().Contains("head"));
if (_head == null)
{
Debug.LogWarning($"{nameof(MapAnim2Ragdoll)}.{nameof(LazyInitialize)}() can not find the head. ");
}
}
public void DynamicallyCreateRagdollForMocap()
{
// Find Ragdoll in parent
Transform parent = this.transform.parent;
ProcRagdollAgent[] ragdolls = parent.GetComponentsInChildren<ProcRagdollAgent>(true);
Assert.AreEqual(ragdolls.Length, 1, "code only supports one RagDollAgent");
ProcRagdollAgent ragDoll = ragdolls[0];
var ragdollForMocap = new GameObject("RagdollForMocap");
ragdollForMocap.transform.SetParent(this.transform, false);
Assert.AreEqual(ragDoll.transform.childCount, 1, "code only supports 1 child");
var ragdollRoot = ragDoll.transform.GetChild(0);
// clone the ragdoll root
var clone = Instantiate(ragdollRoot);
// remove '(clone)' from names
foreach (var t in clone.GetComponentsInChildren<Transform>())
{
t.name = t.name.Replace("(Clone)", "");
}
// swap ArticulatedBody for RidgedBody
List<string> bodiesNamesToDelete = new List<string>();
foreach (var abody in clone.GetComponentsInChildren<ArticulationBody>())
{
var bodyGameobject = abody.gameObject;
var rb = bodyGameobject.AddComponent<Rigidbody>();
rb.mass = abody.mass;
rb.useGravity = abody.useGravity;
// it makes no sense but if i do not set the layer here, then some objects dont have the correct layer
rb.gameObject.layer = this.gameObject.layer;
bodiesNamesToDelete.Add(abody.name);
}
foreach (var name in bodiesNamesToDelete)
{
var abody = clone
.GetComponentsInChildren<ArticulationBody>()
.First(x=>x.name == name);
DestroyImmediate(abody);
}
// make Kinematic
foreach (var rb in clone.GetComponentsInChildren<Rigidbody>())
{
rb.isKinematic = true;
}
//we do this after removing the ArticulationBody, since moving the root in the articulationBody creates TROUBLE
clone.transform.SetParent(ragdollForMocap.transform, false);
// setup HandleOverlap
foreach (var rb in clone.GetComponentsInChildren<Rigidbody>())
{
// remove cloned HandledOverlap
var oldHandleOverlap = rb.GetComponent<HandleOverlap>();
if (oldHandleOverlap != null)
{
DestroyImmediate(oldHandleOverlap);
}
var handleOverlap = rb.gameObject.AddComponent<HandleOverlap>();
handleOverlap.Parent = clone.gameObject;
}
// set the root
this._rigidbodyRoot = clone.GetComponent<Rigidbody>();
// set the layers
ragdollForMocap.layer = this.gameObject.layer;
foreach (Transform child in ragdollForMocap.GetComponentInChildren<Transform>())
{
child.gameObject.layer = this.gameObject.layer;
}
var triggers = ragdollForMocap
.GetComponentsInChildren<Collider>()
.Where(x=>x.isTrigger);
foreach (var trigger in triggers)
{
trigger.gameObject.SetActive(false);
trigger.gameObject.SetActive(true);
}
}
void SetupSensors()
{
_sensors = GetComponentsInChildren<SensorBehavior>()
.Select(x=>x.gameObject)
.ToList();
SensorIsInTouch = Enumerable.Range(0,_sensors.Count).Select(x=>0f).ToList();
}
public void OnStep(float timeDelta) {
LazyInitialize();
if (_lastPositionTime == Time.time)
return;
//if (!_usesMotionMatching)
{
AnimatorStateInfo stateInfo = anim.GetCurrentAnimatorStateInfo(0);
AnimatorClipInfo[] clipInfo = anim.GetCurrentAnimatorClipInfo(0);
Lenght = stateInfo.length;
NormalizedTime = stateInfo.normalizedTime;
IsLoopingAnimation = stateInfo.loop;
var timeStep = stateInfo.length * stateInfo.normalizedTime;
}
MimicAnimation();
// get Center Of Mass velocity in f space
var newCOM = GetCenterOfMass();
var lastCOM = LastCenterOfMassInWorldSpace;
LastCenterOfMassInWorldSpace = newCOM;
var velocity = newCOM - lastCOM;
velocity -= _snapOffset;
velocity /= timeDelta;
CenterOfMassVelocity = velocity;
CenterOfMassVelocityMagnitude = CenterOfMassVelocity.magnitude;
CenterOfMassVelocityInRootSpace = transform.InverseTransformVector(velocity);
CenterOfMassVelocityMagnitudeInRootSpace = CenterOfMassVelocityInRootSpace.magnitude;
HorizontalDirection = new Vector3(0f, transform.eulerAngles.y, 0f);
LastRootPositionInWorldSpace = _root.transform.position;
LastHeadPositionInWorldSpace = _head.transform.position;
var newPosition = _ragDollRigidbody
.Select(x=>x.position)
.ToList();
var newRotation = _ragDollRigidbody
.Select(x=>x.transform.localRotation)
.ToList();
Velocities = LastPosition
// .Zip(newPosition, (last, cur)=> (cur-last)/timeDelta)
.Zip(newPosition, (last, cur)=> (cur-last-_snapOffset)/timeDelta)
.ToList();
AngularVelocities = LastRotation
.Zip(newRotation, (last, cur)=> Utils.GetAngularVelocity(cur, last, timeDelta))
.ToList();
LastPosition = newPosition;
LastRotation = newRotation;
_snapOffset = Vector3.zero;
_lastPositionTime = Time.time;
}
float _lastPositionTime = float.MinValue;
Vector3 _snapOffset = Vector3.zero;
void MimicAnimation() {
if (!anim.enabled)
return;
// copy position for root (assume first target is root)
_ragdollTransforms[0].position = _animTransforms[0].position;
// copy rotation
for (int i = 0; i < _animTransforms.Count; i++)
{
_ragdollTransforms[i].rotation = _animTransforms[i].rotation;
}
}
public Vector3 GetCenterOfMass()
{
var centerOfMass = Vector3.zero;
float totalMass = 0f;
foreach (Rigidbody ab in _ragDollRigidbody)
{
centerOfMass += ab.worldCenterOfMass * ab.mass;
totalMass += ab.mass;
}
centerOfMass /= totalMass;
// centerOfMass -= _spawnableEnv.transform.position;
return centerOfMass;
}
public void OnReset(Quaternion resetRotation)
{
LazyInitialize();
if (!doFixedUpdate)
return;
if (!_hackyNavAgentMode)
{
transform.position = _resetPosition;
// handle character controller skin width
var characterController = GetComponent<CharacterController>();
if (characterController != null)
{
var pos = transform.position;
pos.y += characterController.skinWidth;
transform.position = pos;
}
transform.rotation = resetRotation;
}
MimicAnimation();
_snapOffset = Vector3.zero;
LastCenterOfMassInWorldSpace = GetCenterOfMass();
LastRootPositionInWorldSpace = _root.transform.position;
LastHeadPositionInWorldSpace = _head.transform.position;
LastPosition = _ragDollRigidbody
.Select(x=>x.position)
.ToList();
LastRotation = _ragDollRigidbody
.Select(x=>x.transform.localRotation)
.ToList();
}
public void OnSensorCollisionEnter(Collider sensorCollider, GameObject other)
{
LazyInitialize();
//if (string.Compare(other.name, "Terrain", true) !=0)
if (other.layer != LayerMask.NameToLayer("Ground"))
return;
var sensor = _sensors
.FirstOrDefault(x=>x == sensorCollider.gameObject);
if (sensor != null) {
var idx = _sensors.IndexOf(sensor);
SensorIsInTouch[idx] = 1f;
}
}
public void OnSensorCollisionExit(Collider sensorCollider, GameObject other)
{
LazyInitialize();
if (other.layer != LayerMask.NameToLayer("Ground"))
return;
var sensor = _sensors
.FirstOrDefault(x=>x == sensorCollider.gameObject);
if (sensor != null) {
var idx = _sensors.IndexOf(sensor);
SensorIsInTouch[idx] = 0f;
}
}
public void CopyStatesTo(GameObject target)
{
LazyInitialize();
var targets = target.GetComponentsInChildren<ArticulationBody>().ToList();
if (targets?.Count == 0)
return;
var root = targets.First(x=>x.isRoot);
// root.gameObject.SetActive(false);
var rstat = _ragDollRigidbody.First(x=>x.name == root.name);
root.TeleportRoot(rstat.position, rstat.rotation);
root.transform.position = rstat.position;
root.transform.rotation = rstat.rotation;
// root.gameObject.SetActive(true);
foreach (var targetRb in targets)
{
var stat = _ragDollRigidbody.First(x=>x.name == targetRb.name);
if (targetRb.isRoot)
continue;
// bool shouldDebug = targetRb.name == "articulation:mixamorig:RightArm";
// bool didDebug = false;
if (targetRb.jointType == ArticulationJointType.SphericalJoint)
{
float stiffness = 0f;
float damping = float.MaxValue;
float forceLimit = 0f;
// if (shouldDebug)
// didDebug = true;
Vector3 decomposedRotation = Utils.GetSwingTwist(stat.transform.localRotation);
int j=0;
List<float> thisJointPosition = Enumerable.Range(0,targetRb.dofCount).Select(x=>0f).ToList();
if (targetRb.twistLock == ArticulationDofLock.LimitedMotion)
{
var drive = targetRb.xDrive;
var deg = decomposedRotation.x;
thisJointPosition[j++] = deg * Mathf.Deg2Rad;
drive.stiffness = stiffness;
drive.damping = damping;
drive.forceLimit = forceLimit;
drive.target = deg;
targetRb.xDrive = drive;
}
if (targetRb.swingYLock == ArticulationDofLock.LimitedMotion)
{
var drive = targetRb.yDrive;
var deg = decomposedRotation.y;
thisJointPosition[j++] = deg * Mathf.Deg2Rad;
drive.stiffness = stiffness;
drive.damping = damping;
drive.forceLimit = forceLimit;
drive.target = deg;
targetRb.yDrive = drive;
}
if (targetRb.swingZLock == ArticulationDofLock.LimitedMotion)
{
var drive = targetRb.zDrive;
var deg = decomposedRotation.z;
thisJointPosition[j++] = deg * Mathf.Deg2Rad;
drive.stiffness = stiffness;
drive.damping = damping;
drive.forceLimit = forceLimit;
drive.target = deg;
targetRb.zDrive = drive;
}
switch (targetRb.dofCount)
{
case 1:
targetRb.jointPosition = new ArticulationReducedSpace(thisJointPosition[0]);
break;
case 2:
targetRb.jointPosition = new ArticulationReducedSpace(
thisJointPosition[0],
thisJointPosition[1]);
break;
case 3:
targetRb.jointPosition = new ArticulationReducedSpace(
thisJointPosition[0],
thisJointPosition[1],
thisJointPosition[2]);
break;
default:
break;
}
}
}
foreach (var childAb in root.GetComponentsInChildren<ArticulationBody>())
{
childAb.angularVelocity = Vector3.zero;
childAb.velocity = Vector3.zero;
}
}
public void CopyVelocityTo(GameObject targetGameObject, Vector3 velocity)
{
LazyInitialize();
var targets = targetGameObject.GetComponentsInChildren<ArticulationBody>().ToList();
if (targets?.Count == 0)
return;
var root = targets.First(x=>x.isRoot);
if (Velocities == null || Velocities.Count == 0)
return;
Vector3 aveVelocity = Vector3.zero;
Vector3 aveAngularVelocity = Vector3.zero;
for (int i = 0; i < _ragDollRigidbody.Count; i++)
{
var source = _ragDollRigidbody[i];
var target = targets.First(x=>x.name == source.name);
var vel = Velocities[i];
var angVel = AngularVelocities[i];
foreach (var childAb in target.GetComponentsInChildren<ArticulationBody>())
{
if (childAb == target)
continue;
childAb.transform.localPosition = Vector3.zero;
childAb.transform.localEulerAngles = Vector3.zero;
childAb.angularVelocity = Vector3.zero;
childAb.velocity = Vector3.zero;
}
if (target.jointType == ArticulationJointType.SphericalJoint && !target.isRoot)
{
int j=0;
List<float> thisJointVelocity = Enumerable.Range(0, target.dofCount).Select(x=>0f).ToList();
if (target.twistLock == ArticulationDofLock.LimitedMotion)
{
thisJointVelocity[j++] = angVel.x;
}
if (target.swingYLock == ArticulationDofLock.LimitedMotion)
{
thisJointVelocity[j++] = angVel.y;
}
if (target.swingZLock == ArticulationDofLock.LimitedMotion)
{
thisJointVelocity[j++] = angVel.z;
}
switch (target.dofCount)
{
case 1:
target.jointVelocity = new ArticulationReducedSpace(thisJointVelocity[0]);
break;
case 2:
target.jointVelocity = new ArticulationReducedSpace(
thisJointVelocity[0],
thisJointVelocity[1]);
break;
case 3:
target.jointVelocity = new ArticulationReducedSpace(
thisJointVelocity[0],
thisJointVelocity[1],
thisJointVelocity[2]);
break;
default:
break;
}
}
target.velocity = vel;
aveVelocity += Velocities[i];
aveAngularVelocity += AngularVelocities[i];
}
var c = (float)_ragDollRigidbody.Count;
aveVelocity = aveVelocity / c;
aveAngularVelocity = aveAngularVelocity / c;
c = c;
}
public Vector3 SnapTo(Vector3 snapPosition)
{
snapPosition.y = transform.position.y;
var snapDistance = snapPosition-transform.position;
transform.position = snapPosition;
_snapOffset += snapDistance;
return snapDistance;
}
public List<Rigidbody> GetRigidBodies()
{
LazyInitialize();
return GetComponentsInChildren<Rigidbody>().ToList();
}
}