public override void Collide(ref Vector3 position, float spacing) { if (referenceCollider is SphereCollider) { SphereCollider collider = referenceCollider as SphereCollider; if (insideMode) { EZSoftBoneUtility.PointInsideSphere(ref position, collider, spacing + margin); } else { EZSoftBoneUtility.PointOutsideSphere(ref position, collider, spacing + margin); } } else if (referenceCollider is CapsuleCollider) { CapsuleCollider collider = referenceCollider as CapsuleCollider; if (insideMode) { EZSoftBoneUtility.PointInsideCapsule(ref position, collider, spacing + margin); } else { EZSoftBoneUtility.PointOutsideCapsule(ref position, collider, spacing + margin); } } else if (referenceCollider is BoxCollider) { BoxCollider collider = referenceCollider as BoxCollider; if (insideMode) { EZSoftBoneUtility.PointInsideBox(ref position, collider, spacing + margin); } else { EZSoftBoneUtility.PointOutsideBox(ref position, collider, spacing + margin); } } else if (referenceCollider is MeshCollider) { if (!CheckConvex(referenceCollider as MeshCollider)) { Debug.LogError("Non-Convex Mesh Collider is not supported", this); enabled = false; return; } if (insideMode) { Debug.LogError("Inside Mode On Mesh Collider is not supported", this); insideMode = false; return; } EZSoftBoneUtility.PointOutsideCollider(ref position, referenceCollider, spacing + margin); } }
private void UpdateNode(Bone bone) { if (bone.depth > startDepth) { Vector3 oldWorldPosition, newWorldPosition; oldWorldPosition = newWorldPosition = bone.worldPosition; // Damping (inertia attenuation) if (bone.speed.sqrMagnitude < sleepThreshold) { bone.speed = Vector3.zero; } else { newWorldPosition += bone.speed * Time.deltaTime * (1 - bone.damping); } // Resistance (force resistance) Vector3 force = gravity; if (gravityAligner != null) { Vector3 alignedDir = gravityAligner.TransformDirection(gravity).normalized; Vector3 globalDir = gravity.normalized; float attenuation = Mathf.Acos(Vector3.Dot(alignedDir, globalDir)) / Mathf.PI; force *= attenuation; } if (forceModule != null) { force += forceModule.GetForce(bone.normalizedLength, forceSpace); } force.x *= transform.localScale.x; force.y *= transform.localScale.y; force.z *= transform.localScale.z; newWorldPosition += force * (1 - bone.resistance) / iterations; // Stiffness (shape keeper) Vector3 parentOffset = bone.parentBone.worldPosition - bone.parentBone.transform.position; Vector3 expectedPos = bone.parentBone.transform.TransformPoint(bone.originalLocalPosition) + parentOffset; newWorldPosition = Vector3.Lerp(newWorldPosition, expectedPos, bone.stiffness / iterations); // Slackness (length keeper) Vector3 nodeDir = (newWorldPosition - bone.parentBone.worldPosition).normalized; float nodeLength = bone.parentBone.transform.TransformVector(bone.originalLocalPosition).magnitude; nodeDir = bone.parentBone.worldPosition + nodeDir * nodeLength; // Siblings if (siblingConstraints != UnificationMode.None) { int constraints = 1; if (bone.leftBone != null) { Vector3 leftDir = (newWorldPosition - bone.leftBone.worldPosition).normalized; float leftLength = bone.transform.TransformVector(bone.positionToLeft).magnitude; leftDir = bone.leftBone.worldPosition + leftDir * leftLength; nodeDir += leftDir; constraints++; } if (bone.rightBone != null) { Vector3 rightDir = (newWorldPosition - bone.rightBone.worldPosition).normalized; float rightLength = bone.transform.TransformVector(bone.positionToRight).magnitude; rightDir = bone.rightBone.worldPosition + rightDir * rightLength; nodeDir += rightDir; constraints++; } nodeDir /= constraints; } newWorldPosition = Vector3.Lerp(nodeDir, newWorldPosition, bone.slackness / iterations * Time.deltaTime); // Collision if (bone.radius > 0) { foreach (EZSoftBoneColliderBase collider in EZSoftBoneColliderBase.EnabledColliders) { if (bone.transform != collider.transform && collisionLayers.Contains(collider.gameObject.layer)) { collider.Collide(ref newWorldPosition, bone.radius); } } foreach (Collider collider in extraColliders) { if (bone.transform != collider.transform && collider.enabled) { EZSoftBoneUtility.PointOutsideCollider(ref newWorldPosition, collider, bone.radius); } } } bone.speed = (newWorldPosition - oldWorldPosition) / Time.deltaTime; // bone.worldPosition = newWorldPosition; } else { bone.transform.localPosition = bone.originalLocalPosition; bone.worldPosition = bone.transform.position; } for (int i = 0; i < bone.childBones.Count; i++) { UpdateNode(bone.childBones[i]); } }
private void UpdateBones(Bone bone, float deltaTime) { if (bone.depth > startDepth) { Vector3 oldWorldPosition, newWorldPosition, expectedPosition; oldWorldPosition = newWorldPosition = bone.worldPosition; // Resistance (force resistance) Vector3 force = globalForce; if (forceModule != null && forceModule.isActiveAndEnabled) { force += forceModule.GetForce(bone.normalizedLength) * forceScale; } if (customForce != null) { force += customForce(bone.normalizedLength); } force.x *= transform.localScale.x; force.y *= transform.localScale.y; force.z *= transform.localScale.z; bone.speed += force * (1 - bone.resistance) / iterations; // Damping (inertia attenuation) bone.speed *= 1 - bone.damping; if (bone.speed.sqrMagnitude > sleepThreshold) { newWorldPosition += bone.speed * deltaTime; } // Stiffness (shape keeper) Vector3 parentMovement = bone.parentBone.worldPosition - bone.parentBone.transform.position; expectedPosition = bone.parentBone.transform.TransformPoint(bone.localPosition) + parentMovement; newWorldPosition = Vector3.Lerp(newWorldPosition, expectedPosition, bone.stiffness / iterations); // Slackness (length keeper) // Length needs to be calculated with TransformVector to match runtime scaling Vector3 dirToParent = (newWorldPosition - bone.parentBone.worldPosition).normalized; float lengthToParent = bone.parentBone.transform.TransformVector(bone.localPosition).magnitude; expectedPosition = bone.parentBone.worldPosition + dirToParent * lengthToParent; int lengthConstraints = 1; // Sibling constraints if (siblingConstraints != UnificationMode.None) { if (bone.leftBone != null) { Vector3 dirToLeft = (newWorldPosition - bone.leftBone.worldPosition).normalized; float lengthToLeft = bone.transform.TransformVector(bone.leftPosition).magnitude; expectedPosition += bone.leftBone.worldPosition + dirToLeft * lengthToLeft; lengthConstraints++; } if (bone.rightBone != null) { Vector3 dirToRight = (newWorldPosition - bone.rightBone.worldPosition).normalized; float lengthToRight = bone.transform.TransformVector(bone.rightPosition).magnitude; expectedPosition += bone.rightBone.worldPosition + dirToRight * lengthToRight; lengthConstraints++; } } expectedPosition /= lengthConstraints; newWorldPosition = Vector3.Lerp(expectedPosition, newWorldPosition, bone.slackness / iterations); // Collision if (bone.radius > 0) { foreach (EZSoftBoneColliderBase collider in EZSoftBoneColliderBase.EnabledColliders) { if (bone.transform != collider.transform && collisionLayers.Contains(collider.gameObject.layer)) { collider.Collide(ref newWorldPosition, bone.radius); } } foreach (Collider collider in extraColliders) { if (bone.transform != collider.transform && collider.enabled) { EZSoftBoneUtility.PointOutsideCollider(ref newWorldPosition, collider, bone.radius); } } } bone.speed = (bone.speed + (newWorldPosition - oldWorldPosition) / deltaTime) * 0.5f; bone.worldPosition = newWorldPosition; } else { bone.worldPosition = bone.transform.position; } for (int i = 0; i < bone.childBones.Count; i++) { UpdateBones(bone.childBones[i], deltaTime); } }