Example #1
0
        void FixedUpdate()
        {
            float dt = Time.fixedDeltaTime;

            Vector3 linearInputVec = Vector3.zero;

            if (Input.GetKey(KeyCode.W))
            {
                linearInputVec += Vector3.forward;
            }
            if (Input.GetKey(KeyCode.S))
            {
                linearInputVec += Vector3.back;
            }
            if (Input.GetKey(KeyCode.A))
            {
                linearInputVec += Vector3.left;
            }
            if (Input.GetKey(KeyCode.D))
            {
                linearInputVec += Vector3.right;
            }
            if (Input.GetKey(KeyCode.R))
            {
                linearInputVec += Vector3.up;
            }
            if (Input.GetKey(KeyCode.F))
            {
                linearInputVec += Vector3.down;
            }

            bool linearThrustOn = linearInputVec.sqrMagnitude > MathUtil.Epsilon;

            if (linearThrustOn)
            {
                linearInputVec    = linearInputVec.normalized * LinearThrust;
                m_linearVelocity += linearInputVec * dt;
                m_linearVelocity  = VectorUtil.ClampLength(m_linearVelocity, 0.0f, MaxLinearSpeed);
            }
            else
            {
                m_linearVelocity = VectorUtil.ClampLength(m_linearVelocity, 0.0f, Mathf.Max(0.0f, m_linearVelocity.magnitude - LinearDrag * dt));
            }

            float speed  = m_linearVelocity.magnitude;
            float tSpeed = speed * MathUtil.InvSafe(MaxLinearSpeed);

            Quaternion tiltRot          = Quaternion.identity;
            float      tHorizontal      = 1.0f;
            float      tHorizontalSpeed = 0.0f;

            if (speed > MathUtil.Epsilon)
            {
                Vector3 flatVel = m_linearVelocity;
                flatVel.y   = 0.0f;
                tHorizontal =
                    m_linearVelocity.magnitude > 0.01f
            ? 1.0f - Mathf.Clamp01(Mathf.Abs(m_linearVelocity.y) / m_linearVelocity.magnitude)
            : 0.0f;
                tHorizontalSpeed = Mathf.Min(1.0f, speed / Mathf.Max(MathUtil.Epsilon, MaxLinearSpeed)) * tHorizontal;
                Vector3 tiltAxis  = Vector3.Cross(Vector3.up, flatVel).normalized;
                float   tiltAngle = Tilt * MathUtil.Deg2Rad * tHorizontalSpeed;
                tiltRot = QuaternionUtil.AxisAngle(tiltAxis, tiltAngle);
            }

            float angularInput = 0.0f;

            if (Input.GetKey(KeyCode.Q))
            {
                angularInput -= 1.0f;
            }
            if (Input.GetKey(KeyCode.E))
            {
                angularInput += 1.0f;
            }

            bool largerMaxAngularSpeed = Input.GetKey(KeyCode.LeftControl);

            bool angularThurstOn = Mathf.Abs(angularInput) > MathUtil.Epsilon;

            if (angularThurstOn)
            {
                float maxAngularSpeed = MaxAngularSpeed * (largerMaxAngularSpeed ? 2.5f : 1.0f);
                angularInput      *= AngularThrust * MathUtil.Deg2Rad;
                m_angularVelocity += angularInput * dt;
                m_angularVelocity  = Mathf.Clamp(m_angularVelocity, -maxAngularSpeed * MathUtil.Deg2Rad, maxAngularSpeed * MathUtil.Deg2Rad);
            }
            else
            {
                m_angularVelocity -= Mathf.Sign(m_angularVelocity) * Mathf.Min(Mathf.Abs(m_angularVelocity), AngularDrag * MathUtil.Deg2Rad * dt);
            }
            m_yawAngle += m_angularVelocity * dt;
            Quaternion yawRot = QuaternionUtil.AxisAngle(Vector3.up, m_yawAngle);

            m_hoverCenter += m_linearVelocity * dt;
            m_hoverPhase  += Time.deltaTime;

            Vector3 hoverVec =
                0.05f * Mathf.Sin(1.37f * m_hoverPhase) * Vector3.right
                + 0.05f * Mathf.Sin(1.93f * m_hoverPhase + 1.234f) * Vector3.forward
                + 0.04f * Mathf.Sin(0.97f * m_hoverPhase + 4.321f) * Vector3.up;

            hoverVec *= Hover;

            Quaternion hoverQuat = Quaternion.FromToRotation(Vector3.up, hoverVec + Vector3.up);

            transform.position = m_hoverCenter + hoverVec;
            transform.rotation = tiltRot * yawRot * hoverQuat;

            if (Motor != null)
            {
                float motorAngularSpeedDeg = Mathf.Lerp(MotorBaseAngularSpeed, MotorMaxAngularSpeed, tHorizontalSpeed);
                m_motorAngle       += motorAngularSpeedDeg * MathUtil.Deg2Rad * dt;
                Motor.localRotation = QuaternionUtil.AxisAngle(Vector3.up, m_motorAngle - m_yawAngle);
            }

            if (BubbleEmitter != null)
            {
                var emission = BubbleEmitter.emission;
                emission.rateOverTime = Mathf.Lerp(BubbleBaseEmissionRate, BubbleMaxEmissionRate, tSpeed);
            }

            if (Eyes != null)
            {
                m_blinkTimer -= dt;
                if (m_blinkTimer <= 0.0f)
                {
                    bool doubleBlink = !m_lastBlinkWasDouble && Random.Range(0.0f, 1.0f) > 0.75f;
                    m_blinkTimer =
                        doubleBlink
                ? 0.2f
                : BlinkInterval + Random.Range(1.0f, 2.0f);
                    m_lastBlinkWasDouble = doubleBlink;

                    m_eyeScaleSpring.Value.y       = 0.0f;
                    m_eyePositionLsSpring.Value.y -= 0.025f;
                }

                Eyes.localScale    = m_eyeScaleSpring.TrackDampingRatio(m_eyeInitScale, 30.0f, 0.8f, dt);
                Eyes.localPosition = m_eyePositionLsSpring.TrackDampingRatio(m_eyeInitPositionLs, 30.0f, 0.8f, dt);
            }
        }
