You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
8.0 KiB
C#
237 lines
8.0 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System;
|
|
|
|
namespace RootMotion.Dynamics {
|
|
|
|
// Code for storing and sampling mapped poses of the animated target and blending back to the last sampled mapped pose.
|
|
public partial class PuppetMaster: MonoBehaviour {
|
|
|
|
/// <summary>
|
|
/// Store the mapped state of the target automatically?
|
|
/// </summary>
|
|
[HideInInspector] public bool storeTargetMappedState = true;
|
|
|
|
/// <summary>
|
|
/// The pose that the target will be fixed to if calling FixTargetToSampledState(). This should normally be used only by the Puppet Behaviours.
|
|
/// </summary>
|
|
public void SampleTargetMappedState() {
|
|
if (!CheckIfInitiated()) return;
|
|
|
|
sampleTargetMappedState = true;
|
|
|
|
if (!targetMappedStateStored)
|
|
{
|
|
sampleTargetMappedState = true;
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < muscles.Length; i++)
|
|
{
|
|
if (i == 0) muscles[i].targetSampledPosition = muscles[i].targetMappedPosition;
|
|
muscles[i].targetSampledRotation = muscles[i].targetMappedRotation;
|
|
}
|
|
|
|
targetMappedStateSampled = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Blend the target to the pose that was sampled by the last SampleTargetMappedState call. This should normally be used only by the Puppet Behaviours.
|
|
/// </summary>
|
|
public void FixTargetToSampledState(float weight) {
|
|
if (!CheckIfInitiated()) return;
|
|
|
|
if (weight <= 0f) return;
|
|
|
|
if (!targetMappedStateSampled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < muscles.Length; i++)
|
|
{
|
|
if (i == 0) muscles[i].target.position = Vector3.Lerp(muscles[i].target.position, muscles[i].targetSampledPosition, weight);
|
|
muscles[i].target.rotation = Quaternion.Lerp(muscles[i].target.rotation, muscles[i].targetSampledRotation, weight);
|
|
}
|
|
|
|
foreach (Muscle m in muscles) m.positionOffset = m.target.position - m.rigidbody.position;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stores the current pose of the target for sampling. This should normally be used only by the Puppet Behaviours.
|
|
/// </summary>
|
|
public void StoreTargetMappedState() {
|
|
if (!CheckIfInitiated()) return;
|
|
|
|
if (!storeTargetMappedState) return;
|
|
|
|
for (int i = 0; i < muscles.Length; i++)
|
|
{
|
|
if (i == 0) muscles[i].StoreTargetMappedPosition();
|
|
muscles[i].StoreTargetMappedRotation();
|
|
}
|
|
|
|
targetMappedStateStored = true;
|
|
|
|
if (sampleTargetMappedState) SampleTargetMappedState();
|
|
sampleTargetMappedState = false;
|
|
}
|
|
|
|
private bool targetMappedStateStored;
|
|
private bool targetMappedStateSampled;
|
|
private bool sampleTargetMappedState;
|
|
private bool hasProp;
|
|
|
|
// Should be called each time the puppet structure is changed
|
|
private void UpdateHierarchies() {
|
|
for (int i = 0; i < muscles.Length; i++) {
|
|
muscles[i].index = i;
|
|
if (muscles[i].broadcaster != null) muscles[i].broadcaster.muscleIndex = i;
|
|
if (muscles[i].jointBreakBroadcaster != null) muscles[i].jointBreakBroadcaster.muscleIndex = i;
|
|
}
|
|
|
|
targetMappedStateStored = false;
|
|
targetMappedStateSampled = false;
|
|
|
|
AssignParentAndChildIndexes();
|
|
AssignKinshipDegrees();
|
|
UpdateBroadcasterMuscleIndexes();
|
|
|
|
if (disconnectMuscleFlags.Length != muscles.Length)
|
|
{
|
|
Array.Resize(ref disconnectMuscleFlags, muscles.Length);
|
|
Array.Resize(ref muscleDisconnectModes, muscles.Length);
|
|
Array.Resize(ref disconnectDeactivateFlags, muscles.Length);
|
|
Array.Resize(ref reconnectMuscleFlags, muscles.Length);
|
|
}
|
|
|
|
propMuscles = GetComponentsInChildren<PropMuscle>();
|
|
|
|
hasProp = HasProp();
|
|
|
|
if (OnHierarchyChanged != null) OnHierarchyChanged();
|
|
}
|
|
|
|
// Checks if the puppet has a Prop attached
|
|
private bool HasProp() {
|
|
foreach (Muscle m in muscles) if (m.props.group == Muscle.Group.Prop) return true;
|
|
return false;
|
|
}
|
|
|
|
// Updates MuscleCollisionBroadcaster muscle indexes whenever the hierarchy changes
|
|
private void UpdateBroadcasterMuscleIndexes() {
|
|
for (int i = 0; i < muscles.Length; i++) {
|
|
if (muscles[i].broadcaster != null) muscles[i].broadcaster.muscleIndex = i;
|
|
if (muscles[i].jointBreakBroadcaster != null) muscles[i].jointBreakBroadcaster.muscleIndex = i;
|
|
}
|
|
}
|
|
|
|
// Find parent and child muscle indexes for each muscle
|
|
private void AssignParentAndChildIndexes() {
|
|
for (int i = 0; i < muscles.Length; i++) {
|
|
// Parents
|
|
muscles[i].parentIndexes = new int[0];
|
|
|
|
if (muscles[i].joint.connectedBody != null) {
|
|
AddToParentsRecursive(muscles[i].joint.connectedBody.GetComponent<ConfigurableJoint>(), ref muscles[i].parentIndexes);
|
|
}
|
|
|
|
// Children
|
|
muscles[i].childIndexes = new int[0];
|
|
muscles[i].childFlags = new bool[muscles.Length];
|
|
|
|
for (int n = 0; n < muscles.Length; n++) {
|
|
if (i != n && muscles[n].joint.connectedBody == muscles[i].rigidbody) {
|
|
AddToChildrenRecursive(muscles[n].joint, ref muscles[i].childIndexes, ref muscles[i].childFlags);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add all parent indexes to the indexes array recursively
|
|
private void AddToParentsRecursive(ConfigurableJoint joint, ref int[] indexes) {
|
|
if (joint == null) return;
|
|
|
|
int muscleIndex = GetMuscleIndexLowLevel(joint);
|
|
if (muscleIndex == -1) return;
|
|
|
|
Array.Resize(ref indexes, indexes.Length + 1);
|
|
indexes[indexes.Length - 1] = muscleIndex;
|
|
|
|
if (joint.connectedBody == null) return;
|
|
AddToParentsRecursive(joint.connectedBody.GetComponent<ConfigurableJoint>(), ref indexes);
|
|
}
|
|
|
|
// Add all child indexes to the indexes array recursively
|
|
private void AddToChildrenRecursive(ConfigurableJoint joint, ref int[] indexes, ref bool[] childFlags) {
|
|
if (joint == null) return;
|
|
|
|
int muscleIndex = GetMuscleIndexLowLevel(joint);
|
|
if (muscleIndex == -1) return;
|
|
|
|
Array.Resize(ref indexes, indexes.Length + 1);
|
|
indexes[indexes.Length - 1] = muscleIndex;
|
|
|
|
childFlags[muscleIndex] = true;
|
|
|
|
for (int i = 0; i < muscles.Length; i++) {
|
|
if (i != muscleIndex && muscles[i].joint.connectedBody == joint.GetComponent<Rigidbody>()) {
|
|
AddToChildrenRecursive(muscles[i].joint, ref indexes, ref childFlags);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void AssignKinshipDegrees() {
|
|
for (int i = 0; i < muscles.Length; i++) {
|
|
// Parents
|
|
muscles[i].kinshipDegrees = new int[muscles.Length];
|
|
|
|
AssignKinshipsDownRecursive(ref muscles[i].kinshipDegrees, 1, i);
|
|
AssignKinshipsUpRecursive(ref muscles[i].kinshipDegrees, 1, i);
|
|
}
|
|
}
|
|
|
|
private void AssignKinshipsDownRecursive(ref int[] kinshipDegrees, int degree, int index) {
|
|
for (int i = 0; i < muscles.Length; i++) {
|
|
if (i != index) {
|
|
if (muscles[i].joint.connectedBody == muscles[index].rigidbody) {
|
|
kinshipDegrees[i] = degree;
|
|
|
|
AssignKinshipsDownRecursive(ref kinshipDegrees, degree + 1, i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void AssignKinshipsUpRecursive(ref int[] kinshipDegrees, int degree, int index) {
|
|
for (int i = 0; i < muscles.Length; i++) {
|
|
if (i != index) {
|
|
if (muscles[i].rigidbody == muscles[index].joint.connectedBody) {
|
|
kinshipDegrees[i] = degree;
|
|
|
|
AssignKinshipsUpRecursive(ref kinshipDegrees, degree + 1, i);
|
|
|
|
for (int c = 0; c < muscles.Length; c++) {
|
|
if (c != i && c != index) {
|
|
if (muscles[c].joint.connectedBody == muscles[i].rigidbody) {
|
|
kinshipDegrees[c] = degree + 1;
|
|
|
|
AssignKinshipsDownRecursive(ref kinshipDegrees, degree + 2, c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Returns the index of the muscle that has the specified Joint. Returns -1 if not found.
|
|
private int GetMuscleIndexLowLevel(ConfigurableJoint joint) {
|
|
for (int i = 0; i < muscles.Length; i++) {
|
|
if (muscles[i].joint == joint) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
}
|