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); } }
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); }
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; } }
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 }
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; }
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; }
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 ); } } } }