Example #2
0
        public static bool SphereBox(Vector3 centerOffsetA, float radiusA, Vector3 halfExtentB, out Vector3 push)
        {
            push = Vector3.zero;

            Vector3 closestOnB =
                new Vector3
                (
                    Mathf.Clamp(centerOffsetA.x, -halfExtentB.x, halfExtentB.x),
                    Mathf.Clamp(centerOffsetA.y, -halfExtentB.y, halfExtentB.y),
                    Mathf.Clamp(centerOffsetA.z, -halfExtentB.z, halfExtentB.z)
                );

            Vector3 vec = centerOffsetA - closestOnB;
            float   dd  = vec.sqrMagnitude;

            if (dd > radiusA * radiusA)
            {
                return(false);
            }

            int numInBoxAxes =
                ((centerOffsetA.x <-halfExtentB.x || centerOffsetA.x> halfExtentB.x) ? 0 : 1)
                + ((centerOffsetA.y <-halfExtentB.y || centerOffsetA.y> halfExtentB.y) ? 0 : 1)
                + ((centerOffsetA.z <-halfExtentB.z || centerOffsetA.z> halfExtentB.z) ? 0 : 1);

            switch (numInBoxAxes)
            {
            case 0: // hit corner
            case 1: // hit edge
            case 2: // hit face
            {
                push = VectorUtil.NormalizeSafe(vec, Vector3.right) * (radiusA - Mathf.Sqrt(dd));
            }
            break;

            case 3: // inside
            {
                Vector3 penetration =
                    new Vector3
                    (
                        halfExtentB.x - Mathf.Abs(centerOffsetA.x) + radiusA,
                        halfExtentB.y - Mathf.Abs(centerOffsetA.y) + radiusA,
                        halfExtentB.z - Mathf.Abs(centerOffsetA.z) + radiusA
                    );

                if (penetration.x < penetration.y)
                {
                    if (penetration.x < penetration.z)
                    {
                        push = new Vector3(Mathf.Sign(centerOffsetA.x) * penetration.x, 0.0f, 0.0f);
                    }
                    else
                    {
                        push = new Vector3(0.0f, 0.0f, Mathf.Sign(centerOffsetA.z) * penetration.z);
                    }
                }
                else
                {
                    if (penetration.y < penetration.z)
                    {
                        push = new Vector3(0.0f, Mathf.Sign(centerOffsetA.y) * penetration.y, 0.0f);
                    }
                    else
                    {
                        push = new Vector3(0.0f, 0.0f, Mathf.Sign(centerOffsetA.z) * penetration.z);
                    }
                }
            }
            break;
            }

            return(true);
        }
Example #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;
            }
        }
