public override int GetHashCode() { unchecked { return((Damping.GetHashCode() * 397) ^ Friction.GetHashCode()); } }
private void Update(EvaluationContext context) { var v = Value.GetValue(context); var damping = Damping.GetValue(context); var f = (float)(damping * EvaluationContext.LastFrameDuration).Clamp(0f, 1f); _dampedValue = MathUtils.Lerp(v, _dampedValue, f); Result.Value = _dampedValue; }
/// <summary> /// Update is called once per frame /// </summary> public override void UpdateCameraPosition(float lookHorizontal, float lookVertical) { desiredPosition = GetCameraDesiredPosition(lookHorizontal, lookVertical); if (movementSpringDampingEnabled) { transform.position = Damping.SpringDamping(transform.position, desiredPosition, ref movementVelocity, movementSpringStiffness, movementSpringDamping); } else { transform.position = desiredPosition; } }
private void Update(EvaluationContext context) { var v = Value.GetValue(context); var damping = Damping.GetValue(context); var t = context.LocalFxTime; if (Math.Abs(t - _lastEvalTime) < 0.001f) { return; } _lastEvalTime = t; const float FrameRate = 60f; var method = (Methods)Method.GetValue(context).Clamp(0, 1); switch (method) { case Methods.LinearInterpolation: var framesPassed = (int)((Playback.LastFrameDuration * FrameRate) - 0.5f).Clamp(0, 5) + 1; for (int stepIndex = 0; stepIndex < framesPassed; stepIndex++) { _dampedValue = MathUtils.Lerp(v, _dampedValue, damping); } break; case Methods.DampedSpring: _dampedValue = MathUtils.SpringDamp(v, _dampedValue, ref _velocity, 0.5f / (damping + 0.001f), (float)Playback.LastFrameDuration); break; } // Prevent NaN if (float.IsNaN(_dampedValue) || float.IsNaN(_velocity)) { _dampedValue = 0; _velocity = 0; } Result.Value = _dampedValue; }
public static void EditorGUISpringDampingStat(ref float springStiffness, ref float springDamping) { EditorGUILayout.BeginHorizontal(); springStiffness = Mathf.Abs(EditorGUILayout.FloatField("Stiffness", springStiffness)); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); springDamping = Mathf.Abs(EditorGUILayout.FloatField("Damping", springDamping)); EditorGUILayout.EndHorizontal(); float dampingRatio = Damping.GetSpringDampingRatio(springStiffness, springDamping); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Damping ratio", "" + dampingRatio); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); string dampingType = ""; if (dampingRatio < 0.99f) { dampingType = "Underdamped"; } else if (dampingRatio > 1.00f) { dampingType = "Overdamped"; } else { dampingType = "Critically damped"; } EditorGUILayout.LabelField("Damping type", "" + dampingType); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); bool res = GUILayout.Button("Compute critically damped from stiffness"); if (res) { springDamping = 2 * Mathf.Sqrt(springStiffness); } EditorGUILayout.EndHorizontal(); }
internal void Update(double TimeElapsed) { if (Camera.CurrentRestriction == CameraRestrictionMode.NotAvailable) { { // pitch double targetY = Train.Specs.CurrentAverageAcceleration; const double accelerationSlow = 0.25; const double accelerationFast = 2.0; if (SlowY < targetY) { SlowY += accelerationSlow * TimeElapsed; if (SlowY > targetY) { SlowY = targetY; } } else if (SlowY > targetY) { SlowY -= accelerationSlow * TimeElapsed; if (SlowY < targetY) { SlowY = targetY; } } if (FastY < targetY) { FastY += accelerationFast * TimeElapsed; if (FastY > targetY) { FastY = targetY; } } else if (FastY > targetY) { FastY -= accelerationFast * TimeElapsed; if (FastY < targetY) { FastY = targetY; } } double diffY = FastY - SlowY; diffY = (double)Math.Sign(diffY) * diffY * diffY; Pitch = 0.5 * Math.Atan(0.1 * diffY); if (Pitch > 0.1) { Pitch = 0.1; } if (PitchDamping == null) { PitchDamping = new Damping(6.0, 0.3); } PitchDamping.Update(TimeElapsed, ref Pitch, true); } { // roll int c = Train.DriverCar; double frontRadius = Train.Cars[c].FrontAxle.Follower.CurveRadius; double rearRadius = Train.Cars[c].RearAxle.Follower.CurveRadius; double radius; if (frontRadius != 0.0 & rearRadius != 0.0) { if (frontRadius != -rearRadius) { radius = 2.0 * frontRadius * rearRadius / (frontRadius + rearRadius); } else { radius = 0.0; } } else if (frontRadius != 0.0) { radius = 2.0 * frontRadius; } else if (rearRadius != 0.0) { radius = 2.0 * rearRadius; } else { radius = 0.0; } double targetX; if (radius != 0.0) { double speed = Train.Cars[c].CurrentSpeed; targetX = speed * speed / radius; } else { targetX = 0.0; } const double accelerationSlow = 1.0; const double accelerationFast = 10.0; if (SlowX < targetX) { SlowX += accelerationSlow * TimeElapsed; if (SlowX > targetX) { SlowX = targetX; } } else if (SlowX > targetX) { SlowX -= accelerationSlow * TimeElapsed; if (SlowX < targetX) { SlowX = targetX; } } if (FastX < targetX) { FastX += accelerationFast * TimeElapsed; if (FastX > targetX) { FastX = targetX; } } else if (FastX > targetX) { FastX -= accelerationFast * TimeElapsed; if (FastX < targetX) { FastX = targetX; } } double diffX = SlowX - FastX; diffX = (double)Math.Sign(diffX) * diffX * diffX; Roll = 0.5 * Math.Atan(0.3 * diffX); if (RollDamping == null) { RollDamping = new Damping(6.0, 0.3); } RollDamping.Update(TimeElapsed, ref Roll, true); } } }
// update damping internal static void UpdateDamping(ref Damping Damping, double TimeElapsed, ref double Angle) { if (TimeElapsed < 0.0) { TimeElapsed = 0.0; } else if (TimeElapsed > 1.0) { TimeElapsed = 1.0; } if (Damping != null) { if (Damping.CurrentTimeDelta > Damping.NaturalTime) { // update double newDerivative; if (Damping.NaturalFrequency == 0.0) { newDerivative = 0.0; } else if (Damping.DampingRatio == 0.0) { newDerivative = Damping.OriginalDerivative * Math.Cos(Damping.NaturalFrequency * Damping.CurrentTimeDelta) - Damping.NaturalFrequency * Math.Sin(Damping.NaturalFrequency * Damping.CurrentTimeDelta); } else if (Damping.DampingRatio < 1.0) { newDerivative = Math.Exp(-Damping.DampingRatio * Damping.NaturalFrequency * Damping.CurrentTimeDelta) * (Damping.NaturalDampingFrequency * Damping.OriginalDerivative * Math.Cos(Damping.NaturalDampingFrequency * Damping.CurrentTimeDelta) - (Damping.NaturalDampingFrequency * Damping.NaturalDampingFrequency + Damping.DampingRatio * Damping.NaturalFrequency * (Damping.DampingRatio * Damping.NaturalFrequency + Damping.OriginalDerivative)) * Math.Sin(Damping.NaturalDampingFrequency * Damping.CurrentTimeDelta)) / Damping.NaturalDampingFrequency; } else if (Damping.DampingRatio == 1.0) { newDerivative = Math.Exp(-Damping.NaturalFrequency * Damping.CurrentTimeDelta) * (Damping.OriginalDerivative - Damping.NaturalFrequency * (Damping.NaturalFrequency + Damping.OriginalDerivative) * Damping.CurrentTimeDelta); } else { newDerivative = Math.Exp(-Damping.DampingRatio * Damping.NaturalFrequency * Damping.CurrentTimeDelta) * (Damping.NaturalDampingFrequency * Damping.OriginalDerivative * Math.Cosh(Damping.NaturalDampingFrequency * Damping.CurrentTimeDelta) + (Damping.NaturalDampingFrequency * Damping.NaturalDampingFrequency - Damping.DampingRatio * Damping.NaturalFrequency * (Damping.DampingRatio * Damping.NaturalFrequency + Damping.OriginalDerivative)) * Math.Sinh(Damping.NaturalDampingFrequency * Damping.CurrentTimeDelta)) / Damping.NaturalDampingFrequency; } double a = Damping.TargetAngle - Damping.OriginalAngle; Damping.OriginalAngle = Damping.CurrentAngle; Damping.TargetAngle = Angle; double b = Damping.TargetAngle - Damping.OriginalAngle; double r = b == 0.0 ? 1.0 : a / b; Damping.OriginalDerivative = newDerivative * r; if (Damping.NaturalTime > 0.0) { Damping.CurrentTimeDelta = Damping.CurrentTimeDelta % Damping.NaturalTime; } } { // perform double newValue; if (Damping.NaturalFrequency == 0.0) { newValue = 1.0; } else if (Damping.DampingRatio == 0.0) { newValue = Math.Cos(Damping.NaturalFrequency * Damping.CurrentTimeDelta) + Damping.OriginalDerivative * Math.Sin(Damping.NaturalFrequency * Damping.CurrentTimeDelta) / Damping.NaturalFrequency; } else if (Damping.DampingRatio < 1.0) { double n = (Damping.OriginalDerivative + Damping.NaturalFrequency * Damping.DampingRatio) / Damping.NaturalDampingFrequency; newValue = Math.Exp(-Damping.DampingRatio * Damping.NaturalFrequency * Damping.CurrentTimeDelta) * (Math.Cos(Damping.NaturalDampingFrequency * Damping.CurrentTimeDelta) + n * Math.Sin(Damping.NaturalDampingFrequency * Damping.CurrentTimeDelta)); } else if (Damping.DampingRatio == 1.0) { newValue = Math.Exp(-Damping.NaturalFrequency * Damping.CurrentTimeDelta) * (1.0 + (Damping.OriginalDerivative + Damping.NaturalFrequency) * Damping.CurrentTimeDelta); } else { double n = (Damping.OriginalDerivative + Damping.NaturalFrequency * Damping.DampingRatio) / Damping.NaturalDampingFrequency; newValue = Math.Exp(-Damping.DampingRatio * Damping.NaturalFrequency * Damping.CurrentTimeDelta) * (Math.Cosh(Damping.NaturalDampingFrequency * Damping.CurrentTimeDelta) + n * Math.Sinh(Damping.NaturalDampingFrequency * Damping.CurrentTimeDelta)); } Damping.CurrentValue = newValue; Damping.CurrentAngle = Damping.TargetAngle * (1.0 - newValue) + Damping.OriginalAngle * newValue; Damping.CurrentTimeDelta += TimeElapsed; Angle = Damping.CurrentAngle; } } }
public BridgeSample(Microsoft.Xna.Framework.Game game) : base(game) { // Add basic force effects. Simulation.ForceEffects.Add(new Gravity()); Simulation.ForceEffects.Add(new Damping()); // Add a ground plane. RigidBody groundPlane = new RigidBody(new PlaneShape(Vector3F.UnitY, 0)) { Name = "GroundPlane", // Names are not required but helpful for debugging. MotionType = MotionType.Static, }; Simulation.RigidBodies.Add(groundPlane); // We add another damping effect that acts only on the suspension bridge parts. // This damping uses higher damping factors than the standard damping. It makes the // bridge movement smoother and more stable. // We use a ListAreaOfEffect. So the additional damping acts only on bodies in this list. ListAreaOfEffect boardList = new ListAreaOfEffect(new List <RigidBody>()); Damping damping = new Damping { AreaOfEffect = boardList, AngularDamping = 1f, LinearDamping = 0.5f }; Simulation.ForceEffects.Add(damping); const int numberOfBoards = 20; BoxShape boardShape = new BoxShape(0.8f, 0.1f, 1.5f); RigidBody lastBoard = null; for (int i = 0; i < numberOfBoards; i++) { // A single plank of the bridge. RigidBody body = new RigidBody(boardShape) { Pose = new Pose(new Vector3F(-10 + boardShape.WidthX * i, 4, 0)) }; Simulation.RigidBodies.Add(body); // Add the body to the list of the additional damping force effect. boardList.RigidBodies.Add(body); if (lastBoard != null) { // Connect the last body with current body using a hinge. HingeJoint hinge = new HingeJoint { BodyA = lastBoard, // The attachment point is at the right side of the board. // --> To define the constraint anchor orientation: // The columns are the axes. We set the local z axis in the first column. This is // the hinge axis. In the other two columns we set two orthonormal vectors. // (All three columns are orthonormal and form a valid rotation matrix.) AnchorPoseALocal = new Pose(new Vector3F(boardShape.WidthX / 2, 0, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), BodyB = body, // The attachment point is at the left side of the board. // The anchor orientation is defined as above. AnchorPoseBLocal = new Pose(new Vector3F(-boardShape.WidthX / 2, 0, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), CollisionEnabled = false, // ErrorReduction and Softness are tweaked to get a stable and smooth bridge // movement. ErrorReduction = 0.3f, Softness = 0.00005f, }; Simulation.Constraints.Add(hinge); } else if (i == 0) { // To attach the bridge somewhere, connect the the first board to a fixed position in the // world. HingeJoint hinge = new HingeJoint { BodyA = Simulation.World, AnchorPoseALocal = new Pose(new Vector3F(-9, 3, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), BodyB = body, AnchorPoseBLocal = new Pose(new Vector3F(-boardShape.WidthX / 2, 0, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), }; Simulation.Constraints.Add(hinge); } if (i == numberOfBoards - 1) { // To attach the bridge somewhere, connect the the last board to a fixed position in the // world. HingeJoint hinge = new HingeJoint { BodyA = Simulation.World, AnchorPoseALocal = new Pose(new Vector3F(9, 3, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), BodyB = body, AnchorPoseBLocal = new Pose(new Vector3F(boardShape.WidthX / 2, 0, 0), new Matrix33F(0, 0, -1, 0, 1, 0, 1, 0, 0)), }; Simulation.Constraints.Add(hinge); } lastBoard = body; } // The bridge is ready. // Now, add some ramps so that the character controller can walk up to the bridge. BoxShape rampShape = new BoxShape(10, 10, 2); RigidBody ramp0 = new RigidBody(rampShape) { Pose = new Pose(new Vector3F(-12.5f, -3f, 0), Matrix33F.CreateRotationZ(0.3f)), MotionType = MotionType.Static, }; Simulation.RigidBodies.Add(ramp0); RigidBody ramp1 = new RigidBody(rampShape) { Pose = new Pose(new Vector3F(12.5f, -3f, 0), Matrix33F.CreateRotationZ(-0.3f)), MotionType = MotionType.Static, }; Simulation.RigidBodies.Add(ramp1); // Drop a few light boxes onto the bridge. BoxShape boxShape = new BoxShape(1, 1, 1); MassFrame boxMass = MassFrame.FromShapeAndDensity(boxShape, Vector3F.One, 100, 0.01f, 3); for (int i = 0; i < 10; i++) { Vector3F randomPosition = new Vector3F(RandomHelper.Random.NextFloat(-10, 10), 5, 0); QuaternionF randomOrientation = RandomHelper.Random.NextQuaternionF(); RigidBody body = new RigidBody(boxShape, boxMass, null) { Pose = new Pose(randomPosition, randomOrientation), }; Simulation.RigidBodies.Add(body); } }
/** * This is the optimal camera position that the camera moves towards */ public Vector3 GetCameraDesiredPosition(float lookHorizontal, float lookVertical) { if (target == null) { return(lastCameraTargetPosition); } if (cameraType == ChaseCameraType.StayBehind) { Vector3 rotation = target.transform.rotation.eulerAngles; idealSpherical.polar = -rotation.y * Mathf.Deg2Rad - (Mathf.PI * 0.5f); if (lookHorizontalSpringDamped) { lookHorizontalActual = Damping.SpringDamping(lookHorizontalActual, lookHorizontal, ref lookHorizontalVelocity, lookHorizontalSpringStiffness, lookHorizontalSpringDamping); idealSpherical.polar += lookHorizontalActual * (Mathf.PI * 0.99f); } if (lookVerticalSpringDamped) { lookVerticalActual = Damping.SpringDamping(lookVerticalActual, lookVertical, ref lookVerticalVelocity, lookVerticalSpringStiffness, lookVerticalSpringDamping); idealSpherical.elevation = Mathf.Clamp(cameraPitch + lookVerticalActual * Mathf.PI, -Mathf.PI * 0.45f, Mathf.PI * 0.45f); } Quaternion q = Quaternion.FromToRotation(transform.TransformDirection(Vector3.up), target.position); transform.rotation = q * transform.rotation; } else { if (cameraType == ChaseCameraType.LooseAllowMovementUnderCamera) { Vector3 displacement = transform.position - target.position; if (displacement.sqrMagnitude < distance * distance) { return(lastCameraTargetPosition); } } idealSpherical.polar = Mathf.Atan2(transform.position.z - target.position.z, transform.position.x - target.position.x); } Vector3 direction = idealSpherical.ToCartesian(); lastCameraTargetPosition = target.position + direction; if (virtualCameraCollisionTest) { raycastCounter++; if (raycastCounter > 2) { raycastCounter = 0; } raycastResult[raycastCounter] = Physics.Raycast(target.position + raycastOffset[raycastCounter], direction, distance); RaycastHit[] hitInfo = Physics.SphereCastAll(target.position, virtualCameraCollisionRadius, direction, distance); float newCameraDistance = distance; bool partialOcclusion = !raycastResult[0] || !raycastResult[1] || !raycastResult[2]; // allow partially occluded object if hit distance is less than 25% of pref. distance if (hitInfo.Length > 0) { for (int i = 0; i < hitInfo.Length; i++) { bool partiallyOcclusionDistance = hitInfo[i].distance < distance * 0.25f; if (!partiallyOcclusionDistance || !partialOcclusion) { newCameraDistance = hitInfo[i].distance; break; } } } float currentDistance = idealSpherical.radius; if (newCameraDistance < currentDistance || newCameraDistance - currentDistance <= Mathf.Epsilon) // don't damp if target is reached { idealSpherical.radius = newCameraDistance; vccMoveBackVelocity = 0; } else { idealSpherical.radius = Damping.SpringDamping(idealSpherical.radius, newCameraDistance, ref vccMoveBackVelocity, vccMoveBackSpringStiffness, vccMoveBackSpringDamping); } // if distance was updated, then recalculate position if (currentDistance != idealSpherical.radius) { direction = idealSpherical.ToCartesian(); lastCameraTargetPosition = target.position + direction; } } return(lastCameraTargetPosition); }
// ... void LateUpdate() { // Follow position. transform.position = Damping.dampVector3(transform.position, target.position, followTargetSpeed, Time.deltaTime); if (Cursor.lockState == CursorLockMode.Locked) { // Rotation. // Can't get it to smooth when rotating, so I just set the physica time step to 0.01f (half of default). targetRotationEuler.y += mouseInput.x * mouseRotateAmount; targetRotationEuler.x += -mouseInput.y * mouseRotateAmount; targetRotationEuler.x = Mathf.Clamp(targetRotationEuler.x, lookUpDownRange.x, lookUpDownRange.y); targetRotationEuler.z += mouseInput.x * rotateZSpeed; rotationEuler = Damping.dampVector3(rotationEuler, targetRotationEuler, mouseRotateSpeed, Time.deltaTime); transform.eulerAngles = rotationEuler; //transform.rotation *= Quaternion.AngleAxis(mouseRotateSpeed * Time.deltaTime, Vector3.up); // Offset framing. float playerSpeed = player.rb.velocity.magnitude; if (playerSpeed < minPlayerSpeedForOffsetFraming) { offsetMouseFramePosition = offsetStartPosition; } else { if (mouseInput.x > minMouseMoveForOffsetFraming) { offsetMouseFramePosition.x = -offsetFramingAmount; } else if (mouseInput.x < -minMouseMoveForOffsetFraming) { offsetMouseFramePosition.x = offsetFramingAmount; } if (mouseInput.y > minMouseMoveForOffsetFraming) { offsetMouseFramePosition.y = -offsetFramingAmount; } else if (mouseInput.y < -minMouseMoveForOffsetFraming) { offsetMouseFramePosition.y = offsetFramingAmount; } } offsetPositionTarget = Damping.dampVector3(offsetPositionTarget, offsetMouseFramePosition, offsetFramingSpeed, Time.deltaTime); // Balance out rotation around Z back to 0.0f. targetRotationEuler.z = Damping.dampFloat(targetRotationEuler.z, 0.0f, resetZRotationSpeed, Time.deltaTime); // Zoom. // Scrolling happens as 0.1f increments. x10.0f to make it 1.0f. float scroll = Input.GetAxis("Mouse ScrollWheel") * 10.0f; zoomDistance -= scroll * mouseZoomAmount; zoomDistance = Mathf.Clamp(zoomDistance, mouseZoomMin, mouseZoomMax); // Player occlusion check and zoom. RaycastHit hitInfo; checkIfPlayerOccluded(out hitInfo); //float nearestDistance = checkCameraPoints(out hitInfo); Vector3 finalOffsetPositionTarget; RaycastHit hitInfo2; Transform cameraTransform = camera.transform; Vector3 directionToTarget = (target.position - cameraTransform.position).normalized; Vector3 end = target.position - (directionToTarget * (zoomDistance + occlusionZoomOffset)); Physics.Raycast(end, Vector3.down, out hitInfo2, occlusionRaycastDownDistance); Debug.DrawLine(end, end + (Vector3.down * occlusionRaycastDownDistance), Color.white); if (hitInfo.collider) { //finalOffsetPositionTarget = offsetPositionTarget.normalized * nearestDistance; finalOffsetPositionTarget = offsetPositionTarget.normalized * hitInfo.distance; } //if (hitInfo2.collider) //{ // float curveResult = 1.0f - occlisionRaycastDownCurve.Evaluate(hitInfo2.distance / occlusionRaycastDownDistance); // finalOffsetPositionTarget = (offsetPositionTarget.normalized * zoomDistance) * curveResult; //} //else if (hitInfo.collider) //{ // finalOffsetPositionTarget = Vector3.zero; //} else { finalOffsetPositionTarget = offsetPositionTarget.normalized * zoomDistance; } offset.localPosition = Damping.dampVector3(offset.localPosition, finalOffsetPositionTarget, mouseZoomSpeed, Time.deltaTime); } }
public DriverBody(TrainBase train) { this.Train = train; PitchDamping = new Damping(6.0, 0.3); RollDamping = new Damping(6.0, 0.3); }
// Handles the subscriber's NewMeasurements event. private void DataSubscriber_NewMeasurements(object sender, EventArgs <ICollection <IMeasurement> > e) { // Gather statistics. Interlocked.Add(ref m_measurementCount, e.Argument.Count); // Queue the measurements up in the buffer. foreach (IMeasurement measurement in e.Argument) { if (m_channelIndexes.ContainsKey(measurement.ID)) { // Perform a rough per signal upsample if minimum sample rate is not met if (m_sampleRate < MINIMUM_SAMPLE_RATE) { IMeasurement upsampledMeasurement; double frequency = measurement.Value; for (int i = 0; i < MINIMUM_SAMPLE_RATE / m_sampleRate; i++) { upsampledMeasurement = Measurement.Clone(measurement); upsampledMeasurement.Value = Timbre.PureTone(frequency, i, 0, MINIMUM_SAMPLE_RATE) * Damping.Natural(i, MINIMUM_SAMPLE_RATE / m_sampleRate, MINIMUM_SAMPLE_RATE) * (Int16.MaxValue * 0.90D); m_buffer.Enqueue(upsampledMeasurement); } } else { m_buffer.Enqueue(measurement); } } } // If we've managed to buffer a full second of data, // stop the timeout timer and start the dump timer. // The dump timer is sending measurements to the sound card // so change the playback state to playing. if (m_dumpTimer != null && !m_dumpTimer.IsRunning && m_buffer.Count / 2 > m_sampleRate) { if (m_timeoutTimer != null) { m_timeoutTimer.Stop(); } m_dumpTimer.Start(); OnStateChanged(PlaybackState.Playing); } }
// ... void LateUpdate() { transform.rotation = Damping.dampQuaternion(transform.rotation, Quaternion.LookRotation(camera.transform.forward), rotateToCameraForwardSpeed, Time.deltaTime); }
protected bool Equals(Dynamics other) { return(Damping.Equals(other.Damping) && Friction.Equals(other.Friction)); }