Пример #1
0
        public bool Collide(Vector3 boneCenter, float boneRadius, out Vector3 push)
        {
            switch (Shape)
            {
            case Type.Sphere:
            {
                float minScale = VectorUtil.MinComponent(transform.localScale);
                return(Collision.SphereSphere(boneCenter, boneRadius, transform.position, minScale * Radius, out push));
            }

            case Type.Capsule:
            {
                float   minScale = VectorUtil.MinComponent(transform.localScale);
                Vector3 head     = transform.TransformPoint(0.5f * Height * Vector3.up);
                Vector3 tail     = transform.TransformPoint(0.5f * Height * Vector3.down);
                return(Collision.SphereCapsule(boneCenter, boneRadius, head, tail, minScale * Radius, out push));
            }

            case Type.Box:
            {
                Vector3 centerLs          = transform.InverseTransformPoint(boneCenter);
                Vector3 scaledHalfExtents = 0.5f * VectorUtil.ComponentWiseMult(transform.localScale, Dimensions);
                bool    collided          = Collision.SphereBox(centerLs, boneRadius, scaledHalfExtents, out push);
                if (!collided)
                {
                    return(false);
                }

                push = transform.TransformVector(push);
                return(true);
            }

                // TODO?

                /*
                 * case Type.InverseSphere:
                 * {
                 *  float minScale = VectorUtil.MinComponent(transform.localScale);
                 *  return Collision.SphereSphereInverse(boneCenter, boneRadius, transform.position, minScale * Radius, out push);
                 * }
                 *
                 * case Type.InverseCapsule:
                 * {
                 *  float minScale = VectorUtil.MinComponent(transform.localScale);
                 *  Vector3 head = transform.TransformPoint(0.5f * Height * Vector3.up);
                 *  Vector3 tail = transform.TransformPoint(0.5f * Height * Vector3.down);
                 *  return Collision.SphereCapsuleInverse(boneCenter, boneRadius, head, tail, minScale * Radius, out push);
                 * }
                 */
            }

            push = Vector3.zero;
            return(false);
        }