Example #4
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.GlobalScale = rootBone.BlendedScale = rootBone.CachedScale;

                    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.GlobalScale);

                            bone.BlendedScale =
                                Vector3.Lerp
                                (
                                    Vector3.Lerp
                                    (
                                        bone.CachedScale,
                                        volumePreservationScaleVec,
                                        bone.SquashAndStretch
                                    ),
                                    bone.CachedScale,
                                    bone.AnimationBlend
                                );
                        }
                        else
                        {
                            bone.BlendedScale = bone.CachedScale;
                        }

                        bone.GlobalScale = VectorUtil.ComponentWiseMult(parentBone.GlobalScale, bone.BlendedScale);

                        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
            }
Example #5
0
                public void PullResults(BoingBones bones)
                {
                    for (int iChain = 0; iChain < bones.BoneData.Length; ++iChain)
                    {
                        var chain = bones.BoneChains[iChain];
                        var aBone = bones.BoneData[iChain];

                        if (aBone == null)
                        {
                            continue;
                        }

                        // must cache before manipulating bone transforms
                        // otherwise, we'd cache delta propagated down from parent bones
                        foreach (var bone in aBone)
                        {
                            bone.CachedPosition = bone.Transform.position;
                            bone.CachedRotation = bone.Transform.rotation;
                        }

                        // blend bone position
                        for (int iBone = 0; iBone < aBone.Length; ++iBone)
                        {
                            var bone = aBone[iBone];

                            // skip fixed root
                            if (iBone == 0 && !chain.LooseRoot)
                            {
                                bone.BlendedPosition = bone.CachedPosition;
                                continue;
                            }

                            bone.BlendedPosition =
                                Vector3.Lerp
                                (
                                    bone.Instance.PositionSpring.Value,
                                    bone.CachedPosition,
                                    bone.AnimationBlend
                                );
                        }

                        // rotation delta back-propagation
                        if (bones.EnableRotationEffect)
                        {
                            for (int iBone = 0; iBone < aBone.Length; ++iBone)
                            {
                                var bone = aBone[iBone];

                                // skip fixed root
                                if (iBone == 0 && !chain.LooseRoot)
                                {
                                    bone.BlendedRotation = bone.CachedRotation;
                                    continue;
                                }

                                if (bone.ChildIndices == null)
                                {
                                    if (bone.ParentIndex >= 0)
                                    {
                                        var parentBone = aBone[bone.ParentIndex];
                                        bone.BlendedRotation = parentBone.BlendedRotation * (parentBone.RotationInverse * bone.CachedRotation);
                                    }

                                    continue;
                                }

                                Vector3    bonePos        = bone.CachedPosition;
                                Vector3    boneBlendedPos = bone.BlendedPosition;
                                Quaternion boneRot        = bone.CachedRotation;
                                Quaternion boneRotInv     = Quaternion.Inverse(boneRot);

                                Vector4 childRotDeltaPsVecAccumulator = Vector3.zero;
                                float   totalWeight = 0.0f;
                                foreach (int iChild in bone.ChildIndices)
                                {
                                    var childBone = aBone[iChild];

                                    Vector3 childPos         = childBone.CachedPosition;
                                    Vector3 childPosDelta    = childPos - bonePos;
                                    Vector3 childPosDeltaDir = VectorUtil.NormalizeSafe(childPosDelta, Vector3.zero);

                                    Vector3 childBlendedPos         = childBone.BlendedPosition;
                                    Vector3 childBlendedPosDelta    = childBlendedPos - boneBlendedPos;
                                    Vector3 childBlendedPosDeltaDir = VectorUtil.NormalizeSafe(childBlendedPosDelta, Vector3.zero);

                                    Quaternion childRotDelta   = Quaternion.FromToRotation(childPosDeltaDir, childBlendedPosDeltaDir);
                                    Quaternion childRotDeltaPs = boneRotInv * childRotDelta;

                                    Vector4 childRotDeltaPsVec = QuaternionUtil.ToVector4(childRotDeltaPs);
                                    float   weight             = Mathf.Max(MathUtil.Epsilon, chain.MaxLengthFromRoot - childBone.LengthFromRoot);
                                    childRotDeltaPsVecAccumulator += weight * childRotDeltaPsVec;
                                    totalWeight += weight;
                                }

                                if (totalWeight > 0.0f)
                                {
                                    Vector4 avgChildRotDeltaPsVec = childRotDeltaPsVecAccumulator / totalWeight;
                                    bone.RotationBackPropDeltaPs = QuaternionUtil.FromVector4(avgChildRotDeltaPsVec);
                                    bone.BlendedRotation         = (boneRot * bone.RotationBackPropDeltaPs) * boneRot;
                                }
                                else if (bone.ParentIndex >= 0)
                                {
                                    var parentBone = aBone[bone.ParentIndex];
                                    bone.BlendedRotation = parentBone.BlendedRotation * (parentBone.RotationInverse * bone.CachedRotation);
                                }
                            }
                        }

                        // write blended position & adjusted rotation into final transforms
                        for (int iBone = 0; iBone < aBone.Length; ++iBone)
                        {
                            var bone = aBone[iBone];

                            // skip fixed root
                            if (iBone == 0 && !chain.LooseRoot)
                            {
                                bone.Instance.PositionSpring.Reset(bone.CachedPosition);
                                bone.Instance.RotationSpring.Reset(bone.CachedRotation);
                                continue;
                            }

                            bone.Transform.position   = bone.BlendedPosition;
                            bone.Transform.rotation   = bone.BlendedRotation;
                            bone.Transform.localScale = bone.BlendedScale;
                        }
                    }

                    bones.LastPullResultsFrame = Time.frameCount;
                }
