├── ProjectSettings ├── ProjectVersion.txt ├── ClusterInputManager.asset ├── PresetManager.asset ├── EditorBuildSettings.asset ├── XRSettings.asset ├── VersionControlSettings.asset ├── TimeManager.asset ├── VFXManager.asset ├── AudioManager.asset ├── TagManager.asset ├── EditorSettings.asset ├── UnityConnectSettings.asset ├── PackageManagerSettings.asset ├── DynamicsManager.asset ├── NavMeshAreas.asset ├── Physics2DSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset └── QualitySettings.asset ├── Assets ├── Cyclone.meta ├── CommonUnity.meta ├── Cyclone │ ├── Core.meta │ ├── Particles.meta │ ├── Rigid.meta │ ├── Rigid │ │ ├── Forces.meta │ │ ├── Collisions.meta │ │ ├── Constraints.meta │ │ ├── RigidBody.cs.meta │ │ ├── RigidBodyEngine.cs.meta │ │ ├── Forces │ │ │ ├── RigidForce.cs.meta │ │ │ ├── RigidForceArea.cs.meta │ │ │ ├── RigidGravityForce.cs.meta │ │ │ ├── RigidSpringForce.cs.meta │ │ │ ├── RigidForceArea.cs │ │ │ ├── RigidForce.cs │ │ │ ├── RigidGravityForce.cs │ │ │ └── RigidSpringForce.cs │ │ ├── Collisions │ │ │ ├── CollisionBox.cs.meta │ │ │ ├── CollisionData.cs.meta │ │ │ ├── CollisionPlane.cs.meta │ │ │ ├── CollisionDetector.cs.meta │ │ │ ├── CollisionPrimitive.cs.meta │ │ │ ├── CollisionSphere.cs.meta │ │ │ ├── IntersectionTests.cs.meta │ │ │ ├── CollisionSphere.cs │ │ │ ├── CollisionBox.cs │ │ │ ├── CollisionPlane.cs │ │ │ ├── CollisionPrimitive.cs │ │ │ ├── CollisionData.cs │ │ │ └── IntersectionTests.cs │ │ ├── Constraints │ │ │ ├── RidgeContact.cs.meta │ │ │ ├── RigidConstraint.cs.meta │ │ │ ├── CollisionConstraint.cs.meta │ │ │ ├── RigidContactResolver.cs.meta │ │ │ ├── RigidJointConstraint.cs.meta │ │ │ ├── RigidConstraint.cs │ │ │ ├── RigidJointConstraint.cs │ │ │ ├── CollisionConstraint.cs │ │ │ └── RigidContactResolver.cs │ │ └── RigidBodyEngine.cs │ ├── Particles │ │ ├── Forces.meta │ │ ├── Constraints.meta │ │ ├── Particle.cs.meta │ │ ├── ParticleEngine.cs.meta │ │ ├── Forces │ │ │ ├── ParticleForce.cs.meta │ │ │ ├── ParticleDragForce.cs.meta │ │ │ ├── ParticleForceArea.cs.meta │ │ │ ├── ParticleSpringForce.cs.meta │ │ │ ├── ParticleElasticForce.cs.meta │ │ │ ├── ParticleGravityForce.cs.meta │ │ │ ├── ParticleForceArea.cs │ │ │ ├── ParticleForce.cs │ │ │ ├── ParticleGravityForce.cs │ │ │ ├── ParticleDragForce.cs │ │ │ ├── ParticleSpringForce.cs │ │ │ └── ParticleElasticForce.cs │ │ ├── Constraints │ │ │ ├── ParticleConstraint.cs.meta │ │ │ ├── ParticleContact.cs.meta │ │ │ ├── PlaneConstraint.cs.meta │ │ │ ├── ParticleCableConstraint.cs.meta │ │ │ ├── ParticleContactResolver.cs.meta │ │ │ ├── ParticleRodConstraint.cs.meta │ │ │ ├── ParticleConstraint.cs │ │ │ ├── PlaneConstraint.cs │ │ │ ├── ParticleCableConstraint.cs │ │ │ ├── ParticleRodConstraint.cs │ │ │ ├── ParticleContactResolver.cs │ │ │ └── ParticleContact.cs │ │ ├── Particle.cs │ │ └── ParticleEngine.cs │ └── Core │ │ ├── DMath.cs.meta │ │ ├── Matrix3.cs.meta │ │ ├── Matrix4.cs.meta │ │ ├── Quaternion.cs.meta │ │ ├── Vector3d.cs.meta │ │ ├── Quaternion.cs │ │ ├── DMath.cs │ │ ├── Matrix4.cs │ │ └── Matrix3.cs ├── UnityTestScenes.meta ├── UnityTestScenes │ ├── Scenes │ │ ├── RigidTest.unity.meta │ │ └── ParticleTest.unity.meta │ ├── Scenes.meta │ ├── Scripts.meta │ └── Scripts │ │ ├── RigidBox.cs.meta │ │ ├── CollisionPlane.cs.meta │ │ ├── MathExtensions.cs.meta │ │ ├── ParticleRod.cs.meta │ │ ├── ParticleSpring.cs.meta │ │ ├── RigidSphere.cs.meta │ │ ├── RigidPhysicsEngine.cs.meta │ │ ├── ParticlePhysicsEngine.cs.meta │ │ ├── CollisionPlane.cs │ │ ├── ParticlePhysicsEngine.cs │ │ ├── MathExtensions.cs │ │ ├── RigidPhysicsEngine.cs │ │ ├── RigidSphere.cs │ │ ├── RigidBox.cs │ │ ├── ParticleSpring.cs │ │ └── ParticleRod.cs └── CommonUnity │ ├── Cameras.meta │ ├── Drawing.meta │ ├── Drawing │ ├── BaseRenderer.cs.meta │ ├── VextexRenderer.cs.meta │ ├── SegmentRenderer.cs.meta │ ├── BaseRenderer.cs │ ├── VextexRenderer.cs │ └── SegmentRenderer.cs │ └── Cameras │ ├── SimpleCameraController.cs.meta │ └── SimpleCameraController.cs ├── README.md ├── LICENSE ├── .gitattributes └── .gitignore /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2020.1.6f1 2 | m_EditorVersionWithRevision: 2020.1.6f1 (fc477ca6df10) 3 | -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1386491679 &1 4 | PresetManager: 5 | m_ObjectHideFlags: 0 6 | m_DefaultList: [] 7 | -------------------------------------------------------------------------------- /Assets/Cyclone.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e0d3096563f98264aa24df1520a2e643 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/CommonUnity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a51b948b600a5e845bfbbf8769d95921 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Cyclone/Core.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 74de1357ead1c3546a94f4c75031c8d6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 03256bf897fd16d4d8b22688d2cc7944 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c3030cc44c893da4abccb2e3bc51293a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a843e1952e00bf447a47aacbd54a5257 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scenes/RigidTest.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 500236e4f4768bf40bf17dee4a8c5978 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: [] 8 | m_configObjects: {} 9 | -------------------------------------------------------------------------------- /Assets/CommonUnity/Cameras.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b910f1ef0024e5241853b84a4b0fda2e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/CommonUnity/Drawing.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da173af6237ad3b4bb6d9ba9e64dd2a7 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Forces.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 86cf8d717b4af474f8035be26d53503f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b1b95403cf711c34096b434367f6b3b4 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scenes/ParticleTest.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 48f8feda1bedd7945a6fb0e126a217e9 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b4b084e738be06440aca4577676f8834 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fb3f5991268b56d439a284f9f812e93c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Constraints.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 120150dde02fea6449ab37006220ac64 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 23a4ef1660c4ddd4f9fdec4133ba5984 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 515f2489a6848c2489e577f6acd4c6fd 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /ProjectSettings/VersionControlSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!890905787 &1 4 | VersionControlSettings: 5 | m_ObjectHideFlags: 0 6 | m_Mode: Visible Meta Files 7 | m_CollabEditorSettings: 8 | inProgressEnabled: 1 9 | -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /Assets/Cyclone/Core/DMath.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a86099c31cbb72041a45d7dec3f4cb1d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Core/Matrix3.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3df2a6d748c86054d99559b54d876a5f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Core/Matrix4.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ab8f4871b2f80bb489985acc607e0683 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Core/Quaternion.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f4a7b216f1ec4a14bbaa34c20f0acdc4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Core/Vector3d.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb4efd3fb205737478b2c77142aee19e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/RigidBody.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6bdf8590d028dcf48ac83151227ee8c0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Particle.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3a089280f746be041bfaefcee18da542 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/RigidBodyEngine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3b8436c8c2be9fa4b94ba26244ab05d5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/CommonUnity/Drawing/BaseRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2ee727f728c666844aa562a7d4069d8f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/CommonUnity/Drawing/VextexRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 51f9fa99b018b3642a0c6f6d5ab9e5df 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/ParticleEngine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd0db5cf58cfdbb45932863824560422 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Forces/RigidForce.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bdcccf4146515f145975fc6594b79f1c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/RigidBox.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 37c37f89d10dc5a4d94eee148fc63ccf 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/CommonUnity/Drawing/SegmentRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c640c95997cc21a438c60fef9bac06cd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleForce.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a67942514cd256d4aba1894356c7f2fe 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionBox.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 57bb3f7e7923c094aba6044d3108ecc5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 41ec3d3a213d96f4d9d9fd9af936bb5c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionPlane.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9745db5df4412524a866f6f9b1314de4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Constraints/RidgeContact.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e4703b9a079e6134f89ca2c447f61987 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Forces/RigidForceArea.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e377d869fcaec594a95a31563c266caf 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Forces/RigidGravityForce.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bcd8eb788ef8f0b44bc303d96f6c8c02 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Forces/RigidSpringForce.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 699bd6c1592873540b0943ea86bb26ae 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/CollisionPlane.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 68a3c3f735fd80a4a9febd1fa2a75e3a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/MathExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aea4976721edbdf479373dd0f12ce8f4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/ParticleRod.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 590ba1bac20ecb8439d3a49dde3ef523 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/ParticleSpring.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a75735c6af91274a9b7a1bbd861fd1f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/RigidSphere.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ba137f3aa689b754dbfaebc8466738b8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/CommonUnity/Cameras/SimpleCameraController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6d2223c8b8b0021418bdacd2ac82b8e6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleDragForce.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bb568f13cf415e04f8ff8c595605d87c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleForceArea.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9403dfef7d62937429a6017c8b50d0b0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleSpringForce.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 863c88906fe883944948f469f3468a7e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionDetector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8486d955ade96da45818432b85a889a4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionPrimitive.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a7fd32e0b7d10e445960f3cae3acd066 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionSphere.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3eadb50b1276b1e46824ede749496fbb 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/IntersectionTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3a7599d0adb7f474382e9ac1992be7dc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Constraints/RigidConstraint.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eba4af340fb881e46a808f3ed2a7eee4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/RigidPhysicsEngine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5c35f16c12354e8488e2d40f22d4b6b5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/ParticleConstraint.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 93789bc5226390247a0e9dd4f3e32e03 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/ParticleContact.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 48bcca9166ec1be43831be93aae05100 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/PlaneConstraint.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 36b3108169456ca4bb3fd6b2dbf1c53e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleElasticForce.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1692fad5ad90e14409be51ff070da053 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleGravityForce.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a37ca47470d73d14eb1bca975d9d4774 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Constraints/CollisionConstraint.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 89fdd984740e1d54182af7956a73c855 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Constraints/RigidContactResolver.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5cf29c7b2892fd7469e90c6ce6c60aa8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Constraints/RigidJointConstraint.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 50a21051baee33c438b4dba3581267f0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/ParticlePhysicsEngine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d5e3a4e2c290644b87a312dd7cba50a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!937362698 &1 4 | VFXManager: 5 | m_ObjectHideFlags: 0 6 | m_IndirectShader: {fileID: 0} 7 | m_CopyBufferShader: {fileID: 0} 8 | m_SortShader: {fileID: 0} 9 | m_RenderPipeSettingsPath: 10 | m_FixedTimeStep: 0.016666668 11 | m_MaxDeltaTime: 0.05 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/ParticleCableConstraint.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 46432a5c91bce1f45ba62f4513a2b8f4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/ParticleContactResolver.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 67d769851e45fc74c810551281ffcc80 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/ParticleRodConstraint.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5d0ffb5ed6cf6c54b8732afd5e183a76 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | m_Volume: 1 7 | Rolloff Scale: 1 8 | Doppler Factor: 1 9 | Default Speaker Mode: 2 10 | m_SampleRate: 0 11 | m_DSPBufferSize: 1024 12 | m_VirtualVoiceCount: 512 13 | m_RealVoiceCount: 32 14 | m_SpatializerPlugin: 15 | m_AmbisonicDecoderPlugin: 16 | m_DisableAudio: 0 17 | m_VirtualizeEffects: 1 18 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionSphere.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Rigid; 6 | 7 | namespace Cyclone.Rigid.Collisions 8 | { 9 | /// 10 | /// Represents a rigid body that can be treated as a sphere 11 | /// for collision detection. 12 | /// 13 | public class CollisionSphere : CollisionPrimitive 14 | { 15 | public double Radius; 16 | 17 | public CollisionSphere(double radius) 18 | { 19 | Radius = radius; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Forces/RigidForceArea.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Cyclone.Rigid.Forces 6 | { 7 | /// 8 | /// A force that applies to any body that enters the forces area. 9 | /// 10 | public abstract class RigidForceArea 11 | { 12 | /// 13 | /// Overload this in implementations of the interface to calculate 14 | /// and update the force applied to the body. 15 | /// 16 | public abstract void UpdateForce(RigidBody body, double dt); 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleForceArea.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Cyclone.Particles.Forces 6 | { 7 | /// 8 | /// A force that applies to any partice that enters the forces area. 9 | /// 10 | public abstract class ParticleForceArea 11 | { 12 | /// 13 | /// Overload this in implementations of the interface to calculate 14 | /// and update the force applied to the particle. 15 | /// 16 | public abstract void UpdateForce(Particle particle, double dt); 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/CollisionPlane.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | using Cyclone.Core; 6 | 7 | using PLANE = Cyclone.Rigid.Collisions.CollisionPlane; 8 | 9 | namespace CycloneUnityTestScenes 10 | { 11 | public class CollisionPlane : MonoBehaviour 12 | { 13 | 14 | private PLANE m_plane; 15 | 16 | void Start() 17 | { 18 | double y = transform.position.y; 19 | 20 | m_plane = new PLANE(Vector3d.UnitY, y); 21 | 22 | RigidPhysicsEngine.Instance.Collisions.Planes.Add(m_plane); 23 | } 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Forces/RigidForce.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Rigid; 6 | 7 | namespace Cyclone.Rigid.Forces 8 | { 9 | 10 | /// 11 | /// A force that applies to one or more bodies 12 | /// during the duration of the simulation. 13 | /// 14 | public abstract class RigidForce 15 | { 16 | /// 17 | /// Overload this in implementations of the interface to calculate 18 | /// and update the force applied to the bodies. 19 | /// 20 | public abstract void UpdateForce(double dt); 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleForce.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Particles; 6 | 7 | namespace Cyclone.Particles.Forces 8 | { 9 | 10 | /// 11 | /// A force that applies to one or more particles 12 | /// during the duration of the simulation. 13 | /// 14 | public abstract class ParticleForce 15 | { 16 | /// 17 | /// Overload this in implementations of the interface to calculate 18 | /// and update the force applied to the particles. 19 | /// 20 | public abstract void UpdateForce(double dt); 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Rigid.Collisions 7 | { 8 | /// 9 | /// Represents a rigid body that can be treated as an aligned bounding 10 | /// box for collision detection. 11 | /// 12 | public class CollisionBox : CollisionPrimitive 13 | { 14 | /// 15 | /// Holds the half-sizes of the box along each of its local axes. 16 | /// 17 | public Vector3d HalfSize; 18 | 19 | public CollisionBox(double halfSize) 20 | { 21 | HalfSize = new Vector3d(halfSize); 22 | } 23 | 24 | public CollisionBox(Vector3d halfSize) 25 | { 26 | HalfSize = halfSize; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 7 7 | m_ExternalVersionControlSupport: Hidden Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 2 10 | m_DefaultBehaviorMode: 0 11 | m_PrefabRegularEnvironment: {fileID: 0} 12 | m_PrefabUIEnvironment: {fileID: 0} 13 | m_SpritePackerMode: 0 14 | m_SpritePackerPaddingPower: 1 15 | m_EtcTextureCompressorBehavior: 1 16 | m_EtcTextureFastCompressor: 1 17 | m_EtcTextureNormalCompressor: 2 18 | m_EtcTextureBestCompressor: 4 19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp 20 | m_ProjectGenerationRootNamespace: 21 | m_CollabEditorSettings: 22 | inProgressEnabled: 1 23 | m_EnableTextureStreamingInEditMode: 1 24 | m_EnableTextureStreamingInPlayMode: 1 25 | m_AsyncShaderCompilation: 1 26 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Constraints/RigidConstraint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Rigid.Constraints 7 | { 8 | 9 | /// 10 | /// This is the basic polymorphic interface for contact generators 11 | /// applying to rigid bodies. 12 | /// 13 | public abstract class RigidConstraint 14 | { 15 | /// 16 | /// Fills the given contact structure with the generated 17 | /// contact. The contact pointer should point to the first 18 | /// available contact in a contact array, where limit is the 19 | /// maximum number of contacts in the array that can be written 20 | /// to. The method returns the number of contacts that have 21 | /// been written. 22 | /// 23 | public abstract int AddContact(IList bodies, IList contacts, int next); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionPlane.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Rigid.Collisions 7 | { 8 | /// 9 | /// The plane is not a primitive: it doesn't represent another 10 | /// rigid body.It is used for contacts with the immovable 11 | /// world geometry. 12 | /// 13 | public class CollisionPlane 14 | { 15 | /// 16 | /// The plane normal 17 | /// 18 | public Vector3d Direction; 19 | 20 | /// 21 | /// The distance of the plane from the origin. 22 | /// 23 | public double Offset; 24 | 25 | /// 26 | /// 27 | /// 28 | public CollisionPlane(Vector3d direction, double offset) 29 | { 30 | Direction = direction; 31 | Offset = offset; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleGravityForce.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Particles; 6 | 7 | namespace Cyclone.Particles.Forces 8 | { 9 | public class ParticleGravityForce : ParticleForceArea 10 | { 11 | 12 | private Vector3d m_gravity; 13 | 14 | public ParticleGravityForce(double gravity) 15 | { 16 | m_gravity = new Vector3d(0, gravity, 0); 17 | } 18 | 19 | public ParticleGravityForce(Vector3d gravity) 20 | { 21 | m_gravity = gravity; 22 | } 23 | 24 | public override void UpdateForce(Particle particle, double dt) 25 | { 26 | // Check that we do not have infinite mass 27 | if (!particle.HasFiniteMass) return; 28 | 29 | // Apply the mass-scaled force to the particle 30 | particle.AddForce(m_gravity * particle.GetMass()); 31 | } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/ParticleConstraint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Particles; 6 | 7 | namespace Cyclone.Particles.Constraints 8 | { 9 | /// 10 | /// This is the basic polymorphic interface for contact generators 11 | /// applying to particles. 12 | /// 13 | public abstract class ParticleConstraint 14 | { 15 | /// 16 | /// Fills the given contact structure with the generated 17 | /// contact.The contact pointer should point to the first 18 | /// available contact in a contact array, where limit is the 19 | /// maximum number of contacts in the array that can be written 20 | /// to.The method returns the number of contacts that have 21 | /// been written. 22 | /// 23 | public abstract int AddContact(IList particles, IList contacts, int next); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 1 7 | m_Enabled: 0 8 | m_TestMode: 0 9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events 10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events 11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com 12 | m_TestInitMode: 0 13 | CrashReportingSettings: 14 | m_EventUrl: https://perf-events.cloud.unity3d.com 15 | m_Enabled: 0 16 | m_LogBufferSize: 10 17 | m_CaptureEditorExceptions: 1 18 | UnityPurchasingSettings: 19 | m_Enabled: 0 20 | m_TestMode: 0 21 | UnityAnalyticsSettings: 22 | m_Enabled: 0 23 | m_TestMode: 0 24 | m_InitializeOnStartup: 1 25 | UnityAdsSettings: 26 | m_Enabled: 0 27 | m_InitializeOnStartup: 1 28 | m_TestMode: 0 29 | m_IosGameId: 30 | m_AndroidGameId: 31 | m_GameIds: {} 32 | m_GameId: 33 | PerformanceReportingSettings: 34 | m_Enabled: 0 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CyclonePhysicsEngine 2 | C# port of the [Cylcone physics engine](https://github.com/idmillington/cyclone-physics) based on the book Game Physics Engine Design. 3 | 4 | I have made some small changes and restructured the code a little. 5 | 6 | The projects uses Unity to create a few test scenes but the code (all the scripts in the Cyclone folder) is not connected to Unity in any way and can be used as a standonle project if required. 7 | 8 | List of physics projects 9 | 10 | [Position-Based-Dynamics](https://github.com/Scrawk/Position-Based-Dynamics)\ 11 | [PBD-Fluid-in-Unity](https://github.com/Scrawk/PBD-Fluid-in-Unity)\ 12 | [GPU-GEMS-NBody-Simulation](https://github.com/Scrawk/GPU-GEMS-NBody-Simulation)\ 13 | [GPU-GEMS-2D-Fluid-Simulation](https://github.com/Scrawk/GPU-GEMS-2D-Fluid-Simulation)\ 14 | [GPU-GEMS-3D-Fluid-Simulation](https://github.com/Scrawk/GPU-GEMS-3D-Fluid-Simulation)\ 15 | [CyclonePhysicsEngine](https://github.com/Scrawk/CyclonePhysicsEngine)\ 16 | [2D-Deformable-body-in-Unity](https://github.com/Scrawk/2D-Deformable-body-in-Unity) 17 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/ParticlePhysicsEngine.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | using Cyclone.Particles; 6 | using Cyclone.Particles.Forces; 7 | using Cyclone.Particles.Constraints; 8 | 9 | namespace CycloneUnityTestScenes 10 | { 11 | 12 | public class ParticlePhysicsEngine : MonoBehaviour 13 | { 14 | public int iterations = 0; 15 | 16 | public int maxContacts = 100; 17 | 18 | public static ParticleEngine Instance { get; private set; } 19 | 20 | private void Awake() 21 | { 22 | Instance = new ParticleEngine(maxContacts); 23 | Instance.Resolver.Iterations = iterations; 24 | 25 | Instance.ForceAreas.Add(new ParticleGravityForce(-9.81)); 26 | 27 | //Instance.Constraints.Add(new PlaneConstraint(-2)); 28 | } 29 | 30 | private void FixedUpdate() 31 | { 32 | double dt = Time.fixedDeltaTime; 33 | 34 | Instance.StartFrame(); 35 | Instance.RunPhysics(dt); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleDragForce.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Particles; 6 | 7 | namespace Cyclone.Particles.Forces 8 | { 9 | public class ParticleDragForce : ParticleForceArea 10 | { 11 | //Holds the velocity drag coeffificent. 12 | private double k1; 13 | 14 | // Holds the velocity squared drag coeffificent. 15 | private double k2; 16 | 17 | public ParticleDragForce(double k1, double k2) 18 | { 19 | this.k1 = k1; 20 | this.k2 = k2; 21 | } 22 | 23 | public override void UpdateForce(Particle particle, double dt) 24 | { 25 | Vector3d force = particle.Velocity; 26 | 27 | // Calculate the total drag coefficient 28 | double dragCoeff = force.Magnitude; 29 | dragCoeff = k1 * dragCoeff + k2 * dragCoeff * dragCoeff; 30 | 31 | // Calculate the final force and apply it 32 | force.Normalize(); 33 | force *= -dragCoeff; 34 | particle.AddForce(force); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/MathExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | using Cyclone.Core; 6 | using QUATERNION = Cyclone.Core.Quaternion; 7 | 8 | namespace UnityEngine 9 | { 10 | 11 | public static class MathExtension 12 | { 13 | 14 | public static QUATERNION ToQuaternion(this Quaternion q) 15 | { 16 | return new QUATERNION(q.w, q.x, q.y, q.z); 17 | } 18 | 19 | public static Quaternion ToQuaternion(this QUATERNION q) 20 | { 21 | return new Quaternion((float)q.i, (float)q.j, (float)q.k, (float)q.r); 22 | } 23 | 24 | public static Vector3 ToVector3(this Vector3d v) 25 | { 26 | return new Vector3((float)v.x, (float)v.y, (float)v.z); 27 | } 28 | 29 | public static Vector4 ToVector4(this Vector3d v) 30 | { 31 | return new Vector4((float)v.x, (float)v.y, (float)v.z, 1); 32 | } 33 | 34 | public static Vector3d ToVector3d(this Vector3 v) 35 | { 36 | return new Vector3d(v.x, v.y, v.z); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /ProjectSettings/PackageManagerSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &1 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 61 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} 13 | m_Name: 14 | m_EditorClassIdentifier: 15 | m_EnablePreviewPackages: 0 16 | m_EnablePackageDependencies: 0 17 | m_AdvancedSettingsExpanded: 1 18 | m_ScopedRegistriesSettingsExpanded: 1 19 | oneTimeWarningShown: 0 20 | m_Registries: 21 | - m_Id: main 22 | m_Name: 23 | m_Url: https://packages.unity.com 24 | m_Scopes: [] 25 | m_IsDefault: 1 26 | m_Capabilities: 7 27 | m_UserSelectedRegistryName: 28 | m_UserAddingNewScopedRegistry: 0 29 | m_RegistryInfoDraft: 30 | m_ErrorMessage: 31 | m_Original: 32 | m_Id: 33 | m_Name: 34 | m_Url: 35 | m_Scopes: [] 36 | m_IsDefault: 0 37 | m_Capabilities: 0 38 | m_Modified: 0 39 | m_Name: 40 | m_Url: 41 | m_Scopes: 42 | - 43 | m_SelectedScopeIndex: 0 44 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Forces/RigidGravityForce.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Rigid.Forces 7 | { 8 | 9 | /// 10 | /// A force generator that applies a gravitational force. One instance 11 | /// can be used for multiple rigid bodies. 12 | /// 13 | public class RigidGravityForce : RigidForceArea 14 | { 15 | 16 | /// 17 | /// Holds the acceleration due to gravity. 18 | /// 19 | Vector3d m_gravity; 20 | 21 | public RigidGravityForce(double gravity) 22 | { 23 | m_gravity = new Vector3d(0, gravity, 0); 24 | } 25 | 26 | public RigidGravityForce(Vector3d gravity) 27 | { 28 | m_gravity = gravity; 29 | } 30 | 31 | /// 32 | /// Applies the gravitational force to the given rigid body. 33 | /// 34 | public override void UpdateForce(RigidBody body, double dt) 35 | { 36 | // Check that we do not have infinite mass 37 | if (body.HasInfiniteMass) return; 38 | 39 | // Apply the mass-scaled force to the body 40 | body.AddForce(m_gravity * body.GetMass()); 41 | } 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/RigidPhysicsEngine.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | using Cyclone.Rigid; 6 | using Cyclone.Rigid.Forces; 7 | 8 | namespace CycloneUnityTestScenes 9 | { 10 | 11 | public class RigidPhysicsEngine : MonoBehaviour 12 | { 13 | public int iterations = 0; 14 | 15 | public int maxContacts = 100; 16 | 17 | public double epsilon = 0.01; 18 | 19 | public static RigidBodyEngine Instance { get; private set; } 20 | 21 | private void Awake() 22 | { 23 | Instance = new RigidBodyEngine(maxContacts); 24 | Instance.Resolver.PositionIterations = iterations; 25 | Instance.Resolver.VelocityIterations = iterations; 26 | Instance.Resolver.PositionEpsilon = epsilon; 27 | Instance.Resolver.VelocityEpsilon = epsilon; 28 | Instance.Collisions.Restitution = 0; 29 | Instance.Collisions.Friction = 0.1; 30 | 31 | Instance.ForceAreas.Add(new RigidGravityForce(-9.81)); 32 | } 33 | 34 | private void FixedUpdate() 35 | { 36 | double dt = Time.fixedDeltaTime; 37 | 38 | Instance.StartFrame(); 39 | Instance.RunPhysics(dt); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 11 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_ClothInterCollisionDistance: 0 18 | m_ClothInterCollisionStiffness: 0 19 | m_ContactsGeneration: 1 20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 21 | m_AutoSimulation: 1 22 | m_AutoSyncTransforms: 0 23 | m_ReuseCollisionCallbacks: 1 24 | m_ClothInterCollisionSettingsToggle: 0 25 | m_ContactPairsMode: 0 26 | m_BroadphaseType: 0 27 | m_WorldBounds: 28 | m_Center: {x: 0, y: 0, z: 0} 29 | m_Extent: {x: 250, y: 250, z: 250} 30 | m_WorldSubdivisions: 8 31 | m_FrictionType: 0 32 | m_EnableEnhancedDeterminism: 0 33 | m_EnableUnifiedHeightmaps: 1 34 | m_DefaultMaxAngluarSpeed: 7 35 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/PlaneConstraint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Particles; 6 | 7 | namespace Cyclone.Particles.Constraints 8 | { 9 | /// 10 | /// A contact generator that takes an STL vector of particle pointers and 11 | /// collides them against the ground. 12 | /// 13 | public class PlaneConstraint : ParticleConstraint 14 | { 15 | 16 | public Vector3d m_origin; 17 | 18 | public PlaneConstraint(double height) 19 | { 20 | m_origin = new Vector3d(0, height, 0); 21 | } 22 | 23 | public override int AddContact(IList particles, IList contacts, int next) 24 | { 25 | int count = 0; 26 | foreach(var p in particles) 27 | { 28 | double y = p.Position.y - m_origin.y; 29 | if (y < 0.0) 30 | { 31 | var contact = contacts[next]; 32 | 33 | contact.ContactNormal = Vector3d.UnitY; 34 | contact.Particles[0] = p; 35 | contact.Particles[1] = null; 36 | contact.Penetration = -y; 37 | contact.Restitution = 0.2; 38 | next++; 39 | count++; 40 | } 41 | 42 | if (count >= contacts.Count) return count; 43 | } 44 | 45 | return count; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/RigidSphere.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | using Cyclone.Core; 6 | using Cyclone.Rigid; 7 | using Cyclone.Rigid.Constraints; 8 | using Cyclone.Rigid.Collisions; 9 | 10 | namespace CycloneUnityTestScenes 11 | { 12 | 13 | public class RigidSphere : MonoBehaviour 14 | { 15 | public double mass = 1; 16 | 17 | public double damping = 0.9; 18 | 19 | private RigidBody m_body; 20 | 21 | void Start() 22 | { 23 | var pos = transform.position.ToVector3d(); 24 | var scale = transform.localScale.y * 0.5; 25 | var rot = transform.rotation.ToQuaternion(); 26 | 27 | m_body = new RigidBody(); 28 | m_body.Position = pos; 29 | m_body.Orientation = rot; 30 | m_body.LinearDamping = damping; 31 | m_body.AngularDamping = damping; 32 | m_body.SetMass(mass); 33 | m_body.SetAwake(true); 34 | m_body.SetCanSleep(true); 35 | 36 | var shape = new CollisionSphere(scale); 37 | shape.Body = m_body; 38 | 39 | RigidPhysicsEngine.Instance.Bodies.Add(m_body); 40 | RigidPhysicsEngine.Instance.Collisions.Primatives.Add(shape); 41 | } 42 | 43 | private void Update() 44 | { 45 | transform.position = m_body.Position.ToVector3(); 46 | transform.rotation = m_body.Orientation.ToQuaternion(); 47 | } 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/RigidBox.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | using Cyclone.Core; 6 | using Cyclone.Rigid; 7 | using Cyclone.Rigid.Constraints; 8 | using Cyclone.Rigid.Collisions; 9 | 10 | namespace CycloneUnityTestScenes 11 | { 12 | 13 | public class RigidBox : MonoBehaviour 14 | { 15 | public double mass = 1; 16 | 17 | public double damping = 0.9; 18 | 19 | private RigidBody m_body; 20 | 21 | void Start() 22 | { 23 | var pos = transform.position.ToVector3d(); 24 | var scale = transform.localScale.ToVector3d() * 0.5; 25 | var rot = transform.rotation.ToQuaternion(); 26 | 27 | m_body = new RigidBody(); 28 | m_body.Position = pos; 29 | m_body.Orientation = rot; 30 | m_body.LinearDamping = damping; 31 | m_body.AngularDamping = damping; 32 | m_body.SetMass(mass); 33 | m_body.SetAwake(true); 34 | m_body.SetCanSleep(true); 35 | 36 | var shape = new CollisionBox(scale); 37 | shape.Body = m_body; 38 | 39 | RigidPhysicsEngine.Instance.Bodies.Add(m_body); 40 | RigidPhysicsEngine.Instance.Collisions.Primatives.Add(shape); 41 | } 42 | 43 | private void Update() 44 | { 45 | transform.position = m_body.Position.ToVector3(); 46 | transform.rotation = m_body.Orientation.ToQuaternion(); 47 | } 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | debug: 89 | m_Flags: 0 90 | m_SettingNames: 91 | - Humanoid 92 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionPrimitive.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Rigid.Collisions 7 | { 8 | /// 9 | /// Represents a primitive to detect collisions against. 10 | /// 11 | public abstract class CollisionPrimitive 12 | { 13 | 14 | /// 15 | /// The rigid body that is represented by this primitive. 16 | /// 17 | public RigidBody Body; 18 | 19 | /// 20 | /// The offset of this primitive from the given rigid body. 21 | /// 22 | //public Matrix4 Offset; 23 | 24 | /// 25 | /// The resultant transform of the primitive. This is 26 | /// calculated by combining the offset of the primitive 27 | /// with the transform of the rigid body. 28 | /// 29 | public Matrix4 Transform; 30 | 31 | /// 32 | /// 33 | /// 34 | public CollisionPrimitive() 35 | { 36 | Transform = Matrix4.Identity; 37 | } 38 | 39 | /// 40 | /// Calculates the internals for the primitive. 41 | /// 42 | public void CalculateInternals() 43 | { 44 | Transform = Body.Transform /* * Offset*/ ; 45 | } 46 | 47 | /// 48 | /// This is a convenience function to allow access to the 49 | /// axis vectors in the transform for this primitive. 50 | /// 51 | public Vector3d GetAxis(int index) 52 | { 53 | return Transform.GetAxisVector(index); 54 | } 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleSpringForce.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Particles; 6 | 7 | namespace Cyclone.Particles.Forces 8 | { 9 | public class ParticleSpringForce : ParticleForce 10 | { 11 | /// 12 | /// The particle at the other end of the spring. 13 | /// 14 | private Particle m_particleA, m_particleB; 15 | 16 | /// 17 | /// Holds the sprint constant. 18 | /// 19 | private double m_springConstant; 20 | 21 | /// 22 | /// Holds the rest length of the spring. 23 | /// 24 | private double m_restLength; 25 | 26 | public ParticleSpringForce(Particle a, Particle b, double springConstant, double restLength) 27 | { 28 | m_particleA = a; 29 | m_particleB = b; 30 | m_springConstant = springConstant; 31 | m_restLength = restLength; 32 | } 33 | 34 | public override void UpdateForce(double dt) 35 | { 36 | UpdateForce(m_particleA, m_particleB); 37 | UpdateForce(m_particleB, m_particleA); 38 | } 39 | 40 | private void UpdateForce(Particle particle, Particle other) 41 | { 42 | if (particle.HasInfiniteMass) return; 43 | 44 | // Calculate the vector of the spring 45 | Vector3d force = particle.Position - other.Position; 46 | 47 | // Calculate the magnitude of the force 48 | double magnitude = force.Magnitude; 49 | // Calculate the magnitude of the force 50 | magnitude = (m_restLength - magnitude) * m_springConstant; 51 | 52 | // Calculate the final force and apply it 53 | force.Normalize(); 54 | force *= magnitude; 55 | particle.AddForce(force); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Forces/ParticleElasticForce.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Particles; 6 | 7 | namespace Cyclone.Particles.Forces 8 | { 9 | public class ParticleElasticForce : ParticleForce 10 | { 11 | /// 12 | /// The particle at the other end of the spring. 13 | /// 14 | private Particle m_particleA, m_particleB; 15 | 16 | /// 17 | /// Holds the sprint constant. 18 | /// 19 | private double m_springConstant; 20 | 21 | /// 22 | /// Holds the rest length of the spring. 23 | /// 24 | private double m_restLength; 25 | 26 | public ParticleElasticForce(Particle a, Particle b, double springConstant, double restLength) 27 | { 28 | m_particleA = a; 29 | m_particleB = b; 30 | m_springConstant = springConstant; 31 | m_restLength = restLength; 32 | } 33 | 34 | public override void UpdateForce(double dt) 35 | { 36 | UpdateForce(m_particleA, m_particleB); 37 | UpdateForce(m_particleB, m_particleA); 38 | } 39 | 40 | private void UpdateForce(Particle particle, Particle other) 41 | { 42 | if (particle.HasInfiniteMass) return; 43 | 44 | // Calculate the vector of the spring 45 | Vector3d force = particle.Position - other.Position; 46 | 47 | // Calculate the magnitude of the force 48 | double magnitude = force.Magnitude; 49 | if (magnitude <= m_restLength) return; 50 | 51 | // Calculate the magnitude of the force 52 | magnitude = (m_restLength - magnitude) * m_springConstant; 53 | 54 | // Calculate the final force and apply it 55 | force.Normalize(); 56 | force *= magnitude; 57 | particle.AddForce(force); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_JobOptions: 23 | serializedVersion: 2 24 | useMultithreading: 0 25 | useConsistencySorting: 0 26 | m_InterpolationPosesPerJob: 100 27 | m_NewContactsPerJob: 30 28 | m_CollideContactsPerJob: 100 29 | m_ClearFlagsPerJob: 200 30 | m_ClearBodyForcesPerJob: 200 31 | m_SyncDiscreteFixturesPerJob: 50 32 | m_SyncContinuousFixturesPerJob: 50 33 | m_FindNearestContactsPerJob: 100 34 | m_UpdateTriggerContactsPerJob: 100 35 | m_IslandSolverCostThreshold: 100 36 | m_IslandSolverBodyCostScale: 1 37 | m_IslandSolverContactCostScale: 10 38 | m_IslandSolverJointCostScale: 10 39 | m_IslandSolverBodiesPerJob: 50 40 | m_IslandSolverContactsPerJob: 50 41 | m_AutoSimulation: 1 42 | m_QueriesHitTriggers: 1 43 | m_QueriesStartInColliders: 1 44 | m_CallbacksOnDisable: 1 45 | m_ReuseCollisionCallbacks: 1 46 | m_AutoSyncTransforms: 0 47 | m_AlwaysShowColliders: 0 48 | m_ShowColliderSleep: 1 49 | m_ShowColliderContacts: 0 50 | m_ShowColliderAABB: 0 51 | m_ContactArrowScale: 0.2 52 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 53 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 54 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 55 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 56 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2003-2009 Ian Millington 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | MIT License 24 | 25 | Copyright (c) 2019 Justin 26 | 27 | Permission is hereby granted, free of charge, to any person obtaining a copy 28 | of this software and associated documentation files (the "Software"), to deal 29 | in the Software without restriction, including without limitation the rights 30 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 31 | copies of the Software, and to permit persons to whom the Software is 32 | furnished to do so, subject to the following conditions: 33 | 34 | The above copyright notice and this permission notice shall be included in all 35 | copies or substantial portions of the Software. 36 | 37 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 38 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 39 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 40 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 41 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 42 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 43 | SOFTWARE. 44 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/ParticleCableConstraint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Particles.Constraints 7 | { 8 | 9 | /// 10 | /// Cables link a pair of particles, generating a contact if they 11 | /// stray too far apart. 12 | /// 13 | public class ParticleCableConstraint : ParticleConstraint 14 | { 15 | 16 | /// 17 | /// The particle at the other end of the cable. 18 | /// 19 | private Particle m_particleA, m_particleB; 20 | 21 | /// 22 | /// Holds the maximum length of the cable. 23 | /// 24 | private double m_maxLength; 25 | 26 | /// 27 | /// Holds the restitution (bounciness) of the cable. 28 | /// 29 | private double m_restitution; 30 | 31 | public ParticleCableConstraint(Particle a, Particle b, double maxLength, double restitution = 0) 32 | { 33 | m_particleA = a; 34 | m_particleB = b; 35 | m_maxLength = maxLength; 36 | m_restitution = restitution; 37 | } 38 | 39 | /// 40 | /// Fills the given contact structure with the contact needed 41 | /// to keep the cable from over-extending. 42 | /// 43 | public override int AddContact(IList particles, IList contacts, int next) 44 | { 45 | // Find the length of the cable 46 | double length = Vector3d.Distance(m_particleA.Position, m_particleB.Position); 47 | 48 | // Check if we're over-extended 49 | if (length < m_maxLength) return 0; 50 | 51 | var contact = contacts[next]; 52 | 53 | // Otherwise return the contact 54 | contact.Particles[0] = m_particleA; 55 | contact.Particles[1] = m_particleB; 56 | 57 | // Calculate the normal 58 | Vector3d normal = m_particleB.Position - m_particleA.Position; 59 | normal.Normalize(); 60 | contact.ContactNormal = normal; 61 | 62 | contact.Penetration = length - m_maxLength; 63 | contact.Restitution = m_restitution; 64 | 65 | return 1; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/ParticleSpring.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | using Common.Unity.Drawing; 6 | using Cyclone.Core; 7 | using Cyclone.Particles; 8 | using Cyclone.Particles.Forces; 9 | using Cyclone.Particles.Constraints; 10 | 11 | namespace CycloneUnityTestScenes 12 | { 13 | 14 | public class ParticleSpring : MonoBehaviour 15 | { 16 | 17 | List m_particles; 18 | 19 | SegmentRenderer m_lines; 20 | 21 | VertexRenderer m_verts; 22 | 23 | void Start() 24 | { 25 | m_lines = new SegmentRenderer(); 26 | m_lines.Color = Color.red; 27 | 28 | m_verts = new VertexRenderer(0.05f); 29 | m_verts.Color = Color.yellow; 30 | 31 | CreateParticles(); 32 | } 33 | 34 | private void CreateParticles() 35 | { 36 | double mass = 1; 37 | double damping = 0.5; 38 | double len = 1; 39 | double springStrength = 4; 40 | 41 | var pos = transform.position.ToVector3d(); 42 | 43 | var p0 = new Particle(); 44 | p0.Position = pos + new Vector3d(0, 0, 0); 45 | p0.SetMass(0); 46 | p0.Damping = damping; 47 | 48 | var p1 = new Particle(); 49 | p1.Position = new Vector3d(-1, 0, 0); 50 | p1.SetMass(mass); 51 | p1.Damping = damping; 52 | 53 | m_particles = new List(); 54 | m_particles.Add(p0); 55 | m_particles.Add(p1); 56 | 57 | ParticlePhysicsEngine.Instance.Particles.AddRange(m_particles); 58 | ParticlePhysicsEngine.Instance.Forces.Add(new ParticleSpringForce(p0, p1, springStrength, len)); 59 | } 60 | 61 | private void OnRenderObject() 62 | { 63 | var cam = Camera.current; 64 | if (cam == null) return; 65 | 66 | var points = new List(); 67 | foreach (var p in m_particles) 68 | points.Add(p.Position); 69 | 70 | m_lines.Clear(); 71 | m_lines.Load(points); 72 | 73 | m_verts.Clear(); 74 | m_verts.Load(points); 75 | 76 | m_lines.Draw(cam); 77 | m_verts.Draw(cam); 78 | } 79 | 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 12 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 38 | m_PreloadedShaders: [] 39 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 40 | type: 0} 41 | m_CustomRenderPipeline: {fileID: 0} 42 | m_TransparencySortMode: 0 43 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 44 | m_DefaultRenderingPath: 1 45 | m_DefaultMobileRenderingPath: 1 46 | m_TierSettings: [] 47 | m_LightmapStripping: 0 48 | m_FogStripping: 0 49 | m_InstancingStripping: 0 50 | m_LightmapKeepPlain: 1 51 | m_LightmapKeepDirCombined: 1 52 | m_LightmapKeepDynamicPlain: 1 53 | m_LightmapKeepDynamicDirCombined: 1 54 | m_LightmapKeepShadowMask: 1 55 | m_LightmapKeepSubtractive: 1 56 | m_FogKeepLinear: 1 57 | m_FogKeepExp: 1 58 | m_FogKeepExp2: 1 59 | m_AlbedoSwatchInfos: [] 60 | m_LightsUseLinearIntensity: 0 61 | m_LightsUseColorTemperature: 0 62 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/ParticleRodConstraint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Particles.Constraints 7 | { 8 | /// 9 | /// Rods link a pair of particles, generating a contact if they 10 | /// stray too far apart or too close. 11 | /// 12 | public class ParticleRodConstraint : ParticleConstraint 13 | { 14 | 15 | /// 16 | /// The particle at the other end of the rod. 17 | /// 18 | private Particle m_particleA, m_particleB; 19 | 20 | /// 21 | /// Holds the length of the rod. 22 | /// 23 | private double m_length; 24 | 25 | public ParticleRodConstraint(Particle a, Particle b, double length) 26 | { 27 | m_particleA = a; 28 | m_particleB = b; 29 | m_length = length; 30 | } 31 | 32 | /// 33 | /// Fills the given contact structure with the contact needed 34 | /// to keep the rod from extending or compressing. 35 | /// 36 | public override int AddContact(IList particles, IList contacts, int next) 37 | { 38 | // Find the length of the cable 39 | double currentLen = Vector3d.Distance(m_particleA.Position, m_particleB.Position); 40 | 41 | // Check if we're over-extended 42 | if (currentLen == m_length) return 0; 43 | 44 | var contact = contacts[next]; 45 | 46 | // Otherwise return the contact 47 | contact.Particles[0] = m_particleA; 48 | contact.Particles[1] = m_particleB; 49 | 50 | // Calculate the normal 51 | Vector3d normal = m_particleB.Position - m_particleA.Position; 52 | normal.Normalize(); 53 | 54 | // The contact normal depends on whether we're extending or compressing 55 | if (currentLen > m_length) 56 | { 57 | contact.ContactNormal = normal; 58 | contact.Penetration = currentLen - m_length; 59 | } 60 | else 61 | { 62 | contact.ContactNormal = normal * -1; 63 | contact.Penetration = m_length - currentLen; 64 | } 65 | 66 | // Always use zero restitution (no bounciness) 67 | contact.Restitution = 0; 68 | 69 | return 1; 70 | } 71 | 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Assets/CommonUnity/Drawing/BaseRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.Rendering; 5 | 6 | namespace Common.Unity.Drawing 7 | { 8 | 9 | public enum DRAW_ORIENTATION { XY, XZ }; 10 | 11 | public abstract class BaseRenderer 12 | { 13 | public static readonly IList CUBE_INDICES = new int[] 14 | { 15 | 0, 1, 1, 2, 2, 3, 3, 0, 16 | 4, 5, 5, 6, 6, 7, 7, 4, 17 | 0, 4, 1, 5, 2, 6, 3, 7 18 | }; 19 | 20 | public static readonly IList SQUARE_INDICES = new int[] 21 | { 22 | 0, 1, 1, 2, 2, 3, 3, 0 23 | }; 24 | 25 | protected List m_vertices = new List(); 26 | 27 | protected List m_indices = new List(); 28 | 29 | public BaseRenderer() 30 | { 31 | LocalToWorld = Matrix4x4.identity; 32 | Orientation = DRAW_ORIENTATION.XY; 33 | Color = Color.white; 34 | Material = new Material(Shader.Find("Hidden/Internal-Colored")); 35 | } 36 | 37 | public Matrix4x4 LocalToWorld { get; set; } 38 | 39 | public DRAW_ORIENTATION Orientation { get; set; } 40 | 41 | public Color Color { get; set; } 42 | 43 | public CompareFunction ZTest 44 | { 45 | get { return (CompareFunction)Material.GetInt("_ZTest"); } 46 | set { Material.SetInt("_ZTest", (int)CompareFunction.Always); } 47 | } 48 | 49 | protected Material Material { get; set; } 50 | 51 | public virtual void Clear() 52 | { 53 | m_vertices.Clear(); 54 | m_indices.Clear(); 55 | } 56 | 57 | public void SetIndices(int vertexCount, IList indices) 58 | { 59 | int current = m_vertices.Count; 60 | 61 | if (indices == null) 62 | { 63 | for (int i = 0; i < vertexCount - 1; i++) 64 | { 65 | m_indices.Add(i + current); 66 | m_indices.Add(i + 1 + current); 67 | } 68 | } 69 | else 70 | { 71 | for (int i = 0; i < indices.Count; i++) 72 | m_indices.Add(indices[i] + current); 73 | } 74 | 75 | } 76 | 77 | public void Draw(Camera camera) 78 | { 79 | Draw(camera, Matrix4x4.identity); 80 | } 81 | 82 | public abstract void Draw(Camera camera, Matrix4x4 localToWorld); 83 | 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Forces/RigidSpringForce.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Rigid.Forces 7 | { 8 | 9 | /// 10 | /// 11 | /// 12 | public class RigidSpringForce : RigidForce 13 | { 14 | 15 | /// 16 | /// The bodies at the other end of the spring. 17 | /// 18 | private RigidBody m_bodyA, m_bodyB; 19 | 20 | /// 21 | /// The point of connection of the spring, in local coordinates. 22 | /// 23 | private Vector3d m_connectionA, m_connectionB; 24 | 25 | /// 26 | /// Holds the sprint constant 27 | /// 28 | private double m_springConstant; 29 | 30 | /// 31 | /// Holds the rest length of the spring 32 | /// 33 | private double m_restLength; 34 | 35 | /// 36 | /// 37 | /// 38 | public RigidSpringForce(RigidBody a, RigidBody b, Vector3d connectionA, Vector3d connectionB, double springConstant, double restLength) 39 | { 40 | m_bodyA = a; 41 | m_bodyB = b; 42 | m_connectionA = connectionA; 43 | m_connectionB = connectionB; 44 | m_springConstant = springConstant; 45 | m_restLength = restLength; 46 | } 47 | 48 | public override void UpdateForce(double dt) 49 | { 50 | UpdateForce(m_bodyA, m_bodyB, m_connectionA, m_connectionB, dt); 51 | UpdateForce(m_bodyB, m_bodyA, m_connectionB, m_connectionA, dt); 52 | } 53 | 54 | private void UpdateForce(RigidBody body, RigidBody other, Vector3d connection, Vector3d otherConnection, double dt) 55 | { 56 | if (body.HasInfiniteMass) return; 57 | 58 | // Calculate the two ends in world space 59 | Vector3d lws = body.GetPointInWorldSpace(connection); 60 | Vector3d ows = other.GetPointInWorldSpace(otherConnection); 61 | 62 | // Calculate the vector of the spring 63 | Vector3d force = lws - ows; 64 | 65 | // Calculate the magnitude of the force 66 | double magnitude = force.Magnitude; 67 | // Calculate the magnitude of the force 68 | magnitude = (m_restLength - magnitude) * m_springConstant; 69 | 70 | // Calculate the final force and apply it 71 | force.Normalize(); 72 | force *= magnitude; 73 | body.AddForceAtPoint(force, lws); 74 | 75 | } 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Assets/UnityTestScenes/Scripts/ParticleRod.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | using Common.Unity.Drawing; 6 | using Cyclone.Core; 7 | using Cyclone.Particles; 8 | using Cyclone.Particles.Forces; 9 | using Cyclone.Particles.Constraints; 10 | 11 | namespace CycloneUnityTestScenes 12 | { 13 | 14 | public class ParticleRod : MonoBehaviour 15 | { 16 | 17 | List m_particles; 18 | 19 | SegmentRenderer m_lines; 20 | 21 | VertexRenderer m_verts; 22 | 23 | void Start() 24 | { 25 | m_lines = new SegmentRenderer(); 26 | m_lines.Color = Color.red; 27 | 28 | m_verts = new VertexRenderer(0.05f); 29 | m_verts.Color = Color.yellow; 30 | 31 | CreateParticles(); 32 | } 33 | 34 | private void CreateParticles() 35 | { 36 | double mass = 1; 37 | double damping = 0.5; 38 | double len = 1; 39 | 40 | var pos = transform.position.ToVector3d(); 41 | 42 | var p0 = new Particle(); 43 | p0.Position = pos + new Vector3d(0,0,0); 44 | p0.SetMass(0); 45 | p0.Damping = damping; 46 | 47 | var p1 = new Particle(); 48 | p1.Position = pos + new Vector3d(1, 0, 0); 49 | p1.SetMass(mass); 50 | p1.Damping = damping; 51 | 52 | var p2 = new Particle(); 53 | p2.Position = pos + new Vector3d(3, 0, 0); 54 | p2.SetMass(mass); 55 | p2.Damping = damping; 56 | 57 | var p3 = new Particle(); 58 | p3.Position = pos + new Vector3d(3, 0, 0); 59 | p3.SetMass(mass); 60 | p3.Damping = damping; 61 | 62 | m_particles = new List(); 63 | m_particles.Add(p0); 64 | m_particles.Add(p1); 65 | m_particles.Add(p2); 66 | m_particles.Add(p3); 67 | 68 | ParticlePhysicsEngine.Instance.Particles.AddRange(m_particles); 69 | ParticlePhysicsEngine.Instance.Constraints.Add(new ParticleRodConstraint(p0, p1, len)); 70 | ParticlePhysicsEngine.Instance.Constraints.Add(new ParticleRodConstraint(p1, p2, len)); 71 | ParticlePhysicsEngine.Instance.Constraints.Add(new ParticleRodConstraint(p2, p3, len)); 72 | } 73 | 74 | private void OnRenderObject() 75 | { 76 | var cam = Camera.current; 77 | if (cam == null) return; 78 | 79 | var points = new List(); 80 | foreach (var p in m_particles) 81 | points.Add(p.Position); 82 | 83 | m_lines.Clear(); 84 | m_lines.Load(points); 85 | 86 | m_verts.Clear(); 87 | m_verts.Load(points); 88 | 89 | m_lines.Draw(cam); 90 | m_verts.Draw(cam); 91 | } 92 | 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/CollisionData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Rigid.Constraints; 5 | 6 | namespace Cyclone.Rigid.Collisions 7 | { 8 | 9 | /// 10 | /// A helper structure that contains information for the detector to use 11 | /// in building its contact data. 12 | /// 13 | public class CollisionData 14 | { 15 | /// 16 | /// Holds the contact array to write into. 17 | /// 18 | public IList Contacts; 19 | 20 | /// 21 | /// Holds the maximum number of contacts the array can take. 22 | /// 23 | public int ContactsLeft { get; private set; } 24 | 25 | /// 26 | /// Holds the number of contacts found so far. 27 | /// 28 | public int ContactCount { get; private set; } 29 | 30 | /// 31 | /// Holds the friction value to write into any collisions. 32 | /// 33 | public double Friction; 34 | 35 | /// 36 | /// Holds the restitution value to write into any collisions. 37 | /// 38 | public double Restitution; 39 | 40 | /// 41 | /// Holds the collision tolerance, even uncolliding objects this 42 | /// close should have collisions generated. 43 | /// 44 | public double Tolerance; 45 | 46 | /// 47 | /// Checks if there are more contacts. 48 | /// 49 | public bool HasMoreContacts() 50 | { 51 | return ContactsLeft > 0; 52 | } 53 | 54 | /// 55 | /// Checks if there are no more contacts. 56 | /// 57 | public bool NoMoreContacts() 58 | { 59 | return ContactsLeft <= 0; 60 | } 61 | 62 | /// 63 | /// Resets the data so that it has no used contacts recorded. 64 | /// 65 | public void Reset(int start) 66 | { 67 | ContactsLeft = Contacts.Count - start; 68 | ContactCount = start; 69 | } 70 | 71 | /// 72 | /// Notifies the data that the given number of contacts have 73 | /// been added. 74 | /// 75 | private void AddContacts(int count) 76 | { 77 | // Reduce the number of contacts remaining, add number used 78 | ContactsLeft -= count; 79 | ContactCount += count; 80 | } 81 | 82 | /// 83 | /// 84 | /// 85 | /// 86 | public RigidContact GetContact() 87 | { 88 | if (NoMoreContacts()) 89 | throw new InvalidOperationException("No more contacts."); 90 | 91 | var contact = Contacts[ContactCount]; 92 | AddContacts(1); 93 | return contact; 94 | } 95 | } 96 | 97 | } -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Constraints/RigidJointConstraint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Rigid.Constraints 7 | { 8 | 9 | /// 10 | /// Joints link together two rigid bodies and make sure they do not 11 | /// separate. In a general phyiscs engine there may be many 12 | /// different types of joint, that reduce the number of relative 13 | /// degrees of freedom between two objects. This joint is a common 14 | /// position joint: each object has a location (given in 15 | /// body-coordinates) that will be kept at the same point in the 16 | /// simulation. 17 | /// 18 | public class RigidJointConstraint : RigidConstraint 19 | { 20 | 21 | /// 22 | /// Holds the two rigid bodies that are connected by this joint. 23 | /// 24 | private RigidBody[] m_body; 25 | 26 | /// 27 | /// Holds the relative location of the connection for each 28 | /// body, given in local coordinates. 29 | /// 30 | private Vector3d[] m_position; 31 | 32 | /// 33 | /// Holds the maximum displacement at the joint before the 34 | /// joint is considered to be violated. This is normally a 35 | /// small, epsilon value. It can be larger, however, in which 36 | /// case the joint will behave as if an inelastic cable joined 37 | /// the bodies at their joint locations. 38 | /// 39 | private double m_error; 40 | 41 | /// 42 | /// Configures the joint in one go. 43 | /// 44 | public RigidJointConstraint(RigidBody a, Vector3d posA, RigidBody b, Vector3d posB, double error) 45 | { 46 | m_body = new RigidBody[] { a, b }; 47 | m_position = new Vector3d[] { posA, posB }; 48 | m_error = error; 49 | } 50 | 51 | /// 52 | /// Generates the contacts required to restore the joint if it 53 | /// has been violated. 54 | /// 55 | public override int AddContact(IList bodies, IList contacts, int next) 56 | { 57 | // Calculate the position of each connection point in world coordinates 58 | Vector3d a_pos_world = m_body[0].GetPointInWorldSpace(m_position[0]); 59 | Vector3d b_pos_world = m_body[1].GetPointInWorldSpace(m_position[1]); 60 | 61 | // Calculate the length of the joint 62 | Vector3d a_to_b = b_pos_world - a_pos_world; 63 | Vector3d normal = a_to_b; 64 | normal.Normalize(); 65 | double length = a_to_b.Magnitude; 66 | 67 | // Check if it is violated 68 | if (Math.Abs(length) > m_error) 69 | { 70 | var contact = contacts[next]; 71 | contact.Body[0] = m_body[0]; 72 | contact.Body[1] = m_body[1]; 73 | contact.ContactNormal = normal; 74 | contact.ContactPoint = (a_pos_world + b_pos_world) * 0.5; 75 | contact.Penetration = length - m_error; 76 | contact.Friction = 1.0; 77 | contact.Restitution = 0; 78 | return 1; 79 | } 80 | 81 | return 0; 82 | } 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /Assets/CommonUnity/Drawing/VextexRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | using Cyclone.Core; 6 | 7 | namespace Common.Unity.Drawing 8 | { 9 | 10 | public class VertexRenderer : BaseRenderer 11 | { 12 | 13 | public VertexRenderer(float size) 14 | { 15 | Size = size; 16 | } 17 | 18 | public VertexRenderer(float size, DRAW_ORIENTATION orientation) 19 | { 20 | Size = size; 21 | Orientation = DRAW_ORIENTATION.XY; 22 | } 23 | 24 | public float Size = 0.1f; 25 | 26 | #region DOUBLE 27 | public void Load(IEnumerable vertices) 28 | { 29 | foreach (var v in vertices) 30 | { 31 | m_vertices.Add(v.ToVector4()); 32 | } 33 | } 34 | 35 | public void Load(Vector3d vertex) 36 | { 37 | m_vertices.Add(vertex.ToVector4()); 38 | } 39 | 40 | #endregion 41 | 42 | #region UNITY 43 | public void Load(IEnumerable vertices) 44 | { 45 | foreach (var v in vertices) 46 | { 47 | m_vertices.Add(v); 48 | } 49 | } 50 | 51 | public void Load(IEnumerable vertices) 52 | { 53 | foreach (var v in vertices) 54 | { 55 | m_vertices.Add(v); 56 | } 57 | } 58 | #endregion 59 | 60 | #region DRAW 61 | public override void Draw(Camera camera, Matrix4x4 localToWorld) 62 | { 63 | GL.PushMatrix(); 64 | 65 | GL.LoadIdentity(); 66 | GL.modelview = camera.worldToCameraMatrix * LocalToWorld; 67 | GL.LoadProjectionMatrix(camera.projectionMatrix); 68 | 69 | Material.SetPass(0); 70 | GL.Begin(GL.QUADS); 71 | GL.Color(Color); 72 | 73 | switch (Orientation) 74 | { 75 | case DRAW_ORIENTATION.XY: 76 | DrawXY(); 77 | break; 78 | 79 | case DRAW_ORIENTATION.XZ: 80 | DrawXZ(); 81 | break; 82 | } 83 | 84 | GL.End(); 85 | 86 | GL.PopMatrix(); 87 | } 88 | 89 | private void DrawXY() 90 | { 91 | float half = Size * 0.5f; 92 | for (int i = 0; i < m_vertices.Count; i++) 93 | { 94 | float x = m_vertices[i].x; 95 | float y = m_vertices[i].y; 96 | float z = m_vertices[i].z; 97 | 98 | GL.Vertex3(x + half, y + half, z); 99 | GL.Vertex3(x + half, y - half, z); 100 | GL.Vertex3(x - half, y - half, z); 101 | GL.Vertex3(x - half, y + half, z); 102 | } 103 | } 104 | 105 | private void DrawXZ() 106 | { 107 | float half = Size * 0.5f; 108 | for (int i = 0; i < m_vertices.Count; i++) 109 | { 110 | float x = m_vertices[i].x; 111 | float y = m_vertices[i].y; 112 | float z = m_vertices[i].z; 113 | 114 | GL.Vertex3(x + half, y, z + half); 115 | GL.Vertex3(x + half, y, z - half); 116 | GL.Vertex3(x - half, y, z - half); 117 | GL.Vertex3(x - half, y, z + half); 118 | } 119 | } 120 | #endregion 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Constraints/CollisionConstraint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Rigid.Collisions; 6 | 7 | namespace Cyclone.Rigid.Constraints 8 | { 9 | 10 | /// 11 | /// Find all collisions between objects by directly testing each object 12 | /// against all others in a O(N^2) operation with no broad phase 13 | /// or any other optimization. Simple but slow. 14 | /// 15 | public class CollisionConstraint : RigidConstraint 16 | { 17 | 18 | /// 19 | /// Holds the friction value to write into any collisions. 20 | /// 21 | public double Friction; 22 | 23 | /// 24 | /// Holds the restitution value to write into any collisions. 25 | /// 26 | public double Restitution; 27 | 28 | /// 29 | /// Holds the collision tolerance, even uncolliding objects this 30 | /// close should have collisions generated. 31 | /// 32 | public double Tolerance; 33 | 34 | public List Planes; 35 | 36 | public List Primatives; 37 | 38 | public CollisionConstraint() 39 | { 40 | Planes = new List(); 41 | Primatives = new List(); 42 | } 43 | 44 | public override int AddContact(IList bodies, IList contacts, int next) 45 | { 46 | var data = new CollisionData(); 47 | data.Contacts = contacts; 48 | data.Reset(next); 49 | data.Friction = Friction; 50 | data.Restitution = Restitution; 51 | data.Tolerance = Tolerance; 52 | 53 | foreach (var primative in Primatives) 54 | primative.CalculateInternals(); 55 | 56 | foreach(var primative in Primatives) 57 | { 58 | if (data.NoMoreContacts()) break; 59 | 60 | switch(primative) 61 | { 62 | case CollisionSphere sphere: 63 | DetectCollisions(sphere, data); 64 | break; 65 | 66 | case CollisionBox box: 67 | DetectCollisions(box, data); 68 | break; 69 | } 70 | } 71 | 72 | return data.ContactCount; 73 | } 74 | 75 | private void DetectCollisions(CollisionSphere sphere, CollisionData data) 76 | { 77 | foreach (var plane in Planes) 78 | CollisionDetector.SphereAndHalfSpace(sphere, plane, data); 79 | 80 | foreach (var primative in Primatives) 81 | { 82 | if (primative == sphere) continue; 83 | if (data.NoMoreContacts()) break; 84 | 85 | switch (primative) 86 | { 87 | case CollisionSphere sphere2: 88 | CollisionDetector.SphereAndSphere(sphere, sphere2, data); 89 | break; 90 | 91 | case CollisionBox box: 92 | CollisionDetector.BoxAndSphere(box, sphere, data); 93 | break; 94 | } 95 | } 96 | } 97 | 98 | private void DetectCollisions(CollisionBox box, CollisionData data) 99 | { 100 | foreach (var plane in Planes) 101 | CollisionDetector.BoxAndHalfSpace(box, plane, data); 102 | 103 | foreach (var primative in Primatives) 104 | { 105 | if (primative == box) continue; 106 | if (data.NoMoreContacts()) break; 107 | 108 | switch (primative) 109 | { 110 | case CollisionSphere sphere: 111 | CollisionDetector.BoxAndSphere(box, sphere, data); 112 | break; 113 | 114 | case CollisionBox box2: 115 | CollisionDetector.BoxAndBox(box, box2, data); 116 | break; 117 | } 118 | } 119 | } 120 | 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Particle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Particles 7 | { 8 | public class Particle 9 | { 10 | /// 11 | /// Holds the inverse of the mass of the particle. It 12 | /// is more useful to hold the inverse mass because 13 | /// integration is simpler, and because in real time 14 | /// simulation it is more useful to have objects with 15 | /// infinite mass(immovable) than zero mass 16 | /// (completely unstable in numerical simulation). 17 | /// 18 | public double InverseMass; 19 | 20 | /// 21 | /// Returns true if the mass of the particle is finite. 22 | /// 23 | public bool HasFiniteMass => InverseMass != 0; 24 | 25 | /// 26 | /// Returns true if the mass of the particle is infinite. 27 | /// 28 | public bool HasInfiniteMass => InverseMass == 0; 29 | 30 | /// 31 | /// Holds the amount of damping applied to linear 32 | /// motion. Damping is required to remove energy added 33 | /// through numerical instability in the integrator. 34 | /// 35 | public double Damping = 0.99; 36 | 37 | /// 38 | /// Holds the linear position of the particle in 39 | /// world space. 40 | /// 41 | public Vector3d Position; 42 | 43 | /// 44 | /// Holds the linear velocity of the particle in 45 | /// world space. 46 | /// 47 | public Vector3d Velocity; 48 | 49 | /// 50 | /// Holds the accumulated force to be applied at the next 51 | /// simulation iteration only.This value is zeroed at each 52 | /// integration step. 53 | /// 54 | public Vector3d ForceAccum; 55 | 56 | /// 57 | /// Holds the acceleration of the particle. This value 58 | /// can be used to set acceleration due to gravity(its primary 59 | /// use), or any other constant acceleration. 60 | /// 61 | public Vector3d Acceleration; 62 | 63 | /// 64 | /// Get the mass of the particle. 65 | /// 66 | /// 67 | public double GetMass() 68 | { 69 | if (InverseMass == 0) 70 | return double.PositiveInfinity; 71 | else 72 | return 1.0 / InverseMass; 73 | } 74 | 75 | /// 76 | /// Set the mass of the particle. 77 | /// 78 | public void SetMass(double mass) 79 | { 80 | if (mass <= 0) 81 | InverseMass = 0; 82 | else 83 | InverseMass = 1.0 / mass; 84 | } 85 | 86 | /// 87 | /// Accumalate force. 88 | /// 89 | public void AddForce(Vector3d force) 90 | { 91 | ForceAccum += force; 92 | } 93 | 94 | /// 95 | /// Clears the forces applied to the particle. This will be 96 | /// called automatically after each integration step. 97 | /// 98 | public void ClearAccumulator() 99 | { 100 | ForceAccum = Vector3d.Zero; 101 | } 102 | 103 | /// 104 | /// Integrates the particle forward in time by the given amount. 105 | /// This function uses a Newton-Euler integration method, which is a 106 | /// linear approximation to the correct integral. For this reason it 107 | /// may be inaccurate in some cases. 108 | /// 109 | public void Integrate(double dt) 110 | { 111 | // We don't integrate things with zero mass. 112 | if (InverseMass <= 0.0) return; 113 | if (dt <= 0) return; 114 | 115 | // Update linear position. 116 | Position += Velocity * dt; 117 | 118 | // Work out the acceleration from the force 119 | Vector3d resultingAcc = Acceleration; 120 | resultingAcc += ForceAccum * InverseMass; 121 | 122 | // Update linear velocity from the acceleration. 123 | Velocity += resultingAcc * dt; 124 | 125 | // Impose drag. 126 | Velocity *= Math.Pow(Damping, dt); 127 | 128 | // Clear the forces. 129 | ClearAccumulator(); 130 | } 131 | 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Collisions/IntersectionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Rigid; 6 | 7 | namespace Cyclone.Rigid.Collisions 8 | { 9 | /// 10 | /// A wrapper class that holds fast intersection tests. These 11 | /// can be used to drive the coarse collision detection system or 12 | /// as an early out in the full collision tests below. 13 | /// 14 | public static class IntersectionTests 15 | { 16 | public static bool SphereAndHalfSpace(CollisionSphere sphere, CollisionPlane plane) 17 | { 18 | // Find the distance from the origin 19 | double ballDistance = Vector3d.Dot(plane.Direction, sphere.GetAxis(3)) - sphere.Radius; 20 | 21 | // Check for the intersection 22 | return ballDistance <= plane.Offset; 23 | } 24 | 25 | public static bool SphereAndSphere(CollisionSphere one, CollisionSphere two) 26 | { 27 | // Find the vector between the objects 28 | Vector3d midline = one.GetAxis(3) - two.GetAxis(3); 29 | 30 | // See if it is large enough. 31 | return midline.SqrMagnitude < (one.Radius + two.Radius) * (one.Radius + two.Radius); 32 | } 33 | 34 | public static bool BoxAndBox(CollisionBox one, CollisionBox two) 35 | { 36 | // Find the vector between the two centres 37 | Vector3d toCentre = two.GetAxis(3) - one.GetAxis(3); 38 | 39 | if (!OverlapOnAxis(one, two, one.GetAxis(0), toCentre)) return false; 40 | if (!OverlapOnAxis(one, two, one.GetAxis(1), toCentre)) return false; 41 | if (!OverlapOnAxis(one, two, one.GetAxis(2), toCentre)) return false; 42 | 43 | if (!OverlapOnAxis(one, two, two.GetAxis(0), toCentre)) return false; 44 | if (!OverlapOnAxis(one, two, two.GetAxis(1), toCentre)) return false; 45 | if (!OverlapOnAxis(one, two, two.GetAxis(2), toCentre)) return false; 46 | 47 | if (!OverlapOnAxis(one, two, Vector3d.Cross(one.GetAxis(0), two.GetAxis(0)), toCentre)) return false; 48 | if (!OverlapOnAxis(one, two, Vector3d.Cross(one.GetAxis(0), two.GetAxis(1)), toCentre)) return false; 49 | if (!OverlapOnAxis(one, two, Vector3d.Cross(one.GetAxis(0), two.GetAxis(2)), toCentre)) return false; 50 | 51 | if (!OverlapOnAxis(one, two, Vector3d.Cross(one.GetAxis(1), two.GetAxis(0)), toCentre)) return false; 52 | if (!OverlapOnAxis(one, two, Vector3d.Cross(one.GetAxis(1), two.GetAxis(1)), toCentre)) return false; 53 | if (!OverlapOnAxis(one, two, Vector3d.Cross(one.GetAxis(1), two.GetAxis(2)), toCentre)) return false; 54 | 55 | if (!OverlapOnAxis(one, two, Vector3d.Cross(one.GetAxis(2), two.GetAxis(0)), toCentre)) return false; 56 | if (!OverlapOnAxis(one, two, Vector3d.Cross(one.GetAxis(2), two.GetAxis(1)), toCentre)) return false; 57 | if (!OverlapOnAxis(one, two, Vector3d.Cross(one.GetAxis(2), two.GetAxis(2)), toCentre)) return false; 58 | 59 | return true; 60 | } 61 | 62 | public static bool BoxAndHalfSpace(CollisionBox box, CollisionPlane plane) 63 | { 64 | // Work out the projected radius of the box onto the plane direction 65 | double projectedRadius = TransformToAxis(box, plane.Direction); 66 | 67 | // Work out how far the box is from the origin 68 | double boxDistance = Vector3d.Dot(plane.Direction, box.GetAxis(3)) - projectedRadius; 69 | 70 | // Check for the intersection 71 | return boxDistance <= plane.Offset; 72 | } 73 | 74 | /// 75 | /// This function checks if the two boxes overlap 76 | /// along the given axis.The final parameter toCentre 77 | /// is used to pass in the vector between the boxes centre 78 | /// points, to avoid having to recalculate it each time. 79 | /// 80 | private static bool OverlapOnAxis(CollisionBox one, CollisionBox two, Vector3d axis, Vector3d toCentre) 81 | { 82 | // Project the half-size of one onto axis 83 | double oneProject = TransformToAxis(one, axis); 84 | double twoProject = TransformToAxis(two, axis); 85 | 86 | // Project this onto the axis 87 | double distance = Vector3d.AbsDot(toCentre, axis); 88 | 89 | // Check for overlap 90 | return distance < oneProject + twoProject; 91 | } 92 | 93 | private static double TransformToAxis(CollisionBox box, Vector3d axis) 94 | { 95 | return 96 | box.HalfSize.x * Vector3d.AbsDot(axis, box.GetAxis(0)) + 97 | box.HalfSize.y * Vector3d.AbsDot(axis, box.GetAxis(1)) + 98 | box.HalfSize.z * Vector3d.AbsDot(axis, box.GetAxis(2)); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/ParticleContactResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Particles; 6 | 7 | namespace Cyclone.Particles.Constraints 8 | { 9 | /// 10 | /// The contact resolution routine for particle contacts. One 11 | /// resolver instance can be shared for the whole simulation. 12 | /// 13 | /// The resolver uses an iterative satisfaction algorithm; it loops 14 | /// through each contact and tries to resolve it.This is a very fast 15 | /// algorithm but can be unstable when the contacts are highly 16 | /// inter-related. 17 | /// 18 | public class ParticleContactResolver 19 | { 20 | 21 | /// 22 | /// 23 | /// 24 | public ParticleContactResolver(int iterations = 0) 25 | { 26 | Iterations = iterations; 27 | } 28 | 29 | /// 30 | /// The number of iterations through the 31 | /// resolution algorithm.This should be at least the number of 32 | /// contacts (otherwise some constraints will not be resolved - 33 | /// although sometimes this is not noticable). If the 34 | /// iterations are not needed they will not be used, so adding 35 | /// more iterations may not make any difference.But in some 36 | /// cases you would need millions of iterations.Think about 37 | /// the number of iterations as a bound: if you specify a large 38 | /// number, sometimes the algorithm WILL use it, and you may 39 | /// drop frames. 40 | /// 41 | public int Iterations; 42 | 43 | /// 44 | /// This is a performance tracking value - we keep a record 45 | /// of the actual number of iterations used. 46 | /// 47 | public int IterationsUsed; 48 | 49 | /// 50 | /// Resolves a set of particle contacts for both penetration 51 | /// and velocity. 52 | /// 53 | /// Contacts that cannot interact with each other should be 54 | /// passed to separate calls to resolveContacts, as the 55 | /// resolution algorithm takes much longer for lots of contacts 56 | /// than it does for the same number of contacts in small sets. 57 | /// 58 | /// 59 | /// 60 | public void ResolveContacts(IList contacts, int numContacts, double dt) 61 | { 62 | if (numContacts == 0) return; 63 | 64 | if (Iterations <= 0) 65 | Iterations = numContacts * 2; 66 | 67 | IterationsUsed = 0; 68 | while (IterationsUsed < Iterations) 69 | { 70 | // Find the contact with the largest closing velocity. 71 | double max = double.PositiveInfinity; 72 | int maxIndex = numContacts; 73 | for (int i = 0; i < numContacts; i++) 74 | { 75 | double sepVel = contacts[i].CalculateSeparatingVelocity(); 76 | if (sepVel < max && (sepVel < 0 || contacts[i].Penetration > 0)) 77 | { 78 | max = sepVel; 79 | maxIndex = i; 80 | } 81 | } 82 | 83 | // Do we have anything worth resolving? 84 | if (maxIndex == numContacts) break; 85 | 86 | // Resolve this contact 87 | contacts[maxIndex].Resolve(dt); 88 | 89 | // Update the interpenetrations for all particles 90 | Vector3d[] move = contacts[maxIndex].ParticlesMovement; 91 | for (int i = 0; i < numContacts; i++) 92 | { 93 | if (contacts[i].Particles[0] == contacts[maxIndex].Particles[0]) 94 | { 95 | contacts[i].Penetration -= Vector3d.Dot(move[0], contacts[i].ContactNormal); 96 | } 97 | else if (contacts[i].Particles[0] == contacts[maxIndex].Particles[1]) 98 | { 99 | contacts[i].Penetration -= Vector3d.Dot(move[1], contacts[i].ContactNormal); 100 | } 101 | 102 | if (contacts[i].Particles[1] != null) 103 | { 104 | if (contacts[i].Particles[1] == contacts[maxIndex].Particles[0]) 105 | { 106 | contacts[i].Penetration += Vector3d.Dot(move[0], contacts[i].ContactNormal); 107 | } 108 | else if (contacts[i].Particles[1] == contacts[maxIndex].Particles[1]) 109 | { 110 | contacts[i].Penetration += Vector3d.Dot(move[1], contacts[i].ContactNormal); 111 | } 112 | } 113 | } 114 | 115 | IterationsUsed++; 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Assets/Cyclone/Core/Quaternion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Cyclone.Core 5 | { 6 | /// 7 | /// Holds a three degree of freedom orientation. 8 | /// 9 | /// Quaternions have 10 | /// several mathematical properties that make them useful for 11 | /// representing orientations, but require four items of data to 12 | /// hold the three degrees of freedom.These four items of data can 13 | /// be viewed as the coefficients of a complex number with three 14 | /// imaginary parts.The mathematics of the quaternion is then 15 | /// defined and is roughly correspondent to the math of 3D 16 | /// rotations.A quaternion is only a valid rotation if it is 17 | /// normalised: i.e.it has a length of 1. 18 | /// 19 | /// @note Angular velocity and acceleration can be correctly 20 | /// represented as vectors. Quaternions are only needed for 21 | /// orientation. 22 | /// 23 | public struct Quaternion 24 | { 25 | /// 26 | /// Holds the real component of the quaternion. 27 | /// 28 | public double r; 29 | 30 | /// 31 | /// Holds the first complex component of the quaternion. 32 | /// 33 | public double i; 34 | 35 | /// 36 | /// Holds the second complex component of the quaternion. 37 | /// 38 | public double j; 39 | 40 | /// 41 | /// Holds the third complex component of the quaternion. 42 | /// 43 | public double k; 44 | 45 | /// 46 | /// 47 | /// 48 | public readonly static Quaternion Identity = new Quaternion(1, 0, 0, 0); 49 | 50 | /// 51 | /// The explicit constructor creates a quaternion with the given components. 52 | /// 53 | /// The real component of the rigid body's orientation quaternion. 54 | /// The first complex component of the rigid body's orientation quaternion 55 | /// The second complex component of the rigid body's orientation quaternion 56 | /// The third complex component of the rigid body's orientation quaternion 57 | public Quaternion(double r, double i, double j, double k) 58 | { 59 | this.r = r; 60 | this.i = i; 61 | this.j = j; 62 | this.k = k; 63 | } 64 | 65 | /// 66 | /// Normalises the quaternion to unit length, making it a valid 67 | /// orientation quaternion. 68 | /// 69 | public void Normalise() 70 | { 71 | double d = r * r + i * i + j * j + k * k; 72 | 73 | // Check for zero length quaternion, and use the no-rotation 74 | // quaternion in that case. 75 | if (d < DMath.EPS) 76 | { 77 | i = j = k = 0; 78 | r = 1; 79 | return; 80 | } 81 | 82 | d = 1.0 / Math.Sqrt(d); 83 | r *= d; 84 | i *= d; 85 | j *= d; 86 | k *= d; 87 | } 88 | 89 | /// 90 | /// Multiplies the quaternion by the given quaternion. 91 | /// 92 | public static Quaternion operator *(Quaternion q1, Quaternion q2) 93 | { 94 | Quaternion q = new Quaternion(); 95 | 96 | q.r = q1.r * q2.r - q1.i * q2.i - 97 | q1.j * q2.j - q1.k * q2.k; 98 | q.i = q1.r * q2.i + q1.i * q2.r + 99 | q1.j * q2.k - q1.k * q2.j; 100 | q.j = q1.r * q2.j + q1.j * q2.r + 101 | q1.k * q2.i - q1.i * q2.k; 102 | q.k = q1.r * q2.k + q1.k * q2.r + 103 | q1.i * q2.j - q1.j * q2.i; 104 | 105 | return q; 106 | } 107 | 108 | /// 109 | /// Adds the given vector to this, scaled by the given amount. 110 | /// This is used to update the orientation quaternion by a rotation 111 | /// 112 | /// The vector to add. 113 | /// The amount of the vector to add. 114 | public void AddScaledVector(Vector3d vector, double scale) 115 | { 116 | Quaternion q = new Quaternion(0, 117 | vector.x * scale, 118 | vector.y * scale, 119 | vector.z * scale); 120 | 121 | q = q * this; 122 | r += q.r * 0.5; 123 | i += q.i * 0.5; 124 | j += q.j * 0.5; 125 | k += q.k * 0.5; 126 | } 127 | 128 | /// 129 | /// 130 | /// 131 | /// 132 | public void RotateByVector(Vector3d vector) 133 | { 134 | Quaternion q = new Quaternion(0, vector.x, vector.y, vector.z); 135 | 136 | q = this * q; 137 | r = q.r; 138 | i = q.i; 139 | j = q.j; 140 | k = q.k; 141 | } 142 | } 143 | 144 | 145 | } -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/ParticleEngine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Particles.Forces; 6 | using Cyclone.Particles.Constraints; 7 | 8 | namespace Cyclone.Particles 9 | { 10 | public class ParticleEngine 11 | { 12 | /// 13 | /// Holds the particles. 14 | /// 15 | public List Particles; 16 | 17 | /// 18 | /// Holds the force areas for the in this world. 19 | /// 20 | public List ForceAreas; 21 | 22 | /// 23 | /// Holds the forces for the particles in this world. 24 | /// 25 | public List Forces; 26 | 27 | /// 28 | /// Contact generators. 29 | /// 30 | public List Constraints; 31 | 32 | /// 33 | /// Holds the resolver for contacts. 34 | /// 35 | public ParticleContactResolver Resolver; 36 | 37 | /// 38 | /// Holds the list of contacts. 39 | /// 40 | private ParticleContact[] m_contacts; 41 | 42 | /// 43 | /// Creates a new particle simulator that can handle up to the 44 | /// given number of contacts per frame.You can also optionally 45 | /// give a number of contact-resolution iterations to use. If you 46 | /// don't give a number of iterations, then twice the number of 47 | /// contacts will be used. 48 | /// 49 | public ParticleEngine(int maxContacts) 50 | { 51 | Particles = new List(); 52 | ForceAreas = new List(); 53 | Forces = new List(); 54 | Constraints = new List(); 55 | Resolver = new ParticleContactResolver(); 56 | 57 | m_contacts = new ParticleContact[maxContacts]; 58 | for (int i = 0; i < maxContacts; i++) 59 | m_contacts[i] = new ParticleContact(); 60 | } 61 | 62 | /// 63 | /// Initializes the world for a simulation frame. This clears 64 | /// the force accumulators for particles in the world.After 65 | /// calling this, the particles can have their forces for this 66 | /// frame added. 67 | /// 68 | public void StartFrame() 69 | { 70 | foreach (var p in Particles) 71 | p.ClearAccumulator(); 72 | } 73 | 74 | /// 75 | /// Processes all the physics for the particle world. 76 | /// 77 | /// 78 | public void RunPhysics(double dt) 79 | { 80 | // First apply the forces 81 | ApplyForces(dt); 82 | 83 | // Then integrate the objects 84 | Integrate(dt); 85 | 86 | // Generate contacts 87 | int usedContacts = GenerateContacts(); 88 | 89 | // And process them 90 | if (usedContacts > 0) 91 | Resolver.ResolveContacts(m_contacts, usedContacts, dt); 92 | } 93 | 94 | /// 95 | /// Apply the forces. 96 | /// 97 | /// 98 | private void ApplyForces(double dt) 99 | { 100 | foreach (var f in ForceAreas) 101 | { 102 | foreach(var p in Particles) 103 | f.UpdateForce(p, dt); 104 | } 105 | 106 | foreach (var f in Forces) 107 | f.UpdateForce(dt); 108 | } 109 | 110 | /// 111 | /// Calls each of the registered contact generators to report 112 | /// their contacts.Returns the number of generated contacts. 113 | /// 114 | /// 115 | private int GenerateContacts() 116 | { 117 | ClearContacts(); 118 | 119 | int limit = m_contacts.Length; 120 | int nextContact = 0; 121 | 122 | foreach(var g in Constraints) 123 | { 124 | int used = g.AddContact(Particles, m_contacts, nextContact); 125 | limit -= used; 126 | nextContact += used; 127 | 128 | // We've run out of contacts to fill. This means we're missing contacts. 129 | if (limit <= 0) break; 130 | } 131 | 132 | // Return the number of contacts used. 133 | return m_contacts.Length - limit; 134 | } 135 | 136 | /// 137 | /// Integrates all the particles in this world forward in time 138 | /// by the given duration. 139 | /// 140 | /// 141 | private void Integrate(double dt) 142 | { 143 | foreach (var p in Particles) 144 | p.Integrate(dt); 145 | } 146 | 147 | /// 148 | /// 149 | /// 150 | private void ClearContacts() 151 | { 152 | foreach (var contact in m_contacts) 153 | contact.Clear(); 154 | } 155 | 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /Assets/Cyclone/Core/DMath.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace Cyclone.Core 5 | { 6 | public class DMath 7 | { 8 | 9 | public const double EPS = 1e-18; 10 | 11 | public const double PI = Math.PI; 12 | 13 | public const double SQRT2 = 1.414213562373095; 14 | 15 | public const double Rad2Deg = 180.0 / PI; 16 | 17 | public const double Deg2Rad = PI / 180.0; 18 | 19 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 20 | public static double SafeAcos(double r) 21 | { 22 | return Math.Acos(Math.Min(1.0, Math.Max(-1.0, r))); 23 | } 24 | 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static double SafeAsin(double r) 27 | { 28 | return Math.Asin(Math.Min(1.0, Math.Max(-1.0, r))); 29 | } 30 | 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public static double SafeSqrt(double v) 33 | { 34 | if (v <= 0.0) return 0.0; 35 | return Math.Sqrt(v); 36 | } 37 | 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | public static double SafeLog(double v) 40 | { 41 | if (v <= 0.0) return 0.0; 42 | return Math.Log(v); 43 | } 44 | 45 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 46 | public static double SafeLog10(double v) 47 | { 48 | if (v <= 0.0) return 0.0; 49 | return Math.Log10(v); 50 | } 51 | 52 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 53 | public static double SafeInvSqrt(double n, double d, double eps = EPS) 54 | { 55 | if (d <= 0.0) return 0.0; 56 | d = Math.Sqrt(d); 57 | if (d < eps) return 0.0; 58 | return n / d; 59 | } 60 | 61 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 62 | public static double SafeInv(double v, double eps = EPS) 63 | { 64 | if (Math.Abs(v) < eps) return 0.0; 65 | return 1.0 / v; 66 | } 67 | 68 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 69 | public static double SafeDiv(double n, double d, double eps = EPS) 70 | { 71 | if (Math.Abs(d) < eps) return 0.0; 72 | return n / d; 73 | } 74 | 75 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 76 | public static bool IsZero(double v, double eps = EPS) 77 | { 78 | return Math.Abs(v) < eps; 79 | } 80 | 81 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 82 | public static bool IsFinite(double f) 83 | { 84 | return !(double.IsInfinity(f) || double.IsNaN(f)); 85 | } 86 | 87 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 88 | public static double Sqr(double v) 89 | { 90 | return v * v; 91 | } 92 | 93 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 94 | public static double Pow3(double v) 95 | { 96 | return v * v * v; 97 | } 98 | 99 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 100 | public static double Pow4(double v) 101 | { 102 | return v * v * v * v; 103 | } 104 | 105 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 106 | public static double Clamp(double v, double min, double max) 107 | { 108 | if (v < min) v = min; 109 | if (v > max) v = max; 110 | return v; 111 | } 112 | 113 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 114 | public static double Clamp01(double v) 115 | { 116 | if (v < 0.0) v = 0.0; 117 | if (v > 1.0) v = 1.0; 118 | return v; 119 | } 120 | 121 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 122 | public static double SmoothStep(double edge0, double edge1, double x) 123 | { 124 | double t = Clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); 125 | return t * t * (3.0 - 2.0 * t); 126 | } 127 | 128 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 129 | public static double Frac(double x) 130 | { 131 | return x - Math.Floor(x); 132 | } 133 | 134 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 135 | public static double Lerp(double v0, double v1, double a) 136 | { 137 | return v0 * (1.0 - a) + v1 * a; 138 | } 139 | 140 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 141 | public static double SignOrZero(double v) 142 | { 143 | if (v == 0) return 0; 144 | return Math.Sign(v); 145 | } 146 | 147 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 148 | public static double Min(double a, double b, double c) 149 | { 150 | return Math.Min(a, Math.Min(b, c)); 151 | } 152 | 153 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 154 | public static double Max(double a, double b, double c) 155 | { 156 | return Math.Max(a, Math.Max(b, c)); 157 | } 158 | 159 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 160 | public static double Normalize(double a, double min, double max) 161 | { 162 | double len = max - min; 163 | if (len <= 0) return 0; 164 | return (a - min) / len; 165 | } 166 | 167 | } 168 | } 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/RigidBodyEngine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Rigid.Constraints; 6 | using Cyclone.Rigid.Forces; 7 | 8 | namespace Cyclone.Rigid 9 | { 10 | 11 | /// 12 | /// The world represents an independent simulation of physics. It 13 | /// keeps track of a set of rigid bodies, and provides the means to 14 | /// update them all. 15 | /// 16 | public class RigidBodyEngine 17 | { 18 | /// 19 | /// The list of bodies. 20 | /// 21 | public List Bodies; 22 | 23 | /// 24 | /// Holds the force areas for the in this world. 25 | /// 26 | public List ForceAreas; 27 | 28 | /// 29 | /// Holds the forces for the particles in this world. 30 | /// 31 | public List Forces; 32 | 33 | /// 34 | /// The list of contact generators. 35 | /// 36 | public List Constraints; 37 | 38 | /// 39 | /// The collision geometry. 40 | /// 41 | public CollisionConstraint Collisions; 42 | 43 | /// 44 | /// Holds the resolver for sets of contacts. 45 | /// 46 | public RigidContactResolver Resolver; 47 | 48 | /// 49 | /// Holds an array of contacts, for filling by the contact 50 | /// generators. 51 | /// 52 | private RigidContact[] m_contacts; 53 | 54 | /// 55 | /// Creates a new simulator that can handle up to the given 56 | /// number of contacts per frame. You can also optionally give 57 | /// a number of contact-resolution iterations to use. If you 58 | /// don't give a number of iterations, then four times the 59 | /// number of detected contacts will be used for each frame. 60 | /// 61 | public RigidBodyEngine(int maxContacts) 62 | { 63 | Bodies = new List(); 64 | ForceAreas = new List(); 65 | Forces = new List(); 66 | Constraints = new List(); 67 | Resolver = new RigidContactResolver(); 68 | 69 | Collisions = new CollisionConstraint(); 70 | Constraints.Add(Collisions); 71 | 72 | m_contacts = new RigidContact[maxContacts]; 73 | for (int i = 0; i < maxContacts; i++) 74 | m_contacts[i] = new RigidContact(); 75 | } 76 | 77 | /// 78 | /// Initialises the world for a simulation frame. This clears 79 | /// the force and torque accumulators for bodies in the 80 | /// world. After calling this, the bodies can have their forces 81 | /// and torques for this frame added. 82 | /// 83 | public void StartFrame() 84 | { 85 | foreach (var body in Bodies) 86 | { 87 | // Remove all forces from the accumulator 88 | body.ClearAccumulators(); 89 | body.CalculateDerivedData(); 90 | } 91 | } 92 | 93 | /// 94 | /// Processes all the physics for the world. 95 | /// 96 | public void RunPhysics(double dt) 97 | { 98 | // First apply the force.s 99 | ApplyForces(dt); 100 | 101 | Integrate(dt); 102 | 103 | // Generate contacts 104 | int usedContacts = GenerateContacts(); 105 | 106 | // And process them 107 | if (usedContacts > 0) 108 | Resolver.ResolveContacts(m_contacts, usedContacts, dt); 109 | } 110 | 111 | /// 112 | /// Apply the forces. 113 | /// 114 | /// 115 | private void ApplyForces(double dt) 116 | { 117 | foreach (var f in ForceAreas) 118 | { 119 | foreach (var b in Bodies) 120 | f.UpdateForce(b, dt); 121 | } 122 | 123 | foreach (var f in Forces) 124 | f.UpdateForce(dt); 125 | } 126 | 127 | /// 128 | /// Calls each of the registered contact generators to report 129 | /// their contacts. Returns the number of generated contacts. 130 | /// 131 | private int GenerateContacts() 132 | { 133 | ClearContacts(); 134 | 135 | int limit = m_contacts.Length; 136 | int nextContact = 0; 137 | 138 | foreach (var gen in Constraints) 139 | { 140 | int used = gen.AddContact(Bodies, m_contacts, nextContact); 141 | limit -= used; 142 | nextContact += used; 143 | 144 | // We've run out of contacts to fill. This means we're missing 145 | // contacts. 146 | if (limit <= 0) break; 147 | } 148 | 149 | // Return the number of contacts used. 150 | return m_contacts.Length - limit; 151 | } 152 | 153 | /// 154 | /// Integrates all the bodies in this world forward in time 155 | /// by the given dt. 156 | /// 157 | /// 158 | private void Integrate(double dt) 159 | { 160 | foreach (var b in Bodies) 161 | b.Integrate(dt); 162 | } 163 | 164 | /// 165 | /// 166 | /// 167 | private void ClearContacts() 168 | { 169 | foreach (var contact in m_contacts) 170 | contact.Clear(); 171 | } 172 | 173 | } 174 | 175 | } -------------------------------------------------------------------------------- /Assets/CommonUnity/Cameras/SimpleCameraController.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Common.Unity.Cameras 4 | { 5 | public class SimpleCameraController : MonoBehaviour 6 | { 7 | class CameraState 8 | { 9 | public float yaw; 10 | public float pitch; 11 | public float roll; 12 | public float x; 13 | public float y; 14 | public float z; 15 | 16 | public void SetFromTransform(Transform t) 17 | { 18 | pitch = t.eulerAngles.x; 19 | yaw = t.eulerAngles.y; 20 | roll = t.eulerAngles.z; 21 | x = t.position.x; 22 | y = t.position.y; 23 | z = t.position.z; 24 | } 25 | 26 | public void Translate(Vector3 translation) 27 | { 28 | Vector3 rotatedTranslation = Quaternion.Euler(pitch, yaw, roll) * translation; 29 | 30 | x += rotatedTranslation.x; 31 | y += rotatedTranslation.y; 32 | z += rotatedTranslation.z; 33 | } 34 | 35 | public void LerpTowards(CameraState target, float positionLerpPct, float rotationLerpPct) 36 | { 37 | yaw = Mathf.Lerp(yaw, target.yaw, rotationLerpPct); 38 | pitch = Mathf.Lerp(pitch, target.pitch, rotationLerpPct); 39 | roll = Mathf.Lerp(roll, target.roll, rotationLerpPct); 40 | 41 | x = Mathf.Lerp(x, target.x, positionLerpPct); 42 | y = Mathf.Lerp(y, target.y, positionLerpPct); 43 | z = Mathf.Lerp(z, target.z, positionLerpPct); 44 | } 45 | 46 | public void UpdateTransform(Transform t) 47 | { 48 | t.eulerAngles = new Vector3(pitch, yaw, roll); 49 | t.position = new Vector3(x, y, z); 50 | } 51 | } 52 | 53 | CameraState m_TargetCameraState = new CameraState(); 54 | CameraState m_InterpolatingCameraState = new CameraState(); 55 | 56 | [Header("Movement Settings")] 57 | [Tooltip("Exponential boost factor on translation, controllable by mouse wheel.")] 58 | public float boost = 3.5f; 59 | 60 | [Tooltip("Time it takes to interpolate camera position 99% of the way to the target."), Range(0.001f, 1f)] 61 | public float positionLerpTime = 0.2f; 62 | 63 | [Header("Rotation Settings")] 64 | [Tooltip("X = Change in mouse position.\nY = Multiplicative factor for camera rotation.")] 65 | public AnimationCurve mouseSensitivityCurve = new AnimationCurve(new Keyframe(0f, 0.5f, 0f, 5f), new Keyframe(1f, 2.5f, 0f, 0f)); 66 | 67 | [Tooltip("Time it takes to interpolate camera rotation 99% of the way to the target."), Range(0.001f, 1f)] 68 | public float rotationLerpTime = 0.01f; 69 | 70 | [Tooltip("Whether or not to invert our Y axis for mouse input to rotation.")] 71 | public bool invertY = false; 72 | 73 | void OnEnable() 74 | { 75 | m_TargetCameraState.SetFromTransform(transform); 76 | m_InterpolatingCameraState.SetFromTransform(transform); 77 | } 78 | 79 | Vector3 GetInputTranslationDirection() 80 | { 81 | Vector3 direction = new Vector3(); 82 | if (Input.GetKey(KeyCode.W)) 83 | { 84 | direction += Vector3.forward; 85 | } 86 | if (Input.GetKey(KeyCode.S)) 87 | { 88 | direction += Vector3.back; 89 | } 90 | if (Input.GetKey(KeyCode.A)) 91 | { 92 | direction += Vector3.left; 93 | } 94 | if (Input.GetKey(KeyCode.D)) 95 | { 96 | direction += Vector3.right; 97 | } 98 | if (Input.GetKey(KeyCode.Q)) 99 | { 100 | direction += Vector3.down; 101 | } 102 | if (Input.GetKey(KeyCode.E)) 103 | { 104 | direction += Vector3.up; 105 | } 106 | return direction; 107 | } 108 | 109 | void Update() 110 | { 111 | 112 | // Rotation 113 | if (Input.GetMouseButton(1)) 114 | { 115 | var mouseMovement = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y") * (invertY ? 1 : -1)); 116 | 117 | var mouseSensitivityFactor = mouseSensitivityCurve.Evaluate(mouseMovement.magnitude); 118 | 119 | m_TargetCameraState.yaw += mouseMovement.x * mouseSensitivityFactor; 120 | m_TargetCameraState.pitch += mouseMovement.y * mouseSensitivityFactor; 121 | } 122 | 123 | // Translation 124 | var translation = GetInputTranslationDirection() * Time.deltaTime; 125 | 126 | // Speed up movement when shift key held 127 | if (Input.GetKey(KeyCode.LeftShift)) 128 | { 129 | translation *= 10.0f; 130 | } 131 | 132 | // Modify movement by a boost factor (defined in Inspector and modified in play mode through the mouse scroll wheel) 133 | boost += Input.mouseScrollDelta.y * 0.2f; 134 | translation *= Mathf.Pow(2.0f, boost); 135 | 136 | m_TargetCameraState.Translate(translation); 137 | 138 | // Framerate-independent interpolation 139 | // Calculate the lerp amount, such that we get 99% of the way to our target in the specified time 140 | var positionLerpPct = 1f - Mathf.Exp((Mathf.Log(1f - 0.99f) / positionLerpTime) * Time.deltaTime); 141 | var rotationLerpPct = 1f - Mathf.Exp((Mathf.Log(1f - 0.99f) / rotationLerpTime) * Time.deltaTime); 142 | m_InterpolatingCameraState.LerpTowards(m_TargetCameraState, positionLerpPct, rotationLerpPct); 143 | 144 | m_InterpolatingCameraState.UpdateTransform(transform); 145 | } 146 | } 147 | 148 | } -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Axes: 8 | - serializedVersion: 3 9 | m_Name: Horizontal 10 | descriptiveName: 11 | descriptiveNegativeName: 12 | negativeButton: left 13 | positiveButton: right 14 | altNegativeButton: a 15 | altPositiveButton: d 16 | gravity: 3 17 | dead: 0.001 18 | sensitivity: 3 19 | snap: 1 20 | invert: 0 21 | type: 0 22 | axis: 0 23 | joyNum: 0 24 | - serializedVersion: 3 25 | m_Name: Vertical 26 | descriptiveName: 27 | descriptiveNegativeName: 28 | negativeButton: down 29 | positiveButton: up 30 | altNegativeButton: s 31 | altPositiveButton: w 32 | gravity: 3 33 | dead: 0.001 34 | sensitivity: 3 35 | snap: 1 36 | invert: 0 37 | type: 0 38 | axis: 0 39 | joyNum: 0 40 | - serializedVersion: 3 41 | m_Name: Fire1 42 | descriptiveName: 43 | descriptiveNegativeName: 44 | negativeButton: 45 | positiveButton: left ctrl 46 | altNegativeButton: 47 | altPositiveButton: mouse 0 48 | gravity: 1000 49 | dead: 0.001 50 | sensitivity: 1000 51 | snap: 0 52 | invert: 0 53 | type: 0 54 | axis: 0 55 | joyNum: 0 56 | - serializedVersion: 3 57 | m_Name: Fire2 58 | descriptiveName: 59 | descriptiveNegativeName: 60 | negativeButton: 61 | positiveButton: left alt 62 | altNegativeButton: 63 | altPositiveButton: mouse 1 64 | gravity: 1000 65 | dead: 0.001 66 | sensitivity: 1000 67 | snap: 0 68 | invert: 0 69 | type: 0 70 | axis: 0 71 | joyNum: 0 72 | - serializedVersion: 3 73 | m_Name: Fire3 74 | descriptiveName: 75 | descriptiveNegativeName: 76 | negativeButton: 77 | positiveButton: left shift 78 | altNegativeButton: 79 | altPositiveButton: mouse 2 80 | gravity: 1000 81 | dead: 0.001 82 | sensitivity: 1000 83 | snap: 0 84 | invert: 0 85 | type: 0 86 | axis: 0 87 | joyNum: 0 88 | - serializedVersion: 3 89 | m_Name: Jump 90 | descriptiveName: 91 | descriptiveNegativeName: 92 | negativeButton: 93 | positiveButton: space 94 | altNegativeButton: 95 | altPositiveButton: 96 | gravity: 1000 97 | dead: 0.001 98 | sensitivity: 1000 99 | snap: 0 100 | invert: 0 101 | type: 0 102 | axis: 0 103 | joyNum: 0 104 | - serializedVersion: 3 105 | m_Name: Mouse X 106 | descriptiveName: 107 | descriptiveNegativeName: 108 | negativeButton: 109 | positiveButton: 110 | altNegativeButton: 111 | altPositiveButton: 112 | gravity: 0 113 | dead: 0 114 | sensitivity: 0.1 115 | snap: 0 116 | invert: 0 117 | type: 1 118 | axis: 0 119 | joyNum: 0 120 | - serializedVersion: 3 121 | m_Name: Mouse Y 122 | descriptiveName: 123 | descriptiveNegativeName: 124 | negativeButton: 125 | positiveButton: 126 | altNegativeButton: 127 | altPositiveButton: 128 | gravity: 0 129 | dead: 0 130 | sensitivity: 0.1 131 | snap: 0 132 | invert: 0 133 | type: 1 134 | axis: 1 135 | joyNum: 0 136 | - serializedVersion: 3 137 | m_Name: Mouse ScrollWheel 138 | descriptiveName: 139 | descriptiveNegativeName: 140 | negativeButton: 141 | positiveButton: 142 | altNegativeButton: 143 | altPositiveButton: 144 | gravity: 0 145 | dead: 0 146 | sensitivity: 0.1 147 | snap: 0 148 | invert: 0 149 | type: 1 150 | axis: 2 151 | joyNum: 0 152 | - serializedVersion: 3 153 | m_Name: Horizontal 154 | descriptiveName: 155 | descriptiveNegativeName: 156 | negativeButton: 157 | positiveButton: 158 | altNegativeButton: 159 | altPositiveButton: 160 | gravity: 0 161 | dead: 0.19 162 | sensitivity: 1 163 | snap: 0 164 | invert: 0 165 | type: 2 166 | axis: 0 167 | joyNum: 0 168 | - serializedVersion: 3 169 | m_Name: Vertical 170 | descriptiveName: 171 | descriptiveNegativeName: 172 | negativeButton: 173 | positiveButton: 174 | altNegativeButton: 175 | altPositiveButton: 176 | gravity: 0 177 | dead: 0.19 178 | sensitivity: 1 179 | snap: 0 180 | invert: 1 181 | type: 2 182 | axis: 1 183 | joyNum: 0 184 | - serializedVersion: 3 185 | m_Name: Fire1 186 | descriptiveName: 187 | descriptiveNegativeName: 188 | negativeButton: 189 | positiveButton: joystick button 0 190 | altNegativeButton: 191 | altPositiveButton: 192 | gravity: 1000 193 | dead: 0.001 194 | sensitivity: 1000 195 | snap: 0 196 | invert: 0 197 | type: 0 198 | axis: 0 199 | joyNum: 0 200 | - serializedVersion: 3 201 | m_Name: Fire2 202 | descriptiveName: 203 | descriptiveNegativeName: 204 | negativeButton: 205 | positiveButton: joystick button 1 206 | altNegativeButton: 207 | altPositiveButton: 208 | gravity: 1000 209 | dead: 0.001 210 | sensitivity: 1000 211 | snap: 0 212 | invert: 0 213 | type: 0 214 | axis: 0 215 | joyNum: 0 216 | - serializedVersion: 3 217 | m_Name: Fire3 218 | descriptiveName: 219 | descriptiveNegativeName: 220 | negativeButton: 221 | positiveButton: joystick button 2 222 | altNegativeButton: 223 | altPositiveButton: 224 | gravity: 1000 225 | dead: 0.001 226 | sensitivity: 1000 227 | snap: 0 228 | invert: 0 229 | type: 0 230 | axis: 0 231 | joyNum: 0 232 | - serializedVersion: 3 233 | m_Name: Jump 234 | descriptiveName: 235 | descriptiveNegativeName: 236 | negativeButton: 237 | positiveButton: joystick button 3 238 | altNegativeButton: 239 | altPositiveButton: 240 | gravity: 1000 241 | dead: 0.001 242 | sensitivity: 1000 243 | snap: 0 244 | invert: 0 245 | type: 0 246 | axis: 0 247 | joyNum: 0 248 | - serializedVersion: 3 249 | m_Name: Submit 250 | descriptiveName: 251 | descriptiveNegativeName: 252 | negativeButton: 253 | positiveButton: return 254 | altNegativeButton: 255 | altPositiveButton: joystick button 0 256 | gravity: 1000 257 | dead: 0.001 258 | sensitivity: 1000 259 | snap: 0 260 | invert: 0 261 | type: 0 262 | axis: 0 263 | joyNum: 0 264 | - serializedVersion: 3 265 | m_Name: Submit 266 | descriptiveName: 267 | descriptiveNegativeName: 268 | negativeButton: 269 | positiveButton: enter 270 | altNegativeButton: 271 | altPositiveButton: space 272 | gravity: 1000 273 | dead: 0.001 274 | sensitivity: 1000 275 | snap: 0 276 | invert: 0 277 | type: 0 278 | axis: 0 279 | joyNum: 0 280 | - serializedVersion: 3 281 | m_Name: Cancel 282 | descriptiveName: 283 | descriptiveNegativeName: 284 | negativeButton: 285 | positiveButton: escape 286 | altNegativeButton: 287 | altPositiveButton: joystick button 1 288 | gravity: 1000 289 | dead: 0.001 290 | sensitivity: 1000 291 | snap: 0 292 | invert: 0 293 | type: 0 294 | axis: 0 295 | joyNum: 0 296 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.obj 68 | *.iobj 69 | *.pch 70 | *.pdb 71 | *.ipdb 72 | *.pgc 73 | *.pgd 74 | *.rsp 75 | *.sbr 76 | *.tlb 77 | *.tli 78 | *.tlh 79 | *.tmp 80 | *.tmp_proj 81 | *_wpftmp.csproj 82 | *.log 83 | *.vspscc 84 | *.vssscc 85 | .builds 86 | *.pidb 87 | *.svclog 88 | *.scc 89 | 90 | # Chutzpah Test files 91 | _Chutzpah* 92 | 93 | # Visual C++ cache files 94 | ipch/ 95 | *.aps 96 | *.ncb 97 | *.opendb 98 | *.opensdf 99 | *.sdf 100 | *.cachefile 101 | *.VC.db 102 | *.VC.VC.opendb 103 | 104 | # Visual Studio profiler 105 | *.psess 106 | *.vsp 107 | *.vspx 108 | *.sap 109 | 110 | # Visual Studio Trace Files 111 | *.e2e 112 | 113 | # TFS 2012 Local Workspace 114 | $tf/ 115 | 116 | # Guidance Automation Toolkit 117 | *.gpState 118 | 119 | # ReSharper is a .NET coding add-in 120 | _ReSharper*/ 121 | *.[Rr]e[Ss]harper 122 | *.DotSettings.user 123 | 124 | # JustCode is a .NET coding add-in 125 | .JustCode 126 | 127 | # TeamCity is a build add-in 128 | _TeamCity* 129 | 130 | # DotCover is a Code Coverage Tool 131 | *.dotCover 132 | 133 | # AxoCover is a Code Coverage Tool 134 | .axoCover/* 135 | !.axoCover/settings.json 136 | 137 | # Visual Studio code coverage results 138 | *.coverage 139 | *.coveragexml 140 | 141 | # NCrunch 142 | _NCrunch_* 143 | .*crunch*.local.xml 144 | nCrunchTemp_* 145 | 146 | # MightyMoose 147 | *.mm.* 148 | AutoTest.Net/ 149 | 150 | # Web workbench (sass) 151 | .sass-cache/ 152 | 153 | # Installshield output folder 154 | [Ee]xpress/ 155 | 156 | # DocProject is a documentation generator add-in 157 | DocProject/buildhelp/ 158 | DocProject/Help/*.HxT 159 | DocProject/Help/*.HxC 160 | DocProject/Help/*.hhc 161 | DocProject/Help/*.hhk 162 | DocProject/Help/*.hhp 163 | DocProject/Help/Html2 164 | DocProject/Help/html 165 | 166 | # Click-Once directory 167 | publish/ 168 | 169 | # Publish Web Output 170 | *.[Pp]ublish.xml 171 | *.azurePubxml 172 | # Note: Comment the next line if you want to checkin your web deploy settings, 173 | # but database connection strings (with potential passwords) will be unencrypted 174 | *.pubxml 175 | *.publishproj 176 | 177 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 178 | # checkin your Azure Web App publish settings, but sensitive information contained 179 | # in these scripts will be unencrypted 180 | PublishScripts/ 181 | 182 | # NuGet Packages 183 | *.nupkg 184 | # The packages folder can be ignored because of Package Restore 185 | **/[Pp]ackages/* 186 | # except build/, which is used as an MSBuild target. 187 | !**/[Pp]ackages/build/ 188 | # Uncomment if necessary however generally it will be regenerated when needed 189 | #!**/[Pp]ackages/repositories.config 190 | # NuGet v3's project.json files produces more ignorable files 191 | *.nuget.props 192 | *.nuget.targets 193 | 194 | # Microsoft Azure Build Output 195 | csx/ 196 | *.build.csdef 197 | 198 | # Microsoft Azure Emulator 199 | ecf/ 200 | rcf/ 201 | 202 | # Windows Store app package directories and files 203 | AppPackages/ 204 | BundleArtifacts/ 205 | Package.StoreAssociation.xml 206 | _pkginfo.txt 207 | *.appx 208 | 209 | # Visual Studio cache files 210 | # files ending in .cache can be ignored 211 | *.[Cc]ache 212 | # but keep track of directories ending in .cache 213 | !?*.[Cc]ache/ 214 | 215 | # Others 216 | ClientBin/ 217 | ~$* 218 | *~ 219 | *.dbmdl 220 | *.dbproj.schemaview 221 | *.jfm 222 | *.pfx 223 | *.publishsettings 224 | orleans.codegen.cs 225 | 226 | # Including strong name files can present a security risk 227 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 228 | #*.snk 229 | 230 | # Since there are multiple workflows, uncomment next line to ignore bower_components 231 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 232 | #bower_components/ 233 | 234 | # RIA/Silverlight projects 235 | Generated_Code/ 236 | 237 | # Backup & report files from converting an old project file 238 | # to a newer Visual Studio version. Backup files are not needed, 239 | # because we have git ;-) 240 | _UpgradeReport_Files/ 241 | Backup*/ 242 | UpgradeLog*.XML 243 | UpgradeLog*.htm 244 | ServiceFabricBackup/ 245 | *.rptproj.bak 246 | 247 | # SQL Server files 248 | *.mdf 249 | *.ldf 250 | *.ndf 251 | 252 | # Business Intelligence projects 253 | *.rdl.data 254 | *.bim.layout 255 | *.bim_*.settings 256 | *.rptproj.rsuser 257 | *- Backup*.rdl 258 | 259 | # Microsoft Fakes 260 | FakesAssemblies/ 261 | 262 | # GhostDoc plugin setting file 263 | *.GhostDoc.xml 264 | 265 | # Node.js Tools for Visual Studio 266 | .ntvs_analysis.dat 267 | node_modules/ 268 | 269 | # Visual Studio 6 build log 270 | *.plg 271 | 272 | # Visual Studio 6 workspace options file 273 | *.opt 274 | 275 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 276 | *.vbw 277 | 278 | # Visual Studio LightSwitch build output 279 | **/*.HTMLClient/GeneratedArtifacts 280 | **/*.DesktopClient/GeneratedArtifacts 281 | **/*.DesktopClient/ModelManifest.xml 282 | **/*.Server/GeneratedArtifacts 283 | **/*.Server/ModelManifest.xml 284 | _Pvt_Extensions 285 | 286 | # Paket dependency manager 287 | .paket/paket.exe 288 | paket-files/ 289 | 290 | # FAKE - F# Make 291 | .fake/ 292 | 293 | # JetBrains Rider 294 | .idea/ 295 | *.sln.iml 296 | 297 | # CodeRush personal settings 298 | .cr/personal 299 | 300 | # Python Tools for Visual Studio (PTVS) 301 | __pycache__/ 302 | *.pyc 303 | 304 | # Cake - Uncomment if you are using it 305 | # tools/** 306 | # !tools/packages.config 307 | 308 | # Tabs Studio 309 | *.tss 310 | 311 | # Telerik's JustMock configuration file 312 | *.jmconfig 313 | 314 | # BizTalk build output 315 | *.btp.cs 316 | *.btm.cs 317 | *.odx.cs 318 | *.xsd.cs 319 | 320 | # OpenCover UI analysis results 321 | OpenCover/ 322 | 323 | # Azure Stream Analytics local run output 324 | ASALocalRun/ 325 | 326 | # MSBuild Binary and Structured Log 327 | *.binlog 328 | 329 | # NVidia Nsight GPU debugger configuration file 330 | *.nvuser 331 | 332 | # MFractors (Xamarin productivity tool) working folder 333 | .mfractor/ 334 | 335 | # Local History for Visual Studio 336 | .localhistory/ 337 | 338 | # BeatPulse healthcheck temp database 339 | healthchecksdb 340 | /Library 341 | /Temp 342 | /UserSettings 343 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!47 &1 4 | QualitySettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 5 7 | m_CurrentQuality: 5 8 | m_QualitySettings: 9 | - serializedVersion: 2 10 | name: Very Low 11 | pixelLightCount: 0 12 | shadows: 0 13 | shadowResolution: 0 14 | shadowProjection: 1 15 | shadowCascades: 1 16 | shadowDistance: 15 17 | shadowNearPlaneOffset: 3 18 | shadowCascade2Split: 0.33333334 19 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 20 | shadowmaskMode: 0 21 | blendWeights: 1 22 | textureQuality: 1 23 | anisotropicTextures: 0 24 | antiAliasing: 0 25 | softParticles: 0 26 | softVegetation: 0 27 | realtimeReflectionProbes: 0 28 | billboardsFaceCameraPosition: 0 29 | vSyncCount: 0 30 | lodBias: 0.3 31 | maximumLODLevel: 0 32 | streamingMipmapsActive: 0 33 | streamingMipmapsAddAllCameras: 1 34 | streamingMipmapsMemoryBudget: 512 35 | streamingMipmapsRenderersPerFrame: 512 36 | streamingMipmapsMaxLevelReduction: 2 37 | streamingMipmapsMaxFileIORequests: 1024 38 | particleRaycastBudget: 4 39 | asyncUploadTimeSlice: 2 40 | asyncUploadBufferSize: 16 41 | asyncUploadPersistentBuffer: 1 42 | resolutionScalingFixedDPIFactor: 1 43 | excludedTargetPlatforms: [] 44 | - serializedVersion: 2 45 | name: Low 46 | pixelLightCount: 0 47 | shadows: 0 48 | shadowResolution: 0 49 | shadowProjection: 1 50 | shadowCascades: 1 51 | shadowDistance: 20 52 | shadowNearPlaneOffset: 3 53 | shadowCascade2Split: 0.33333334 54 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 55 | shadowmaskMode: 0 56 | blendWeights: 2 57 | textureQuality: 0 58 | anisotropicTextures: 0 59 | antiAliasing: 0 60 | softParticles: 0 61 | softVegetation: 0 62 | realtimeReflectionProbes: 0 63 | billboardsFaceCameraPosition: 0 64 | vSyncCount: 0 65 | lodBias: 0.4 66 | maximumLODLevel: 0 67 | streamingMipmapsActive: 0 68 | streamingMipmapsAddAllCameras: 1 69 | streamingMipmapsMemoryBudget: 512 70 | streamingMipmapsRenderersPerFrame: 512 71 | streamingMipmapsMaxLevelReduction: 2 72 | streamingMipmapsMaxFileIORequests: 1024 73 | particleRaycastBudget: 16 74 | asyncUploadTimeSlice: 2 75 | asyncUploadBufferSize: 16 76 | asyncUploadPersistentBuffer: 1 77 | resolutionScalingFixedDPIFactor: 1 78 | excludedTargetPlatforms: [] 79 | - serializedVersion: 2 80 | name: Medium 81 | pixelLightCount: 1 82 | shadows: 1 83 | shadowResolution: 0 84 | shadowProjection: 1 85 | shadowCascades: 1 86 | shadowDistance: 20 87 | shadowNearPlaneOffset: 3 88 | shadowCascade2Split: 0.33333334 89 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 90 | shadowmaskMode: 0 91 | blendWeights: 2 92 | textureQuality: 0 93 | anisotropicTextures: 1 94 | antiAliasing: 0 95 | softParticles: 0 96 | softVegetation: 0 97 | realtimeReflectionProbes: 0 98 | billboardsFaceCameraPosition: 0 99 | vSyncCount: 1 100 | lodBias: 0.7 101 | maximumLODLevel: 0 102 | streamingMipmapsActive: 0 103 | streamingMipmapsAddAllCameras: 1 104 | streamingMipmapsMemoryBudget: 512 105 | streamingMipmapsRenderersPerFrame: 512 106 | streamingMipmapsMaxLevelReduction: 2 107 | streamingMipmapsMaxFileIORequests: 1024 108 | particleRaycastBudget: 64 109 | asyncUploadTimeSlice: 2 110 | asyncUploadBufferSize: 16 111 | asyncUploadPersistentBuffer: 1 112 | resolutionScalingFixedDPIFactor: 1 113 | excludedTargetPlatforms: [] 114 | - serializedVersion: 2 115 | name: High 116 | pixelLightCount: 2 117 | shadows: 2 118 | shadowResolution: 1 119 | shadowProjection: 1 120 | shadowCascades: 2 121 | shadowDistance: 40 122 | shadowNearPlaneOffset: 3 123 | shadowCascade2Split: 0.33333334 124 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 125 | shadowmaskMode: 1 126 | blendWeights: 2 127 | textureQuality: 0 128 | anisotropicTextures: 1 129 | antiAliasing: 0 130 | softParticles: 0 131 | softVegetation: 1 132 | realtimeReflectionProbes: 1 133 | billboardsFaceCameraPosition: 1 134 | vSyncCount: 1 135 | lodBias: 1 136 | maximumLODLevel: 0 137 | streamingMipmapsActive: 0 138 | streamingMipmapsAddAllCameras: 1 139 | streamingMipmapsMemoryBudget: 512 140 | streamingMipmapsRenderersPerFrame: 512 141 | streamingMipmapsMaxLevelReduction: 2 142 | streamingMipmapsMaxFileIORequests: 1024 143 | particleRaycastBudget: 256 144 | asyncUploadTimeSlice: 2 145 | asyncUploadBufferSize: 16 146 | asyncUploadPersistentBuffer: 1 147 | resolutionScalingFixedDPIFactor: 1 148 | excludedTargetPlatforms: [] 149 | - serializedVersion: 2 150 | name: Very High 151 | pixelLightCount: 3 152 | shadows: 2 153 | shadowResolution: 2 154 | shadowProjection: 1 155 | shadowCascades: 2 156 | shadowDistance: 70 157 | shadowNearPlaneOffset: 3 158 | shadowCascade2Split: 0.33333334 159 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 160 | shadowmaskMode: 1 161 | blendWeights: 4 162 | textureQuality: 0 163 | anisotropicTextures: 2 164 | antiAliasing: 2 165 | softParticles: 1 166 | softVegetation: 1 167 | realtimeReflectionProbes: 1 168 | billboardsFaceCameraPosition: 1 169 | vSyncCount: 1 170 | lodBias: 1.5 171 | maximumLODLevel: 0 172 | streamingMipmapsActive: 0 173 | streamingMipmapsAddAllCameras: 1 174 | streamingMipmapsMemoryBudget: 512 175 | streamingMipmapsRenderersPerFrame: 512 176 | streamingMipmapsMaxLevelReduction: 2 177 | streamingMipmapsMaxFileIORequests: 1024 178 | particleRaycastBudget: 1024 179 | asyncUploadTimeSlice: 2 180 | asyncUploadBufferSize: 16 181 | asyncUploadPersistentBuffer: 1 182 | resolutionScalingFixedDPIFactor: 1 183 | excludedTargetPlatforms: [] 184 | - serializedVersion: 2 185 | name: Ultra 186 | pixelLightCount: 4 187 | shadows: 2 188 | shadowResolution: 2 189 | shadowProjection: 1 190 | shadowCascades: 4 191 | shadowDistance: 150 192 | shadowNearPlaneOffset: 3 193 | shadowCascade2Split: 0.33333334 194 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 195 | shadowmaskMode: 1 196 | blendWeights: 4 197 | textureQuality: 0 198 | anisotropicTextures: 2 199 | antiAliasing: 2 200 | softParticles: 1 201 | softVegetation: 1 202 | realtimeReflectionProbes: 1 203 | billboardsFaceCameraPosition: 1 204 | vSyncCount: 1 205 | lodBias: 2 206 | maximumLODLevel: 0 207 | streamingMipmapsActive: 0 208 | streamingMipmapsAddAllCameras: 1 209 | streamingMipmapsMemoryBudget: 512 210 | streamingMipmapsRenderersPerFrame: 512 211 | streamingMipmapsMaxLevelReduction: 2 212 | streamingMipmapsMaxFileIORequests: 1024 213 | particleRaycastBudget: 4096 214 | asyncUploadTimeSlice: 2 215 | asyncUploadBufferSize: 16 216 | asyncUploadPersistentBuffer: 1 217 | resolutionScalingFixedDPIFactor: 1 218 | excludedTargetPlatforms: [] 219 | m_PerPlatformDefaultQuality: 220 | Android: 2 221 | Lumin: 5 222 | Nintendo 3DS: 5 223 | Nintendo Switch: 5 224 | PS4: 5 225 | PSP2: 2 226 | Standalone: 5 227 | WebGL: 3 228 | Windows Store Apps: 5 229 | XboxOne: 5 230 | iPhone: 2 231 | tvOS: 2 232 | -------------------------------------------------------------------------------- /Assets/Cyclone/Particles/Constraints/ParticleContact.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | using Cyclone.Particles; 6 | 7 | namespace Cyclone.Particles.Constraints 8 | { 9 | /// 10 | /// A Contact represents two objects in contact (in this case 11 | /// ParticleContact representing two Particles). Resolving a 12 | /// contact removes their interpenetration, and applies sufficient 13 | /// impulse to keep them apart.Colliding bodies may also rebound. 14 | /// 15 | /// The contact has no callable functions, it just holds the 16 | /// contact details. To resolve a set of contacts, use the particle 17 | /// contact resolver class. 18 | /// 19 | public class ParticleContact 20 | { 21 | /// 22 | /// Holds the particles that are involved in the contact. The 23 | /// second of these can be NULL, for contacts with the scenery. 24 | /// 25 | public Particle[] Particles; 26 | 27 | /// 28 | /// Holds the normal restitution coefficient at the contact. 29 | /// 30 | public double Restitution; 31 | 32 | /// 33 | /// Holds the direction of the contact in world coordinates. 34 | /// 35 | public Vector3d ContactNormal; 36 | 37 | /// 38 | /// Holds the depth of penetration at the contact. 39 | /// 40 | public double Penetration; 41 | 42 | /// 43 | /// Holds the amount each particle is moved by during 44 | /// interpenetration resolution. 45 | /// 46 | public Vector3d[] ParticlesMovement; 47 | 48 | /// 49 | /// 50 | /// 51 | public ParticleContact() 52 | { 53 | Particles = new Particle[2]; 54 | ParticlesMovement = new Vector3d[2]; 55 | } 56 | 57 | /// 58 | /// 59 | /// 60 | public void Clear() 61 | { 62 | Particles[0] = null; 63 | Particles[1] = null; 64 | } 65 | 66 | /// 67 | /// Resolves this contact, for both velocity and interpenetration. 68 | /// 69 | /// 70 | public void Resolve(double dt) 71 | { 72 | ResolveVelocity(dt); 73 | ResolveInterpenetration(dt); 74 | } 75 | 76 | /// 77 | /// Calculates the separating velocity at this contact. 78 | /// 79 | /// 80 | public double CalculateSeparatingVelocity() 81 | { 82 | Vector3d relativeVelocity = Particles[0].Velocity; 83 | if (Particles[1] != null) 84 | relativeVelocity -= Particles[1].Velocity; 85 | 86 | return Vector3d.Dot(relativeVelocity, ContactNormal); 87 | } 88 | 89 | /// 90 | /// Handles the impulse calculations for this collision. 91 | /// 92 | /// 93 | private void ResolveVelocity(double dt) 94 | { 95 | // Find the velocity in the direction of the contact 96 | double separatingVelocity = CalculateSeparatingVelocity(); 97 | 98 | // Check if it needs to be resolved 99 | if (separatingVelocity > 0) 100 | { 101 | // The contact is either separating, or stationary - there's 102 | // no impulse required. 103 | return; 104 | } 105 | 106 | // Calculate the new separating velocity 107 | double newSepVelocity = -separatingVelocity * Restitution; 108 | 109 | // Check the velocity build-up due to acceleration only 110 | Vector3d accCausedVelocity = Particles[0].Acceleration; 111 | if (Particles[1] != null) accCausedVelocity -= Particles[1].Acceleration; 112 | double accCausedSepVelocity = Vector3d.Dot(accCausedVelocity, ContactNormal) * dt; 113 | 114 | // If we've got a closing velocity due to acceleration build-up, 115 | // remove it from the new separating velocity 116 | if (accCausedSepVelocity < 0) 117 | { 118 | newSepVelocity += Restitution * accCausedSepVelocity; 119 | 120 | // Make sure we haven't removed more than was 121 | // there to remove. 122 | if (newSepVelocity < 0) newSepVelocity = 0; 123 | } 124 | 125 | double deltaVelocity = newSepVelocity - separatingVelocity; 126 | 127 | // We apply the change in velocity to each object in proportion to 128 | // their inverse mass (i.e. those with lower inverse mass [higher 129 | // actual mass] get less change in velocity).. 130 | double totalInverseMass = Particles[0].InverseMass; 131 | if (Particles[1] != null) totalInverseMass += Particles[1].InverseMass; 132 | 133 | // If all m_particless have infinite mass, then impulses have no effect 134 | if (totalInverseMass <= 0) return; 135 | 136 | // Calculate the impulse to apply 137 | double impulse = deltaVelocity / totalInverseMass; 138 | 139 | // Find the amount of impulse per unit of inverse mass 140 | Vector3d impulsePerIMass = ContactNormal * impulse; 141 | 142 | // Apply impulses: they are applied in the direction of the contact, 143 | // and are proportional to the inverse mass. 144 | Particles[0].Velocity += impulsePerIMass * Particles[0].InverseMass; 145 | 146 | if (Particles[1] != null) 147 | { 148 | // Particle 1 goes in the opposite direction 149 | Particles[1].Velocity += impulsePerIMass * -Particles[1].InverseMass; 150 | } 151 | } 152 | 153 | /// 154 | /// Handles the interpenetration resolution for this contact. 155 | /// 156 | /// 157 | private void ResolveInterpenetration(double dt) 158 | { 159 | // If we don't have any penetration, skip this step. 160 | if (Penetration <= 0) return; 161 | 162 | // The movement of each object is based on their inverse mass, so 163 | // total that. 164 | double totalInverseMass = Particles[0].InverseMass; 165 | if (Particles[1] != null) totalInverseMass += Particles[1].InverseMass; 166 | 167 | // If all m_particless have infinite mass, then we do nothing 168 | if (totalInverseMass <= 0) return; 169 | 170 | // Find the amount of penetration resolution per unit of inverse mass 171 | Vector3d movePerIMass = ContactNormal * (Penetration / totalInverseMass); 172 | 173 | // Calculate the the movement amounts 174 | ParticlesMovement[0] = movePerIMass * Particles[0].InverseMass; 175 | if (Particles[1] != null) 176 | ParticlesMovement[1] = movePerIMass * -Particles[1].InverseMass; 177 | else 178 | ParticlesMovement[1] = Vector3d.Zero; 179 | 180 | // Apply the penetration resolution 181 | Particles[0].Position += ParticlesMovement[0]; 182 | if (Particles[1] != null) 183 | Particles[1].Position += ParticlesMovement[1]; 184 | } 185 | 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /Assets/CommonUnity/Drawing/SegmentRenderer.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | using Cyclone.Core; 6 | 7 | namespace Common.Unity.Drawing 8 | { 9 | 10 | public enum LINE_MODE { LINES = 2, TRIANGLES = 3, TETRAHEDRON = 4 }; 11 | 12 | public class SegmentRenderer : BaseRenderer 13 | { 14 | 15 | public SegmentRenderer() 16 | { 17 | LineMode = LINE_MODE.LINES; 18 | } 19 | 20 | public SegmentRenderer(LINE_MODE lineMode, DRAW_ORIENTATION orientation) 21 | { 22 | LineMode = LINE_MODE.LINES; 23 | Orientation = DRAW_ORIENTATION.XY; 24 | } 25 | 26 | public LINE_MODE LineMode { get; set; } 27 | 28 | #region DOUBLE 29 | 30 | public void Load(IList vertices, IList indices = null) 31 | { 32 | SetIndices(vertices.Count, indices); 33 | 34 | foreach (var v in vertices) 35 | m_vertices.Add(v.ToVector4()); 36 | } 37 | 38 | public void Load(Vector3d a, Vector3d b) 39 | { 40 | SetIndices(2, null); 41 | 42 | m_vertices.Add(a.ToVector4()); 43 | m_vertices.Add(b.ToVector4()); 44 | } 45 | 46 | #endregion 47 | 48 | #region UNITY 49 | 50 | public void Load(IList vertices, IList indices = null) 51 | { 52 | SetIndices(vertices.Count, indices); 53 | 54 | foreach (var v in vertices) 55 | m_vertices.Add(v); 56 | } 57 | 58 | public void Load(IList vertices, IList indices = null) 59 | { 60 | SetIndices(vertices.Count, indices); 61 | 62 | foreach (var v in vertices) 63 | m_vertices.Add(v); 64 | } 65 | 66 | public void Load(Vector3 a, Vector3 b) 67 | { 68 | SetIndices(2, null); 69 | 70 | m_vertices.Add(a); 71 | m_vertices.Add(b); 72 | } 73 | 74 | public void Load(IList vertices, IList indices = null) 75 | { 76 | SetIndices(vertices.Count, indices); 77 | 78 | foreach (var v in vertices) 79 | m_vertices.Add(v); 80 | } 81 | 82 | public void Load(Vector2 a, Vector2 b) 83 | { 84 | SetIndices(2, null); 85 | 86 | if (Orientation == DRAW_ORIENTATION.XY) 87 | { 88 | m_vertices.Add(a); 89 | m_vertices.Add(b); 90 | } 91 | else if (Orientation == DRAW_ORIENTATION.XZ) 92 | { 93 | m_vertices.Add(new Vector4(a.x, 0, a.y, 1)); 94 | m_vertices.Add(new Vector4(b.x, 0, b.y, 1)); 95 | } 96 | } 97 | 98 | #endregion 99 | 100 | #region DRAW 101 | 102 | public override void Draw(Camera camera, Matrix4x4 localToWorld) 103 | { 104 | switch (LineMode) 105 | { 106 | case LINE_MODE.LINES: 107 | DrawVerticesAsLines(camera, localToWorld); 108 | break; 109 | 110 | case LINE_MODE.TRIANGLES: 111 | DrawVerticesAsTriangles(camera, localToWorld); 112 | break; 113 | 114 | case LINE_MODE.TETRAHEDRON: 115 | DrawVerticesAsTetrahedron(camera, localToWorld); 116 | break; 117 | } 118 | } 119 | 120 | private void DrawVerticesAsLines(Camera camera, Matrix4x4 localToWorld) 121 | { 122 | GL.PushMatrix(); 123 | 124 | GL.LoadIdentity(); 125 | GL.modelview = camera.worldToCameraMatrix * localToWorld; 126 | GL.LoadProjectionMatrix(camera.projectionMatrix); 127 | 128 | Material.SetPass(0); 129 | GL.Begin(GL.LINES); 130 | GL.Color(Color); 131 | 132 | int vertexCount = m_vertices.Count; 133 | 134 | for (int i = 0; i < m_indices.Count / 2; i++) 135 | { 136 | int i0 = m_indices[i * 2 + 0]; 137 | int i1 = m_indices[i * 2 + 1]; 138 | 139 | if (i0 < 0 || i0 >= vertexCount) continue; 140 | if (i1 < 0 || i1 >= vertexCount) continue; 141 | 142 | GL.Vertex(m_vertices[i0]); 143 | GL.Vertex(m_vertices[i1]); 144 | } 145 | 146 | GL.End(); 147 | 148 | GL.PopMatrix(); 149 | } 150 | 151 | private void DrawVerticesAsTriangles(Camera camera, Matrix4x4 localToWorld) 152 | { 153 | GL.PushMatrix(); 154 | 155 | GL.LoadIdentity(); 156 | GL.MultMatrix(camera.worldToCameraMatrix * localToWorld); 157 | GL.LoadProjectionMatrix(camera.projectionMatrix); 158 | 159 | Material.SetPass(0); 160 | GL.Begin(GL.LINES); 161 | GL.Color(Color); 162 | 163 | int vertexCount = m_vertices.Count; 164 | 165 | for (int i = 0; i < m_indices.Count / 3; i++) 166 | { 167 | int i0 = m_indices[i * 3 + 0]; 168 | int i1 = m_indices[i * 3 + 1]; 169 | int i2 = m_indices[i * 3 + 2]; 170 | 171 | if (i0 < 0 || i0 >= vertexCount) continue; 172 | if (i1 < 0 || i1 >= vertexCount) continue; 173 | if (i2 < 0 || i2 >= vertexCount) continue; 174 | 175 | GL.Vertex(m_vertices[i0]); 176 | GL.Vertex(m_vertices[i1]); 177 | 178 | GL.Vertex(m_vertices[i0]); 179 | GL.Vertex(m_vertices[i2]); 180 | 181 | GL.Vertex(m_vertices[i2]); 182 | GL.Vertex(m_vertices[i1]); 183 | } 184 | 185 | GL.End(); 186 | 187 | GL.PopMatrix(); 188 | } 189 | 190 | private void DrawVerticesAsTetrahedron(Camera camera, Matrix4x4 localToWorld) 191 | { 192 | GL.PushMatrix(); 193 | 194 | GL.LoadIdentity(); 195 | GL.MultMatrix(camera.worldToCameraMatrix * localToWorld); 196 | GL.LoadProjectionMatrix(camera.projectionMatrix); 197 | 198 | Material.SetPass(0); 199 | GL.Begin(GL.LINES); 200 | GL.Color(Color); 201 | 202 | int vertexCount = m_vertices.Count; 203 | 204 | for (int i = 0; i < m_indices.Count / 4; i++) 205 | { 206 | int i0 = m_indices[i * 4 + 0]; 207 | int i1 = m_indices[i * 4 + 1]; 208 | int i2 = m_indices[i * 4 + 2]; 209 | int i3 = m_indices[i * 4 + 3]; 210 | 211 | if (i0 < 0 || i0 >= vertexCount) continue; 212 | if (i1 < 0 || i1 >= vertexCount) continue; 213 | if (i2 < 0 || i2 >= vertexCount) continue; 214 | if (i3 < 0 || i3 >= vertexCount) continue; 215 | 216 | GL.Vertex(m_vertices[i0]); 217 | GL.Vertex(m_vertices[i1]); 218 | 219 | GL.Vertex(m_vertices[i0]); 220 | GL.Vertex(m_vertices[i2]); 221 | 222 | GL.Vertex(m_vertices[i0]); 223 | GL.Vertex(m_vertices[i3]); 224 | 225 | GL.Vertex(m_vertices[i1]); 226 | GL.Vertex(m_vertices[i2]); 227 | 228 | GL.Vertex(m_vertices[i3]); 229 | GL.Vertex(m_vertices[i2]); 230 | 231 | GL.Vertex(m_vertices[i1]); 232 | GL.Vertex(m_vertices[i3]); 233 | } 234 | 235 | GL.End(); 236 | 237 | GL.PopMatrix(); 238 | } 239 | 240 | #endregion 241 | 242 | } 243 | 244 | } -------------------------------------------------------------------------------- /Assets/Cyclone/Core/Matrix4.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Cyclone.Core 5 | { 6 | 7 | /// 8 | /// Holds a transform matrix, consisting of a rotation matrix and 9 | /// a position.The matrix has 12 elements, it is assumed that the 10 | /// remaining four are(0,0,0,1); producing a homogenous matrix. 11 | /// 12 | public struct Matrix4 13 | { 14 | 15 | public double data0, data1, data2, data3; 16 | public double data4, data5, data6, data7; 17 | public double data8, data9, data10, data11; 18 | 19 | 20 | /// 21 | /// Creates an identity matrix. 22 | /// 23 | static readonly public Matrix4 Identity = new Matrix4(1, 0, 0, 0, 24 | 0, 1, 0, 0, 25 | 0, 0, 1, 0); 26 | 27 | 28 | public Matrix4(double m0, double m1, double m2, double m3, 29 | double m4, double m5, double m6, double m7, 30 | double m8, double m9, double m10, double m11) 31 | { 32 | data0 = m0; data1 = m1; data2 = m2; data3 = m3; 33 | data4 = m4; data5 = m5; data6 = m6; data7 = m7; 34 | data8 = m8; data9 = m9; data10 = m10; data11 = m11; 35 | } 36 | 37 | /// 38 | /// Access the varible at index i 39 | /// 40 | unsafe public double this[int i] 41 | { 42 | get 43 | { 44 | if ((uint)i >= 12) 45 | throw new IndexOutOfRangeException("Matrix4 index out of range."); 46 | 47 | fixed (Matrix4* array = &this) { return ((double*)array)[i]; } 48 | } 49 | set 50 | { 51 | if ((uint)i >= 12) 52 | throw new IndexOutOfRangeException("Matrix4 index out of range."); 53 | 54 | fixed (double* array = &data0) { array[i] = value; } 55 | } 56 | } 57 | 58 | /// 59 | /// Returns a matrix which is this matrix multiplied by the given 60 | /// other matrix. 61 | /// 62 | public static Matrix4 operator *(Matrix4 m1, Matrix4 m2) 63 | { 64 | Matrix4 result = new Matrix4(); 65 | result.data0 = (m2.data0 * m1.data0) + (m2.data4 * m1.data1) + (m2.data8 * m1.data2); 66 | result.data4 = (m2.data0 * m1.data4) + (m2.data4 * m1.data5) + (m2.data8 * m1.data6); 67 | result.data8 = (m2.data0 * m1.data8) + (m2.data4 * m1.data9) + (m2.data8 * m1.data10); 68 | 69 | result.data1 = (m2.data1 * m1.data0) + (m2.data5 * m1.data1) + (m2.data9 * m1.data2); 70 | result.data5 = (m2.data1 * m1.data4) + (m2.data5 * m1.data5) + (m2.data9 * m1.data6); 71 | result.data9 = (m2.data1 * m1.data8) + (m2.data5 * m1.data9) + (m2.data9 * m1.data10); 72 | 73 | result.data2 = (m2.data2 * m1.data0) + (m2.data6 * m1.data1) + (m2.data10 * m1.data2); 74 | result.data6 = (m2.data2 * m1.data4) + (m2.data6 * m1.data5) + (m2.data10 * m1.data6); 75 | result.data10 = (m2.data2 * m1.data8) + (m2.data6 * m1.data9) + (m2.data10 * m1.data10); 76 | 77 | result.data3 = (m2.data3 * m1.data0) + (m2.data7 * m1.data1) + (m2.data11 * m1.data2) + m1.data3; 78 | result.data7 = (m2.data3 * m1.data4) + (m2.data7 * m1.data5) + (m2.data11 * m1.data6) + m1.data7; 79 | result.data11 = (m2.data3 * m1.data8) + (m2.data7 * m1.data9) + (m2.data11 * m1.data10) + m1.data11; 80 | 81 | return result; 82 | } 83 | 84 | /// 85 | /// Transform the given vector by this matrix. 86 | /// 87 | public static Vector3d operator *(Matrix4 m, Vector3d vector) 88 | { 89 | return new Vector3d( 90 | vector.x * m.data0 + 91 | vector.y * m.data1 + 92 | vector.z * m.data2 + m.data3, 93 | 94 | vector.x * m.data4 + 95 | vector.y * m.data5 + 96 | vector.z * m.data6 + m.data7, 97 | 98 | vector.x * m.data8 + 99 | vector.y * m.data9 + 100 | vector.z * m.data10 + m.data11 101 | ); 102 | } 103 | 104 | /// 105 | /// A matrix as a string. 106 | /// 107 | public override string ToString() 108 | { 109 | return data0 + "," + data1 + "," + data2 + "," + data3 + "\n" + 110 | data4 + "," + data5 + "," + data6 + "," + data7 + "\n" + 111 | data8 + "," + data9 + "," + data10 + "," + data11; 112 | } 113 | 114 | /// 115 | /// Sets the matrix to be a diagonal matrix with the given coefficients. 116 | /// 117 | public void SetDiagonal(double a, double b, double c) 118 | { 119 | data0 = a; 120 | data5 = b; 121 | data10 = c; 122 | } 123 | 124 | /// 125 | /// Transform the given vector by this matrix. 126 | /// 127 | public Vector3d Transform(Vector3d vector) 128 | { 129 | return this * vector; 130 | } 131 | 132 | /// 133 | /// Returns the determinant of the matrix. 134 | /// 135 | public double GetDeterminant() 136 | { 137 | return -data8 * data5 * data2 + 138 | data4 * data9 * data2 + 139 | data8 * data1 * data6 - 140 | data0 * data9 * data6 - 141 | data4 * data1 * data10 + 142 | data0 * data5 * data10; 143 | } 144 | 145 | /// 146 | /// Sets the matrix to be the inverse of the given matrix. 147 | /// 148 | public void SetInverse(Matrix4 m) 149 | { 150 | // Make sure the determinant is non-zero. 151 | double det = m.GetDeterminant(); 152 | if (det == 0) return; 153 | det = 1.0 / det; 154 | 155 | data0 = (-m.data9 * m.data6 + m.data5 * m.data10) * det; 156 | data4 = (m.data8 * m.data6 - m.data4 * m.data10) * det; 157 | data8 = (-m.data8 * m.data5 + m.data4 * m.data9) * det; 158 | 159 | data1 = (m.data9 * m.data2 - m.data1 * m.data10) * det; 160 | data5 = (-m.data8 * m.data2 + m.data0 * m.data10) * det; 161 | data9 = (m.data8 * m.data1 - m.data0 * m.data9) * det; 162 | 163 | data2 = (-m.data5 * m.data2 + m.data1 * m.data6) * det; 164 | data6 = (+m.data4 * m.data2 - m.data0 * m.data6) * det; 165 | data10 = (-m.data4 * m.data1 + m.data0 * m.data5) * det; 166 | 167 | data3 = (m.data9 * m.data6 * m.data3 168 | - m.data5 * m.data10 * m.data3 169 | - m.data9 * m.data2 * m.data7 170 | + m.data1 * m.data10 * m.data7 171 | + m.data5 * m.data2 * m.data11 172 | - m.data1 * m.data6 * m.data11) * det; 173 | data7 = (-m.data8 * m.data6 * m.data3 174 | + m.data4 * m.data10 * m.data3 175 | + m.data8 * m.data2 * m.data7 176 | - m.data0 * m.data10 * m.data7 177 | - m.data4 * m.data2 * m.data11 178 | + m.data0 * m.data6 * m.data11) * det; 179 | data11 = (m.data8 * m.data5 * m.data3 180 | - m.data4 * m.data9 * m.data3 181 | - m.data8 * m.data1 * m.data7 182 | + m.data0 * m.data9 * m.data7 183 | + m.data4 * m.data1 * m.data11 184 | - m.data0 * m.data5 * m.data11) * det; 185 | } 186 | 187 | /// 188 | /// Returns a new matrix containing the inverse of this matrix. 189 | /// 190 | public Matrix4 Inverse() 191 | { 192 | Matrix4 result = Matrix4.Identity; 193 | result.SetInverse(this); 194 | return result; 195 | } 196 | 197 | /// 198 | /// Inverts the matrix. 199 | /// 200 | public void Invert() 201 | { 202 | SetInverse(this); 203 | } 204 | 205 | /// 206 | /// Transform the given direction vector by this matrix. 207 | /// 208 | /// @note When a direction is converted between frames of 209 | /// reference, there is no translation required. 210 | /// 211 | public Vector3d TransformDirection(Vector3d vector) 212 | { 213 | return new Vector3d( 214 | vector.x * data0 + 215 | vector.y * data1 + 216 | vector.z * data2, 217 | 218 | vector.x * data4 + 219 | vector.y * data5 + 220 | vector.z * data6, 221 | 222 | vector.x * data8 + 223 | vector.y * data9 + 224 | vector.z * data10 225 | ); 226 | } 227 | 228 | /// 229 | /// Transform the given direction vector by the 230 | /// transformational inverse of this matrix. 231 | /// 232 | /// @note This function relies on the fact that the inverse of 233 | /// a pure rotation matrix is its transpose. It separates the 234 | /// translational and rotation components, transposes the 235 | /// rotation, and multiplies out. If the matrix is not a 236 | /// scale and shear free transform matrix, then this function 237 | /// will not give correct results. 238 | /// 239 | /// @note When a direction is converted between frames of 240 | /// reference, there is no translation required. 241 | /// 242 | public Vector3d TransformInverseDirection(Vector3d vector) 243 | { 244 | return new Vector3d( 245 | vector.x * data0 + 246 | vector.y * data4 + 247 | vector.z * data8, 248 | 249 | vector.x * data1 + 250 | vector.y * data5 + 251 | vector.z * data9, 252 | 253 | vector.x * data2 + 254 | vector.y * data6 + 255 | vector.z * data10 256 | ); 257 | } 258 | 259 | /// 260 | /// Transform the given vector by the transformational inverse 261 | /// of this matrix. 262 | /// 263 | /// @note This function relies on the fact that the inverse of 264 | /// a pure rotation matrix is its transpose. It separates the 265 | /// translational and rotation components, transposes the 266 | /// rotation, and multiplies out. If the matrix is not a 267 | /// scale and shear free transform matrix, then this function 268 | /// will not give correct results. 269 | /// 270 | public Vector3d TransformInverse(Vector3d vector) 271 | { 272 | Vector3d tmp = vector; 273 | tmp.x -= data3; 274 | tmp.y -= data7; 275 | tmp.z -= data11; 276 | return new Vector3d( 277 | tmp.x * data0 + 278 | tmp.y * data4 + 279 | tmp.z * data8, 280 | 281 | tmp.x * data1 + 282 | tmp.y * data5 + 283 | tmp.z * data9, 284 | 285 | tmp.x * data2 + 286 | tmp.y * data6 + 287 | tmp.z * data10 288 | ); 289 | } 290 | 291 | /// 292 | /// Gets a vector representing one axis (i.e. one column) in the matrix. 293 | /// 294 | /// The row to return. Row 3 corresponds 295 | /// to the position of the transform matrix. 296 | /// 297 | public Vector3d GetAxisVector(int i) 298 | { 299 | return new Vector3d(this[i], this[i + 4], this[i + 8]); 300 | } 301 | 302 | /** 303 | * Sets this matrix to be the rotation matrix corresponding to 304 | * the given quaternion. 305 | */ 306 | public void SetOrientationAndPos(Quaternion q, Vector3d pos) 307 | { 308 | data0 = 1 - (2 * q.j * q.j + 2 * q.k * q.k); 309 | data1 = 2 * q.i * q.j + 2 * q.k * q.r; 310 | data2 = 2 * q.i * q.k - 2 * q.j * q.r; 311 | data3 = pos.x; 312 | 313 | data4 = 2 * q.i * q.j - 2 * q.k * q.r; 314 | data5 = 1 - (2 * q.i * q.i + 2 * q.k * q.k); 315 | data6 = 2 * q.j * q.k + 2 * q.i * q.r; 316 | data7 = pos.y; 317 | 318 | data8 = 2 * q.i * q.k + 2 * q.j * q.r; 319 | data9 = 2 * q.j * q.k - 2 * q.i * q.r; 320 | data10 = 1 - (2 * q.i * q.i + 2 * q.j * q.j); 321 | data11 = pos.z; 322 | } 323 | 324 | } 325 | 326 | } -------------------------------------------------------------------------------- /Assets/Cyclone/Core/Matrix3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Cyclone.Core 5 | { 6 | 7 | /// 8 | /// Holds an inertia tensor, consisting of a 3x3 row-major matrix. 9 | /// This matrix is not padding to produce an aligned structure, since 10 | /// it is most commonly used with a mass(single double) and two 11 | /// damping coefficients to make the 12-element characteristics array 12 | /// of a rigid body. 13 | /// 14 | public struct Matrix3 15 | { 16 | public double data0, data1, data2; 17 | public double data3, data4, data5; 18 | public double data6, data7, data8; 19 | 20 | /// 21 | /// Creates an identity matrix. 22 | /// 23 | static readonly public Matrix3 Identity = new Matrix3(1, 0, 0, 24 | 0, 1, 0, 25 | 0, 0, 1); 26 | 27 | 28 | public Matrix3(double m0, double m1, double m2, 29 | double m3, double m4, double m5, 30 | double m6, double m7, double m8) 31 | { 32 | data0 = m0; data1 = m1; data2 = m2; 33 | data3 = m3; data4 = m4; data5 = m5; 34 | data6 = m6; data7 = m7; data8 = m8; 35 | } 36 | 37 | /// 38 | /// Creates a new matrix with the given three vectors making 39 | /// up its columns. 40 | /// 41 | public Matrix3(Vector3d compOne, Vector3d compTwo, Vector3d compThree) 42 | { 43 | data0 = compOne.x; data1 = compTwo.x; data2 = compThree.x; 44 | data3 = compOne.y; data4 = compTwo.y; data5 = compThree.y; 45 | data6 = compOne.z; data7 = compTwo.z; data8 = compThree.z; 46 | } 47 | 48 | /// 49 | /// Access the varible at index i 50 | /// 51 | unsafe public double this[int i] 52 | { 53 | get 54 | { 55 | if ((uint)i >= 9) 56 | throw new IndexOutOfRangeException("Matrix3 index out of range."); 57 | 58 | fixed (Matrix3* array = &this) { return ((double*)array)[i]; } 59 | } 60 | set 61 | { 62 | if ((uint)i >= 9) 63 | throw new IndexOutOfRangeException("Matrix3 index out of range."); 64 | 65 | fixed (double* array = &data0) { array[i] = value; } 66 | } 67 | } 68 | 69 | /// 70 | /// Transform the given vector by this matrix. 71 | /// 72 | public static Vector3d operator *(Matrix3 m, Vector3d vector) 73 | { 74 | return new Vector3d( 75 | vector.x * m.data0 + vector.y * m.data1 + vector.z * m.data2, 76 | vector.x * m.data3 + vector.y * m.data4 + vector.z * m.data5, 77 | vector.x * m.data6 + vector.y * m.data7 + vector.z * m.data8 78 | ); 79 | } 80 | 81 | /// 82 | /// Returns a matrix which is this matrix multiplied by the given 83 | /// other matrix. 84 | /// 85 | public static Matrix3 operator *(Matrix3 m1, Matrix3 m2) 86 | { 87 | return new Matrix3( 88 | m1.data0 * m2.data0 + m1.data1 * m2.data3 + m1.data2 * m2.data6, 89 | m1.data0 * m2.data1 + m1.data1 * m2.data4 + m1.data2 * m2.data7, 90 | m1.data0 * m2.data2 + m1.data1 * m2.data5 + m1.data2 * m2.data8, 91 | 92 | m1.data3 * m2.data0 + m1.data4 * m2.data3 + m1.data5 * m2.data6, 93 | m1.data3 * m2.data1 + m1.data4 * m2.data4 + m1.data5 * m2.data7, 94 | m1.data3 * m2.data2 + m1.data4 * m2.data5 + m1.data5 * m2.data8, 95 | 96 | m1.data6 * m2.data0 + m1.data7 * m2.data3 + m1.data8 * m2.data6, 97 | m1.data6 * m2.data1 + m1.data7 * m2.data4 + m1.data8 * m2.data7, 98 | m1.data6 * m2.data2 + m1.data7 * m2.data5 + m1.data8 * m2.data8 99 | ); 100 | } 101 | 102 | /// 103 | /// Multiplies this matrix in place by the given scalar. 104 | /// 105 | public static Matrix3 operator *(Matrix3 m1, double scalar) 106 | { 107 | return new Matrix3( 108 | m1.data0 * scalar, m1.data1 * scalar, m1.data2 * scalar, 109 | m1.data3 * scalar, m1.data4 * scalar, m1.data5 * scalar, 110 | m1.data6 * scalar, m1.data7 * scalar, m1.data8 * scalar); 111 | } 112 | 113 | /// 114 | /// Do a component-wise addition of this matrix and the given 115 | /// matrix. 116 | /// 117 | public static Matrix3 operator +(Matrix3 m1, Matrix3 m2) 118 | { 119 | return new Matrix3( 120 | m1.data0 + m2.data0, m1.data1 + m2.data1, m1.data2 + m2.data2, 121 | m1.data3 + m2.data3, m1.data4 + m2.data4, m1.data5 + m2.data5, 122 | m1.data6 + m2.data6, m1.data7 + m2.data7, m1.data8 + m2.data8); 123 | } 124 | 125 | /// 126 | /// Do a component-wise subtraction of this matrix and the given 127 | /// matrix. 128 | /// 129 | public static Matrix3 operator -(Matrix3 m1, Matrix3 m2) 130 | { 131 | return new Matrix3( 132 | m1.data0 - m2.data0, m1.data1 - m2.data1, m1.data2 - m2.data2, 133 | m1.data3 - m2.data3, m1.data4 - m2.data4, m1.data5 - m2.data5, 134 | m1.data6 - m2.data6, m1.data7 - m2.data7, m1.data8 - m2.data8); 135 | } 136 | 137 | /// 138 | /// A matrix as a string. 139 | /// 140 | public override string ToString() 141 | { 142 | return data0 + "," + data1 + "," + data2 + "\n" + 143 | data3 + "," + data4 + "," + data5 + "\n" + 144 | data6 + "," + data7 + "," + data8; 145 | } 146 | 147 | /// 148 | /// Sets the value of the matrix from inertia tensor values. 149 | /// 150 | public void SetInertiaTensorCoeffs(double ix, double iy, double iz, double ixy = 0, double ixz = 0, double iyz = 0) 151 | { 152 | data0 = ix; 153 | data1 = data3 = -ixy; 154 | data2 = data6 = -ixz; 155 | data4 = iy; 156 | data5 = data7 = -iyz; 157 | data8 = iz; 158 | } 159 | 160 | /// 161 | /// Sets the value of the matrix as an inertia tensor of 162 | /// a rectangular block aligned with the body's coordinate 163 | /// system with the given axis half-sizes and mass. 164 | /// 165 | public void SetBlockInertiaTensor(Vector3d halfSizes, double mass) 166 | { 167 | Vector3d squares = halfSizes * halfSizes; 168 | SetInertiaTensorCoeffs(0.3 * mass * (squares.y + squares.z), 0.3 * mass * (squares.x + squares.z), 0.3 * mass * (squares.x + squares.y)); 169 | } 170 | 171 | /// 172 | /// Sets the matrix to be a skew symmetric matrix based on 173 | /// the given vector.The skew symmetric matrix is the equivalent 174 | /// of the vector product.So if a, b are vectors.a x b = A_s b 175 | /// where A_s is the skew symmetric form of a. 176 | /// 177 | public void SetSkewSymmetric(Vector3d vector) 178 | { 179 | data0 = data4 = data8 = 0; 180 | data1 = -vector.z; 181 | data2 = vector.y; 182 | data3 = vector.z; 183 | data5 = -vector.x; 184 | data6 = -vector.y; 185 | data7 = vector.x; 186 | } 187 | 188 | /// 189 | /// Sets the matrix values from the given three vector components. 190 | /// These are arranged as the three columns of the vector. 191 | /// 192 | public void SetComponents(Vector3d compOne, Vector3d compTwo, Vector3d compThree) 193 | { 194 | data0 = compOne.x; data1 = compTwo.x; data2 = compThree.x; 195 | data3 = compOne.y; data4 = compTwo.y; data5 = compThree.y; 196 | data6 = compOne.z; data7 = compTwo.z; data8 = compThree.z; 197 | } 198 | 199 | /// 200 | /// Transform the given vector by this matrix. 201 | /// 202 | public Vector3d Transform(Vector3d vector) 203 | { 204 | return this * vector; 205 | } 206 | 207 | /// 208 | /// Transform the given vector by the transpose of this matrix. 209 | /// 210 | public Vector3d TransformTranspose(Vector3d vector) 211 | { 212 | return new Vector3d( 213 | vector.x * data0 + vector.y * data3 + vector.z * data6, 214 | vector.x * data1 + vector.y * data4 + vector.z * data7, 215 | vector.x * data2 + vector.y * data5 + vector.z * data8 216 | ); 217 | } 218 | 219 | /// 220 | /// Gets a vector representing one row in the matrix. 221 | /// 222 | /// The row to return. 223 | public Vector3d GetRowVector(int i) 224 | { 225 | return new Vector3d(this[i * 3], this[i * 3 + 1], this[i * 3 + 2]); 226 | } 227 | 228 | /// 229 | /// Gets a vector representing one axis (i.e. one column) in the matrix. 230 | /// 231 | /// The row to return. 232 | public Vector3d GetAxisVector(int i) 233 | { 234 | return new Vector3d(this[i], this[i + 3], this[i + 6]); 235 | } 236 | 237 | /// 238 | /// Sets the matrix to be the inverse of the given matrix. 239 | /// 240 | public void SetInverse(Matrix3 m) 241 | { 242 | double t4 = m.data0 * m.data4; 243 | double t6 = m.data0 * m.data5; 244 | double t8 = m.data1 * m.data3; 245 | double t10 = m.data2 * m.data3; 246 | double t12 = m.data1 * m.data6; 247 | double t14 = m.data2 * m.data6; 248 | 249 | // Calculate the determinant 250 | double t16 = (t4 * m.data8 - t6 * m.data7 - t8 * m.data8 + 251 | t10 * m.data7 + t12 * m.data5 - t14 * m.data4); 252 | 253 | // Make sure the determinant is non-zero. 254 | if (t16 == 0.0) return; 255 | double t17 = 1 / t16; 256 | 257 | data0 = (m.data4 * m.data8 - m.data5 * m.data7) * t17; 258 | data1 = -(m.data1 * m.data8 - m.data2 * m.data7) * t17; 259 | data2 = (m.data1 * m.data5 - m.data2 * m.data4) * t17; 260 | data3 = -(m.data3 * m.data8 - m.data5 * m.data6) * t17; 261 | data4 = (m.data0 * m.data8 - t14) * t17; 262 | data5 = -(t6 - t10) * t17; 263 | data6 = (m.data3 * m.data7 - m.data4 * m.data6) * t17; 264 | data7 = -(m.data0 * m.data7 - t12) * t17; 265 | data8 = (t4 - t8) * t17; 266 | } 267 | 268 | /// 269 | /// Returns a new matrix containing the inverse of this matrix. 270 | /// 271 | public Matrix3 Inverse() 272 | { 273 | Matrix3 result = Identity; 274 | result.SetInverse(this); 275 | return result; 276 | } 277 | 278 | /// 279 | /// Inverts the matrix. 280 | /// 281 | public void Invert() 282 | { 283 | SetInverse(this); 284 | } 285 | 286 | /// 287 | /// Sets the matrix to be the transpose of the given matrix. 288 | /// 289 | public void SetTranspose(Matrix3 m) 290 | { 291 | data0 = m.data0; 292 | data1 = m.data3; 293 | data2 = m.data6; 294 | data3 = m.data1; 295 | data4 = m.data4; 296 | data5 = m.data7; 297 | data6 = m.data2; 298 | data7 = m.data5; 299 | data8 = m.data8; 300 | } 301 | 302 | /// 303 | /// Returns a new matrix containing the transpose of this matrix. 304 | /// 305 | public Matrix3 Transpose() 306 | { 307 | Matrix3 result = Identity; 308 | result.SetTranspose(this); 309 | return result; 310 | } 311 | 312 | /// 313 | /// Sets this matrix to be the rotation matrix corresponding to 314 | /// the given quaternion. 315 | /// 316 | public void SetOrientation(Quaternion q) 317 | { 318 | data0 = 1 - (2 * q.j * q.j + 2 * q.k * q.k); 319 | data1 = 2 * q.i * q.j + 2 * q.k * q.r; 320 | data2 = 2 * q.i * q.k - 2 * q.j * q.r; 321 | data3 = 2 * q.i * q.j - 2 * q.k * q.r; 322 | data4 = 1 - (2 * q.i * q.i + 2 * q.k * q.k); 323 | data5 = 2 * q.j * q.k + 2 * q.i * q.r; 324 | data6 = 2 * q.i * q.k + 2 * q.j * q.r; 325 | data7 = 2 * q.j * q.k - 2 * q.i * q.r; 326 | data8 = 1 - (2 * q.i * q.i + 2 * q.j * q.j); 327 | } 328 | 329 | /// 330 | /// Interpolates a couple of matrices. 331 | /// 332 | public static Matrix3 LinearInterpolate(Matrix3 a, Matrix3 b, double prop) 333 | { 334 | Matrix3 result = new Matrix3(); 335 | for (int i = 0; i < 9; i++) 336 | result[i] = a[i] * (1 - prop) + b[i] * prop; 337 | 338 | return result; 339 | } 340 | } 341 | 342 | } -------------------------------------------------------------------------------- /Assets/Cyclone/Rigid/Constraints/RigidContactResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | using Cyclone.Core; 5 | 6 | namespace Cyclone.Rigid.Constraints 7 | { 8 | 9 | /// 10 | /// The contact resolution routine. One resolver instance 11 | /// can be shared for the whole simulation, as long as you need 12 | /// roughly the same parameters each time (which is normal). 13 | /// 14 | /// @section algorithm Resolution Algorithm 15 | /// 16 | /// The resolver uses an iterative satisfaction algorithm; it loops 17 | /// through each contact and tries to resolve it. Each contact is 18 | /// resolved locally, which may in turn put other contacts in a worse 19 | /// position. The algorithm then revisits other contacts and repeats 20 | /// the process up to a specified iteration limit. It can be proved 21 | /// that given enough iterations, the simulation will get to the 22 | /// correct result. As with all approaches, numerical stability can 23 | /// cause problems that make a correct resolution impossible. 24 | /// 25 | /// @subsection strengths Strengths 26 | /// 27 | /// This algorithm is very fast, much faster than other physics 28 | /// approaches. Even using many more iterations than there are 29 | /// contacts, it will be faster than global approaches. 30 | /// 31 | /// Many global algorithms are unstable under high friction, this 32 | /// approach is very robust indeed for high friction and low 33 | /// restitution values. 34 | /// 35 | /// The algorithm produces visually believable behaviour. Tradeoffs 36 | /// have been made to err on the side of visual realism rather than 37 | /// computational expense or numerical accuracy. 38 | /// 39 | /// @subsection weaknesses Weaknesses 40 | /// 41 | /// The algorithm does not cope well with situations with many 42 | /// inter-related contacts: stacked boxes, for example. In this 43 | /// case the simulation may appear to jiggle slightly, which often 44 | /// dislodges a box from the stack, allowing it to collapse. 45 | /// 46 | /// Another issue with the resolution mechanism is that resolving 47 | /// one contact may make another contact move sideways against 48 | /// friction, because each contact is handled independently, this 49 | /// friction is not taken into account. If one object is pushing 50 | /// against another, the pushed object may move across its support 51 | /// without friction, even though friction is set between those bodies. 52 | /// 53 | /// In general this resolver is not suitable for stacks of bodies, 54 | /// but is perfect for handling impact, explosive, and flat resting 55 | /// situations. 56 | /// 57 | public class RigidContactResolver 58 | { 59 | 60 | /// 61 | /// Holds the number of iterations to perform when resolving 62 | /// velocity. 63 | /// 64 | public int VelocityIterations; 65 | 66 | /// 67 | /// Holds the number of iterations to perform when resolving 68 | /// position. 69 | /// 70 | public int PositionIterations; 71 | 72 | /// 73 | /// To avoid instability velocities smaller 74 | /// than this value are considered to be zero. Too small and the 75 | /// simulation may be unstable, too large and the bodies may 76 | /// interpenetrate visually. A good starting point is the default 77 | /// of 0.01. 78 | /// 79 | public double VelocityEpsilon; 80 | 81 | /// 82 | /// To avoid instability penetrations 83 | /// smaller than this value are considered to be not interpenetrating. 84 | /// Too small and the simulation may be unstable, too large and the 85 | /// bodies may interpenetrate visually. A good starting point is 86 | /// the default of 0.01. 87 | /// 88 | public double PositionEpsilon; 89 | 90 | /// 91 | /// Stores the number of velocity iterations used in the 92 | /// last call to resolve contacts. 93 | /// 94 | public int VelocityIterationsUsed; 95 | 96 | /// 97 | /// Stores the number of position iterations used in the 98 | /// last call to resolve contacts. 99 | /// 100 | public int PositionIterationsUsed; 101 | 102 | /// 103 | /// Creates a new contact resolver. 104 | /// 105 | public RigidContactResolver(int iterations = 0) 106 | { 107 | VelocityIterations = iterations; 108 | PositionIterations = iterations; 109 | VelocityEpsilon = 0.001; 110 | PositionEpsilon = 0.001; 111 | } 112 | 113 | /// 114 | /// Resolves a set of contacts for both penetration and velocity. 115 | /// 116 | /// Contacts that cannot interact with 117 | /// each other should be passed to separate calls to resolveContacts, 118 | /// as the resolution algorithm takes much longer for lots of 119 | /// contacts than it does for the same number of contacts in small 120 | /// sets. 121 | /// 122 | /// @param contactArray Pointer to an array of contact objects. 123 | /// 124 | /// @param numContacts The number of contacts in the array to resolve. 125 | /// 126 | /// @param numIterations The number of iterations through the 127 | /// resolution algorithm. This should be at least the number of 128 | /// contacts (otherwise some constraints will not be resolved - 129 | /// although sometimes this is not noticable). If the iterations are 130 | /// not needed they will not be used, so adding more iterations may 131 | /// not make any difference. In some cases you would need millions 132 | /// of iterations. Think about the number of iterations as a bound: 133 | /// if you specify a large number, sometimes the algorithm WILL use 134 | /// it, and you may drop lots of frames. 135 | /// 136 | /// @param dt The duration of the previous integration step. 137 | /// This is used to compensate for forces applied. 138 | /// 139 | public void ResolveContacts(IList contacts, int numContacts, double dt) 140 | { 141 | // Make sure we have something to do. 142 | if (numContacts == 0) return; 143 | 144 | if (VelocityIterations <= 0) 145 | VelocityIterations = numContacts * 4; 146 | 147 | if(PositionIterations <= 0) 148 | PositionIterations = numContacts * 4; 149 | 150 | // Prepare the contacts for processing 151 | PrepareContacts(contacts, numContacts, dt); 152 | 153 | // Resolve the interpenetration problems with the contacts. 154 | AdjustPositions(contacts, numContacts, dt); 155 | 156 | // Resolve the velocity problems with the contacts. 157 | AdjustVelocities(contacts, numContacts, dt); 158 | } 159 | 160 | /// 161 | /// Sets up contacts ready for processing. This makes sure their 162 | /// internal data is configured correctly and the correct set of bodies 163 | /// is made alive. 164 | /// 165 | public void PrepareContacts(IList contacts, int numContacts, double dt) 166 | { 167 | // Generate contact velocity and axis information. 168 | for (int i = 0; i < numContacts; i++) 169 | { 170 | // Calculate the internal contact data (inertia, basis, etc). 171 | contacts[i].CalculateInternals(dt); 172 | } 173 | } 174 | 175 | /// 176 | /// Resolves the velocity issues with the given array of constraints, 177 | /// using the given number of iterations. 178 | /// 179 | public void AdjustVelocities(IList contacts, int numContacts, double dt) 180 | { 181 | var c = contacts; 182 | Vector3d[] velocityChange = new Vector3d[2]; 183 | Vector3d[] rotationChange = new Vector3d[2]; 184 | Vector3d deltaVel; 185 | 186 | // iteratively handle impacts in order of severity. 187 | VelocityIterationsUsed = 0; 188 | while (VelocityIterationsUsed < VelocityIterations) 189 | { 190 | // Find contact with maximum magnitude of probable velocity change. 191 | double max = VelocityEpsilon; 192 | int index = numContacts; 193 | for (int i = 0; i < numContacts; i++) 194 | { 195 | if (c[i].DesiredDeltaVelocity > max) 196 | { 197 | max = c[i].DesiredDeltaVelocity; 198 | index = i; 199 | } 200 | } 201 | 202 | if (index == numContacts) break; 203 | 204 | // Match the awake state at the contact 205 | c[index].MatchAwakeState(); 206 | 207 | // Do the resolution on the contact that came out top. 208 | c[index].ApplyVelocityChange(velocityChange, rotationChange); 209 | 210 | // With the change in velocity of the two bodies, the update of 211 | // contact velocities means that some of the relative closing 212 | // velocities need recomputing. 213 | for (int i = 0; i < numContacts; i++) 214 | { 215 | // Check each body in the contact 216 | for (int b = 0; b < 2; b++) 217 | { 218 | if (c[i].Body[b] == null) continue; 219 | 220 | // Check for a match with each body in the newly 221 | // resolved contact 222 | for (int d = 0; d < 2; d++) 223 | { 224 | if (c[i].Body[b] == c[index].Body[d]) 225 | { 226 | deltaVel = velocityChange[d] + Vector3d.Cross(rotationChange[d], c[i].RelativeContactPosition[b]); 227 | 228 | // The sign of the change is negative if we're dealing 229 | // with the second body in a contact. 230 | c[i].ContactVelocity += c[i].ContactToWorld.TransformTranspose(deltaVel) * (b != 0 ? -1 : 1); 231 | c[i].CalculateDesiredDeltaVelocity(dt); 232 | } 233 | } 234 | } 235 | } 236 | 237 | VelocityIterationsUsed++; 238 | } 239 | } 240 | 241 | /// 242 | /// Resolves the positional issues with the given array of constraints, 243 | /// using the given number of iterations. 244 | /// 245 | public void AdjustPositions(IList contacts, int numContacts, double dt) 246 | { 247 | var c = contacts; 248 | int i, index; 249 | Vector3d[] linearChange = new Vector3d[2]; 250 | 251 | Vector3d[] angularChange = new Vector3d[2]; 252 | double max; 253 | Vector3d deltaPosition; 254 | 255 | // iteratively resolve interpenetrations in order of severity. 256 | PositionIterationsUsed = 0; 257 | while (PositionIterationsUsed < PositionIterations) 258 | { 259 | // Find biggest penetration 260 | max = PositionEpsilon; 261 | index = numContacts; 262 | for (i = 0; i < numContacts; i++) 263 | { 264 | if (c[i].Penetration > max) 265 | { 266 | max = c[i].Penetration; 267 | index = i; 268 | } 269 | } 270 | 271 | if (index == numContacts) break; 272 | 273 | // Match the awake state at the contact 274 | c[index].MatchAwakeState(); 275 | 276 | // Resolve the penetration. 277 | c[index].ApplyPositionChange(linearChange, angularChange, max); 278 | 279 | // Again this action may have changed the penetration of other 280 | // bodies, so we update contacts. 281 | for (i = 0; i < numContacts; i++) 282 | { 283 | // Check each body in the contact 284 | for (int b = 0; b < 2; b++) 285 | { 286 | 287 | if (c[i].Body[b] == null) continue; 288 | 289 | // Check for a match with each body in the newly 290 | // resolved contact 291 | for (int d = 0; d < 2; d++) 292 | { 293 | if (c[i].Body[b] == c[index].Body[d]) 294 | { 295 | deltaPosition = linearChange[d] + Vector3d.Cross(angularChange[d], c[i].RelativeContactPosition[b]); 296 | 297 | // The sign of the change is positive if we're 298 | // dealing with the second body in a contact 299 | // and negative otherwise (because we're 300 | // subtracting the resolution).. 301 | c[i].Penetration += Vector3d.Dot(deltaPosition, c[i].ContactNormal) * (b != 0 ? 1 : -1); 302 | } 303 | } 304 | } 305 | } 306 | 307 | PositionIterationsUsed++; 308 | } 309 | } 310 | 311 | } 312 | 313 | } 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | --------------------------------------------------------------------------------