Пример #2
0
            public void Execute(BoingBones bones, float dt)
            {
                float maxCollisionResolutionPushLen = bones.MaxCollisionResolutionSpeed * dt;

                for (int iChain = 0; iChain < bones.BoneData.Length; ++iChain)
                {
                    var chain = bones.BoneChains[iChain];
                    var aBone = bones.BoneData[iChain];

                    if (aBone == null)
                    {
                        continue;
                    }

                    Vector3 gravityDt = chain.Gravity * dt;

                    // execute boing work
                    for (int iBone = 0; iBone < aBone.Length; ++iBone) // skip root
                    {
                        var bone = aBone[iBone];

                        // no gravity on root
                        if (iBone > 0)
                        {
                            bone.Instance.PositionSpring.Velocity += gravityDt;
                        }

                        if (chain.ParamsOverride == null)
                        {
                            bone.Instance.Execute(ref bones.Params, dt);
                        }
                        else
                        {
                            bone.Instance.Execute(ref chain.ParamsOverride.Params, dt);
                        }
                    }

                    var rootBone = aBone[0];
                    rootBone.ScaleWs = rootBone.BlendedScaleLs = rootBone.CachedScaleLs;

                    rootBone.UpdateBounds();
                    chain.Bounds = rootBone.Bounds;

                    Vector3 rootAnimPos = rootBone.Transform.position;

                    // apply length stiffness & volume preservation
                    for (int iBone = 1; iBone < aBone.Length; ++iBone) // skip root
                    {
                        var bone       = aBone[iBone];
                        var parentBone = aBone[bone.ParentIndex];

                        float tLengthStiffness = 1.0f - Mathf.Pow(1.0f - bone.LengthStiffness, 30.0f * dt); // a factor of 30.0f is what makes 0.5 length stiffness looks like 50% stiffness

                        Vector3 toParentVec           = parentBone.Instance.PositionSpring.Value - bone.Instance.PositionSpring.Value;
                        Vector3 toParentDir           = VectorUtil.NormalizeSafe(toParentVec, Vector3.zero);
                        float   fullyStiffToParentLen = (parentBone.Transform.position - bone.Transform.position).magnitude;
                        float   toParentLen           = toParentVec.magnitude;
                        float   fullyStiffLenDelta    = toParentLen - fullyStiffToParentLen;
                        float   toParentAdjustLen     = tLengthStiffness * fullyStiffLenDelta;

                        // length stiffness
                        {
                            bone.Instance.PositionSpring.Value += toParentAdjustLen * toParentDir;
                            Vector3 velocityInParentAdjustDir = Vector3.Project(bone.Instance.PositionSpring.Velocity, toParentDir);
                            bone.Instance.PositionSpring.Velocity -= tLengthStiffness * velocityInParentAdjustDir;
                        }

                        // bend angle cap
                        if (bone.BendAngleCap < MathUtil.Pi - MathUtil.Epsilon)
                        {
                            Vector3 animPos  = bone.Transform.position;
                            Vector3 posDelta = bone.Instance.PositionSpring.Value - rootAnimPos;
                            posDelta = VectorUtil.ClampBend(posDelta, animPos - rootAnimPos, bone.BendAngleCap);
                            bone.Instance.PositionSpring.Value = rootAnimPos + posDelta;
                        }

                        // volume preservation
                        if (bone.SquashAndStretch > 0.0f)
                        {
                            float toParentLenRatio        = toParentLen * MathUtil.InvSafe(fullyStiffToParentLen);
                            float volumePreservationScale = Mathf.Sqrt(1.0f / toParentLenRatio);
                            volumePreservationScale = Mathf.Clamp(volumePreservationScale, 1.0f / Mathf.Max(1.0f, chain.MaxStretch), Mathf.Max(1.0f, chain.MaxSquash));
                            Vector3 volumePreservationScaleVec = VectorUtil.ComponentWiseDivSafe(volumePreservationScale * Vector3.one, parentBone.ScaleWs);

                            bone.BlendedScaleLs =
                                Vector3.Lerp
                                (
                                    Vector3.Lerp
                                    (
                                        bone.CachedScaleLs,
                                        volumePreservationScaleVec,
                                        bone.SquashAndStretch
                                    ),
                                    bone.CachedScaleLs,
                                    bone.AnimationBlend
                                );
                        }
                        else
                        {
                            bone.BlendedScaleLs = bone.CachedScaleLs;
                        }

                        bone.ScaleWs = VectorUtil.ComponentWiseMult(parentBone.ScaleWs, bone.BlendedScaleLs);

                        bone.UpdateBounds();
                        chain.Bounds.Encapsulate(bone.Bounds);
                    }
                    chain.Bounds.Expand(0.2f * Vector3.one);

                    // Boing Kit colliders
                    if (chain.EnableBoingKitCollision)
                    {
                        foreach (var collider in bones.BoingColliders)
                        {
                            if (collider == null)
                            {
                                continue;
                            }

                            if (!chain.Bounds.Intersects(collider.Bounds))
                            {
                                continue;
                            }

                            foreach (var bone in aBone)
                            {
                                if (!bone.Bounds.Intersects(collider.Bounds))
                                {
                                    continue;
                                }

                                Vector3 push;
                                bool    collided = collider.Collide(bone.Instance.PositionSpring.Value, bones.MinScale * bone.CollisionRadius, out push);
                                if (!collided)
                                {
                                    continue;
                                }

                                bone.Instance.PositionSpring.Value    += VectorUtil.ClampLength(push, 0.0f, maxCollisionResolutionPushLen);
                                bone.Instance.PositionSpring.Velocity -= Vector3.Project(bone.Instance.PositionSpring.Velocity, push);
                            }
                        }
                    }

                    // Unity colliders
                    var sharedSphereCollider = BoingManager.SharedSphereCollider;
                    if (chain.EnableUnityCollision && sharedSphereCollider != null)
                    {
                        sharedSphereCollider.enabled = true;

                        foreach (var collider in bones.UnityColliders)
                        {
                            if (collider == null)
                            {
                                continue;
                            }

                            if (!chain.Bounds.Intersects(collider.bounds))
                            {
                                continue;
                            }

                            foreach (var bone in aBone)
                            {
                                if (!bone.Bounds.Intersects(collider.bounds))
                                {
                                    continue;
                                }

                                sharedSphereCollider.center = bone.Instance.PositionSpring.Value;
                                sharedSphereCollider.radius = bone.CollisionRadius;

                                Vector3 pushDir;
                                float   pushDist;
                                bool    collided =
                                    Physics.ComputePenetration
                                    (
                                        sharedSphereCollider, Vector3.zero, Quaternion.identity,
                                        collider, collider.transform.position, collider.transform.rotation,
                                        out pushDir, out pushDist
                                    );
                                if (!collided)
                                {
                                    continue;
                                }

                                bone.Instance.PositionSpring.Value    += VectorUtil.ClampLength(pushDir * pushDist, 0.0f, maxCollisionResolutionPushLen);
                                bone.Instance.PositionSpring.Velocity -= Vector3.Project(bone.Instance.PositionSpring.Velocity, pushDir);
                            }
                        }

                        sharedSphereCollider.enabled = false;
                    }

                    // self collision
                    if (chain.EnableInterChainCollision)
                    {
                        foreach (var bone in aBone)
                        {
                            for (int iOtherChain = iChain + 1; iOtherChain < bones.BoneData.Length; ++iOtherChain)
                            {
                                var otherChain = bones.BoneChains[iOtherChain];
                                var aOtherBone = bones.BoneData[iOtherChain];

                                if (aOtherBone == null)
                                {
                                    continue;
                                }

                                if (!otherChain.EnableInterChainCollision)
                                {
                                    continue;
                                }

                                if (!chain.Bounds.Intersects(otherChain.Bounds))
                                {
                                    continue;
                                }

                                foreach (var otherBone in aOtherBone)
                                {
                                    Vector3 push;
                                    bool    collided =
                                        Collision.SphereSphere
                                        (
                                            bone.Instance.PositionSpring.Value,
                                            bones.MinScale * bone.CollisionRadius,
                                            otherBone.Instance.PositionSpring.Value,
                                            bones.MinScale * otherBone.CollisionRadius,
                                            out push
                                        );
                                    if (!collided)
                                    {
                                        continue;
                                    }

                                    push = VectorUtil.ClampLength(push, 0.0f, maxCollisionResolutionPushLen);

                                    float pushRatio = otherBone.CollisionRadius * MathUtil.InvSafe(bone.CollisionRadius + otherBone.CollisionRadius);
                                    bone.Instance.PositionSpring.Value      += pushRatio * push;
                                    otherBone.Instance.PositionSpring.Value -= (1.0f - pushRatio) * push;

                                    bone.Instance.PositionSpring.Velocity      -= Vector3.Project(bone.Instance.PositionSpring.Velocity, push);
                                    otherBone.Instance.PositionSpring.Velocity -= Vector3.Project(otherBone.Instance.PositionSpring.Velocity, push);
                                }
                            }
                        }
                    }
                } // end: foreach bone chain
            }