Example #6
0
                public void AccumulateTarget(ref Params p, ref BoingEffector.Params effector)
                {
                    Vector3 effectRefPos =
                        effector.Bits.IsBitSet(BoingWork.EffectorFlags.ContinuousMotion)
              ? VectorUtil.GetClosestPointOnSegment(PositionOrigin, effector.PrevPosition, effector.CurrPosition)
              : effector.CurrPosition;

                    Vector3 deltaPos = PositionOrigin - effectRefPos;

                    Vector3 deltaPos3D = deltaPos;

                    if (p.Bits.IsBitSet(ReactorFlags.TwoDDistanceCheck))
                    {
                        switch (p.TwoDPlane)
                        {
                        case TwoDPlaneEnum.XY: deltaPos.z = 0.0f; break;

                        case TwoDPlaneEnum.XZ: deltaPos.y = 0.0f; break;

                        case TwoDPlaneEnum.YZ: deltaPos.x = 0.0f; break;
                        }
                    }

                    bool inRange =
                        Mathf.Abs(deltaPos.x) <= effector.Radius &&
                        Mathf.Abs(deltaPos.y) <= effector.Radius &&
                        Mathf.Abs(deltaPos.z) <= effector.Radius &&
                        deltaPos.sqrMagnitude <= effector.Radius * effector.Radius;

                    if (!inRange)
                    {
                        return;
                    }

                    float deltaDist  = deltaPos.magnitude;
                    float tDeltaDist =
                        effector.Radius - effector.FullEffectRadius > MathUtil.Epsilon
            ? 1.0f - Mathf.Clamp01((deltaDist - effector.FullEffectRadius) / (effector.Radius - effector.FullEffectRadius))
            : 1.0f;

                    Vector3 upWsPos     = m_upWs;
                    Vector3 upWsRot     = m_upWs;
                    Vector3 deltaDirPos = VectorUtil.NormalizeSafe(deltaPos3D, m_upWs);
                    Vector3 deltaDirRot = deltaDirPos;

                    if (p.Bits.IsBitSet(ReactorFlags.TwoDPositionInfluence))
                    {
                        switch (p.TwoDPlane)
                        {
                        case TwoDPlaneEnum.XY: deltaDirPos.z = 0.0f; upWsPos.z = 0.0f; break;

                        case TwoDPlaneEnum.XZ: deltaDirPos.y = 0.0f; upWsPos.y = 0.0f; break;

                        case TwoDPlaneEnum.YZ: deltaDirPos.x = 0.0f; upWsPos.x = 0.0f; break;
                        }

                        if (upWsPos.sqrMagnitude < MathUtil.Epsilon)
                        {
                            switch (p.TwoDPlane)
                            {
                            case TwoDPlaneEnum.XY: upWsPos = Vector3.up; break;

                            case TwoDPlaneEnum.XZ: upWsPos = Vector3.forward; break;

                            case TwoDPlaneEnum.YZ: upWsPos = Vector3.up; break;
                            }
                        }
                        else
                        {
                            upWsPos.Normalize();
                        }

                        deltaDirPos = VectorUtil.NormalizeSafe(deltaDirPos, upWsPos);
                    }

                    if (p.Bits.IsBitSet(ReactorFlags.TwoDRotationInfluence))
                    {
                        switch (p.TwoDPlane)
                        {
                        case TwoDPlaneEnum.XY: deltaDirRot.z = 0.0f; upWsRot.z = 0.0f; break;

                        case TwoDPlaneEnum.XZ: deltaDirRot.y = 0.0f; upWsRot.y = 0.0f; break;

                        case TwoDPlaneEnum.YZ: deltaDirRot.x = 0.0f; upWsRot.x = 0.0f; break;
                        }

                        if (upWsRot.sqrMagnitude < MathUtil.Epsilon)
                        {
                            switch (p.TwoDPlane)
                            {
                            case TwoDPlaneEnum.XY: upWsRot = Vector3.up;      break;

                            case TwoDPlaneEnum.XZ: upWsRot = Vector3.forward; break;

                            case TwoDPlaneEnum.YZ: upWsRot = Vector3.up;      break;
                            }
                        }
                        else
                        {
                            upWsRot.Normalize();
                        }

                        deltaDirRot = VectorUtil.NormalizeSafe(deltaDirRot, upWsRot);
                    }

                    if (p.Bits.IsBitSet(ReactorFlags.EnablePositionEffect))
                    {
                        Vector3 moveVec = tDeltaDist * p.MoveReactionMultiplier * effector.MoveDistance * deltaDirPos;
                        PositionTarget += moveVec;

                        PositionSpring.Velocity += tDeltaDist * p.LinearImpulseMultiplier * effector.LinearImpulse * effector.LinearVelocityDir;
                    }

                    if (p.Bits.IsBitSet(ReactorFlags.EnableRotationEffect))
                    {
                        Vector3 rotAxis = VectorUtil.NormalizeSafe(Vector3.Cross(upWsRot, deltaDirRot), VectorUtil.FindOrthogonal(upWsRot));
                        Vector3 rotVec  = tDeltaDist * p.RotationReactionMultiplier * effector.RotateAngle * rotAxis;
                        RotationTarget += QuaternionUtil.ToVector4(QuaternionUtil.FromAngularVector(rotVec));

                        Vector3 angularImpulseDir     = VectorUtil.NormalizeSafe(Vector3.Cross(effector.LinearVelocityDir, deltaDirRot - 0.01f * Vector3.up), rotAxis);
                        float   angularImpulseMag     = tDeltaDist * p.AngularImpulseMultiplier * effector.AngularImpulse;
                        Vector4 angularImpulseDirQuat = QuaternionUtil.ToVector4(QuaternionUtil.FromAngularVector(angularImpulseDir));
                        RotationSpring.VelocityVec += angularImpulseMag * angularImpulseDirQuat;
                    }

                    ++m_numEffectors;
                }
