diff --git a/.vs/OpenRelativity/v15/Browse.VC.db b/.vs/OpenRelativity/v15/Browse.VC.db index f8fa9f35..8624524c 100644 Binary files a/.vs/OpenRelativity/v15/Browse.VC.db and b/.vs/OpenRelativity/v15/Browse.VC.db differ diff --git a/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide b/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide index 420a3839..5c4592b0 100644 Binary files a/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide and b/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide differ diff --git a/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide-shm b/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide-shm index ca12a9fd..a9f4e8d4 100644 Binary files a/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide-shm and b/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide-shm differ diff --git a/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide-wal b/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide-wal index 04734678..ad4020a1 100644 Binary files a/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide-wal and b/.vs/OpenRelativity/v15/Server/sqlite3/storage.ide-wal differ diff --git a/Assets/Example/Materials/DefaultPhysic.physicMaterial b/Assets/Example/Materials/DefaultPhysic.physicMaterial new file mode 100644 index 00000000..2faab0bf Binary files /dev/null and b/Assets/Example/Materials/DefaultPhysic.physicMaterial differ diff --git a/Assets/Example/Materials/DefaultPhysic.physicMaterial.meta b/Assets/Example/Materials/DefaultPhysic.physicMaterial.meta new file mode 100644 index 00000000..d8490fdd --- /dev/null +++ b/Assets/Example/Materials/DefaultPhysic.physicMaterial.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 45ce7002213212f4d93fc6903e7b2cb0 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 13400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Example/Resources/GameObjects/Rigidbody1.prefab b/Assets/Example/Resources/GameObjects/Rigidbody1.prefab index 69fc28cc..71987889 100644 Binary files a/Assets/Example/Resources/GameObjects/Rigidbody1.prefab and b/Assets/Example/Resources/GameObjects/Rigidbody1.prefab differ diff --git a/Assets/Example/Scenes/newFeatures.unity b/Assets/Example/Scenes/newFeatures.unity index fd96650b..cdc9d00c 100644 Binary files a/Assets/Example/Scenes/newFeatures.unity and b/Assets/Example/Scenes/newFeatures.unity differ diff --git a/Assets/OpenRelativity/Scripts/GameState.cs b/Assets/OpenRelativity/Scripts/GameState.cs index 25e0cf0c..f29758aa 100644 --- a/Assets/OpenRelativity/Scripts/GameState.cs +++ b/Assets/OpenRelativity/Scripts/GameState.cs @@ -15,14 +15,6 @@ public class GameState : MonoBehaviour //Player orientation private Quaternion orientation = Quaternion.identity; - //world rotation so that we can transform between the two - private Matrix4x4 worldRotation; - //Player's velocity in vector format - private Vector3 playerVelocityVector; - //Player's acceleration in vector format - private Vector3 playerAccelerationVector; - //Lorentz transformation matrix between world and player rest frame - private Matrix4x4 playerLorentzMatrix; //grab the player's transform so that we can use it public Transform playerTransform; @@ -30,24 +22,12 @@ public class GameState : MonoBehaviour private bool movementFrozen = false; //player Velocity as a scalar magnitude public double playerVelocity { get; set; } - //time passed since last frame in the world frame - private double deltaTimeWorld; - //time passed since last frame in the player frame - private double deltaTimePlayer; - //total time passed in the player frame - private double totalTimePlayer; - //total time passed in the world frame - private double totalTimeWorld; //speed of light private double c = 200; //Speed of light that is affected by the Unity editor public double totalC = 200; //max speed the player can achieve (starting value accessible from Unity Editor) public double maxPlayerSpeed; - //max speed, for game use, not accessible from Unity Editor - private double maxSpeed; - //speed of light squared, kept for easy access in many calculations - private double cSqrd; //Use this to determine the state of the color shader. If it's True, all you'll see is the lorenz transform. private bool shaderOff = false; @@ -57,10 +37,6 @@ public class GameState : MonoBehaviour //Did we hit the shader key? public bool shaderKeyDown { get; set; } - - //This is a value that gets used in many calculations, so we calculate it each frame - private double sqrtOneMinusVSquaredCWDividedByCSquared; - //This is the equivalent of the above value for an accelerated player frame //private double inverseAcceleratedGamma; @@ -73,32 +49,30 @@ public class GameState : MonoBehaviour public Vector3 cameraForward { get; set; } public float deltaCameraAngle { get; set; } - - #endregion #region Properties public bool MovementFrozen { get { return movementFrozen; } set { movementFrozen = value; } } - public Matrix4x4 WorldRotation { get { return worldRotation; } } + public Matrix4x4 WorldRotation { get; private set; } public Quaternion Orientation { get { return orientation; } } - public Vector3 PlayerVelocityVector { get { return playerVelocityVector; } set { playerVelocityVector = value; } } - public Vector3 PlayerAccelerationVector { get { return playerAccelerationVector; } set { playerAccelerationVector = value; } } - public Vector3 PlayerAngularVelocityVector { get { if (deltaTimePlayer == 0) { return Vector3.zero; } else { return (float)(deltaCameraAngle * Mathf.Deg2Rad / deltaTimePlayer) * playerTransform.up; } } } - public Matrix4x4 PlayerLorentzMatrix { get { return playerLorentzMatrix; } } + public Vector3 PlayerVelocityVector { get; set; } + public Vector3 PlayerAccelerationVector { get; set; } + public Vector3 PlayerAngularVelocityVector { get { if (DeltaTimePlayer == 0) { return Vector3.zero; } else { return (float)(deltaCameraAngle * Mathf.Deg2Rad / DeltaTimePlayer) * playerTransform.up; } } } + public Matrix4x4 PlayerLorentzMatrix { get; private set; } public double PctOfSpdUsing { get { return pctOfSpdUsing; } set { pctOfSpdUsing = value; } } public double PlayerVelocity { get { return playerVelocity; } } - public double SqrtOneMinusVSquaredCWDividedByCSquared { get { return sqrtOneMinusVSquaredCWDividedByCSquared; } } + public double SqrtOneMinusVSquaredCWDividedByCSquared { get; private set; } //public double InverseAcceleratedGamma { get { return inverseAcceleratedGamma; } } - public double DeltaTimeWorld { get { return deltaTimeWorld; } } + public double DeltaTimeWorld { get; private set; } private double _fixedDeltaTimeWorld; public double FixedDeltaTimeWorld { get { if (conformalMap == null) { - return Time.fixedDeltaTime / sqrtOneMinusVSquaredCWDividedByCSquared; + return Time.fixedDeltaTime / SqrtOneMinusVSquaredCWDividedByCSquared; } else { return _fixedDeltaTimeWorld; @@ -106,15 +80,15 @@ public double FixedDeltaTimeWorld { } } //public double FixedDeltaTimeWorld { get { return Time.fixedDeltaTime / inverseAcceleratedGamma; } } - public double DeltaTimePlayer { get { return deltaTimePlayer; } } + public double DeltaTimePlayer { get; private set; } public double FixedDeltaTimePlayer { get { return Time.fixedDeltaTime; } } - public double TotalTimePlayer { get { return totalTimePlayer; } } - public double TotalTimeWorld { get { return totalTimeWorld; } } - public double SpeedOfLight { get { return c; } set { c = value; cSqrd = value * value; } } - public double SpeedOfLightSqrd { get { return cSqrd; } } + public double TotalTimePlayer { get; private set; } + public double TotalTimeWorld { get; private set; } + public double SpeedOfLight { get { return c; } set { c = value; SpeedOfLightSqrd = value * value; } } + public double SpeedOfLightSqrd { get; private set; } public bool keyHit { get; set; } - public double MaxSpeed { get { return maxSpeed; } set { maxSpeed = value; } } + public double MaxSpeed { get; set; } public bool HasWorldGravity { get; set; } @@ -129,30 +103,35 @@ public double FixedDeltaTimeWorld { public const int splitDistance = 21000; #endregion + public bool IsInitDone + { + get + { + return SqrtOneMinusVSquaredCWDividedByCSquared != 0; + } + } + public void Awake() { + // This is the "flag" that lets us know initialization is not complete. + SqrtOneMinusVSquaredCWDividedByCSquared = 0; + if (conformalMap != null) { conformalMap.state = this; } //Initialize the player's speed to zero - playerVelocityVector = Vector3.zero; playerVelocity = 0; - //If the player starts out resting on a surface, then their initial acceleration is due to gravity. - // If the player is in free fall (i.e. "not affected by gravity" in the sense of Einstein equivalance principle,) - // then their acceleration is zero. - //oldPlayerVelocityVector = Vector3.zero; - playerAccelerationVector = Vector3.zero; //Set our constants MaxSpeed = maxPlayerSpeed; pctOfSpdUsing = NORM_PERCENT_SPEED; c = totalC; - cSqrd = c * c; - //And ensure that the game starts/ + SpeedOfLightSqrd = c * c; + //And ensure that the game starts movementFrozen = false; menuKeyDown = false; shaderKeyDown = false; @@ -161,7 +140,7 @@ public void Awake() playerRotation = Vector3.zero; deltaRotation = Vector3.zero; - playerLorentzMatrix = Matrix4x4.identity; + PlayerLorentzMatrix = Matrix4x4.identity; } public void reset() { @@ -228,15 +207,15 @@ public void LateUpdate() //if we reached max speed, forward or backwards, keep at max speed - if (playerVelocityVector.magnitude >= (float)MaxSpeed - .01f) + if (PlayerVelocityVector.magnitude >= (float)MaxSpeed - .01f) { - playerVelocityVector = playerVelocityVector.normalized * ((float)MaxSpeed - .01f); + PlayerVelocityVector = PlayerVelocityVector.normalized * ((float)MaxSpeed - .01f); } //update our player velocity - playerVelocity = playerVelocityVector.magnitude; - Vector4 vpc = new Vector4(-playerVelocityVector.x, -playerVelocityVector.y, -playerVelocityVector.z, 0) / (float)c; - playerLorentzMatrix = SRelativityUtil.GetLorentzTransformMatrix(vpc); + playerVelocity = PlayerVelocityVector.magnitude; + Vector4 vpc = -PlayerVelocityVector / (float)c; + PlayerLorentzMatrix = SRelativityUtil.GetLorentzTransformMatrix(vpc); //update our acceleration (which relates rapidities rather than velocities) //playerAccelerationVector = (playerVelocityVector.Gamma() * playerVelocityVector - oldPlayerVelocityVector.Gamma() * oldPlayerVelocityVector) / Time.deltaTime; @@ -259,9 +238,9 @@ public void LateUpdate() //Send velocities and acceleration to shader Shader.SetGlobalVector("_vpc", vpc); - Shader.SetGlobalVector("_pap", playerAccelerationVector); + Shader.SetGlobalVector("_pap", PlayerAccelerationVector); Shader.SetGlobalVector("_avp", PlayerAngularVelocityVector); - Shader.SetGlobalMatrix("_vpcLorentzMatrix", playerLorentzMatrix); + Shader.SetGlobalMatrix("_vpcLorentzMatrix", PlayerLorentzMatrix); /****************************** * PART TWO OF ALGORITHM @@ -269,27 +248,27 @@ public void LateUpdate() * THE TIME PASSED IN WORLD FRAME * ****************************/ //find this constant - sqrtOneMinusVSquaredCWDividedByCSquared = (double)Math.Sqrt(1 - (playerVelocity * playerVelocity) / cSqrd); + SqrtOneMinusVSquaredCWDividedByCSquared = Math.Sqrt(1 - (playerVelocity * playerVelocity) / SpeedOfLightSqrd); //inverseAcceleratedGamma = SRelativityUtil.InverseAcceleratedGamma(playerAccelerationVector, playerVelocityVector, deltaTimePlayer); //Set by Unity, time since last update - deltaTimePlayer = (double)Time.deltaTime; + DeltaTimePlayer = (double)Time.deltaTime; //Get the total time passed of the player and world for display purposes - totalTimePlayer += deltaTimePlayer; + TotalTimePlayer += DeltaTimePlayer; //if (!double.IsNaN(inverseAcceleratedGamma)) - if (!double.IsNaN(sqrtOneMinusVSquaredCWDividedByCSquared)) + if (!double.IsNaN(SqrtOneMinusVSquaredCWDividedByCSquared)) { //Get the delta time passed for the world, changed by relativistic effects - deltaTimeWorld = deltaTimePlayer / sqrtOneMinusVSquaredCWDividedByCSquared; + DeltaTimeWorld = DeltaTimePlayer / SqrtOneMinusVSquaredCWDividedByCSquared; //NOTE: Dan says, there should also be a correction for acceleration in the 00 component of the metric tensor. // This correction is dependent on object position and needs to factored by the RelativisticObject itself. // (Pedagogical explanation at http://aether.lbl.gov/www/classes/p139/homework/eight.pdf. // See "The Metric for a Uniformly Accelerating System.") - totalTimeWorld += deltaTimeWorld; + TotalTimeWorld += DeltaTimeWorld; } //Set our rigidbody's velocity - if (!double.IsNaN(deltaTimePlayer) && !double.IsNaN(sqrtOneMinusVSquaredCWDividedByCSquared)) + if (!double.IsNaN(DeltaTimePlayer) && !double.IsNaN(SqrtOneMinusVSquaredCWDividedByCSquared)) { } @@ -313,7 +292,7 @@ public void LateUpdate() orientation = Quaternion.AngleAxis(playerRotation.y, Vector3.up) * Quaternion.AngleAxis(playerRotation.x, Vector3.right); Quaternion WorldOrientation = Quaternion.Inverse(orientation); Normalize(orientation); - worldRotation = CreateFromQuaternion(WorldOrientation); + WorldRotation = CreateFromQuaternion(WorldOrientation); //Add up our rotation so that we know where the character (NOT CAMERA) should be facing playerRotation += deltaRotation; @@ -331,21 +310,21 @@ public void LateUpdate() private void FixedUpdate() { if (!MovementFrozen && - !double.IsNaN(deltaTimePlayer) && - sqrtOneMinusVSquaredCWDividedByCSquared > 0 && - !double.IsNaN(sqrtOneMinusVSquaredCWDividedByCSquared) && SpeedOfLight > 0) + !double.IsNaN(DeltaTimePlayer) && + SqrtOneMinusVSquaredCWDividedByCSquared > 0 && + !double.IsNaN(SqrtOneMinusVSquaredCWDividedByCSquared) && SpeedOfLight > 0) { if (conformalMap != null) { // Assume local player coordinates are comoving Vector4 piw4 = conformalMap.ComoveOptical((float)FixedDeltaTimePlayer, playerTransform.position); playerTransform.position = piw4; - _fixedDeltaTimeWorld = piw4.w / sqrtOneMinusVSquaredCWDividedByCSquared; + _fixedDeltaTimeWorld = piw4.w / SqrtOneMinusVSquaredCWDividedByCSquared; } Rigidbody playerRB = GameObject.FindGameObjectWithTag(Tags.playerMesh).GetComponent(); - Vector3 velocity = -playerVelocityVector; - playerRB.velocity = velocity / (float)sqrtOneMinusVSquaredCWDividedByCSquared; + Vector3 velocity = -PlayerVelocityVector; + playerRB.velocity = velocity / (float)SqrtOneMinusVSquaredCWDividedByCSquared; } } #region Matrix/Quat math diff --git a/Assets/OpenRelativity/Scripts/MovementScripts.cs b/Assets/OpenRelativity/Scripts/MovementScripts.cs index 0f53f603..412f46c8 100644 --- a/Assets/OpenRelativity/Scripts/MovementScripts.cs +++ b/Assets/OpenRelativity/Scripts/MovementScripts.cs @@ -9,7 +9,7 @@ public class MovementScripts : MonoBehaviour { //Consts private const float SLOW_DOWN_RATE = 0.75f; - private const float ACCEL_RATE = 7.5f; + private const float ACCEL_RATE = 2.0f; private const int INIT_FRAME_WAIT = 5; private const float DEGREE_TO_RADIAN_CONST = 57.2957795f; public bool useGravity = false; diff --git a/Assets/OpenRelativity/Scripts/Objects/RelativisticObject.cs b/Assets/OpenRelativity/Scripts/Objects/RelativisticObject.cs index bb0fd894..12bfdf50 100644 --- a/Assets/OpenRelativity/Scripts/Objects/RelativisticObject.cs +++ b/Assets/OpenRelativity/Scripts/Objects/RelativisticObject.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; //using System.Linq; //For debugging purposes only using UnityEngine; @@ -7,10 +8,21 @@ namespace OpenRelativity.Objects { public class RelativisticObject : MonoBehaviour { - #region Rigid body physics - //Since we don't have direct access to the level of rigid bodies or PhysX in Unity, - // we need to manually update some relativistic rigid body mechanics, for the time-being. + #region Public Settings + public bool isKinematic = false; + public bool isLightMapStatic = false; + public bool useGravity; public Vector3 initialViw; + public Vector3 initialAviw; + #endregion + + #region Rigid body physics + // How long (in seconds) do we wait before we detect collisions with an object we just collided with? + private float collideWait = 0f; + // If we have intrinsic proper acceleration besides gravity, how quickly does it degrade? + // (This isn't physically how we want to handle changing acceleration, but it's a stop-gap to experiment with smooth-ish changes in proper acceleration.) + private float accelDrag = 0f; + private Vector3 _viw = Vector3.zero; public Vector3 viw { @@ -18,69 +30,30 @@ public Vector3 viw { return _viw; } - //Changing velocities lose continuity of position, - // unless we transform the world position to optical position with the old velocity, - // and inverse transform the optical position with the new the velocity. - // (This keeps the optical and Minkowski position fixed.) + set { // Skip this all, if the change is negligible. - if (isKinematic || (value - viw).sqrMagnitude < SRelativityUtil.divByZeroCutoff) + if (IsNaNOrInf(value.sqrMagnitude) || (value - _viw).sqrMagnitude < SRelativityUtil.divByZeroCutoff) { return; } - // This makes instantiation cleaner: - initialViw = value; - - // Under instantaneous changes in velocity, the optical position should be invariant. - piw = ((Vector4)((Vector4)piw).WorldToOptical(_viw, Get4Acceleration())).OpticalToWorldHighPrecision(value, Get4Acceleration()); - if (!nonrelativisticShader && !IsNaNOrInf(piw.magnitude)) + if (isKinematic) { - transform.position = piw; + _viw = value; + return; } - _viw = value; - // Also update the Rigidbody, if any - UpdateRigidbodyVelocity(value, aviw); - - // Update the shader parameters if necessary - UpdateShaderParams(); - } - } - public Matrix4x4 viwLorentz { get; private set; } - - public void SetViwAndPosition(Vector3 newViw, Vector3 newPiw) - { - piw = newPiw; - _viw = newViw; - initialViw = newViw; - if (nonrelativisticShader) - { - newPiw = ((Vector4)newPiw).WorldToOptical(newViw, Get4Acceleration()); - } - transform.position = newPiw; - - if (nonrelativisticShader) - { - if (contractor == null) SetUpContractor(); - contractor.position = transform.position; - transform.localPosition = Vector3.zero; - ContractLength(); - } - MarkStaticColliderPos(); + // This keeps the public parameter up-to-date: + initialViw = value; - //Also update the Rigidbody, if any - if (!isKinematic) - { - UpdateRigidbodyVelocity(newViw, aviw); + UpdateViwAndAccel(_viw, _properAiw, value, _properAiw); } - - UpdateShaderParams(); } + public Matrix4x4 viwLorentz { get; private set; } //Store this object's angular velocity here. - public Vector3 initialAviw; private Vector3 _aviw; public Vector3 aviw { @@ -100,7 +73,63 @@ public Vector3 aviw } //Store object's acceleration; - public Vector3 properAiw = Vector3.zero; + public Vector3 _properAiw; + public Vector3 properAiw + { + get + { + return _properAiw; + } + + set + { + // Skip this all, if the change is negligible. + if (IsNaNOrInf(value.sqrMagnitude) || (value - _properAiw).sqrMagnitude < SRelativityUtil.divByZeroCutoff) + { + return; + } + + if (isKinematic) + { + _properAiw = value; + return; + } + + UpdateViwAndAccel(_viw, _properAiw, _viw, value); + } + } + + public void UpdateViwAndAccel(Vector3 vi, Vector3 ai, Vector3 vf, Vector3 af) + { + //Changing velocities lose continuity of position, + // unless we transform the world position to optical position with the old velocity, + // and inverse transform the optical position with the new the velocity. + // (This keeps the optical position fixed.) + + piw = ((Vector4)((Vector4)piw).WorldToOptical(vi, ai)).OpticalToWorldHighPrecision(vf, af); + + if (!IsNaNOrInf(piw.magnitude)) + { + if (nonrelativisticShader) + { + UpdateContractorPosition(); + } + else + { + transform.position = piw; + } + } + + _viw = vf; + _properAiw = af; + + // Also update the Rigidbody and Collider, if any + UpdateRigidbodyVelocity(_viw, _aviw); + UpdateColliderPosition(); + + // Update the shader parameters if necessary + UpdateShaderParams(); + } public bool isRBKinematic { @@ -114,41 +143,8 @@ public bool isRBKinematic } } - public bool useGravity; - - //This is a velocity we "sleep" the rigid body at: - private const float sleepVelocity = 0.01f; - //Gravity might keep the velocity above this, so we also check whether the position is changing: - private const float sleepDistance = 0.01f; - private const float sleepAngle = 6f; - private Vector3 sleepOldPosition; - private Vector3 sleepOldOrientation; - //Once we're below the sleep velocity threshold, this is how many frames we wait for - // before sleeping the object: - private const int sleepFrameDelay = 3; - private int sleepFrameCounter; - private bool isRestingOnCollider; //TODO: Rigidbody doesn't stay asleep. Figure out why, and get rid of this: private bool isSleeping; - //Length contraction and rounding error pulls sleeping objects off the surfaces they rest on. - // Save the original orientation on sleep, and force it back while sleeping. - private Quaternion sleepRotation; - //This is a cap on penalty method collision. - //(It's roughly the Unity units equivalent of Young's Modulus of diamond.) - private const float maxYoungsModulus = 1220.0e9f; - //The center of mass calculation in the rigidbody becomes non-physical when we transform the collider - public Vector3 opticalWorldCenterOfMass { get; set; } - //private const float drag = 0.1f; - //private const float angularDrag = 0.1f; - public float initBounciness = 0.4f; - //During collision, viw getters and setters trigger many "enter" rather than "stay" events, so we smooth this: - private class RecentCollision - { - public double LastTime { get; set; } - public Collider Collider { get; set; } - } - private List collidedWith; - private float collideAgainWait = 0.3f; #endregion //Keep track of our own Mesh Filter private MeshFilter meshFilter; @@ -203,6 +199,8 @@ public void ResetLocalTime() //private int? oldParentID; //Store world position, mostly for a nonrelativistic shader: public Vector3 piw { get; set; } + //Store rotation quaternion + public Quaternion riw { get; set; } //We use an attached shader to transform the collider verts: public ComputeShader colliderShader; @@ -212,7 +210,6 @@ public void ResetLocalTime() private Vector3[] trnsfrmdMeshVerts; //If we have a collider to transform, we cache it here private Collider[] myColliders; - private PhysicMaterial myPhysicMaterial; //If we specifically have a mesh collider, we need to know to transform the verts of the mesh itself. private bool myColliderIsMesh; private bool myColliderIsBox; @@ -223,22 +220,6 @@ public void ResetLocalTime() private Rigidbody myRigidbody; //If we have a Renderer, we cache it, too. public Renderer myRenderer { get; set; } - //Did we collide last frame? - private bool didCollide; - //What was the translational velocity result? - private Vector3 collisionResultVel3; - //What was the angular velocity result? - private Vector3 collisionResultAngVel3; - //Time when the collision started - public double collideTimeStart { get; set; } - //Collision-softening time - //public float collideSoftenTime = 0.2f; - //For penalty methods, we need an intermediate collision velocity result - private Vector3 oldCollisionResultVel3; - private Vector3 oldCollisionResultAngVel3; - //If the shader is nonrelativistic, and if the object is static, it helps to save and restore the initial position - public bool isKinematic = false; - public bool isLightMapStatic = false; public void MarkStaticColliderPos() { @@ -275,10 +256,8 @@ private bool IsNaNOrInf(float p) private void UpdateMeshCollider(MeshCollider transformCollider) { - //Debug.Log("Updating mesh collider."); - //Freeze the physics if the global state is frozen. - if (state.MovementFrozen || viw.sqrMagnitude >= state.SpeedOfLightSqrd || state.SqrtOneMinusVSquaredCWDividedByCSquared <= 0) + if (state.MovementFrozen) { if (!wasFrozen) { @@ -287,7 +266,6 @@ private void UpdateMeshCollider(MeshCollider transformCollider) wasKinematic = myRigidbody.isKinematic; myRigidbody.isKinematic = true; } - collideTimeStart += state.DeltaTimeWorld; return; } else if (wasFrozen) @@ -343,10 +321,9 @@ private void UpdateMeshCollider(MeshCollider transformCollider) trnsfrmdMesh.RecalculateBounds(); transformCollider.sharedMesh = trnsfrmdMesh; - //Cache actual world center of mass, and then reset local (rest frame) center of mass: - myRigidbody.ResetCenterOfMass(); - opticalWorldCenterOfMass = myRigidbody.worldCenterOfMass; - myRigidbody.centerOfMass = initCOM; + // Reset physics: + //myRigidbody.ResetCenterOfMass(); + //myRigidbody.ResetInertiaTensor(); //Debug.Log("Finished updating mesh collider."); } @@ -371,7 +348,7 @@ public void SetStartTime() { Vector3 playerPos = state.playerTransform.position; float timeDelayToPlayer = (float)Math.Sqrt((((Vector4)piw).WorldToOptical(viw, Get4Acceleration()) - playerPos).sqrMagnitude / state.SpeedOfLightSqrd); - timeDelayToPlayer *= (float)GetTimeFactor(); + timeDelayToPlayer *= GetTimeFactor(); startTime = (float)(state.TotalTimeWorld - timeDelayToPlayer); if (myRenderer != null) myRenderer.enabled = false; @@ -381,7 +358,7 @@ public virtual void SetDeathTime() { Vector3 playerPos = state.playerTransform.position; float timeDelayToPlayer = (float)Math.Sqrt((((Vector4)piw).WorldToOptical(viw, Get4Acceleration()) - playerPos).sqrMagnitude / state.SpeedOfLightSqrd); - timeDelayToPlayer *= (float)GetTimeFactor(); + timeDelayToPlayer *= GetTimeFactor(); DeathTime = (float)(state.TotalTimeWorld - timeDelayToPlayer); } void CombineParent() @@ -605,14 +582,14 @@ void Start() { _viw = initialViw; _aviw = initialAviw; + _properAiw = useGravity ? Physics.gravity : Vector3.zero; + piw = transform.position; + riw = transform.rotation; + isSleeping = false; - isRestingOnCollider = false; - didCollide = false; - sleepFrameCounter = 0; myRigidbody = GetComponent(); rawVertsBufferLength = 0; - collidedWith = new List(); wasKinematic = false; wasFrozen = false; @@ -633,7 +610,6 @@ void Start() { for (int i = 0; i < myColliders.Length; i++) { - myColliders[i].material.bounciness = initBounciness; if (myColliderIsMesh) { ((MeshCollider)myColliders[i]).sharedMesh.MarkDynamic(); @@ -695,11 +671,6 @@ void Start() //And stick it back into our renderer. We'll do the SetVector thing every frame. myRenderer.materials[i] = quickSwapMaterial; - - //set our start time and start position in the shader. - //tempRenderer.materials[i].SetFloat("_strtTime", (float)startTime); - //tempRenderer.materials[i].SetVector("_strtPos", new Vector4(transform.position.x, transform.position.y, transform.position.z, 0)); - //} } } @@ -717,17 +688,7 @@ void Start() } //If the shader is nonrelativistic, map the object from world space to optical space and handle length contraction: - if (nonrelativisticShader) - { - transform.position = ((Vector4)piw).WorldToOptical(viw, Get4Acceleration()); - if (contractor == null) SetUpContractor(); - ContractLength(); - } - - if (myRigidbody != null) - { - opticalWorldCenterOfMass = myRigidbody.worldCenterOfMass; - } + UpdateContractorPosition(); } private void UpdateCollider() @@ -762,108 +723,101 @@ private void UpdateCollider() myColliderIsBox = false; myColliderIsMesh = false; } - - Collider collider = GetComponent(); - if (collider != null) - { - myPhysicMaterial = collider.material; - } } private void EnforceCollision() { - oldCollisionResultVel3 = collisionResultVel3; - oldCollisionResultAngVel3 = collisionResultAngVel3; + // Like how Rigidbody components are co-opted for efficient relativistic motion, + // it's feasible to get (at least reasonable, if not exact) relativistic collision + // handling by transforming the end state after PhysX collisions. - if (didCollide) - { - //Finish and shut off enforcement - if (!IsNaNOrInf(collisionResultVel3.magnitude)) - { - viw = collisionResultVel3; - } + // We pass the RelativisticObject's rapidity to the rigidbody, right before the physics update + // We restore the time-dilated visual apparent velocity, afterward. - if (!IsNaNOrInf(collisionResultAngVel3.magnitude)) - { - aviw = collisionResultAngVel3; - myRigidbody.angularVelocity = aviw; - } - didCollide = false; + // Get the position and rotation after the collision: + riw = myRigidbody.rotation; + //piw = nonrelativisticShader ? ((Vector4)transform.position).OpticalToWorldHighPrecision(viw, Get4Acceleration()) : transform.position; + + // Now, update the velocity and angular velocity based on the collision result: + Vector3 myViw = myRigidbody.velocity.RapidityToVelocity(); + // Make sure we're not updating to faster than max speed + float mySpeed = myViw.magnitude; + if (mySpeed > state.MaxSpeed) + { + myViw = (float)state.MaxSpeed / mySpeed * myViw; } + + float gamma = GetTimeFactor(myViw); + Vector3 myAccel = accelDrag <= 0 ? properAiw : (properAiw + (myViw * gamma - viw * viw.Gamma()) * Mathf.Log(1 + (float)state.FixedDeltaTimePlayer * accelDrag) / accelDrag); + + UpdateViwAndAccel(viw, properAiw, myViw, myAccel); + aviw = myRigidbody.angularVelocity / gamma; } - public void UpdateGravity() + public void Update() { - if (useGravity && !isRestingOnCollider) + if (state.MovementFrozen || nonrelativisticShader || meshFilter != null) { - if (isSleeping) WakeUp(); - properAiw = Physics.gravity; + UpdateShaderParams(); + return; } - else + + if (myRigidbody != null) { - properAiw = Vector3.zero; + UpdateRigidbodyVelocity(viw, aviw); } - } - public void Update() - { - EnforceCollision(); + ObjectMeshDensity density = GetComponent(); - if (meshFilter != null && !state.MovementFrozen) + if (density == null) { - #region meshDensity - //This is where I'm going to change our mesh density. - //I'll take the model, and pass MeshDensity the mesh and unchanged vertices - //If it comes back as having changed something, I'll edit the mesh. + UpdateShaderParams(); + return; + } - //If the shader is nonrelativistic, there's no reason to change the mesh density. - if (!nonrelativisticShader) { - ObjectMeshDensity density = GetComponent(); + #region meshDensity + //This is where I'm going to change our mesh density. + //I'll take the model, and pass MeshDensity the mesh and unchanged vertices + //If it comes back as having changed something, I'll edit the mesh. - if (density != null) + //Only run MeshDensity if the mesh needs to change, and if it's passed a threshold distance. + if (rawVertsBuffer != null && density.change != null) + { + //This checks if we're within our large range, first mesh density circle + //If we're within a distance of 40, split this mesh + if (!(density.state) && (RecursiveTransform(rawVertsBuffer[0], meshFilter.transform).sqrMagnitude < (21000 * 21000))) + { + Mesh meshFilterMesh = meshFilter.mesh; + if (density.ReturnVerts(meshFilterMesh, true)) { - - //Only run MeshDensity if the mesh needs to change, and if it's passed a threshold distance. - if (rawVertsBuffer != null && density.change != null) + Vector3[] meshVerts = meshFilterMesh.vertices; + rawVertsBufferLength = meshVerts.Length; + if (rawVertsBuffer.Length < rawVertsBufferLength) { - //This checks if we're within our large range, first mesh density circle - //If we're within a distance of 40, split this mesh - if (!(density.state) && (RecursiveTransform(rawVertsBuffer[0], meshFilter.transform).sqrMagnitude < (21000 * 21000))) - { - Mesh meshFilterMesh = meshFilter.mesh; - if (density.ReturnVerts(meshFilterMesh, true)) - { - Vector3[] meshVerts = meshFilterMesh.vertices; - rawVertsBufferLength = meshVerts.Length; - if (rawVertsBuffer.Length < rawVertsBufferLength) - { - rawVertsBuffer = new Vector3[rawVertsBufferLength]; - } - System.Array.Copy(meshVerts, rawVertsBuffer, rawVertsBufferLength); - } - } - - //If the object leaves our wide range, revert mesh to original state - else if (density.state && (RecursiveTransform(rawVertsBuffer[0], meshFilter.transform).sqrMagnitude > (21000 * 21000))) - { - Mesh meshFilterMesh = meshFilter.mesh; - if (density.ReturnVerts(meshFilterMesh, false)) - { - Vector3[] meshVerts = meshFilterMesh.vertices; - rawVertsBufferLength = meshVerts.Length; - if (rawVertsBuffer.Length < rawVertsBufferLength) - { - rawVertsBuffer = new Vector3[rawVertsBufferLength]; - } - System.Array.Copy(meshVerts, rawVertsBuffer, rawVertsBufferLength); - } - } + rawVertsBuffer = new Vector3[rawVertsBufferLength]; + } + System.Array.Copy(meshVerts, rawVertsBuffer, rawVertsBufferLength); + } + } + //If the object leaves our wide range, revert mesh to original state + else if (density.state && (RecursiveTransform(rawVertsBuffer[0], meshFilter.transform).sqrMagnitude > (21000 * 21000))) + { + Mesh meshFilterMesh = meshFilter.mesh; + if (density.ReturnVerts(meshFilterMesh, false)) + { + Vector3[] meshVerts = meshFilterMesh.vertices; + rawVertsBufferLength = meshVerts.Length; + if (rawVertsBuffer.Length < rawVertsBufferLength) + { + rawVertsBuffer = new Vector3[rawVertsBufferLength]; } + System.Array.Copy(meshVerts, rawVertsBuffer, rawVertsBufferLength); } } - #endregion + } + #endregion UpdateShaderParams(); } @@ -878,19 +832,6 @@ public float GetTisw(Vector3? pos = null) } void FixedUpdate() { - int lcv = 0; - while (lcv < collidedWith.Count) - { - if (collidedWith[lcv].LastTime + collideAgainWait <= state.TotalTimeWorld) - { - collidedWith.RemoveAt(lcv); - } - else - { - lcv++; - } - } - if (state.MovementFrozen) { // If our rigidbody is not null, and movement is frozen, then set the object to standstill. @@ -904,23 +845,23 @@ void FixedUpdate() { return; } - double deltaTime = state.FixedDeltaTimePlayer * GetTimeFactor(); - double localDeltaT = deltaTime - state.FixedDeltaTimeWorld; + // FOR THE PHYSICS UPDATE ONLY, we give our rapidity to the Rigidbody + //EnforceCollision(); + + float deltaTime = (float)state.FixedDeltaTimePlayer * GetTimeFactor(); + float localDeltaT = deltaTime - (float)state.FixedDeltaTimeWorld; if (state.conformalMap != null) { //Update comoving position - Vector3 opiw = nonrelativisticShader ? transform.position : ((Vector4)piw).WorldToOptical(viw, Get4Acceleration()); - - Vector4 piw4 = state.conformalMap.ComoveOptical((float)deltaTime, opiw); - piw4 = nonrelativisticShader ? piw4 : piw4.OpticalToWorld(viw, state.playerTransform.position, -state.PlayerVelocityVector, state.PlayerAccelerationVector, state.PlayerAngularVelocityVector, Get4Acceleration()); + Vector4 piw4 = state.conformalMap.ComoveOptical(deltaTime, piw); float testMag = piw4.sqrMagnitude; if (!IsNaNOrInf(testMag)) { piw = piw4; if (nonrelativisticShader) { - contractor.position = piw; + contractor.position = ((Vector4)piw).WorldToOptical(viw, Get4Acceleration()); transform.localPosition = Vector3.zero; } deltaTime = piw4.w; @@ -973,38 +914,10 @@ void FixedUpdate() { } } - //This might be nonphysical, but we want resting colliders to stay "glued" to the floor: - if (myColliderIsBox && isSleeping && isRestingOnCollider) - { - int myLayer = gameObject.layer; - gameObject.layer = 1 << LayerMask.NameToLayer("Ignore Raycast"); - - float extentY = myColliders[0].bounds.extents.y; - float maxDist = 100f; - Ray downRay = new Ray() - { - direction = Physics.gravity.normalized, - origin = transform.TransformPoint(((BoxCollider)myColliders[0]).center + extentY * Vector3.up) - }; - RaycastHit hitInfo; - if (Physics.Raycast(downRay, out hitInfo, maxDist, gameObject.layer)) - { - if (nonrelativisticShader) - { - contractor.position += (hitInfo.distance - 2.0f * extentY) * Vector3.down; - transform.localPosition = Vector3.zero; - } - else - { - transform.position += (hitInfo.distance - 2.0f * extentY) * Vector3.down; - } - } - - gameObject.layer = myLayer; - } - + #region rigidbody // The rest of the updates are for objects with Rigidbodies that move and aren't asleep. - if (isKinematic || isSleeping || myRigidbody == null) { + if (isKinematic || isSleeping || myRigidbody == null) + { if (myRigidbody != null) { @@ -1020,84 +933,74 @@ void FixedUpdate() { UpdateColliderPosition(); } + UpdateShaderParams(); + // We're done. return; } - if (nonrelativisticShader) + if (accelDrag > 0) { - // Update the position in world, if necessary: - piw += transform.position - contractor.position; - transform.localPosition = Vector3.zero; - Vector3 testPos = ((Vector4)piw).WorldToOptical(viw, Get4Acceleration(), viwLorentz); - float testMag = testPos.sqrMagnitude; - if (!IsNaNOrInf(testMag)) + + Vector3 myAccel = properAiw; + + if (useGravity) { - contractor.position = testPos; - ContractLength(); + myAccel -= Physics.gravity; } - } - piw = transform.position; + float jerkDiff = (1 + deltaTime * accelDrag); + myAccel = myAccel / jerkDiff; - if (!myColliderIsVoxel) - { - UpdateColliderPosition(); - } + if (useGravity) + { + myAccel += Physics.gravity; + } - // Gravity can affect proper acceleration - UpdateGravity(); + properAiw = myAccel; + } // Accelerate after updating gravity's effect on proper acceleration - viw += properAiw * (float)deltaTime; + viw += properAiw * deltaTime; - //Correct for both time dilation and change in metric due to player acceleration: + // Set the Rigidbody parameters, dependent on player's point of view UpdateRigidbodyVelocity(viw, aviw); - float sleepThreshold = sleepVelocity * sleepVelocity; - bool isFallingAsleep = (viw.sqrMagnitude < sleepThreshold) && (aviw.sqrMagnitude < sleepThreshold); - if (!isFallingAsleep) + Vector3 testVec = deltaTime * viw; + if (!IsNaNOrInf(testVec.sqrMagnitude)) { - sleepFrameCounter = 0; - } - else - { - sleepFrameCounter++; - if (sleepFrameCounter >= sleepFrameDelay) + Quaternion diffRot = Quaternion.Euler(deltaTime * aviw); + riw = riw * diffRot; + myRigidbody.MoveRotation(riw); + + piw += testVec; + + if (nonrelativisticShader) { - if (useGravity && myColliders != null && myColliders.Length > 0) + transform.localPosition = Vector3.zero; + testVec = ((Vector4)piw).WorldToOptical(viw, Get4Acceleration()); + if (!IsNaNOrInf(testVec.sqrMagnitude)) { - int myLayer = gameObject.layer; - gameObject.layer = 1 << LayerMask.NameToLayer("Ignore Raycast"); - Ray down = new Ray(opticalWorldCenterOfMass, Vector3.down); - float extentY = myColliders[0].bounds.extents.y; - RaycastHit hitInfo; - float distance = (transform.position - transform.TransformPoint(Vector3.down * extentY)).magnitude; - if (Physics.Raycast(down, out hitInfo, distance + 0.01f)) - { - sleepFrameCounter = sleepFrameDelay; - Sleep(); - isRestingOnCollider = true; - } - gameObject.layer = myLayer; - } - else - { - sleepFrameCounter = sleepFrameDelay; - Sleep(); + contractor.position = testVec; + ContractLength(); } } + else + { + myRigidbody.MovePosition(piw); + } } - if ((sleepOldPosition - piw).sqrMagnitude >= (sleepDistance * sleepDistance)) + if (!myColliderIsVoxel) { - sleepOldPosition = piw; + UpdateColliderPosition(); } + #endregion - if (Vector3.Angle(sleepOldOrientation, transform.forward) >= sleepAngle) - { - sleepOldOrientation = transform.forward; - } + // FOR THE PHYSICS UPDATE ONLY, we give our rapidity to the Rigidbody + float gamma = viw.Gamma(); + myRigidbody.velocity = gamma * viw; + myRigidbody.angularVelocity = gamma * aviw; } public void UpdateColliderPosition(Collider toUpdate = null) @@ -1115,7 +1018,7 @@ public void UpdateColliderPosition(Collider toUpdate = null) else if (!nonrelativisticShader && (myColliders != null) && (myColliders.Length > 0)) { //If we have a MeshCollider and a compute shader, transform the collider verts relativistically: - if (myColliderIsMesh && (colliderShader != null) && SystemInfo.supportsComputeShaders) + if (myColliderIsMesh && (colliderShader != null) && SystemInfo.supportsComputeShaders && state.IsInitDone) { for (int i = 0; i < myColliders.Length; i++) { @@ -1143,11 +1046,6 @@ public void UpdateColliderPosition(Collider toUpdate = null) } } } - - if (myRigidbody != null) - { - opticalWorldCenterOfMass = myRigidbody.worldCenterOfMass; - } } private void UpdateShaderParams() @@ -1208,31 +1106,22 @@ private void checkSpeed() } } - private void checkCollisionSpeed() - { - if (collisionResultVel3.magnitude > state.MaxSpeed - .01) - { - oldCollisionResultVel3 = oldCollisionResultVel3.normalized * (float)(state.MaxSpeed - .01f); - collisionResultVel3 = oldCollisionResultVel3; - } - } - public void ResetDeathTime() { DeathTime = float.PositiveInfinity; } #region 4D Rigid body mechanics - //This is a reference type to package collision points with collision normal vectors - private class PointAndNorm + + private IEnumerator EnableCollision(float delay, Collider otherCollider) { - public Vector3 point; - public Vector3 normal; + yield return new WaitForSeconds(delay); + Physics.IgnoreCollision(GetComponent(), otherCollider, false); } - public void OnCollisionStay(Collision collision) + public void OnCollisionEnter(Collision collision) { - if (myRigidbody == null || myRigidbody.isKinematic) + if (myRigidbody == null || myColliders == null || myRigidbody.isKinematic) { return; } @@ -1240,16 +1129,6 @@ public void OnCollisionStay(Collision collision) GameObject otherGO = collision.gameObject; RelativisticObject otherRO = otherGO.GetComponent(); - if (collision.contacts.Length > 1) - { - Ray down = new Ray(opticalWorldCenterOfMass, Vector3.down); - RaycastHit hitInfo; - if (collision.collider.Raycast(down, out hitInfo, (opticalWorldCenterOfMass - otherRO.opticalWorldCenterOfMass).magnitude)) - { - isRestingOnCollider = true; - } - } - //Lorentz transformation might make us come "unglued" from a collider we're resting on. // If we're asleep, and the other collider has zero velocity, we don't need to wake up: if (isSleeping && otherRO.viw == Vector3.zero) @@ -1257,64 +1136,41 @@ public void OnCollisionStay(Collision collision) return; } - //If we made it this far, we shouldn't be sleeping: - WakeUp(); - - PhysicMaterial otherMaterial = collision.collider.material; - float combFriction = CombinePhysics(myPhysicMaterial.frictionCombine, myPhysicMaterial.staticFriction, otherMaterial.staticFriction); - float combRestCoeff = CombinePhysics(myPhysicMaterial.bounceCombine, myPhysicMaterial.bounciness, otherMaterial.bounciness); - - //Tangental relationship scales normalized "bounciness" to a Young's modulus + if ((viw.AddVelocity(-otherRO.viw).magnitude < Physics.bounceThreshold)) + { + // If we're lower than the bounce threshold, just reset the state. + // We often end up here when player acceleration puts high apparent curvature on a too low vertex mesh collider. + // PhysX will force the objects apart, but this might be the least error we can get away with. + viw = Vector3.zero; + aviw = Vector3.zero; + UpdateRigidbodyVelocity(viw, aviw); - float combYoungsModulus = GetYoungsModulus(combRestCoeff); + return; + } - PointAndNorm contactPoint = DecideContactPoint(collision); - ApplyPenalty(collision, otherRO, contactPoint, combFriction, combYoungsModulus); - didCollide = true; - } + //If we made it this far, we shouldn't be sleeping: + WakeUp(); - private float GetYoungsModulus(float combRestCoeff) - { - float combYoungsModulus; - if (combRestCoeff < 1.0f) - { - combYoungsModulus = Mathf.Tan(combRestCoeff); - //If the Young's modulus is higher than a realistic material, cap it. - if (combYoungsModulus > maxYoungsModulus) combYoungsModulus = maxYoungsModulus; - } - else + // We don't want to bug out, on many collisions with the same object + if (collideWait > 0) { - //If the coeffecient of restitution is one, set the Young's modulus to max: - combYoungsModulus = maxYoungsModulus; + Physics.IgnoreCollision(GetComponent(), collision.collider, true); + StartCoroutine(EnableCollision(collideWait, collision.collider)); } - return combYoungsModulus; + // Let's start simple: + // At low enough velocities, where the Newtonian approximation is reasonable, + // PhysX is probably MORE accurate for even relativistic collision than the hacky relativistic collision we had + // (which is still in the commit history, for reference). + EnforceCollision(); } - public void OnCollisionEnter(Collision collision) + public void OnCollisionStay(Collision collision) { - if (myRigidbody == null || myColliders == null || myRigidbody.isKinematic) + if (myRigidbody == null || myRigidbody.isKinematic) { return; } - else if (collidedWith.Count > 0) - { - for (int i = 0; i < collidedWith.Count; i++) - { - //If this collision is returned, redirect to OnCollisionStay - if (collision.collider.Equals(collidedWith[i].Collider)) - { - collidedWith[i].LastTime = state.TotalTimeWorld; - //Then, immediately finish. - return; - } - } - } - collidedWith.Add(new RecentCollision() - { - Collider = collision.collider, - LastTime = state.TotalTimeWorld - }); GameObject otherGO = collision.gameObject; RelativisticObject otherRO = otherGO.GetComponent(); @@ -1326,426 +1182,39 @@ public void OnCollisionEnter(Collision collision) return; } - //If we made it this far, we shouldn't be sleeping: - WakeUp(); - didCollide = true; - - PointAndNorm contactPoint = DecideContactPoint(collision); - if (contactPoint == null) - { - return; - } - - PhysicMaterial otherMaterial = collision.collider.material; - float myFriction = isSleeping ? myPhysicMaterial.staticFriction : myPhysicMaterial.dynamicFriction; - float otherFriction = otherRO.isSleeping ? otherMaterial.staticFriction : otherMaterial.dynamicFriction; - float combFriction = CombinePhysics(myPhysicMaterial.frictionCombine, myFriction, otherFriction); - float combRestCoeff = CombinePhysics(myPhysicMaterial.bounceCombine, myPhysicMaterial.bounciness, otherMaterial.bounciness); - - oldCollisionResultVel3 = viw; - oldCollisionResultAngVel3 = aviw; - otherRO.oldCollisionResultVel3 = otherRO.viw; - otherRO.oldCollisionResultAngVel3 = otherRO.aviw; - Collide(collision, otherRO, contactPoint, combRestCoeff, combFriction, (collision.rigidbody == null) || (collision.rigidbody.isKinematic)); - } - - private float CombinePhysics(PhysicMaterialCombine physMatCombine, float mine, float theirs) - { - float effectiveValue = 0.0f; - switch (physMatCombine) - { - case PhysicMaterialCombine.Average: - effectiveValue = (mine + theirs) * 0.5f; - break; - case PhysicMaterialCombine.Maximum: - effectiveValue = Mathf.Max(mine, theirs); - break; - case PhysicMaterialCombine.Minimum: - effectiveValue = Mathf.Min(mine, theirs); - break; - default: - effectiveValue = mine; - break; - } - return effectiveValue; - } - - private PointAndNorm DecideContactPoint(Collision collision) - { - PointAndNorm contactPoint; - if (collision.contacts.Length == 0) - { - return null; - } - else if (collision.contacts.Length == 1) - { - contactPoint = new PointAndNorm() - { - point = collision.contacts[0].point, - normal = collision.contacts[0].normal - }; - } - else - { - contactPoint = new PointAndNorm(); - for (int i = 0; i < collision.contacts.Length; i++) - { - contactPoint.point += collision.contacts[i].point; - contactPoint.normal += collision.contacts[i].normal; - } - contactPoint.point = 1.0f / (float)collision.contacts.Length * contactPoint.point; - contactPoint.normal.Normalize(); - } - if ((contactPoint.point - transform.position).sqrMagnitude == 0.0f) - { - contactPoint.point = 0.001f * collision.collider.transform.position; - } - return contactPoint; - } - - private void Collide(Collision collision, RelativisticObject otherRO, PointAndNorm contactPoint, float combRestCoeff, float combFriction, bool isReflected) - { - //We grab the velocities from the RelativisticObject rather than the Rigidbody, - // since the Rigidbody velocity is not directly physical. - float mass = myRigidbody.mass; - Vector3 myVel = oldCollisionResultVel3; - Vector3 myAngVel = oldCollisionResultAngVel3; - Rigidbody otherRB = collision.rigidbody; - Vector3 otherVel = otherRO.oldCollisionResultVel3; - Vector3 otherAngVel = otherRO.oldCollisionResultAngVel3; - - Vector3 myPRelVel = myVel.AddVelocity(-state.PlayerVelocityVector); - Vector4 myAccel = Get4Acceleration(); - - //We want to find the contact offset relative the centers of mass of in each object's inertial frame; - Vector3 myLocPoint, otLocPoint, contact, com; - if (myColliderIsMesh) - { - contact = ((Vector4)(contactPoint.point)).OpticalToWorld(myVel, myAccel); - com = ((Vector4)opticalWorldCenterOfMass).OpticalToWorld(myVel, myAccel); - myLocPoint = contact - com; - } - else if (nonrelativisticShader) - { - contact = contactPoint.point; - com = ((Vector4)opticalWorldCenterOfMass).OpticalToWorld(myVel, myAccel); - myLocPoint = (contact - com).InverseContractLengthBy(myVel); - } - else - { - contact = contactPoint.point; - com = ((Vector4)opticalWorldCenterOfMass).OpticalToWorld(myVel, myAccel); - myLocPoint = (contact - com); - } - - if (otherRO.myColliderIsMesh) - { - contact = ((Vector4)(contactPoint.point)).OpticalToWorld(otherVel, myAccel); - com = ((Vector4)(otherRO.opticalWorldCenterOfMass)).OpticalToWorld(otherVel, myAccel); - otLocPoint = contact - com; - } - else if (otherRO.nonrelativisticShader) - { - contact = contactPoint.point; - com = ((Vector4)(otherRO.opticalWorldCenterOfMass)).OpticalToWorld(otherVel, myAccel); - otLocPoint = (contact - com).InverseContractLengthBy(otherVel); - } - else - { - contact = contactPoint.point; - com = ((Vector4)opticalWorldCenterOfMass).OpticalToWorld(otherVel, myAccel); - otLocPoint = (contact - com); - } - - Vector3 myAngTanVel = Vector3.Cross(myAngVel, myLocPoint); - Vector3 myTotalVel = myVel.AddVelocity(myAngTanVel); - Vector3 otherAngTanVel = Vector3.Cross(otherAngVel, otLocPoint); - Vector3 otherTotalVel = otherVel.AddVelocity(otherAngTanVel); - Vector3 lineOfAction = -contactPoint.normal.InverseContractLengthBy(myVel); - lineOfAction.Normalize(); - //Decompose velocity in parallel and perpendicular components: - Vector3 myParraVel = Vector3.Project(myTotalVel, lineOfAction); - Vector3 myPerpVel = (myTotalVel - myParraVel) * myParraVel.Gamma(); - //Boost to the inertial frame where my velocity is entirely along the line of action: - Vector3 otherContactVel = otherTotalVel.AddVelocity(-myPerpVel); - //Find the relative velocity: - Vector3 relVel = myParraVel.RelativeVelocityTo(otherContactVel); - //Find the relative rapidity on the line of action, where my contact velocity is 0: - float relVelGamma = relVel.Gamma(); - Vector3 rapidityOnLoA = relVelGamma * relVel; - - Vector3 myPos = opticalWorldCenterOfMass; - Vector3 otherPos = otherRO.opticalWorldCenterOfMass; - float penDist = GetPenetrationDepth(collision, myColliders[0], myPRelVel, myPos, otherPos, ref contactPoint); - - //We will apply penalty methods after the initial collision, in order to stabilize objects coming to rest on flat surfaces with gravity. - // Our penalty methods can give a somewhat obvious apparent deviation from conservation of energy and momentum, - // unless we account for the initial energy and momentum loss due to "spring-loading": - float springImpulse = 0; - if (penDist > 0.0f) - { - float combYoungsModulus = GetYoungsModulus(combRestCoeff); - //Potential energy as if from a spring, - //H = K + V = p^2/(2m) + 1/2*k*l^2 - // from which it can be shown that this is the change in momentum from the implied initial loading of the "spring": - springImpulse = Mathf.Sqrt(hookeMultiplier * combYoungsModulus * penDist * penDist * myRigidbody.mass); - } - - //Rotate my relative contact point: - Vector3 rotatedLoc = Quaternion.Inverse(transform.rotation) * myLocPoint; - rotatedLoc.Scale(rotatedLoc); - //The relative contact point is the lever arm of the torque: - float myMOI = Vector3.Dot(myRigidbody.inertiaTensor, rotatedLoc); - //In special relativity, the impulse relates the change in rapidities, rather than the change in velocities. - float impulse; - if (isReflected) - { - impulse = -rapidityOnLoA.magnitude * (combRestCoeff + 1.0f) / (1.0f / mass + Vector3.Dot(lineOfAction, Vector3.Cross(1.0f / myMOI * Vector3.Cross(myLocPoint, lineOfAction), myLocPoint))); - } - else + if ((viw.AddVelocity(-otherRO.viw).magnitude < Physics.bounceThreshold)) { - rotatedLoc = Quaternion.Inverse(otherRB.transform.rotation) * otLocPoint; - rotatedLoc.Scale(rotatedLoc); - float otherMOI = Vector3.Dot(otherRB.inertiaTensor, rotatedLoc); - impulse = -rapidityOnLoA.magnitude * (combRestCoeff + 1.0f) / (1.0f / mass + 1.0f / otherRB.mass + Vector3.Dot(lineOfAction, Vector3.Cross(1.0f / myMOI * Vector3.Cross(myLocPoint, lineOfAction), myLocPoint)) + Vector3.Dot(lineOfAction, Vector3.Cross(1.0f / otherMOI * Vector3.Cross(otLocPoint, lineOfAction), otLocPoint))); - } - - impulse -= springImpulse; + // If we're lower than the bounce threshold, just reset the state. + // We often end up here when player acceleration puts high apparent curvature on a too low vertex mesh collider. + // PhysX will force the objects apart, but this might be the least error we can get away with. + viw = Vector3.zero; + aviw = Vector3.zero; + UpdateRigidbodyVelocity(viw, aviw); - Vector3 tanNorm = Vector3.Cross(Vector3.Cross(lineOfAction, relVel), lineOfAction).normalized; - Vector3 frictionChange = combFriction * impulse * tanNorm; - //The change in rapidity on the line of action: - Vector3 finalLinearRapidity = relVelGamma * myVel + (impulse * lineOfAction + frictionChange) / mass; - //The change in rapidity perpendincular to the line of action: - Vector3 finalTanRapidity = relVelGamma * myAngTanVel + Vector3.Cross(1.0f / myMOI * Vector3.Cross(myLocPoint, impulse * lineOfAction + frictionChange), myLocPoint); - //Velocities aren't linearly additive in special relativity, but rapidities are: - float finalRapidityMag = (finalLinearRapidity + finalTanRapidity).magnitude; - Vector3 tanVelFinal = finalTanRapidity.RapidityToVelocity(finalRapidityMag); - //This is a hack. We save the new velocities to overwrite the Rigidbody velocities on the next frame: - collisionResultVel3 = finalLinearRapidity.RapidityToVelocity(finalRapidityMag); - //If the angle of the torque is close to 0 or 180, we have rounding problems: - float angle = Vector3.Angle(myAngVel, myLocPoint); - if (angle > 2.0f && angle < 178.0f) - { - collisionResultAngVel3 = Vector3.Cross(tanVelFinal, myLocPoint) / myLocPoint.sqrMagnitude; - } - else - { - collisionResultAngVel3 = myAngVel; + return; } - //In the ideal, it shouldn't be necessary to clamp the speed - // in order to prevent FTL collision results, but we could - // still exceed the max speed and come very close to the speed of light - checkCollisionSpeed(); - - //Velocity overwrite will come on next frame: - //oldCollisionResultVel3 = collisionResultVel3; - //oldCollisionResultAngVel3 = collisionResultAngVel3; - didCollide = true; - } - - //EXPERIMENTAL PENALTY METHOD CODE BELOW - private const float hookeMultiplier = 1.0f; - private void ApplyPenalty(Collision collision, RelativisticObject otherRO, PointAndNorm contactPoint, float combFriction, float combYoungsModulus) - { - //We grab the velocities from the RelativisticObject rather than the Rigidbody, - // since the Rigidbody velocity is not directly physical. - float mass = myRigidbody.mass; - Vector3 myVel = oldCollisionResultVel3; - Vector3 myAngVel = oldCollisionResultAngVel3; - Rigidbody otherRB = collision.rigidbody; - Vector3 otherVel = otherRO.oldCollisionResultVel3; - Vector3 otherAngVel = otherRO.oldCollisionResultAngVel3; - Vector3 myPRelVel = myVel.AddVelocity(-state.PlayerVelocityVector); - Vector4 myAccel = Get4Acceleration(); - - //We want to find the contact offset relative the centers of mass of in each object's inertial frame; - Vector3 myLocPoint, otLocPoint, contact, com; - if (myColliderIsMesh) - { - contact = ((Vector4)(contactPoint.point)).OpticalToWorld(myVel, myAccel); - com = ((Vector4)opticalWorldCenterOfMass).OpticalToWorld(myVel, myAccel); - myLocPoint = contact - com; - } - else if (nonrelativisticShader) - { - contact = contactPoint.point; - com = ((Vector4)opticalWorldCenterOfMass).OpticalToWorld(myVel, myAccel); - myLocPoint = (contact - com).InverseContractLengthBy(myVel); - } - else - { - contact = contactPoint.point; - com = ((Vector4)opticalWorldCenterOfMass).OpticalToWorld(myVel, myAccel); - myLocPoint = (contact - com); - } + //If we made it this far, we shouldn't be sleeping: + WakeUp(); - myAccel = Get4Acceleration(); - if (otherRO.myColliderIsMesh) - { - contact = ((Vector4)(contactPoint.point)).OpticalToWorld(otherVel, myAccel); - com = ((Vector4)(otherRO.opticalWorldCenterOfMass)).OpticalToWorld(otherVel, myAccel); - otLocPoint = contact - com; - } - else if (otherRO.nonrelativisticShader) - { - contact = contactPoint.point; - com = ((Vector4)(otherRO.opticalWorldCenterOfMass)).OpticalToWorld(otherVel, myAccel); - otLocPoint = (contact - com).InverseContractLengthBy(otherVel); - } - else - { - contact = contactPoint.point; - com = ((Vector4)opticalWorldCenterOfMass).OpticalToWorld(otherVel, myAccel); - otLocPoint = (contact - com); - } - - Vector3 myAngTanVel = Vector3.Cross(myAngVel, myLocPoint); - Vector3 myTotalVel = myVel.AddVelocity(myAngTanVel); - Vector3 otherAngTanVel = Vector3.Cross(otherAngVel, otLocPoint); - Vector3 otherTotalVel = otherVel.AddVelocity(otherAngTanVel); - Vector3 lineOfAction = -contactPoint.normal.InverseContractLengthBy(myVel); - lineOfAction.Normalize(); - //Decompose velocity in parallel and perpendicular components: - Vector3 myParraVel = Vector3.Project(myTotalVel, lineOfAction); - Vector3 myPerpVel = (myTotalVel - myParraVel) * myParraVel.Gamma(); - //Boost to the inertial frame where my velocity is entirely along the line of action: - Vector3 otherContactVel = otherTotalVel.AddVelocity(-myPerpVel); - //Find the relative velocity: - Vector3 relVel = myParraVel.RelativeVelocityTo(otherContactVel); - //Find the relative rapidity on the line of action, where my contact velocity is 0: - float relVelGamma = relVel.Gamma(); - //Vector3 rapidityOnLoA = relVelGamma * relVel; - - Vector3 myPos = opticalWorldCenterOfMass; - Vector3 otherPos = otherRO.opticalWorldCenterOfMass; - float penDist = GetPenetrationDepth(collision, myColliders[0], myPRelVel, myPos, otherPos, ref contactPoint); - - - - //Rotate my relative contact point: - Vector3 rotatedLoc = Quaternion.Inverse(transform.rotation) * myLocPoint; - //The relative contact point is the lever arm of the torque: - float myMOI = Vector3.Dot(myRigidbody.inertiaTensor, new Vector3(rotatedLoc.x * rotatedLoc.x, rotatedLoc.y * rotatedLoc.y, rotatedLoc.z * rotatedLoc.z)); - - Vector3 finalLinearRapidity; - Vector3 finalTanRapidity; - if (penDist > 0) - { - float impulse = (float)(hookeMultiplier * combYoungsModulus * penDist * state.FixedDeltaTimePlayer * GetTimeFactor()); - - Vector3 tanNorm = Vector3.Cross(Vector3.Cross(lineOfAction, relVel), lineOfAction).normalized; - Vector3 frictionChange = combFriction * impulse * tanNorm; - //The change in rapidity on the line of action: - finalLinearRapidity = relVelGamma * myVel + (impulse * lineOfAction + frictionChange) / mass; - //The change in rapidity perpendincular to the line of action: - finalTanRapidity = relVelGamma * myAngTanVel + Vector3.Cross(1.0f / myMOI * Vector3.Cross(myLocPoint, impulse * lineOfAction + frictionChange), myLocPoint); - } - else + // We don't want to bug out, on many collisions with the same object + if (collideWait > 0) { - finalLinearRapidity = relVelGamma * myVel * combFriction; - finalTanRapidity = relVelGamma * myAngTanVel * combFriction; - } - //Velocities aren't linearly additive in special relativity, but rapidities are: - float finalRapidityMag = (finalLinearRapidity + finalTanRapidity).magnitude; - Vector3 tanVelFinal = finalTanRapidity.RapidityToVelocity(finalRapidityMag); - //This is a hack. We save the new velocities to overwrite the Rigidbody velocities on the next frame: - collisionResultVel3 = finalLinearRapidity.RapidityToVelocity(finalRapidityMag); - //If the angle of the torque is close to 0 or 180, we have rounding problems: - float angle = Vector3.Angle(myAngVel, myLocPoint); - if (angle > 2.0f && angle < 178.0f) - { - collisionResultAngVel3 = Vector3.Cross(tanVelFinal, myLocPoint) / myLocPoint.sqrMagnitude; - } - else - { - collisionResultAngVel3 = myAngVel; - } - //In the ideal, it shouldn't be necessary to clamp the speed - // in order to prevent FTL collision results, but we could - // still exceed the max speed and come very close to the speed of light - checkCollisionSpeed(); - - didCollide = true; - } - - private float GetPenetrationDepth(Collision collision, Collider myCollider, Vector3 myPRelVel, Vector3 myPos, Vector3 otherPos, ref PointAndNorm contactPoint) - { - //Raycast with other collider in a collision - - //float gamma = myPRelVel.Gamma(); - - Vector3 testNormal; - float penDist = 0.0f; - float penTest = 0.0f; - Vector3 myExtents = myCollider.bounds.extents; - Vector3 otherExtents = collision.collider.bounds.extents; - float startDist = 4.0f * Mathf.Max(otherExtents.x, otherExtents.y, otherExtents.z, myExtents.x, myExtents.y, myExtents.z); - RaycastHit hitInfo; - ContactPoint point; - float maxLCV = collision.contacts.Length; - Ray ray = new Ray(); - for (int i = 0; i < maxLCV; i++) - { - point = collision.contacts[i]; - testNormal = point.normal; - ray.origin = myPos + startDist * testNormal; - ray.direction = -testNormal; - - if (collision.collider.Raycast(ray, out hitInfo, startDist)) - { - penTest = hitInfo.distance - startDist; - } - else - { - penTest = 0.0f; - } - if (penTest > penDist) - { - penDist = penTest; - contactPoint.point = point.point; - contactPoint.normal = point.normal; - } - - ray.origin = otherPos - startDist * testNormal; - ray.direction = testNormal; - - if (myCollider.Raycast(ray, out hitInfo, startDist)) - { - penTest = hitInfo.distance - startDist; - } - else - { - penTest = 0.0f; - } - - if (penTest > penDist) - { - penDist = penTest; - contactPoint.point = point.point; - contactPoint.normal = point.normal; - } + Physics.IgnoreCollision(GetComponent(), collision.collider, true); + StartCoroutine(EnableCollision(collideWait, collision.collider)); } - return penDist; + // Let's start simple: + // At low enough velocities, where the Newtonian approximation is reasonable, + // PhysX is probably MORE accurate for even relativistic collision than the hacky relativistic collision we had + // (which is still in the commit history, for reference). + EnforceCollision(); } - private void Sleep() + public void Sleep() { - if (!isSleeping) - { - //The sleep rotation has to be held fixed to keep sleeping objects - // resting flush on stationary surfaces below them. - sleepRotation = transform.rotation; - } - transform.rotation = sleepRotation; viw = Vector3.zero; - collisionResultVel3 = Vector3.zero; - oldCollisionResultVel3 = Vector3.zero; aviw = Vector3.zero; - collisionResultAngVel3 = Vector3.zero; - oldCollisionResultAngVel3 = Vector3.zero; properAiw = Vector3.zero; if (myRigidbody != null) @@ -1758,10 +1227,9 @@ private void Sleep() isSleeping = true; } - private void WakeUp() + public void WakeUp() { isSleeping = false; - isRestingOnCollider = false; if (myRigidbody != null) { myRigidbody.WakeUp(); @@ -1863,47 +1331,58 @@ private void UpdateRigidbodyVelocity(Vector3 mViw, Vector3 mAviw) return; } - if ((!state.MovementFrozen) && (state.SqrtOneMinusVSquaredCWDividedByCSquared > 0)) + // If movement is frozen, set to zero. + if (state.MovementFrozen) { - Vector3 pVel = state.PlayerVelocityVector; - //This works so long as our metric uses synchronous coordinates: - Matrix4x4 metric = GetMetric(); - - float timeFac = (float)((state.SpeedOfLightSqrd + Vector4.Dot(pVel, metric * pVel)) / state.SpeedOfLightSqrd); - if (!IsNaNOrInf(timeFac) && timeFac > 0) - { - myRigidbody.velocity = mViw * timeFac; - myRigidbody.angularVelocity = mAviw * timeFac; - } - else - { - myRigidbody.velocity = Vector3.zero; - myRigidbody.angularVelocity = Vector3.zero; - } + myRigidbody.velocity = Vector3.zero; + myRigidbody.angularVelocity = Vector3.zero; + + return; } - else + + // If we're in an invalid state, (such as before full initialization,) set to zero. + float timeFac = GetTimeFactor(); + if (IsNaNOrInf(timeFac) || timeFac == 0) { myRigidbody.velocity = Vector3.zero; myRigidbody.angularVelocity = Vector3.zero; + + return; } + + myRigidbody.velocity = mViw * timeFac; + myRigidbody.angularVelocity = mAviw * timeFac; } - public double GetTimeFactor() + public void UpdateContractorPosition() { - if (state.SqrtOneMinusVSquaredCWDividedByCSquared <= 0) + if (nonrelativisticShader) { - return 1; + if (contractor == null) + { + SetUpContractor(); + } + contractor.position = ((Vector4)piw).WorldToOptical(viw, Get4Acceleration()); + transform.localPosition = Vector3.zero; + ContractLength(); + } + } + + public float GetTimeFactor(Vector3? pVel = null) + { + if (!pVel.HasValue) + { + pVel = state.PlayerVelocityVector; } - Vector3 pVel = state.PlayerVelocityVector; - //This works so long as our metric uses synchronous coordinates: Matrix4x4 metric = GetMetric(); - float timeFac = (float)((state.SpeedOfLightSqrd + Vector4.Dot(pVel, metric * pVel)) / state.SpeedOfLightSqrd); - if (timeFac < 0) + float timeFac = 1 / Mathf.Sqrt(1 - (float)(Vector4.Dot(pVel.Value, metric * pVel.Value) / state.SpeedOfLightSqrd)); + if (IsNaNOrInf(timeFac)) { - timeFac = 0; + timeFac = 1; } + return timeFac; } } diff --git a/Assets/OpenRelativity/Scripts/Objects/RelativisticParent.cs b/Assets/OpenRelativity/Scripts/Objects/RelativisticParent.cs index 9750a5a7..915740f5 100644 --- a/Assets/OpenRelativity/Scripts/Objects/RelativisticParent.cs +++ b/Assets/OpenRelativity/Scripts/Objects/RelativisticParent.cs @@ -299,39 +299,52 @@ void Update() //make our rigidbody's velocity viw if (GetComponent() != null) { - - if (!double.IsNaN((double)state.SqrtOneMinusVSquaredCWDividedByCSquared) && (float)state.SqrtOneMinusVSquaredCWDividedByCSquared != 0) - //if (!double.IsNaN((double)state.InverseAcceleratedGamma) && (float)state.InverseAcceleratedGamma != 0) + float timeFac = GetTimeFactor(); + if ((float)state.SqrtOneMinusVSquaredCWDividedByCSquared != 0 + && IsNaNOrInf(timeFac)) { - Vector3 tempViw = viw; - //ASK RYAN WHY THESE WERE DIVIDED BY THIS - tempViw /= (float)state.SqrtOneMinusVSquaredCWDividedByCSquared; - //Attempt to correct for acceleration: - Vector3 playerPos = state.playerTransform.position; - Vector3 playerVel = state.PlayerVelocityVector; - tempViw /= (float)(1.0 + 1.0 / state.SpeedOfLightSqrd * Vector3.Dot(state.PlayerAccelerationVector, transform.position - playerPos)); - - GetComponent().velocity = tempViw; + GetComponent().velocity = viw / timeFac; } - - } } } - public Vector4 Get4Acceleration() + private bool IsNaNOrInf(double p) + { + return double.IsInfinity(p) || double.IsNaN(p); + } + + private bool IsNaNOrInf(float p) + { + return float.IsInfinity(p) || float.IsNaN(p); + } + + public Matrix4x4 GetMetric() { - Vector4 playerPos = state.playerTransform.position; - Vector3 propAccel = Vector4.zero; - if (useGravity && !isStatic) + return SRelativityUtil.GetRindlerMetric(transform.position); + } + + public float GetTimeFactor(Vector3? pVel = null) + { + if (!pVel.HasValue) { - propAccel += Physics.gravity; + pVel = state.PlayerVelocityVector; } - if (properAiw.sqrMagnitude > 0) + + Matrix4x4 metric = GetMetric(); + + float timeFac = 1 / Mathf.Sqrt(1 - (float)(Vector4.Dot(pVel.Value, metric * pVel.Value) / state.SpeedOfLightSqrd)); + if (IsNaNOrInf(timeFac)) { - propAccel += properAiw; + timeFac = 1; } - return propAccel.ProperToWorldAccel(viw); + + return timeFac; + } + + public Vector4 Get4Acceleration() + { + return properAiw.ProperToWorldAccel(viw); } } } \ No newline at end of file diff --git a/Assets/OpenRelativity/Scripts/Objects/SupportScripts/ObjectBoxColliderDensity.cs b/Assets/OpenRelativity/Scripts/Objects/SupportScripts/ObjectBoxColliderDensity.cs index de16c5aa..4e1ee98c 100644 --- a/Assets/OpenRelativity/Scripts/Objects/SupportScripts/ObjectBoxColliderDensity.cs +++ b/Assets/OpenRelativity/Scripts/Objects/SupportScripts/ObjectBoxColliderDensity.cs @@ -230,14 +230,6 @@ private IEnumerator CPUUpdatePositions() } change[i].center = newPos; } - //Cache actual world center of mass, and then reset local (rest frame) center of mass: - if (!isStatic) - { - myRB.ResetCenterOfMass(); - myRO.opticalWorldCenterOfMass = myRB.worldCenterOfMass; - myRB.centerOfMass = initCOM; - } - //} finishedCoroutine = true; coroutineTimer.Stop(); coroutineTimer.Reset(); @@ -262,7 +254,6 @@ private IEnumerator GPUUpdatePositions() myRO.wasKinematic = myRB.isKinematic; myRB.isKinematic = true; } - myRO.collideTimeStart += gameState.DeltaTimeWorld; } else if (myRO.wasFrozen) { @@ -351,16 +342,6 @@ private IEnumerator GPUUpdatePositions() } } - if (!isStatic) - { - //Cache actual world center of mass, and then reset local (rest frame) center of mass: - myRB.ResetCenterOfMass(); - myRO.opticalWorldCenterOfMass = myRB.worldCenterOfMass; - myRB.centerOfMass = initCOM; - } - - //Debug.Log("Finished updating mesh collider."); - finishedCoroutine = true; coroutineTimer.Stop(); coroutineTimer.Reset(); diff --git a/Assets/OpenRelativity/Scripts/RindlerHorizon.cs b/Assets/OpenRelativity/Scripts/RindlerHorizon.cs index 6c992d4b..d685f9ee 100644 --- a/Assets/OpenRelativity/Scripts/RindlerHorizon.cs +++ b/Assets/OpenRelativity/Scripts/RindlerHorizon.cs @@ -23,19 +23,22 @@ void Update() { Vector3 pAccel = state.PlayerAccelerationVector; float pAccelMag = pAccel.magnitude; + if (pAccelMag < MIN_ACCEL) { myRenderer.enabled = false; - } else - { - myRenderer.enabled = true; - // Quads face "backwards," if we use a default Unity quad. - Vector3 frwd = -pAccel / pAccelMag; - transform.forward = frwd; - Vector3 pos = (frwd * (float)state.SpeedOfLightSqrd / pAccelMag) + state.playerTransform.position; - //transform.Translate(transform.InverseTransformPoint(pos - transform.position)); - transform.position = pos; + return; } + + // TODO: Make this for kinematic RelativisticObject + + myRenderer.enabled = true; + // Quads face "backwards," if we use a default Unity quad. + Vector3 frwd = -pAccel / pAccelMag; + transform.forward = frwd; + Vector3 pos = (frwd * (float)state.SpeedOfLightSqrd / pAccelMag) + state.playerTransform.position; + //transform.Translate(transform.InverseTransformPoint(pos - transform.position)); + transform.position = pos; } } } diff --git a/Assets/OpenRelativity/Scripts/SRelativityUtil.cs b/Assets/OpenRelativity/Scripts/SRelativityUtil.cs index 1b94970d..501a52c0 100644 --- a/Assets/OpenRelativity/Scripts/SRelativityUtil.cs +++ b/Assets/OpenRelativity/Scripts/SRelativityUtil.cs @@ -6,36 +6,26 @@ namespace OpenRelativity { public static class SRelativityUtil { - public static float c { get { return (float)srCamera.SpeedOfLight; } } - public static float cSqrd { get { return (float)srCamera.SpeedOfLightSqrd; } } - public static float maxVel { get { return (float)srCamera.MaxSpeed; } } + public static float c { get { return (float)state.SpeedOfLight; } } + public static float cSqrd { get { return (float)state.SpeedOfLightSqrd; } } + public static float maxVel { get { return (float)state.MaxSpeed; } } + public const float divByZeroCutoff = 1e-8f; - private static GameState _srCamera; - private static GameState srCamera + private static GameState _state; + private static GameState state { get { - if (_srCamera == null) + if (_state == null) { GameObject cameraGO = GameObject.FindGameObjectWithTag(Tags.player); - _srCamera = cameraGO.GetComponent(); + _state = cameraGO.GetComponent(); } - return _srCamera; + return _state; } } - private static Vector3 GetSpatial(this Vector4 st) - { - return new Vector3(st.x, st.y, st.z); - } - - private static Vector4 MakeVel(this Vector3 spatial) - { - return new Vector4(spatial.x, spatial.y, spatial.z, c); - - } - public static Vector3 AddVelocity(this Vector3 orig, Vector3 toAdd) { Vector3 parra = Vector3.Project(toAdd, orig); @@ -45,12 +35,6 @@ public static Vector3 AddVelocity(this Vector3 orig, Vector3 toAdd) return parra + perp; } - public static Vector4 AddVelocity(this Vector4 orig, Vector4 toAdd) - { - Vector3 new3Vel = orig.GetSpatial().AddVelocity(toAdd.GetSpatial()); - return new Vector4(new3Vel.x, new3Vel.y, new3Vel.z, c); - } - public static Vector3 RelativeVelocityTo(this Vector3 myWorldVel, Vector3 otherWorldVel) { float speedSqr = myWorldVel.sqrMagnitude / cSqrd; @@ -77,42 +61,6 @@ public static Vector3 RelativeVelocityTo(this Vector3 myWorldVel, Vector3 otherW return vr * c; } - public static Vector4 RelativeVelocityTo(this Vector4 myWorldVel, Vector4 otherWorldVel) - { - Vector3 new3Vel = myWorldVel.GetSpatial().RelativeVelocityTo(otherWorldVel.GetSpatial()); - return new Vector4(new3Vel.x, new3Vel.y, new3Vel.z, c); - } - - - public static Vector4 ContractLengthBy(this Vector4 interval, Vector4 velocity) - { - float sqrMag = velocity.sqrMagnitude; - if (sqrMag == 0.0f) - { - return interval; - } - float invGamma = Mathf.Sqrt(1.0f + sqrMag / cSqrd); - Quaternion rot = Quaternion.FromToRotation(1.0f / sqrMag * velocity, Vector3.right); - Vector3 rotInt = rot * new Vector3(interval.x, interval.y, interval.z); - rotInt = new Vector3(rotInt.x * invGamma, rotInt.y, rotInt.z); - rotInt = Quaternion.Inverse(rot) * rotInt; - return new Vector4(rotInt.x, rotInt.y, rotInt.z, interval.w / invGamma); - } - public static Vector4 InverseContractLengthBy(this Vector4 interval, Vector4 velocity) - { - float sqrMag = velocity.sqrMagnitude; - if (sqrMag == 0.0f) - { - return interval; - } - float invGamma = Mathf.Sqrt(1.0f + sqrMag / cSqrd); - Quaternion rot = Quaternion.FromToRotation(1.0f / sqrMag * velocity, Vector3.right); - Vector3 rotInt = rot * new Vector3(interval.x, interval.y, interval.z); - rotInt = new Vector3(rotInt.x / invGamma, rotInt.y, rotInt.z); - rotInt = Quaternion.Inverse(rot) * rotInt; - return new Vector4(rotInt.x, rotInt.y, rotInt.z, interval.w * invGamma); - } - public static Vector3 ContractLengthBy(this Vector3 interval, Vector3 velocity) { float speedSqr = velocity.sqrMagnitude; @@ -141,8 +89,6 @@ public static Vector3 InverseContractLengthBy(this Vector3 interval, Vector3 vel return Quaternion.Inverse(rot) * rotInt; } - public const float divByZeroCutoff = 1e-8f; - public static Matrix4x4 GetLorentzTransformMatrix(Vector3 vpc) { float beta = vpc.magnitude; @@ -170,22 +116,24 @@ public static Matrix4x4 GetLorentzTransformMatrix(Vector3 vpc) public static Matrix4x4 GetRindlerMetric(Vector4 riw) { - return GetRindlerMetric(riw, srCamera.PlayerAccelerationVector, srCamera.PlayerAngularVelocityVector); + return GetRindlerMetric(riw, state.PlayerAccelerationVector, state.PlayerAngularVelocityVector); } public static Matrix4x4 GetRindlerMetric(Vector4 riw, Vector4 pap, Vector3 avp) { //Find metric based on player acceleration and rest frame: - Vector3 angFac = Vector3.Cross(avp, riw) / c; - float linFac = Vector3.Dot(pap, riw) / cSqrd; - linFac = ((1 + linFac) * (1 + linFac) - angFac.sqrMagnitude) * cSqrd; - angFac *= -2; + float linFac = 1 + Vector3.Dot(pap, riw) / cSqrd; + linFac *= linFac; + float angFac = Vector3.Dot(avp, riw) / c; + angFac *= angFac; + float avpMagSqr = avp.sqrMagnitude; + Vector3 angVec = avpMagSqr < divByZeroCutoff ? Vector3.zero : 2 * angFac / (c * avpMagSqr) * avp.normalized; Matrix4x4 metric = new Matrix4x4( - new Vector4(-1, 0, 0, angFac.x), - new Vector4(0, -1, 0, angFac.y), - new Vector4(0, 0, -1, angFac.z), - new Vector4(angFac.x, angFac.y, angFac.z, linFac) + new Vector4(-1, 0, 0, -angVec.x), + new Vector4(0, -1, 0, -angVec.y), + new Vector4(0, 0, -1, -angVec.z), + new Vector4(-angVec.x, -angVec.y, -angVec.z, (linFac * (1 - angFac) - angFac)) ); return metric; @@ -193,7 +141,7 @@ public static Matrix4x4 GetRindlerMetric(Vector4 riw, Vector4 pap, Vector3 avp) public static float GetTisw(this Vector4 stpiw, Vector3 velocity, Vector4 aiw) { - return stpiw.GetTisw(stpiw, velocity, srCamera.playerTransform.position, srCamera.PlayerAccelerationVector, srCamera.PlayerAngularVelocityVector, aiw); + return stpiw.GetTisw(stpiw, velocity, state.playerTransform.position, state.PlayerAccelerationVector, state.PlayerAngularVelocityVector, aiw); } public static float GetTisw(this Vector4 stpiw, Vector3 velocity, Vector3 origin, Vector3 playerVel, Vector3 pap, Vector3 avp, Vector4 aiw) @@ -241,12 +189,12 @@ public static float GetTisw(this Vector4 stpiw, Vector3 velocity, Vector3 origin return tisw; } - public static Vector3 WorldToOptical(this Vector4 stpiw, Vector3 velocity, Vector4? aiw = null, Matrix4x4? viwLorentzMatrix = null) + public static Vector3 WorldToOptical(this Vector4 stpiw, Vector3 velocity, Vector4 aiw, Matrix4x4? viwLorentzMatrix = null) { - return stpiw.WorldToOptical(velocity, srCamera.playerTransform.position, srCamera.PlayerVelocityVector, srCamera.PlayerAccelerationVector, srCamera.PlayerAngularVelocityVector, aiw, srCamera.PlayerLorentzMatrix, viwLorentzMatrix); + return stpiw.WorldToOptical(velocity, state.playerTransform.position, state.PlayerVelocityVector, state.PlayerAccelerationVector, state.PlayerAngularVelocityVector, aiw, state.PlayerLorentzMatrix, viwLorentzMatrix); } - public static Vector3 WorldToOptical(this Vector4 stpiw, Vector3 velocity, Vector3 origin, Vector3 playerVel, Vector3 pap, Vector3 avp, Vector4? aiw = null, Matrix4x4? vpcLorentzMatrix = null, Matrix4x4? viwLorentzMatrix = null) + public static Vector3 WorldToOptical(this Vector4 stpiw, Vector3 velocity, Vector3 origin, Vector3 playerVel, Vector3 pap, Vector3 avp, Vector4 aiw, Matrix4x4? vpcLorentzMatrix = null, Matrix4x4? viwLorentzMatrix = null) { Vector3 vpc = -playerVel / c; Vector3 viw = velocity / c; @@ -280,12 +228,7 @@ public static Vector3 WorldToOptical(this Vector4 stpiw, Vector3 velocity, Vecto //We are free to translate our position in time such that this is the case. //Apply Lorentz transform; - //metric = mul(transpose(viwLorentzMatrix), mul(metric, viwLorentzMatrix)); - if (aiw == null) - { - aiw = Vector3.zero.ProperToWorldAccel(viw); - } - Vector4 aiwTransformed = viwLorentzMatrix.Value * aiw.Value; + Vector4 aiwTransformed = viwLorentzMatrix.Value * aiw; aiwTransformed.w = 0; Vector4 riwTransformed = viwLorentzMatrix.Value * riw; //Translate in time: @@ -307,12 +250,7 @@ public static Vector3 WorldToOptical(this Vector4 stpiw, Vector3 velocity, Vecto { t2 = -Mathf.Sqrt(sqrtArg); } - //else - //{ - // //Unruh effect? - // //Seems to happen with points behind the player. - // bool putBreakPointHere = true; - //} + tisw += t2; //add the position offset due to acceleration if (aiwMag > divByZeroCutoff) @@ -343,12 +281,12 @@ public static Vector3 WorldToOptical(this Vector4 stpiw, Vector3 velocity, Vecto const int defaultOpticalToWorldMaxIterations = 5; const float defaultOpticalToWorldSqrErrorTolerance = 0.0001f; - public static Vector4 OpticalToWorld(this Vector4 opticalPos, Vector3 velocity, Vector4? aiw = null, Matrix4x4? vpcLorentzMatrix = null, Matrix4x4? viwLorentzMatrix = null) + public static Vector4 OpticalToWorld(this Vector4 opticalPos, Vector3 velocity, Vector4 aiw, Matrix4x4? vpcLorentzMatrix = null, Matrix4x4? viwLorentzMatrix = null) { - return opticalPos.OpticalToWorld(velocity, srCamera.playerTransform.position, srCamera.PlayerVelocityVector, srCamera.PlayerAccelerationVector, srCamera.PlayerAngularVelocityVector, aiw, vpcLorentzMatrix, viwLorentzMatrix); + return opticalPos.OpticalToWorld(velocity, state.playerTransform.position, state.PlayerVelocityVector, state.PlayerAccelerationVector, state.PlayerAngularVelocityVector, aiw, vpcLorentzMatrix, viwLorentzMatrix); } - public static Vector4 OpticalToWorld(this Vector4 opticalPos, Vector3 velocity, Vector3 origin, Vector3 playerVel, Vector3 pap, Vector3 avp, Vector4? aiw = null, Matrix4x4? vpcLorentzMatrix = null, Matrix4x4? viwLorentzMatrix = null) + public static Vector4 OpticalToWorld(this Vector4 opticalPos, Vector3 velocity, Vector3 origin, Vector3 playerVel, Vector3 pap, Vector3 avp, Vector4 aiw, Matrix4x4? vpcLorentzMatrix = null, Matrix4x4? viwLorentzMatrix = null) { Vector3 vpc = -playerVel / c; Vector3 viw = velocity / c; @@ -374,11 +312,7 @@ public static Vector4 OpticalToWorld(this Vector4 opticalPos, Vector3 velocity, Vector4 riwTransformed = viwToZRot * ((Vector3)riw - velocity * tisw); riwTransformed.w = tisw; Vector3 avpTransformed = viwToZRot * avp; - if (!aiw.HasValue) - { - aiw = Vector3.zero.ProperToWorldAccel(viw); - } - Vector3 aiwTransformed = viwToZRot * aiw.Value; + Vector3 aiwTransformed = viwToZRot * aiw; //We'll also Lorentz transform the vectors: if (viwLorentzMatrix == null) @@ -394,9 +328,9 @@ public static Vector4 OpticalToWorld(this Vector4 opticalPos, Vector3 velocity, float t2 = riwTransformed.w; - if (aiw.Value.sqrMagnitude > divByZeroCutoff) + float aiwMag = aiwTransformed.magnitude; + if (aiwMag> divByZeroCutoff) { - float aiwMag = aiwTransformed.magnitude; //add the position offset due to acceleration riwTransformed += (Vector4)(aiwTransformed) / aiwMag * c * c * (Mathf.Sqrt(1 + (aiwMag * t2 / c) * (aiwMag * t2 / c)) - 1); } @@ -410,9 +344,10 @@ public static Vector4 OpticalToWorld(this Vector4 opticalPos, Vector3 velocity, return riw; } + public static Vector3 OpticalToWorldHighPrecision(this Vector4 opticalPos, Vector3 velocity, Vector4 aiw, Matrix4x4? vpcLorentzMatrix = null, Matrix4x4? viwLorentzMatrix = null) { - return opticalPos.OpticalToWorldHighPrecision(velocity, srCamera.playerTransform.position, srCamera.PlayerVelocityVector, srCamera.PlayerAccelerationVector, srCamera.PlayerAngularVelocityVector, aiw, vpcLorentzMatrix, viwLorentzMatrix); + return opticalPos.OpticalToWorldHighPrecision(velocity, state.playerTransform.position, state.PlayerVelocityVector, state.PlayerAccelerationVector, state.PlayerAngularVelocityVector, aiw, vpcLorentzMatrix, viwLorentzMatrix); } public static Vector3 OpticalToWorldHighPrecision(this Vector4 opticalPos, Vector3 velocity, Vector3 origin, Vector3 playerVel, Vector4 pap, Vector3 avp, Vector4 aiw, Matrix4x4? vpcLorentz = null, Matrix4x4? viwLorentz = null) @@ -464,166 +399,6 @@ public static Vector3 RapidityToVelocity(this Vector3 rapidity, float? altMag = return (float)(c * Math.Tanh(mag / c) / mag) * rapidity; } - public static Vector3 GetGravity(Vector3 origin) - { - return Physics.gravity; - } - - public static Vector4 LorentzTransform(this Vector4 pos4, Vector3 vel3) - { - float gamma = vel3.Gamma(); - Vector3 pos3 = pos4; - Vector3 parra = Vector3.Project(pos3, vel3.normalized); - float tnew = gamma * (pos4.w - Vector3.Dot(parra, vel3) / cSqrd); - pos3 = gamma * (parra - vel3 * pos4.w) + (pos3 - parra); - return new Vector4(pos3.x, pos3.y, pos3.z, tnew); - } - - public static Vector4 InverseLorentzTransform(this Vector4 pos4, Vector3 vel3) - { - float gamma = vel3.Gamma(); - Vector3 pos3 = pos4; - Vector3 parra = Vector3.Project(pos3, vel3.normalized); - float tnew = gamma * (pos4.w + Vector3.Dot(parra, vel3) / cSqrd); - pos3 = gamma * (parra + vel3 * pos4.w) + (pos3 - parra); - return new Vector4(pos3.x, pos3.y, pos3.z, tnew); - } - - //http://answers.unity3d.com/questions/530178/how-to-get-a-component-from-an-object-and-add-it-t.html - public static T GetCopyOf(this Component comp, T other) where T : Component - { - Type type = comp.GetType(); - if (type != other.GetType()) return null; // type mis-match - BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default; - PropertyInfo[] pinfos = type.GetProperties(flags); - foreach (var pinfo in pinfos) - { - if (pinfo.CanWrite) - { - try - { - pinfo.SetValue(comp, pinfo.GetValue(other, null), null); - } - catch { } // In case of NotImplementedException being thrown. For some reason specifying that exception didn't seem to catch it, so I didn't catch anything specific. - } - } - FieldInfo[] finfos = type.GetFields(flags); - foreach (var finfo in finfos) - { - finfo.SetValue(comp, finfo.GetValue(other)); - } - return comp as T; - } - - public static T AddComponent(this GameObject go, T toAdd) where T : Component - { - return go.AddComponent().GetCopyOf(toAdd) as T; - } - - public static Vector3 SphericalToCartesian(this Vector3 spherical) - { - float radius = spherical.x; - float elevation = spherical.y; - float polar = spherical.z; - Vector3 outCart; - - float a = radius * Mathf.Cos(elevation); - outCart.x = a * Mathf.Cos(polar); - outCart.y = radius * Mathf.Sin(elevation); - outCart.z = a * Mathf.Sin(polar); - - return outCart; - } - - public static Vector4 Spherical4ToCartesian4(this Vector4 spherical) - { - float radius = spherical.x; - float elevation = spherical.y; - float polar = spherical.z; - float time = spherical.w; - Vector4 outCart; - - float a = radius * Mathf.Cos(elevation); - outCart.x = a * Mathf.Cos(polar); - outCart.y = radius * Mathf.Sin(elevation); - outCart.z = a * Mathf.Sin(polar); - outCart.w = time; - - return outCart; - } - - public static Vector3 CartesianToSpherical(this Vector3 cartesian) - { - float radius, polar, elevation; - radius = cartesian.magnitude; - if (radius == 0) - { - polar = 0; - elevation = 0; - } - else - { - float sqrtXSqrYSqr = Mathf.Sqrt(cartesian.x * cartesian.x + cartesian.y * cartesian.y); - if ((cartesian.z == 0) && (sqrtXSqrYSqr == 0)) - { - elevation = 0; - } - else - { - elevation = Mathf.Atan2(sqrtXSqrYSqr, cartesian.z); - } - - if ((cartesian.y == 0) && (cartesian.x == 0)) - { - polar = 0; - } - else - { - polar = Mathf.Atan2(cartesian.y, cartesian.x); - - } - } - - return new Vector3(radius, elevation, polar); - } - - public static Vector4 Cartesian4ToSpherical4(this Vector4 cartesian) - { - float outTime = cartesian.w; - float radius, polar, elevation; - Vector3 spatial = new Vector3(cartesian.x, cartesian.y, cartesian.z); - radius = spatial.magnitude; - if (radius == 0) - { - polar = 0; - elevation = 0; - } - else - { - float sqrtXSqrYSqr = Mathf.Sqrt(cartesian.x * cartesian.x + cartesian.y * cartesian.y); - if ((cartesian.z == 0) && (sqrtXSqrYSqr == 0)) - { - elevation = 0; - } - else - { - elevation = Mathf.Atan2(sqrtXSqrYSqr, cartesian.z); - } - - if ((cartesian.y == 0) && (cartesian.x == 0)) - { - polar = 0; - } - else - { - polar = Mathf.Atan2(cartesian.y, cartesian.x); - - } - } - - return new Vector4(radius, elevation, polar, outTime); - } - public static Vector4 ToMinkowski4Viw(this Vector3 viw) { return new Vector4(viw.x, viw.y, viw.z, (float)(Math.Sqrt(c - viw.sqrMagnitude) / c)); diff --git a/Assets/OpenRelativity/Shaders/Lit/relativityEmissiveAccel.shader b/Assets/OpenRelativity/Shaders/Lit/relativityEmissiveAccel.shader index 7bf2ef14..d3bcf74d 100644 --- a/Assets/OpenRelativity/Shaders/Lit/relativityEmissiveAccel.shader +++ b/Assets/OpenRelativity/Shaders/Lit/relativityEmissiveAccel.shader @@ -171,16 +171,21 @@ Shader "Relativity/Lit/Emissive/ColorShift" { float4 riwForMetric = mul(vpcLorentzMatrix, riw); //Find metric based on player acceleration and rest frame: - float3 angFac = cross(_avp.xyz, riwForMetric.xyz) / _spdOfLight; - float linFac = dot(_pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; - linFac = ((1 + linFac) * (1 + linFac) - dot(angFac, angFac)) * spdOfLightSqrd; - angFac *= -2 * _spdOfLight; + float linFac = 1 + dot(_pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; + linFac *= linFac; + float angFac = dot(_avp.xyz, riwForMetric.xyz) / _spdOfLight; + angFac *= angFac; + float avpMagSqr = dot(_avp.xyz, _avp.xyz); + float3 angVec = float3(0, 0, 0); + if (avpMagSqr > divByZeroCutoff) { + angVec = 2 * angFac / (_spdOfLight * avpMagSqr) * _avp.xyz; + } float4x4 metric = { - -1, 0, 0, angFac.x, - 0, -1, 0, angFac.y, - 0, 0, -1, angFac.z, - angFac.x, angFac.y, angFac.z, linFac + -1, 0, 0, -angVec.x, + 0, -1, 0, -angVec.y, + 0, 0, -1, -angVec.z, + -angVec.x, -angVec.y, angVec.z, (linFac * (1 - angFac) - angFac) }; //Lorentz boost back to world frame; diff --git a/Assets/OpenRelativity/Shaders/Lit/relativityLitAccel.shader b/Assets/OpenRelativity/Shaders/Lit/relativityLitAccel.shader index 98ea344a..45de6198 100644 --- a/Assets/OpenRelativity/Shaders/Lit/relativityLitAccel.shader +++ b/Assets/OpenRelativity/Shaders/Lit/relativityLitAccel.shader @@ -181,16 +181,21 @@ Shader "Relativity/Lit/ColorShift" { float4 riwForMetric = mul(vpcLorentzMatrix, riw); //Find metric based on player acceleration and rest frame: - float3 angFac = cross(_avp.xyz, riwForMetric.xyz) / _spdOfLight; - float linFac = dot(_pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; - linFac = ((1 + linFac) * (1 + linFac) - dot(angFac, angFac)) * spdOfLightSqrd; - angFac *= -2 * _spdOfLight; + float linFac = 1 + dot(_pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; + linFac *= linFac; + float angFac = dot(_avp.xyz, riwForMetric.xyz) / _spdOfLight; + angFac *= angFac; + float avpMagSqr = dot(_avp.xyz, _avp.xyz); + float3 angVec = float3(0, 0, 0); + if (avpMagSqr > divByZeroCutoff) { + angVec = 2 * angFac / (_spdOfLight * avpMagSqr) * _avp.xyz; + } float4x4 metric = { - -1, 0, 0, angFac.x, - 0, -1, 0, angFac.y, - 0, 0, -1, angFac.z, - angFac.x, angFac.y, angFac.z, linFac + -1, 0, 0, -angVec.x, + 0, -1, 0, -angVec.y, + 0, 0, -1, -angVec.z, + -angVec.x, -angVec.y, angVec.z, (linFac * (1 - angFac) - angFac) }; //Lorentz boost back to world frame; diff --git a/Assets/OpenRelativity/Shaders/Lit/relativityLitSpecularAccel.shader b/Assets/OpenRelativity/Shaders/Lit/relativityLitSpecularAccel.shader index 30e06d85..9a306840 100644 --- a/Assets/OpenRelativity/Shaders/Lit/relativityLitSpecularAccel.shader +++ b/Assets/OpenRelativity/Shaders/Lit/relativityLitSpecularAccel.shader @@ -184,16 +184,21 @@ Shader "Relativity/Lit/Specular/ColorShift" { float4 riwForMetric = mul(vpcLorentzMatrix, riw); //Find metric based on player acceleration and rest frame: - float3 angFac = cross(_avp.xyz, riwForMetric.xyz) / _spdOfLight; - float linFac = dot(_pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; - linFac = ((1 + linFac) * (1 + linFac) - dot(angFac, angFac)) * spdOfLightSqrd; - angFac *= -2 * _spdOfLight; + float linFac = 1 + dot(_pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; + linFac *= linFac; + float angFac = dot(_avp.xyz, riwForMetric.xyz) / _spdOfLight; + angFac *= angFac; + float avpMagSqr = dot(_avp.xyz, _avp.xyz); + float3 angVec = float3(0, 0, 0); + if (avpMagSqr > divByZeroCutoff) { + angVec = 2 * angFac / (_spdOfLight * avpMagSqr) * _avp.xyz; + } float4x4 metric = { - -1, 0, 0, angFac.x, - 0, -1, 0, angFac.y, - 0, 0, -1, angFac.z, - angFac.x, angFac.y, angFac.z, linFac + -1, 0, 0, -angVec.x, + 0, -1, 0, -angVec.y, + 0, 0, -1, -angVec.z, + -angVec.x, -angVec.y, angVec.z, (linFac * (1 - angFac) - angFac) }; //Lorentz boost back to world frame; diff --git a/Assets/OpenRelativity/Shaders/Unlit/relativityAccel.shader b/Assets/OpenRelativity/Shaders/Unlit/relativityAccel.shader index 73ad59e5..bf9a8890 100644 --- a/Assets/OpenRelativity/Shaders/Unlit/relativityAccel.shader +++ b/Assets/OpenRelativity/Shaders/Unlit/relativityAccel.shader @@ -155,16 +155,21 @@ Shader "Relativity/Unlit/ColorShift" float4 riwForMetric = mul(vpcLorentzMatrix, riw); //Find metric based on player acceleration and rest frame: - float3 angFac = cross(_avp.xyz, riwForMetric.xyz) / _spdOfLight; - float linFac = dot(_pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; - linFac = ((1 + linFac) * (1 + linFac) - dot(angFac, angFac)) * spdOfLightSqrd; - angFac *= -2 * _spdOfLight; + float linFac = 1 + dot(_pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; + linFac *= linFac; + float angFac = dot(_avp.xyz, riwForMetric.xyz) / _spdOfLight; + angFac *= angFac; + float avpMagSqr = dot(_avp.xyz, _avp.xyz); + float3 angVec = float3(0, 0, 0); + if (avpMagSqr > divByZeroCutoff) { + angVec = 2 * angFac / (_spdOfLight * avpMagSqr) * _avp.xyz; + } float4x4 metric = { - -1, 0, 0, angFac.x, - 0, -1, 0, angFac.y, - 0, 0, -1, angFac.z, - angFac.x, angFac.y, angFac.z, linFac + -1, 0, 0, -angVec.x, + 0, -1, 0, -angVec.y, + 0, 0, -1, -angVec.z, + -angVec.x, -angVec.y, angVec.z, (linFac * (1 - angFac) - angFac) }; //Lorentz boost back to world frame; diff --git a/Assets/OpenRelativity/Shaders/relativityAccel.compute b/Assets/OpenRelativity/Shaders/relativityAccel.compute index f1473926..9a48cdd8 100644 --- a/Assets/OpenRelativity/Shaders/relativityAccel.compute +++ b/Assets/OpenRelativity/Shaders/relativityAccel.compute @@ -71,16 +71,21 @@ void CSMain(uint3 id : SV_DispatchThreadID) float4 riwForMetric = mul(vpcLorentzMatrix, riw); //Find metric based on player acceleration and rest frame: - float3 angFac = cross(avp.xyz, riwForMetric.xyz) / spdOfLight; - float linFac = dot(pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; - linFac = ((1 + linFac) * (1 + linFac) - dot(angFac, angFac)) * spdOfLightSqrd; - angFac *= -2 * spdOfLight; + float linFac = 1 + dot(pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; + linFac *= linFac; + float angFac = dot(avp.xyz, riwForMetric.xyz) / spdOfLight; + angFac *= angFac; + float avpMagSqr = dot(avp.xyz, avp.xyz); + float3 angVec = float3(0, 0, 0); + if (avpMagSqr > divByZeroCutoff) { + angVec = 2 * angFac / (spdOfLight * avpMagSqr) * avp.xyz; + } float4x4 metric = { - -1, 0, 0, angFac.x, - 0, -1, 0, angFac.y, - 0, 0, -1, angFac.z, - angFac.x, angFac.y, angFac.z, linFac + -1, 0, 0, -angVec.x, + 0, -1, 0, -angVec.y, + 0, 0, -1, -angVec.z, + -angVec.x, -angVec.y, angVec.z, (linFac * (1 - angFac) - angFac) }; //Lorentz boost back to world frame; diff --git a/Assets/OpenRelativity/Shaders/relativityWorldAccel.compute b/Assets/OpenRelativity/Shaders/relativityWorldAccel.compute index 6cbedf72..c5f62d1c 100644 --- a/Assets/OpenRelativity/Shaders/relativityWorldAccel.compute +++ b/Assets/OpenRelativity/Shaders/relativityWorldAccel.compute @@ -69,16 +69,21 @@ void CSMain(uint3 id : SV_DispatchThreadID) float4 riwForMetric = mul(vpcLorentzMatrix, riw); //Find metric based on player acceleration and rest frame: - float3 angFac = cross(avp.xyz, riwForMetric.xyz) / spdOfLight; - float linFac = dot(pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; - linFac = ((1 + linFac) * (1 + linFac) - dot(angFac, angFac)) * spdOfLightSqrd; - angFac *= -2 * spdOfLight; + float linFac = 1 + dot(pap.xyz, riwForMetric.xyz) / spdOfLightSqrd; + linFac *= linFac; + float angFac = dot(avp.xyz, riwForMetric.xyz) / spdOfLight; + angFac *= angFac; + float avpMagSqr = dot(avp.xyz, avp.xyz); + float3 angVec = float3(0, 0, 0); + if (avpMagSqr > divByZeroCutoff) { + angVec = 2 * angFac / (spdOfLight * avpMagSqr) * avp.xyz; + } float4x4 metric = { - -1, 0, 0, angFac.x, - 0, -1, 0, angFac.y, - 0, 0, -1, angFac.z, - angFac.x, angFac.y, angFac.z, linFac + -1, 0, 0, -angVec.x, + 0, -1, 0, -angVec.y, + 0, 0, -1, -angVec.z, + -angVec.x, -angVec.y, angVec.z, (linFac * (1 - angFac) - angFac) }; //Lorentz boost back to world frame; diff --git a/ProjectSettings/DynamicsManager.asset b/ProjectSettings/DynamicsManager.asset index 1b178106..12e57027 100644 Binary files a/ProjectSettings/DynamicsManager.asset and b/ProjectSettings/DynamicsManager.asset differ