Пример #3
0
        public void DrawGizmos()
        {
            switch (Shape)
            {
            case Type.Sphere:
                //case Type.InverseSphere: // TODO?
            {
                float minScale     = VectorUtil.MinComponent(transform.localScale);
                float scaledRadius = minScale * Radius;

                Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);

                if (Shape == Type.Sphere)
                {
                    Gizmos.color = new Color(1.0f, 1.0f, 1.0f, 0.5f);
                    Gizmos.DrawSphere(Vector3.zero, scaledRadius);
                }

                Gizmos.color = Color.white;
                Gizmos.DrawWireSphere(Vector3.zero, scaledRadius);

                Gizmos.matrix = Matrix4x4.identity;
            }
            break;

            case Type.Capsule:
                //case Type.InverseCapsule: // TODO?
            {
                float minScale         = VectorUtil.MinComponent(transform.localScale);
                float scaledRadius     = minScale * Radius;
                float scaledHalfHeight = 0.5f * minScale * Height;

                Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);

                if (Shape == Type.Capsule)
                {
                    Gizmos.color = new Color(1.0f, 1.0f, 1.0f, 0.5f);
                    Gizmos.DrawSphere(scaledHalfHeight * Vector3.up, scaledRadius);
                    Gizmos.DrawSphere(scaledHalfHeight * Vector3.down, scaledRadius);
                }

                Gizmos.color = Color.white;
                Gizmos.DrawWireSphere(scaledHalfHeight * Vector3.up, scaledRadius);
                Gizmos.DrawWireSphere(scaledHalfHeight * Vector3.down, scaledRadius);
                for (int i = 0; i < 4; ++i)
                {
                    float   theta  = i * MathUtil.HalfPi;
                    Vector3 offset = new Vector3(scaledRadius * Mathf.Cos(theta), 0.0f, scaledRadius * Mathf.Sin(theta));
                    Gizmos.DrawLine(offset + scaledHalfHeight * Vector3.up, offset + scaledHalfHeight * Vector3.down);
                }

                Gizmos.matrix = Matrix4x4.identity;
            }
            break;

            case Type.Box:
                //case Type.InverseBox: // TODO?
            {
                Vector3 scaledDimensions = VectorUtil.ComponentWiseMult(transform.localScale, Dimensions);
                Gizmos.matrix = transform.localToWorldMatrix;

                if (Shape == Type.Box)
                {
                    Gizmos.color = new Color(1.0f, 1.0f, 1.0f, 0.5f);
                    Gizmos.DrawCube(Vector3.zero, scaledDimensions);
                }

                Gizmos.color = Color.white;
                Gizmos.DrawWireCube(Vector3.zero, scaledDimensions);

                Gizmos.matrix = Matrix4x4.identity;
            }
            break;
            }
        }