Example #7
0
        public override void PrepareExecute()
        {
            base.PrepareExecute();

            // repurpose rotation effect flag for bone rotation delta back-propagation
            Params.Bits.SetBit(BoingWork.ReactorFlags.EnableRotationEffect, false);

            float dt = Time.fixedDeltaTime;

            m_minScale = Mathf.Min(transform.localScale.x, transform.localScale.y, transform.localScale.z);

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

                if (aBone == null || chain.Root == null || aBone.Length == 0)
                {
                    continue;
                }

                // update length from root
                float maxLengthFromRoot = 0.0f;
                foreach (var bone in aBone)
                {
                    if (bone.ParentIndex < 0)
                    {
                        bone.LengthFromRoot = 0.0f;
                        continue;
                    }

                    var   parentBone     = aBone[bone.ParentIndex];
                    float distFromParent = Vector3.Distance(bone.Transform.position, parentBone.Transform.position);
                    bone.LengthFromRoot = parentBone.LengthFromRoot + distFromParent;
                    maxLengthFromRoot   = Mathf.Max(maxLengthFromRoot, bone.LengthFromRoot);
                }
                float maxLengthFromRootInv = MathUtil.InvSafe(maxLengthFromRoot);

                // set up bones
                foreach (var bone in aBone)
                {
                    // evaluate curves
                    float tBone = bone.LengthFromRoot * maxLengthFromRootInv;
                    bone.AnimationBlend   = Chain.EvaluateCurve(chain.AnimationBlendCurveType, tBone, chain.AnimationBlendCustomCurve);
                    bone.LengthStiffness  = Chain.EvaluateCurve(chain.LengthStiffnessCurveType, tBone, chain.LengthStiffnessCustomCurve);
                    bone.PoseStiffness    = Chain.EvaluateCurve(chain.PoseStiffnessCurveType, tBone, chain.PoseStiffnessCustomCurve);
                    bone.BendAngleCap     = chain.MaxBendAngleCap * MathUtil.Deg2Rad * Chain.EvaluateCurve(chain.BendAngleCapCurveType, tBone, chain.BendAngleCapCustomCurve);
                    bone.CollisionRadius  = chain.MaxCollisionRadius * Chain.EvaluateCurve(chain.CollisionRadiusCurveType, tBone, chain.CollisionRadiusCustomCurve);
                    bone.SquashAndStretch = Chain.EvaluateCurve(chain.SquashAndStretchCurveType, tBone, chain.SquashAndStretchCustomCurve);
                }

                // compute target transform
                var     rootBone    = aBone[0];
                Vector3 rootAnimPos = rootBone.Transform.position;
                foreach (var bone in aBone)
                {
                    bone.RotationInverse       = Quaternion.Inverse(bone.Transform.rotation);
                    bone.SpringRotation        = bone.Instance.RotationSpring.ValueQuat;
                    bone.SpringRotationInverse = Quaternion.Inverse(bone.SpringRotation);

                    Vector3    targetPos = bone.Transform.position;
                    Quaternion targetRot = bone.Transform.rotation;

                    // compute translation & rotation in parent space
                    if (bone.ParentIndex >= 0)
                    {
                        // TODO: use parent spring transform to compute blended position & rotation

                        var parentBone = aBone[bone.ParentIndex];

                        Vector3 parentAnimPos   = parentBone.Transform.position;
                        Vector3 parentSpringPos = parentBone.Instance.PositionSpring.Value;

                        Vector3    springPosPs = parentBone.SpringRotationInverse * (bone.Instance.PositionSpring.Value - parentSpringPos);
                        Quaternion springRotPs = parentBone.SpringRotationInverse * bone.Instance.RotationSpring.ValueQuat;

                        Vector3    animPos   = bone.Transform.position;
                        Quaternion animRot   = bone.Transform.rotation;
                        Vector3    animPosPs = parentBone.RotationInverse * (animPos - parentAnimPos);
                        Quaternion animRotPs = parentBone.RotationInverse * animRot;

                        // apply pose stiffness
                        float      tPoseStiffness = bone.PoseStiffness;
                        Vector3    blendedPosPs   = Vector3.Lerp(springPosPs, animPosPs, tPoseStiffness);
                        Quaternion blendedRotPs   = Quaternion.Slerp(springRotPs, animRotPs, tPoseStiffness);

                        targetPos = parentSpringPos + (parentBone.SpringRotation * blendedPosPs);
                        targetRot = parentBone.SpringRotation * blendedRotPs;

                        // bend angle cap
                        if (bone.BendAngleCap < MathUtil.Pi - MathUtil.Epsilon)
                        {
                            Vector3 targetPosDelta = targetPos - rootAnimPos;
                            targetPosDelta = VectorUtil.ClampBend(targetPosDelta, animPos - rootAnimPos, bone.BendAngleCap);
                            targetPos      = rootAnimPos + targetPosDelta;
                        }
                    }

                    // do we need target-level collision?

                    /*
                     * // Boing Kit colliders
                     * if (chain.EnableBoingKitCollision)
                     * {
                     * foreach (var collider in BoingColliders)
                     * {
                     *  if (collider == null)
                     *    continue;
                     *
                     *  Vector3 push;
                     *  bool collided = collider.Collide(targetPos, MinScale * bone.CollisionRadius, out push);
                     *  if (!collided)
                     *    continue;
                     *
                     *  targetPos += push;
                     * }
                     * }
                     *
                     * // Unity colliders
                     * if (chain.EnableUnityCollision)
                     * {
                     * foreach (var rigidbody in UnityRigidBodies)
                     * {
                     *  if (rigidbody == null)
                     *    continue;
                     *
                     *  var collider = rigidbody.GetComponent<Collider>();
                     *  if (collider == null)
                     *    continue;
                     *
                     *  if (!bone.Bounds.Intersects(collider.bounds))
                     *    continue;
                     *
                     *  SharedSphereCollider.center = targetPos;
                     *  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;
                     *
                     *  targetPos += pushDir * pushDist;
                     * }
                     * }
                     */

                    if (chain.ParamsOverride == null)
                    {
                        bone.Instance.PrepareExecute
                        (
                            ref Params,
                            targetPos,
                            targetRot,
                            MinScale,
                            true
                        );
                    }
                    else
                    {
                        bone.Instance.PrepareExecute
                        (
                            ref chain.ParamsOverride.Params,
                            targetPos,
                            targetRot,
                            MinScale,
                            true
                        );
                    }
                }
            }
        }