├── .gitignore ├── Assets ├── Physics.meta └── Physics │ ├── Color.cginc │ ├── Color.cginc.meta │ ├── DarkMaterial.mat │ ├── DarkMaterial.mat.meta │ ├── GPUPhysics.cs │ ├── GPUPhysics.cs.meta │ ├── GPUPhysicsComputeShader.compute │ ├── GPUPhysicsComputeShader.compute.meta │ ├── InstancedIndirectMaterial.mat │ ├── InstancedIndirectMaterial.mat.meta │ ├── InstancedIndirectSurfaceShader.shader │ ├── InstancedIndirectSurfaceShader.shader.meta │ ├── InstancedIndirectSurfaceShaderNoRotation.shader │ ├── InstancedIndirectSurfaceShaderNoRotation.shader.meta │ ├── Math.cginc │ ├── Math.cginc.meta │ ├── Particle.mat │ ├── Particle.mat.meta │ ├── ParticleForceLineMaterial.mat │ ├── ParticleForceLineMaterial.mat.meta │ ├── ParticleForceLineShader.shader │ ├── ParticleForceLineShader.shader.meta │ ├── PrimitiveMeshFactory.cs │ ├── PrimitiveMeshFactory.cs.meta │ ├── Quaternion.cginc │ ├── Quaternion.cginc.meta │ ├── RailgunBasicShader.shader │ ├── RailgunBasicShader.shader.meta │ ├── SlowMotion.prefab │ ├── SlowMotion.prefab.meta │ ├── StressTest.prefab │ ├── StressTest.prefab.meta │ ├── TangentialForceTest.cs │ ├── TangentialForceTest.cs.meta │ ├── TangentialTest.meta │ ├── TangentialTest │ ├── Black.mat │ ├── Black.mat.meta │ ├── Blue.mat │ ├── Blue.mat.meta │ ├── Green.mat │ ├── Green.mat.meta │ ├── Red.mat │ ├── Red.mat.meta │ ├── TangentialTest.unity │ ├── TangentialTest.unity.meta │ ├── Transparent.mat │ ├── Transparent.mat.meta │ ├── Yellow.mat │ └── Yellow.mat.meta │ ├── TowerFall.prefab │ ├── TowerFall.prefab.meta │ ├── Vector.cginc │ ├── Vector.cginc.meta │ ├── physics.unity │ └── physics.unity.meta ├── Packages └── manifest.json ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── NetworkManager.asset ├── Physics2DSettings.asset ├── PresetManager.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset └── UnityConnectSettings.asset ├── README.md └── gpuphysics.sln /.gitignore: -------------------------------------------------------------------------------- 1 | /[Ll]ibrary/ 2 | /[Tt]emp/ 3 | /[Oo]bj/ 4 | /[Bb]uild/ 5 | /[Bb]uilds/ 6 | /Assets/AssetStoreTools* 7 | 8 | # Visual Studio 2015 cache directory 9 | /.vs/ 10 | .vscode/ 11 | *.sublime-project 12 | *.sublime-workspace 13 | 14 | # Autogenerated VS/MD/Consulo solution and project files 15 | ExportedObj/ 16 | .consulo/ 17 | *.csproj 18 | *.unityproj 19 | *.sln 20 | *.suo 21 | *.tmp 22 | *.user 23 | *.userprefs 24 | *.pidb 25 | *.booproj 26 | *.svd 27 | *.pdb 28 | 29 | # Unity3D generated meta files 30 | *.pidb.meta 31 | 32 | # Unity3D Generated File On Crash Reports 33 | sysinfo.txt 34 | 35 | # Builds 36 | *.apk 37 | *.unitypackage 38 | 39 | -------------------------------------------------------------------------------- /Assets/Physics.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d8d34beae3ac546bb8bd9995da57a4df 3 | folderAsset: yes 4 | timeCreated: 1483657466 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/Color.cginc: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* 3 | Project - Unity CJ Lib 4 | https://github.com/TheAllenChou/unity-cj-lib 5 | 6 | Author - Ming-Lun "Allen" Chou 7 | Web - http://AllenChou.net 8 | Twitter - @TheAllenChou 9 | */ 10 | /******************************************************************************/ 11 | 12 | #ifndef CJ_LIB_COLOR 13 | #define CJ_LIB_COLOR 14 | 15 | float3 hsv2rgb(float3 hsv) 16 | { 17 | hsv.x = hsv.x - floor(hsv.x); 18 | int h = ((int) (hsv.x * 6)); 19 | float f = hsv.x * 6.0 - h; 20 | float p = hsv.z * (1.0 - hsv.y); 21 | float q = hsv.z * (1.0 - f * hsv.y); 22 | float t = hsv.z * (1.0 - (1.0 - f) * hsv.y); 23 | 24 | switch (h) 25 | { 26 | default: 27 | case 0: return float3(hsv.z, t, p); 28 | case 1: return float3(q, hsv.z, p); 29 | case 2: return float3(p, hsv.z, t); 30 | case 3: return float3(p, q, hsv.z); 31 | case 4: return float3(t, p, hsv.z); 32 | case 5: return float3(hsv.z, p, q); 33 | } 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /Assets/Physics/Color.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d29168bdf7611fb43ae31c32f099264e 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/DarkMaterial.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/DarkMaterial.mat -------------------------------------------------------------------------------- /Assets/Physics/DarkMaterial.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 81d044cc442e8b240a461387ec2571e1 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/GPUPhysics.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.Rendering; 5 | 6 | public class GPUPhysics : MonoBehaviour { 7 | 8 | public bool m_debugWireframe; 9 | private bool m_lastDebugWireframe; 10 | // set from editor 11 | public ComputeShader m_computeShader; 12 | public Mesh cubeMesh { 13 | get { 14 | return m_debugWireframe ? CjLib.PrimitiveMeshFactory.BoxWireframe() : CjLib.PrimitiveMeshFactory.BoxFlatShaded(); 15 | } 16 | } 17 | public Mesh sphereMesh { 18 | get { 19 | return CjLib.PrimitiveMeshFactory.SphereWireframe(6, 6); 20 | } 21 | } 22 | public Mesh lineMesh { 23 | get { 24 | return CjLib.PrimitiveMeshFactory.Line(Vector3.zero, new Vector3(1.0f, 1.0f, 1.0f)); 25 | } 26 | } 27 | public Rigidbody[] comparisonCubes; 28 | public Material cubeMaterial; 29 | public Material sphereMaterial; 30 | public Material lineMaterial; 31 | public Material lineAngularMaterial; 32 | public Bounds m_bounds; 33 | public float m_cubeMass; 34 | public float scale; 35 | public int particlesPerEdge; 36 | public float springCoefficient; 37 | public float dampingCoefficient; 38 | public float tangentialCoefficient; 39 | public float gravityCoefficient; 40 | public float frictionCoefficient; 41 | public float angularFrictionCoefficient; 42 | public float angularForceScalar; 43 | public float linearForceScalar; 44 | public int x = 10; 45 | public int y = 20; 46 | public int z = 5; 47 | public int debug_particle_id_count; 48 | public int gridX; 49 | public int gridY; 50 | public int gridZ; 51 | public float dt; 52 | public float tick_rate; 53 | private float ticker; 54 | 55 | public Vector3 m_firstCubeLocation; // eg 56 | public Vector3 m_firstCubeVelocity; 57 | public Vector3 m_firstCubeRotation; 58 | // debug 59 | public bool m_debugRender; 60 | 61 | // calculated 62 | private int total; 63 | private Vector3 m_cubeScale; 64 | private Matrix4x4[] m_matrices; 65 | 66 | // data 67 | private ComputeBuffer m_rigidBodyPositions; // float3 68 | private ComputeBuffer m_previousRigidBodyPositions; // float3 69 | private ComputeBuffer m_rigidBodyQuaternions; // float4 70 | private ComputeBuffer m_previousRigidBodyQuaternions; // float4 71 | private ComputeBuffer m_rigidBodyAngularVelocities; // float3 72 | private ComputeBuffer m_rigidBodyVelocities; // float3 73 | private ComputeBuffer m_rigidBodyInertialTensors; // Matrix4x4 74 | private ComputeBuffer m_particleInitialRelativePositions; // float3 75 | private ComputeBuffer m_particlePositions; // float3 76 | private ComputeBuffer m_particleRelativePositions; // float3 77 | private ComputeBuffer m_particleVelocities; // float3 78 | private ComputeBuffer m_particleForces; // float3 79 | 80 | 81 | 82 | private ComputeBuffer m_debugParticleIds; // int 83 | private ComputeBuffer m_debugParticleVoxelPositions; // int3 // the per particle grid locations 84 | private ComputeBuffer m_voxelCollisionGrid; // int4 85 | 86 | private CommandBuffer m_commandBuffer; 87 | 88 | 89 | public Vector3[] positionArray; // cpu->matrix 90 | public Quaternion[] quaternionArray; // cpu->matrix 91 | public Vector3[] particleForcesArray; 92 | public Vector3[] particleVelocities; 93 | public Vector3[] rigidBodyVelocitiesArray; 94 | public Vector3[] particlePositions; 95 | public Vector3[] particleRelativePositions; 96 | public Vector3[] particleInitialRelativePositions; 97 | public float[] rigidBodyInertialTensors; 98 | 99 | public int[] voxelGridArray; 100 | public int[] particleVoxelPositionsArray; 101 | public int[] debugParticleIds; 102 | private int m_kernel_generateParticleValues; 103 | private int m_kernel_clearGrid; 104 | private int m_kernel_populateGrid; 105 | private int m_kernel_collisionDetection; 106 | private int m_kernel_computeMomenta; 107 | private int m_kernel_computePositionAndRotation; 108 | private int m_kernelSavePreviousPositionAndRotation; 109 | 110 | private int m_threadGroupsPerRigidBody; 111 | private int m_threadGroupsPerParticle; 112 | private int m_threadGroupsPerGridCell; 113 | private int m_deltaTimeShaderProperty; 114 | 115 | public Quaternion m_rigidBodyQuaternion; 116 | public Quaternion m_comparisonQuaternion; 117 | public Vector3 gridStartPosition; 118 | 119 | public float m_maximumVelocity; 120 | private ComputeBuffer m_bufferWithArgs; 121 | private ComputeBuffer m_bufferWithSphereArgs; 122 | private ComputeBuffer m_bufferWithLineArgs; 123 | private int frameCounter; 124 | void Start() { 125 | Application.targetFrameRate = 300; 126 | // Create initial positions 127 | total = x * y * z; 128 | m_matrices = new Matrix4x4[total]; 129 | positionArray = new Vector3[total]; 130 | quaternionArray = new Quaternion[total]; 131 | rigidBodyVelocitiesArray = new Vector3[total]; 132 | m_cubeScale = new Vector3(scale, scale, scale); 133 | m_deltaTimeShaderProperty = Shader.PropertyToID("deltaTime"); 134 | rigidBodyInertialTensors = new float[total*9]; 135 | 136 | int particlesPerEdgeMinusOne = particlesPerEdge-2; 137 | int particlesPerBody = particlesPerEdge * particlesPerEdge * particlesPerEdge - particlesPerEdgeMinusOne*particlesPerEdgeMinusOne*particlesPerEdgeMinusOne; 138 | int n_particles = particlesPerBody * total; 139 | int numGridCells = gridX * gridY * gridZ; 140 | float particleDiameter = scale / particlesPerEdge; 141 | particleForcesArray = new Vector3[n_particles]; 142 | 143 | for (int i = 0; i < x; i++) { 144 | for (int j = 0; j < y; j++) { 145 | for (int k = 0; k < z; k++) { 146 | positionArray[IDX(i, j, k)] = new Vector3(i * scale, j * scale, k * scale) + new Vector3(0.5f * scale, 0.5f * scale, 0.5f * scale); 147 | quaternionArray[IDX(i, j, k)] = Quaternion.identity; 148 | rigidBodyVelocitiesArray[IDX(i, j, k)] = Vector3.zero; 149 | } 150 | } 151 | } 152 | // rigid body velocities 153 | positionArray[IDX(0, y - 1, 0)] = m_firstCubeLocation; 154 | rigidBodyVelocitiesArray[IDX(0, y - 1, 0)] = m_firstCubeVelocity; 155 | quaternionArray[IDX(0, y - 1, 0)] = Quaternion.Euler(m_firstCubeRotation); 156 | particleVelocities = new Vector3[n_particles]; 157 | particlePositions = new Vector3[n_particles]; 158 | particleRelativePositions = new Vector3[n_particles]; 159 | debugParticleIds = new int[debug_particle_id_count]; 160 | voxelGridArray = new int[numGridCells * 4]; 161 | particleVoxelPositionsArray = new int[n_particles * 3]; 162 | 163 | // Get Kernels 164 | m_kernel_generateParticleValues = m_computeShader.FindKernel("GenerateParticleValues"); 165 | m_kernel_clearGrid = m_computeShader.FindKernel("ClearGrid"); 166 | m_kernel_populateGrid = m_computeShader.FindKernel("PopulateGrid"); 167 | m_kernel_collisionDetection = m_computeShader.FindKernel("CollisionDetection"); 168 | m_kernel_computeMomenta = m_computeShader.FindKernel("ComputeMomenta"); 169 | m_kernel_computePositionAndRotation = m_computeShader.FindKernel("ComputePositionAndRotation"); 170 | m_kernelSavePreviousPositionAndRotation = m_computeShader.FindKernel("SavePreviousPositionAndRotation"); 171 | // Count Thread Groups 172 | m_threadGroupsPerRigidBody = Mathf.CeilToInt(total / 8.0f); 173 | m_threadGroupsPerParticle = Mathf.CeilToInt(n_particles / 8f); 174 | m_threadGroupsPerGridCell = Mathf.CeilToInt((gridX * gridY * gridZ) / 8f); 175 | 176 | // Create initial buffers 177 | const int floatThree = 3 * sizeof(float); 178 | const int floatFour = 4 * sizeof(float); 179 | const int intFour = 4 * sizeof(int); 180 | const int intThree = 3 * sizeof(int); 181 | const int floatNine = 9*sizeof(float); 182 | 183 | m_rigidBodyPositions = new ComputeBuffer(total, floatThree); 184 | m_previousRigidBodyPositions = new ComputeBuffer(total, floatThree); 185 | m_rigidBodyQuaternions = new ComputeBuffer(total, floatFour); 186 | m_previousRigidBodyQuaternions = new ComputeBuffer(total, floatFour); 187 | m_rigidBodyAngularVelocities = new ComputeBuffer(total, floatThree); 188 | m_rigidBodyVelocities = new ComputeBuffer(total, floatThree); 189 | m_rigidBodyInertialTensors = new ComputeBuffer(total, floatNine); 190 | 191 | m_particleInitialRelativePositions = new ComputeBuffer(n_particles, floatThree); 192 | m_particlePositions = new ComputeBuffer(n_particles, floatThree); 193 | m_particleRelativePositions = new ComputeBuffer(n_particles, floatThree); 194 | m_particleVelocities = new ComputeBuffer(n_particles, floatThree); 195 | m_particleForces = new ComputeBuffer(n_particles, floatThree); 196 | 197 | m_voxelCollisionGrid = new ComputeBuffer(numGridCells, intFour); 198 | m_debugParticleVoxelPositions = new ComputeBuffer(n_particles, intThree); 199 | m_debugParticleIds = new ComputeBuffer(debug_particle_id_count, sizeof(int)); 200 | Debug.Log("nparticles: " + n_particles); 201 | // initialize constants 202 | int[] gridDimensions = new int[] { gridX, gridY, gridZ }; 203 | m_computeShader.SetInts("gridDimensions", gridDimensions); 204 | m_computeShader.SetInt("gridMax", numGridCells); 205 | m_computeShader.SetInt("particlesPerRigidBody", particlesPerBody); 206 | m_computeShader.SetFloat("particleDiameter", particleDiameter); 207 | m_computeShader.SetFloat("springCoefficient", springCoefficient); 208 | m_computeShader.SetFloat("dampingCoefficient", dampingCoefficient); 209 | m_computeShader.SetFloat("frictionCoefficient", frictionCoefficient); 210 | m_computeShader.SetFloat("angularFrictionCoefficient", angularFrictionCoefficient); 211 | m_computeShader.SetFloat("gravityCoefficient", gravityCoefficient); 212 | m_computeShader.SetFloat("tangentialCoefficient", tangentialCoefficient); 213 | m_computeShader.SetFloat("angularForceScalar", angularForceScalar); 214 | m_computeShader.SetFloat("linearForceScalar", linearForceScalar); 215 | m_computeShader.SetFloat("particleMass", m_cubeMass / particlesPerBody); 216 | m_computeShader.SetFloats("gridStartPosition", new float[] { gridStartPosition.x, gridStartPosition.y, gridStartPosition.z }); 217 | 218 | 219 | // Inertial tensor of a cube formula taken from textbook: 220 | // "Essential Mathematics for Games and Interactive Applications" 221 | // by James Van Verth and Lars Bishop 222 | float twoDimSq = 2.0f * (scale * scale); 223 | float inertialTensorFactor = m_cubeMass * 1.0f / 12.0f * twoDimSq; 224 | float[] inertialTensor = { 225 | inertialTensorFactor, 0.0f, 0.0f, 226 | 0.0f, inertialTensorFactor, 0.0f, 227 | 0.0f, 0.0f, inertialTensorFactor 228 | }; 229 | float[] inverseInertialTensor; 230 | GPUPhysics.Invert(ref inertialTensor, out inverseInertialTensor); 231 | float[] quickInverseInertialTensor = { 232 | 1.0f/inertialTensorFactor, 0.0f, 0.0f, 233 | 0.0f, 1.0f/inertialTensorFactor, 0.0f, 234 | 0.0f, 0.0f, 1.0f/inertialTensorFactor 235 | }; 236 | m_computeShader.SetFloats("inertialTensor", inertialTensor); 237 | m_computeShader.SetFloats("inverseInertialTensor", quickInverseInertialTensor); 238 | 239 | 240 | 241 | // initialize buffers 242 | // initial relative positions 243 | // super dependent on 8/rigid body 244 | particleInitialRelativePositions = new Vector3[n_particles]; 245 | Vector3[] particleInitialsSmall = new Vector3[particlesPerBody]; 246 | int initialRelativePositionIterator = 0; 247 | float centerer = scale * -0.5f + particleDiameter*0.5f; 248 | Vector3 centeringOffset = new Vector3(centerer, centerer, centerer); 249 | for (int xIter = 0; xIter < particlesPerEdge; xIter++) { 250 | for (int yIter = 0; yIter < particlesPerEdge; yIter++) { 251 | for (int zIter = 0; zIter < particlesPerEdge; zIter++) { 252 | if (xIter == 0 || xIter == (particlesPerEdge-1) || yIter == 0 || yIter == (particlesPerEdge-1) || zIter == 0 || zIter == (particlesPerEdge-1)) { 253 | particleInitialsSmall[initialRelativePositionIterator] = centeringOffset + new Vector3(xIter*particleDiameter, yIter*particleDiameter, zIter*particleDiameter); 254 | initialRelativePositionIterator++; 255 | } 256 | } 257 | } 258 | } 259 | for (int i = 0; i < particleInitialRelativePositions.Length; i++) { 260 | particleInitialRelativePositions[i] = particleInitialsSmall[i % particlesPerBody]; 261 | } 262 | 263 | m_particleInitialRelativePositions.SetData(particleInitialRelativePositions); 264 | 265 | // rigid body positions 266 | m_rigidBodyPositions.SetData(positionArray); 267 | 268 | // rigid body quaternions 269 | m_rigidBodyQuaternions.SetData(quaternionArray); 270 | 271 | m_rigidBodyVelocities.SetData(rigidBodyVelocitiesArray); 272 | 273 | // Set matricies to initial positions 274 | SetMatrices(positionArray, quaternionArray); 275 | 276 | // Bind buffers 277 | 278 | // kernel 0 GenerateParticleValues 279 | m_computeShader.SetBuffer(m_kernel_generateParticleValues, "rigidBodyPositions", m_rigidBodyPositions); 280 | m_computeShader.SetBuffer(m_kernel_generateParticleValues, "rigidBodyQuaternions", m_rigidBodyQuaternions); 281 | m_computeShader.SetBuffer(m_kernel_generateParticleValues, "rigidBodyAngularVelocities", m_rigidBodyAngularVelocities); 282 | m_computeShader.SetBuffer(m_kernel_generateParticleValues, "rigidBodyVelocities", m_rigidBodyVelocities); 283 | m_computeShader.SetBuffer(m_kernel_generateParticleValues, "particleInitialRelativePositions", m_particleInitialRelativePositions); 284 | m_computeShader.SetBuffer(m_kernel_generateParticleValues, "particlePositions", m_particlePositions); 285 | m_computeShader.SetBuffer(m_kernel_generateParticleValues, "particleRelativePositions", m_particleRelativePositions); 286 | m_computeShader.SetBuffer(m_kernel_generateParticleValues, "particleVelocities", m_particleVelocities); 287 | //m_computeShader.SetBuffer(m_kernel_generateParticleValues, "debugParticleIds", m_debugParticleIds); 288 | 289 | // kernel 1 ClearGrid 290 | m_computeShader.SetBuffer(m_kernel_clearGrid, "voxelCollisionGrid", m_voxelCollisionGrid); 291 | 292 | // kernel 2 Populate Grid 293 | m_computeShader.SetBuffer(m_kernel_populateGrid, "debugParticleVoxelPositions", m_debugParticleVoxelPositions); 294 | m_computeShader.SetBuffer(m_kernel_populateGrid, "voxelCollisionGrid", m_voxelCollisionGrid); 295 | m_computeShader.SetBuffer(m_kernel_populateGrid, "particlePositions", m_particlePositions); 296 | //m_computeShader.SetBuffer(m_kernel_populateGrid, "debugParticleIds", m_debugParticleIds); 297 | 298 | // kernel 3 Collision Detection 299 | m_computeShader.SetBuffer(m_kernel_collisionDetection, "particlePositions", m_particlePositions); 300 | m_computeShader.SetBuffer(m_kernel_collisionDetection, "particleVelocities", m_particleVelocities); 301 | m_computeShader.SetBuffer(m_kernel_collisionDetection, "voxelCollisionGrid", m_voxelCollisionGrid); 302 | m_computeShader.SetBuffer(m_kernel_collisionDetection, "particleForces", m_particleForces); 303 | 304 | // kernel 4 Computation of Momenta 305 | m_computeShader.SetBuffer(m_kernel_computeMomenta, "particleForces", m_particleForces); 306 | m_computeShader.SetBuffer(m_kernel_computeMomenta, "particleRelativePositions", m_particleRelativePositions); 307 | m_computeShader.SetBuffer(m_kernel_computeMomenta, "rigidBodyAngularVelocities", m_rigidBodyAngularVelocities); 308 | m_computeShader.SetBuffer(m_kernel_computeMomenta, "rigidBodyVelocities", m_rigidBodyVelocities); 309 | m_computeShader.SetBuffer(m_kernel_computeMomenta, "debugParticleIds", m_debugParticleIds); 310 | m_computeShader.SetBuffer(m_kernel_computeMomenta, "rigidBodyQuaternions", m_rigidBodyQuaternions); 311 | 312 | // kernel 5 Compute Position and Rotation 313 | m_computeShader.SetBuffer(m_kernel_computePositionAndRotation, "rigidBodyVelocities", m_rigidBodyVelocities); 314 | m_computeShader.SetBuffer(m_kernel_computePositionAndRotation, "rigidBodyAngularVelocities", m_rigidBodyAngularVelocities); 315 | m_computeShader.SetBuffer(m_kernel_computePositionAndRotation, "rigidBodyPositions", m_rigidBodyPositions); 316 | m_computeShader.SetBuffer(m_kernel_computePositionAndRotation, "rigidBodyQuaternions", m_rigidBodyQuaternions); 317 | m_computeShader.SetBuffer(m_kernel_computePositionAndRotation, "inverseInertialMatrices", m_rigidBodyInertialTensors); 318 | 319 | // kernel 6 Save Previous Position and Rotation 320 | m_computeShader.SetBuffer(m_kernelSavePreviousPositionAndRotation, "rigidBodyPositions", m_rigidBodyPositions); 321 | m_computeShader.SetBuffer(m_kernelSavePreviousPositionAndRotation, "rigidBodyQuaternions", m_rigidBodyQuaternions); 322 | m_computeShader.SetBuffer(m_kernelSavePreviousPositionAndRotation, "previousRigidBodyPositions", m_previousRigidBodyPositions); 323 | m_computeShader.SetBuffer(m_kernelSavePreviousPositionAndRotation, "previousRigidBodyQuaternions", m_previousRigidBodyQuaternions); 324 | // Setup Indirect Renderer 325 | uint[] sphereArgs = new uint[] { sphereMesh.GetIndexCount(0), (uint)n_particles, 0, 0, 0 }; 326 | m_bufferWithSphereArgs = new ComputeBuffer(1, sphereArgs.Length * sizeof(uint), ComputeBufferType.IndirectArguments); 327 | m_bufferWithSphereArgs.SetData(sphereArgs); 328 | 329 | uint[] lineArgs = new uint[] { lineMesh.GetIndexCount(0), (uint)n_particles, 0, 0, 0 }; 330 | m_bufferWithLineArgs = new ComputeBuffer(1, lineArgs.Length * sizeof(uint), ComputeBufferType.IndirectArguments); 331 | m_bufferWithLineArgs.SetData(lineArgs); 332 | 333 | cubeMaterial.SetBuffer("positions", m_rigidBodyPositions); 334 | cubeMaterial.SetBuffer("previousPositions", m_previousRigidBodyPositions); 335 | 336 | cubeMaterial.SetBuffer("quaternions", m_rigidBodyQuaternions); 337 | cubeMaterial.SetBuffer("previousQuaternions", m_previousRigidBodyQuaternions); 338 | 339 | sphereMaterial.SetBuffer("positions", m_particlePositions); 340 | sphereMaterial.SetVector("scale", new Vector4(particleDiameter*0.5f, particleDiameter*0.5f, particleDiameter*0.5f, 1.0f)); 341 | lineMaterial.SetBuffer("positions", m_particlePositions); 342 | lineMaterial.SetBuffer("vectors", m_particleVelocities); 343 | 344 | // Setup Command Buffer 345 | m_commandBuffer = new CommandBuffer(); 346 | m_commandBuffer.BeginSample("GenerateParticleValues"); 347 | m_commandBuffer.DispatchCompute(m_computeShader, m_kernel_generateParticleValues, m_threadGroupsPerRigidBody, 1, 1); 348 | m_commandBuffer.EndSample("GenerateParticleValues"); 349 | 350 | m_commandBuffer.BeginSample("ClearGrid"); 351 | m_commandBuffer.DispatchCompute(m_computeShader, m_kernel_clearGrid, m_threadGroupsPerGridCell, 1, 1); 352 | m_commandBuffer.EndSample("ClearGrid"); 353 | 354 | m_commandBuffer.BeginSample("PopulateGrid"); 355 | m_commandBuffer.DispatchCompute(m_computeShader, m_kernel_populateGrid, m_threadGroupsPerParticle, 1, 1); 356 | m_commandBuffer.EndSample("PopulateGrid"); 357 | 358 | m_commandBuffer.BeginSample("CollisionDetection"); 359 | m_commandBuffer.DispatchCompute(m_computeShader, m_kernel_collisionDetection, m_threadGroupsPerParticle, 1, 1); 360 | m_commandBuffer.EndSample("CollisionDetection"); 361 | 362 | m_commandBuffer.BeginSample("ComputeMomenta"); 363 | m_commandBuffer.DispatchCompute(m_computeShader, m_kernel_computeMomenta, m_threadGroupsPerRigidBody, 1, 1); 364 | m_commandBuffer.EndSample("ComputeMomenta"); 365 | 366 | m_commandBuffer.BeginSample("ComputePositions"); 367 | m_commandBuffer.DispatchCompute(m_computeShader, m_kernel_computePositionAndRotation, m_threadGroupsPerRigidBody, 1, 1); 368 | m_commandBuffer.EndSample("ComputePositions"); 369 | 370 | m_commandBuffer.BeginSample("SavePreviousPositionAndRotation"); 371 | m_commandBuffer.DispatchCompute(m_computeShader, m_kernelSavePreviousPositionAndRotation, m_threadGroupsPerRigidBody, 1, 1); 372 | m_commandBuffer.EndSample("SavePreviousPositionAndRotation"); 373 | // rendering in command buffer - doesnt work for now seems like a unity bug 374 | #if !(UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX) // Command Buffer DrawMeshInstancedIndirect doesnt work on my mac 375 | // rendering from command buffer via update isnt working so disabling this is necessary for delta time use 376 | // m_commandBuffer.BeginSample("DrawMeshInstancedIndirect"); 377 | // m_commandBuffer.DrawMeshInstancedIndirect(cubeMesh, 0, cubeMaterial, 0, m_bufferWithArgs); 378 | // m_commandBuffer.EndSample("DrawMeshInstancedIndirect"); 379 | #endif 380 | 381 | // Camera.main.AddCommandBuffer(CameraEvent.AfterSkybox, m_commandBuffer); 382 | } 383 | 384 | private void SetMatrices(Vector3[] positions, Quaternion[] quaternions) { 385 | for (int i = 0; i < positions.Length; i++) { 386 | m_matrices[i] = Matrix4x4.TRS(positions[i], quaternions[i], m_cubeScale); 387 | } 388 | } 389 | 390 | private int IDX(int i, int j, int k) { 391 | return i + (j * x) + (k * x * y); 392 | } 393 | public Matrix4x4 inverseInertialMatrix; 394 | void Update() { 395 | 396 | if (m_bufferWithArgs == null || m_debugWireframe != m_lastDebugWireframe) { 397 | uint indexCountPerInstance = cubeMesh.GetIndexCount(0); 398 | uint instanceCount = (uint)total; 399 | uint startIndexLocation = 0; 400 | uint baseVertexLocation = 0; 401 | uint startInstanceLocation = 0; 402 | uint[] args = new uint[] { indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation }; 403 | m_bufferWithArgs = new ComputeBuffer(1, args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); 404 | m_bufferWithArgs.SetData(args); 405 | m_lastDebugWireframe = m_debugWireframe; 406 | } 407 | if (frameCounter++ < 10) { 408 | return; 409 | } 410 | /* 411 | //quaternionArray[IDX(0, y - 1, 0)] = Quaternion.Euler(m_firstCubeRotation); 412 | //m_rigidBodyQuaternions.SetData(quaternionArray); 413 | //positionArray[IDX(0, y -1, 0)] = m_firstCubeLocation; 414 | //m_rigidBodyPositions.SetData(positionArray); 415 | //positionArray[IDX(0,y-1,0)] = m_firstCubeLocation; 416 | int idx = IDX(0,y-1,0); 417 | m_rigidBodyQuaternions.GetData(quaternionArray); 418 | m_rigidBodyPositions.GetData(positionArray); 419 | m_particlePositions.GetData(particlePositions); 420 | */ 421 | 422 | 423 | /* 424 | timestep adopted from the appreciated writings of Glenn Fiedler 425 | https://gafferongames.com/post/fix_your_timestep/ 426 | 427 | accumulator += frameTime; 428 | 429 | while ( accumulator >= dt ) 430 | { 431 | previousState = currentState; 432 | integrate( currentState, t, dt ); 433 | t += dt; 434 | accumulator -= dt; 435 | } 436 | 437 | const double alpha = accumulator / dt; 438 | 439 | State state = currentState * alpha + 440 | previousState * ( 1.0 - alpha ); 441 | */ 442 | ticker += Time.deltaTime; 443 | float _dt = 1.0f / tick_rate; 444 | while (ticker >= _dt) { 445 | ticker -= _dt; 446 | m_computeShader.SetFloat(m_deltaTimeShaderProperty, dt); 447 | 448 | Graphics.ExecuteCommandBuffer(m_commandBuffer); 449 | } 450 | float blendAlpha = ticker / _dt; 451 | cubeMaterial.SetFloat("blendAlpha", blendAlpha); 452 | // #if (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX) // Command Buffer DrawMeshInstancedIndirect doesnt work on my mac 453 | 454 | Graphics.DrawMeshInstancedIndirect(cubeMesh, 0, cubeMaterial, m_bounds, m_bufferWithArgs); 455 | if (m_debugWireframe) { 456 | m_computeShader.SetFloat("particleDiameter", scale / particlesPerEdge); 457 | m_computeShader.SetFloat("springCoefficient", springCoefficient); 458 | m_computeShader.SetFloat("dampingCoefficient", dampingCoefficient); 459 | m_computeShader.SetFloat("frictionCoefficient", frictionCoefficient); 460 | m_computeShader.SetFloat("angularFrictionCoefficient", angularFrictionCoefficient); 461 | m_computeShader.SetFloat("gravityCoefficient", gravityCoefficient); 462 | m_computeShader.SetFloat("tangentialCoefficient", tangentialCoefficient); 463 | m_computeShader.SetFloat("angularForceScalar", angularForceScalar); 464 | m_computeShader.SetFloat("linearForceScalar", linearForceScalar); 465 | int particlesPerBody = 8; 466 | m_computeShader.SetFloat("particleMass", m_cubeMass / particlesPerBody); 467 | /* 468 | m_rigidBodyInertialTensors.GetData(rigidBodyInertialTensors); 469 | string floatString = ""; 470 | for (int i = 0; i < rigidBodyInertialTensors.Length; i++) { 471 | if (i % 3 == 0) { 472 | floatString += "\n"; 473 | } 474 | floatString += string.Format("\t{0}", rigidBodyInertialTensors[i].ToString()); 475 | } 476 | Debug.Log("[GPUPhysics] inertialTensor:\n" + floatString); 477 | */ 478 | 479 | Graphics.DrawMeshInstancedIndirect(sphereMesh, 0, sphereMaterial, m_bounds, m_bufferWithSphereArgs); 480 | //lineMaterial.SetBuffer("positions", m_particlePositions); 481 | //lineMaterial.SetBuffer("vectors", m_particleVelocities); 482 | 483 | lineMaterial.SetBuffer("positions", m_rigidBodyPositions); 484 | lineMaterial.SetBuffer("vectors", m_rigidBodyAngularVelocities); 485 | Graphics.DrawMeshInstancedIndirect(lineMesh, 0, lineMaterial, m_bounds, m_bufferWithLineArgs); 486 | m_rigidBodyQuaternions.GetData(quaternionArray); 487 | foreach(var r in comparisonCubes) { 488 | Debug.DrawLine(r.transform.position, r.transform.position + 10*r.angularVelocity, Color.green, Time.deltaTime*2); 489 | m_comparisonQuaternion = r.transform.rotation; 490 | } 491 | 492 | } 493 | // #endif 494 | /* 495 | m_computeShader.Dispatch(m_kernel_generateParticleValues, m_threadGroupsPerRigidBody, 1, 1); 496 | m_computeShader.Dispatch(m_kernel_clearGrid, m_threadGroupsPerGridCell, 1, 1); 497 | m_computeShader.Dispatch(m_kernel_populateGrid, m_threadGroupsPerParticle,1, 1); 498 | m_computeShader.Dispatch(m_kernel_collisionDetection, m_threadGroupsPerParticle, 1, 1); 499 | m_computeShader.Dispatch(m_kernel_computeMomenta, m_threadGroupsPerRigidBody, 1, 1); 500 | m_computeShader.Dispatch(m_kernel_computePositionAndRotation, m_threadGroupsPerRigidBody, 1, 1); 501 | */ 502 | // m_particleRelativePositions.GetData(particleRelativePositions); 503 | // m_particleVelocities.GetData(particleVelocities); 504 | // m_rigidBodyVelocities.GetData(rigidBodyVelocitiesArray); 505 | // m_particleForces.GetData(particleForcesArray); 506 | 507 | // m_particlePositions.GetData(particlePositions); 508 | // m_voxelCollisionGrid.GetData(voxelGridArray); 509 | // m_debugParticleVoxelPositions.GetData(particleVoxelPositionsArray); 510 | 511 | //m_rigidBodyPositions.GetData(positionArray); 512 | //m_rigidBodyQuaternions.GetData(quaternionArray); 513 | 514 | // m_debugParticleIds.GetData(debugParticleIds); 515 | //SetMatrices(positionArray, quaternionArray); 516 | 517 | 518 | //Graphics.DrawMeshInstanced(cubeMesh, 0, cubeMaterial, m_matrices, total, null, UnityEngine.Rendering.ShadowCastingMode.On, true, 0, Camera.main); 519 | //Graphics.ExecuteCommandBuffer(m_commandBuffer); 520 | 521 | } 522 | 523 | void OnDestroy() { 524 | m_rigidBodyPositions.Release(); 525 | m_rigidBodyQuaternions.Release(); 526 | m_rigidBodyAngularVelocities.Release(); 527 | m_rigidBodyVelocities.Release(); 528 | 529 | m_particleInitialRelativePositions.Release(); 530 | m_particlePositions.Release(); 531 | m_particleRelativePositions.Release(); 532 | m_particleVelocities.Release(); 533 | m_particleForces.Release(); 534 | 535 | m_debugParticleVoxelPositions.Release(); 536 | m_voxelCollisionGrid.Release(); 537 | 538 | m_previousRigidBodyQuaternions.Release(); 539 | m_previousRigidBodyPositions.Release(); 540 | m_rigidBodyInertialTensors.Release(); 541 | m_debugParticleIds.Release(); 542 | 543 | if (m_bufferWithSphereArgs != null) { 544 | m_bufferWithSphereArgs.Release(); 545 | } 546 | if (m_bufferWithLineArgs != null) { 547 | m_bufferWithLineArgs.Release(); 548 | } 549 | if (m_bufferWithArgs != null) { 550 | m_bufferWithArgs.Release(); 551 | } 552 | } 553 | 554 | public static int M(int row, int column) { 555 | return (row-1) * 3 + (column-1); 556 | } 557 | public static void Invert(ref float[] value, out float[] result) { 558 | float d11 = value[M(2,2)] * value[M(3,3)] + value[M(2,3)] * -value[M(3,2)]; 559 | float d12 = value[M(2,1)] * value[M(3,3)] + value[M(2,3)] * -value[M(3,1)]; 560 | float d13 = value[M(2,1)] * value[M(3,2)] + value[M(2,2)] * -value[M(3,1)]; 561 | 562 | float det = value[M(1,1)] * d11 - value[M(1,2)] * d12 + value[M(1,3)] * d13; 563 | result = new float[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 564 | 565 | if (Mathf.Abs(det) == 0.0f) { 566 | return; 567 | } 568 | 569 | det = 1f / det; 570 | 571 | float d21 = value[M(1, 2)] * value[M(3, 3)] + value[M(1, 3)] * -value[M(3, 2)]; 572 | float d22 = value[M(1, 1)] * value[M(3, 3)] + value[M(1, 3)] * -value[M(3, 1)]; 573 | float d23 = value[M(1, 1)] * value[M(3, 2)] + value[M(1, 2)] * -value[M(3, 1)]; 574 | 575 | float d31 = (value[M(1, 2)] * value[M(2, 3)]) - (value[M(1, 3)] * value[M(2, 2)]); 576 | float d32 = (value[M(1, 1)] * value[M(2, 3)]) - (value[M(1, 3)] * value[M(2, 1)]); 577 | float d33 = (value[M(1, 1)] * value[M(2, 2)]) - (value[M(1, 2)] * value[M(2, 1)]); 578 | 579 | result[M(1,1)] = +d11 * det; result[M(1,2)] = -d21 * det; result[M(1,3)] = +d31 * det; 580 | result[M(2,1)] = -d12 * det; result[M(2,2)] = +d22 * det; result[M(2,3)] = -d32 * det; 581 | result[M(3,1)] = +d13 * det; result[M(3,2)] = -d23 * det; result[M(3,3)] = +d33 * det; 582 | } 583 | } -------------------------------------------------------------------------------- /Assets/Physics/GPUPhysics.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 67d89b88c176d4beeaeaf139994b1f9b 3 | timeCreated: 1483657476 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Assets/Physics/GPUPhysicsComputeShader.compute: -------------------------------------------------------------------------------- 1 | // Each #kernel tells which function to compile; you can have many kernels 2 | #define CLEAR_GRID_THREAD_COUNT 8 3 | #define RIGID_BODY_THREAD_COUNT 8 4 | #define PARTICLE_THREAD_COUNT 8 5 | #include "Quaternion.cginc" 6 | 7 | // Kernels 8 | // Per Rigid Body 0 9 | #pragma kernel GenerateParticleValues 10 | 11 | // Per Grid Cell 1 12 | #pragma kernel ClearGrid 13 | 14 | // Per Particle 2 15 | #pragma kernel PopulateGrid 16 | 17 | // Per Particle 3 18 | #pragma kernel CollisionDetection 19 | 20 | // Per Rigid Body 4 21 | #pragma kernel ComputeMomenta 22 | 23 | // Per Rigid Body 5 24 | #pragma kernel ComputePositionAndRotation 25 | 26 | // Per Rigid Body 6 27 | #pragma kernel SavePreviousPositionAndRotation 28 | 29 | // Buffers 30 | // rigidBodyPositions (RWStructuredBuffer) 31 | // rigidBodyQuaternions (RWStructuredBuffer) 32 | // rigidBodyAngularVelocities (RWStructuredBuffer) 33 | // rigidBodyVelocities (RWStructuredBuffer) 34 | // particleInitialRelativePositions (StructuredBuffer) 35 | // particlePositions (RWStructuredBuffer) 36 | // particleRelativePositions (RWStructuredBuffer) 37 | // particleVelocities (RWStructuredBuffer) 38 | // particleForces (RWStructuredBuffer) 39 | // voxelCollisionGrid (RWStructuredBuffer) 40 | 41 | 42 | // Constants 43 | // gridStartPosition (float3) // lower left bound 44 | // gridDimensions (int3) 45 | // gridMax (int) gridDimensions.x * gridDimensions.y * gridDimensions.z * 4 46 | // particleDiameter (float) 47 | // springCoefficient (float) (negative) (Equation 10) 48 | // dampingCoefficient (float) (Equation 11) 49 | // tangentialCoefficient (float) (Equation 12) 50 | int particlesPerRigidBody; 51 | float deltaTime; 52 | float particleMass; 53 | float3x3 inertialTensor; 54 | float3x3 inverseInertialTensor; 55 | 56 | 57 | ////////////////////////////// 58 | // Generate Particle Values // 59 | ////////////////////////////// 60 | // Per Rigid Body 61 | // Use rigidBodyPositions and 62 | // rigidBodyQuaternions to 63 | // Generate particlePositions 64 | // and particleRelativePositions 65 | // and particleVelocities 66 | // 67 | // Input 68 | RWStructuredBuffer rigidBodyPositions; 69 | RWStructuredBuffer rigidBodyQuaternions; 70 | RWStructuredBuffer rigidBodyAngularVelocities; 71 | RWStructuredBuffer rigidBodyVelocities; 72 | StructuredBuffer particleInitialRelativePositions; 73 | // 74 | // Output 75 | RWStructuredBuffer particlePositions; 76 | RWStructuredBuffer particleRelativePositions; 77 | RWStructuredBuffer particleVelocities; 78 | ////////////////////////////// 79 | RWStructuredBuffer debugParticleIds; 80 | 81 | 82 | float3 rotateVectorByQuaternion(float4 quaternion, float3 vec) 83 | { 84 | return quat_mul(quaternion, vec); 85 | } 86 | 87 | [numthreads(RIGID_BODY_THREAD_COUNT,1,1)] 88 | void GenerateParticleValues (uint3 id : SV_DispatchThreadID) 89 | { 90 | float3 rigidBodyPosition = rigidBodyPositions[id.x]; 91 | float4 rigidBodyQuaternion = rigidBodyQuaternions[id.x]; 92 | float3 rigidBodyAngularVelocity = rigidBodyAngularVelocities[id.x]; 93 | float3 rigidBodyVelocity = rigidBodyVelocities[id.x]; 94 | 95 | for (int i = 0; i < particlesPerRigidBody; i++) { 96 | int p_id = id.x * particlesPerRigidBody + i; 97 | particleRelativePositions[p_id] = rotateVectorByQuaternion(rigidBodyQuaternion, particleInitialRelativePositions[p_id]); 98 | particlePositions[p_id] = rigidBodyPosition + particleRelativePositions[p_id]; 99 | particleVelocities[p_id] = rigidBodyVelocity + cross(rigidBodyAngularVelocity, particleRelativePositions[p_id]); 100 | } 101 | } 102 | 103 | 104 | ////////////////////// 105 | // Grid Generation // 106 | ///////////////////// 107 | // Per Grid Cell 108 | // Use particlePositions 109 | // to populate the 110 | // voxelCollisionGrid 111 | // Input 112 | // StructuredBuffer particlePositions; (defined above) 113 | int3 gridDimensions; 114 | float3 gridStartPosition; 115 | int gridMax; // gridDimensions.x * gridDimensions.y * gridDimensions.z 116 | float particleDiameter; 117 | // Output 118 | RWStructuredBuffer voxelCollisionGrid; 119 | // DEBUG ONLY 120 | RWStructuredBuffer debugParticleVoxelPositions; 121 | [numthreads(CLEAR_GRID_THREAD_COUNT,1,1)] 122 | void ClearGrid (uint3 id : SV_DispatchThreadID) 123 | { 124 | voxelCollisionGrid[id.x].r = -1; 125 | voxelCollisionGrid[id.x].g = -1; 126 | voxelCollisionGrid[id.x].b = -1; 127 | voxelCollisionGrid[id.x].a = -1; 128 | } 129 | 130 | // Returns the grid index for particle p 131 | // equivalent to _gridIndexFromThree(_gridIndexThree(p_id)) 132 | int _gridIndex(int p_id) { 133 | int3 gridLocation = (particlePositions[p_id] - gridStartPosition) / particleDiameter; 134 | // DEBUG ONLY 135 | //debugParticleVoxelPositions[p_id] = gridLocation; 136 | //debugParticleVoxelPositions[p_id] = int3(1,2,3); 137 | return gridLocation.x + gridDimensions.x * gridLocation.y + (gridDimensions.x * gridDimensions.y * gridLocation.z); 138 | } 139 | 140 | [numthreads(PARTICLE_THREAD_COUNT,1,1)] 141 | void PopulateGrid (uint3 id : SV_DispatchThreadID) 142 | { 143 | int p_id = id.x; 144 | int gridIndex = _gridIndex(p_id); 145 | // clamp gridIndex? 146 | if (gridIndex < gridMax && gridIndex > -1) 147 | { 148 | 149 | int originalValue = 0; 150 | InterlockedCompareExchange(voxelCollisionGrid[gridIndex].x, -1, p_id, originalValue); 151 | if (originalValue != -1) 152 | InterlockedCompareExchange(voxelCollisionGrid[gridIndex].y, -1, p_id, originalValue); 153 | if (originalValue != -1) 154 | InterlockedCompareExchange(voxelCollisionGrid[gridIndex].z, -1, p_id, originalValue); 155 | if (originalValue != -1) 156 | InterlockedCompareExchange(voxelCollisionGrid[gridIndex].w, -1, p_id, originalValue); 157 | } 158 | } 159 | 160 | ///////////////////////// 161 | // Collision Detection // 162 | ///////////////////////// 163 | // Per Particle 164 | // Use particlePositions, grid and velocity to compute Particle force 165 | // Input 166 | // StructuredBuffer particlePositions; (defined in Particle Value computation) 167 | // StructuredBuffer particleVelocities; (defined in Particle Value computation) 168 | // RWStructuredBuffer voxelCollisionGrid; (defined in Grid Generation) 169 | float springCoefficient; 170 | float dampingCoefficient; 171 | float tangentialCoefficient; 172 | // Output 173 | RWStructuredBuffer particleForces; 174 | float3 _collisionReaction(int j_id, int i_id) 175 | { 176 | 177 | // the force on particle i after colliding with particle j is modelled as follows 178 | float3 relativePosition = particlePositions[j_id] - particlePositions[i_id]; // position of j relative to i 179 | float relativePositionMagnitude = length(relativePosition); 180 | 181 | if (relativePositionMagnitude < particleDiameter) 182 | { 183 | float3 relativePositionNormalized = relativePosition / relativePositionMagnitude; 184 | 185 | // repulsive force (Equation 10) 186 | float3 repulsiveForce = -springCoefficient * (particleDiameter - relativePositionMagnitude) * relativePositionNormalized; 187 | // damping force (Equation 11) 188 | // https://www2.msm.ctw.utwente.nl/sluding/PAPERS/luding_alert2008.pdf 189 | // says that the damping force acts along the normal.... 190 | // not sure whether relativeVelocity is relative to particle i's position or particle i's velocity 191 | // using velocity here 192 | float3 relativeVelocity = particleVelocities[j_id] - particleVelocities[i_id]; // not sure if correct 193 | // project relative velocity along the relative position 194 | /* 195 | // Projects a vector onto another vector. 196 | public static Vector3 Project(Vector3 vector, Vector3 onNormal) 197 | { 198 | float sqrMag = Dot(onNormal, onNormal); 199 | if (sqrMag < Mathf.Epsilon) 200 | return zero; 201 | else 202 | return onNormal * Dot(vector, onNormal) / sqrMag; 203 | } 204 | 205 | */ 206 | //relativeVelocity = relativePositionNormalized * dot(relativeVelocity, relativePositionNormalized); 207 | float3 dampingForce = dampingCoefficient * relativeVelocity; 208 | 209 | // tangential force (Equation 12) 210 | float3 tangentialVelocity = relativeVelocity - (dot(relativeVelocity, relativePositionNormalized) * relativePositionNormalized); 211 | float3 tangentialForce = tangentialCoefficient * tangentialVelocity; 212 | 213 | return repulsiveForce + dampingForce + tangentialForce; 214 | } 215 | return float3(0,0,0); 216 | } 217 | 218 | float3 _collisionReactionWithGround(int i_id) { 219 | 220 | float3 groundParticlePosition = particlePositions[i_id]; 221 | groundParticlePosition.y = -particleDiameter*0.5; 222 | 223 | 224 | float3 relativePosition = groundParticlePosition - particlePositions[i_id]; // position of j relative to i 225 | float relativePositionMagnitude = length(relativePosition); 226 | 227 | if (relativePositionMagnitude < particleDiameter) 228 | { 229 | float3 relativePositionNormalized = relativePosition / relativePositionMagnitude; 230 | 231 | // repulsive force (Equation 10) 232 | float3 repulsiveForce = -springCoefficient * (particleDiameter - relativePositionMagnitude) * relativePositionNormalized; 233 | // damping force (Equation 11) 234 | // https://www2.msm.ctw.utwente.nl/sluding/PAPERS/luding_alert2008.pdf 235 | // says that the damping force acts along the normal.... 236 | // not sure whether relativeVelocity is relative to particle i's position or particle i's velocity 237 | // using velocity here 238 | float3 relativeVelocity = float3(0.0f,0.0f,0.0f) - particleVelocities[i_id]; // not sure if correct 239 | //relativeVelocity = relativePositionNormalized * dot(relativeVelocity, relativePositionNormalized); 240 | float3 dampingForce = dampingCoefficient * relativeVelocity; 241 | 242 | // tangential force (Equation 12) 243 | float3 tangentialVelocity = relativeVelocity - (dot(relativeVelocity, relativePositionNormalized) * relativePositionNormalized); 244 | float3 tangentialForce = tangentialCoefficient * tangentialVelocity; 245 | 246 | return repulsiveForce + dampingForce + tangentialForce; 247 | 248 | } 249 | 250 | return float3(0.0f,0.0f,0.0f); 251 | } 252 | 253 | // Returns the grid location for particle p 254 | int3 _gridIndexThree(int p_id) { 255 | return (particlePositions[p_id] - gridStartPosition) / particleDiameter; 256 | } 257 | 258 | // Converts a grid location to a grid index 259 | int _gridIndexFromThree(int x, int y, int z) { 260 | return x + (gridDimensions.x * y) + (gridDimensions.x * gridDimensions.y * z); 261 | } 262 | 263 | // checks cell x,y,z for collision with i, calls _collisionreaction if so 264 | float3 _checkGridCell(int i, int x, int y, int z) { 265 | float3 force = float3(0,0,0); 266 | if (x > -1 && y > -1 && z > -1 && x < gridDimensions.x && y < gridDimensions.y && z < gridDimensions.z) { 267 | int g_index = _gridIndexFromThree(x,y,z); 268 | if (g_index < gridMax) { 269 | int j = voxelCollisionGrid[g_index].x; 270 | if (j > -1 && j != i) 271 | force += _collisionReaction(j, i); 272 | 273 | j = voxelCollisionGrid[g_index].y; 274 | if (j > -1 && j != i) 275 | force +=_collisionReaction(j, i); 276 | 277 | j = voxelCollisionGrid[g_index].z; 278 | if (j > -1 && j != i) 279 | force += _collisionReaction(j, i); 280 | 281 | j = voxelCollisionGrid[g_index].w; 282 | if (j > -1 && j != i) 283 | force += _collisionReaction(j, i); 284 | } 285 | } 286 | return force; 287 | } 288 | 289 | float gravityCoefficient; 290 | [numthreads(PARTICLE_THREAD_COUNT,1,1)] 291 | void CollisionDetection (uint3 id : SV_DispatchThreadID) 292 | { 293 | int i = id.x; 294 | int3 i_gridLocation = _gridIndexThree(i); 295 | float3 force = float3(0,0,0); 296 | force += _checkGridCell(i, i_gridLocation.x, i_gridLocation.y, i_gridLocation.z); 297 | force += _checkGridCell(i, i_gridLocation.x, i_gridLocation.y, i_gridLocation.z+1); 298 | force += _checkGridCell(i, i_gridLocation.x, i_gridLocation.y, i_gridLocation.z-1); 299 | force += _checkGridCell(i, i_gridLocation.x, i_gridLocation.y+1, i_gridLocation.z); 300 | force += _checkGridCell(i, i_gridLocation.x, i_gridLocation.y+1, i_gridLocation.z+1); 301 | force += _checkGridCell(i, i_gridLocation.x, i_gridLocation.y+1, i_gridLocation.z-1); 302 | force += _checkGridCell(i, i_gridLocation.x, i_gridLocation.y-1, i_gridLocation.z); 303 | force += _checkGridCell(i, i_gridLocation.x, i_gridLocation.y-1, i_gridLocation.z+1); 304 | force += _checkGridCell(i, i_gridLocation.x, i_gridLocation.y-1, i_gridLocation.z-1); 305 | 306 | force += _checkGridCell(i, i_gridLocation.x-1, i_gridLocation.y, i_gridLocation.z); 307 | force += _checkGridCell(i, i_gridLocation.x-1, i_gridLocation.y, i_gridLocation.z+1); 308 | force += _checkGridCell(i, i_gridLocation.x-1, i_gridLocation.y, i_gridLocation.z-1); 309 | force += _checkGridCell(i, i_gridLocation.x-1, i_gridLocation.y+1, i_gridLocation.z); 310 | force += _checkGridCell(i, i_gridLocation.x-1, i_gridLocation.y+1, i_gridLocation.z+1); 311 | force += _checkGridCell(i, i_gridLocation.x-1, i_gridLocation.y+1, i_gridLocation.z-1); 312 | force += _checkGridCell(i, i_gridLocation.x-1, i_gridLocation.y-1, i_gridLocation.z); 313 | force += _checkGridCell(i, i_gridLocation.x-1, i_gridLocation.y-1, i_gridLocation.z+1); 314 | force += _checkGridCell(i, i_gridLocation.x-1, i_gridLocation.y-1, i_gridLocation.z-1); 315 | 316 | force += _checkGridCell(i, i_gridLocation.x+1, i_gridLocation.y, i_gridLocation.z); 317 | force += _checkGridCell(i, i_gridLocation.x+1, i_gridLocation.y, i_gridLocation.z+1); 318 | force += _checkGridCell(i, i_gridLocation.x+1, i_gridLocation.y, i_gridLocation.z-1); 319 | force += _checkGridCell(i, i_gridLocation.x+1, i_gridLocation.y+1, i_gridLocation.z); 320 | force += _checkGridCell(i, i_gridLocation.x+1, i_gridLocation.y+1, i_gridLocation.z+1); 321 | force += _checkGridCell(i, i_gridLocation.x+1, i_gridLocation.y+1, i_gridLocation.z-1); 322 | force += _checkGridCell(i, i_gridLocation.x+1, i_gridLocation.y-1, i_gridLocation.z); 323 | force += _checkGridCell(i, i_gridLocation.x+1, i_gridLocation.y-1, i_gridLocation.z+1); 324 | force += _checkGridCell(i, i_gridLocation.x+1, i_gridLocation.y-1, i_gridLocation.z-1); 325 | 326 | force.y -= gravityCoefficient; 327 | force += _collisionReactionWithGround(i); 328 | 329 | particleForces[i] = force; 330 | } 331 | 332 | //////////////////////////// 333 | // Computation Of Momenta // 334 | //////////////////////////// 335 | // Per RigidBdy 336 | // Use particleForces to compute the force and angular force on the rigid body 337 | // Input 338 | // RWStructuredBuffer particleForces; (defined in Collision Detection) 339 | // RWStructuredBuffer particleRelativePositions; (defined in Computation of Particle Values) 340 | 341 | float frictionCoefficient; 342 | float angularFrictionCoefficient; 343 | float angularForceScalar; 344 | float linearForceScalar; 345 | // Output 346 | //RWStructuredBuffer rigidBodyAngularVelocities; // defined in Computation Of Particle Values 347 | //RWStructuredBuffer rigidBodyVelocities; // defined in Computation Of Particle Values 348 | [numthreads(RIGID_BODY_THREAD_COUNT,1,1)] 349 | void ComputeMomenta (uint3 id : SV_DispatchThreadID) 350 | { 351 | float3 relativePosition = float3(0,0,0); 352 | float3 linearForce = float3(0,0,0); 353 | float3 angularForce = float3(0,0,0); 354 | 355 | for (int i = 0; i < particlesPerRigidBody; i++) 356 | { 357 | int p_id = id.x * particlesPerRigidBody + i; 358 | relativePosition = particleRelativePositions[p_id]; 359 | linearForce += particleForces[p_id]; 360 | angularForce += cross(relativePosition, particleForces[p_id]); 361 | } 362 | float threshold = 1.0 / pow(10.0,6); 363 | 364 | float cubeMass = particleMass * particlesPerRigidBody; 365 | rigidBodyVelocities[id.x] /= 1.0 + deltaTime*frictionCoefficient; 366 | rigidBodyVelocities[id.x] += linearForceScalar * deltaTime * linearForce/cubeMass; 367 | if (length(rigidBodyVelocities[id.x]) < threshold) { 368 | rigidBodyVelocities[id.x] = float3(0.0,0.0,0.0); 369 | } 370 | 371 | // old rotation 372 | //float3x3 rotationMatrix = quaternion_to_matrix3x3(rigidBodyQuaternions[id.x]); 373 | //float3x3 inverseInertialMatrix = mul(rotationMatrix, mul(inverseInertialTensor, transpose(rotationMatrix))); 374 | //rigidBodyAngularVelocities[id.x] += deltaTime * mul(inverseInertialMatrix, angularForce); // probably wrong 375 | 376 | // new rotation 377 | rigidBodyAngularVelocities[id.x] /= 1.0 + deltaTime*angularFrictionCoefficient; 378 | rigidBodyAngularVelocities[id.x] += angularForceScalar * deltaTime * angularForce; // probably wrong 379 | if (length(rigidBodyAngularVelocities[id.x]) < threshold) { 380 | rigidBodyAngularVelocities[id.x] = float3(0.0,0.0,0.0); 381 | } 382 | } 383 | 384 | ///////////////////////////// 385 | // Computation Of Position // 386 | ///////////////////////////// 387 | // Per RigidBody 388 | // Use rigidBodyForce and rigidBodyTorque to compute the rigid body position and rotation. 389 | // Input 390 | 391 | // RWStructuredBuffer rigidBodyForce defined in (Computation Of Momenta) 392 | // RWStructuredBuffer rigidBodyTorque defined in (Computation Of Momenta) 393 | // Output 394 | // RWStructuredBuffer rigidBodyPosition; // defined in Computation Of Particle Values 395 | // RWStructuredBuffer rigidBodyQuaternions; 396 | RWStructuredBuffer inverseInertialMatrices; 397 | [numthreads(RIGID_BODY_THREAD_COUNT,1,1)] 398 | void ComputePositionAndRotation (uint3 id : SV_DispatchThreadID) 399 | { 400 | // integrate position 401 | rigidBodyPositions[id.x] = rigidBodyPositions[id.x] + rigidBodyVelocities[id.x] * deltaTime; 402 | 403 | // integration of angular velocity taken from 404 | // "Essential Mathematics for Games and Interactive Applications" 405 | // by James Van Verth and Lars Bishop 406 | 407 | // attempt #1 to apply the inverse inertial tensor.... 408 | // float3x3 rotationMatrix = quaternion_to_matrix3x3(rigidBodyQuaternions[id.x]); 409 | // float3x3 inverseInertialMatrix = mul(rotationMatrix, mul(inverseInertialTensor, transpose(rotationMatrix))); 410 | // inverseInertialMatrices[id.x] = inverseInertialMatrix; 411 | // float3 rigidBodyAngularVelocity = mul(inverseInertialMatrix, rigidBodyAngularVelocities[id.x]); 412 | 413 | 414 | // attempt #2 to apply the inverse inertial tensor.... 415 | // float3x3 rotationMatrix = quaternion_to_matrix3x3(rigidBodyQuaternions[id.x]); 416 | // float3x3 inverseInertialMatrix = mul(rotationMatrix, mul(inverseInertialTensor, transpose(rotationMatrix))); 417 | // inverseInertialMatrices[id.x] = inverseInertialMatrix; 418 | // float3 rigidBodyAngularVelocity = mul(inverseInertialTensor, rigidBodyAngularVelocities[id.x]); 419 | // old rotation 420 | float3 rigidBodyAngularVelocity = rigidBodyAngularVelocities[id.x]; 421 | 422 | 423 | 424 | 425 | // old 426 | //float4 omega = float4(0, rigidBodyAngularVelocities[id.x]); 427 | // new 428 | float4 omega = float4(rigidBodyAngularVelocity, 0); 429 | 430 | float4 q = rigidBodyQuaternions[id.x]; 431 | rigidBodyQuaternions[id.x] = normalize(q + deltaTime * (0.5*quat_concat(omega, q))); 432 | } 433 | 434 | RWStructuredBuffer previousRigidBodyPositions; 435 | RWStructuredBuffer previousRigidBodyQuaternions; 436 | [numthreads(RIGID_BODY_THREAD_COUNT,1,1)] 437 | void SavePreviousPositionAndRotation (uint3 id : SV_DispatchThreadID) 438 | { 439 | previousRigidBodyPositions[id.x] = rigidBodyPositions[id.x]; 440 | previousRigidBodyQuaternions[id.x] = rigidBodyQuaternions[id.x]; 441 | } 442 | -------------------------------------------------------------------------------- /Assets/Physics/GPUPhysicsComputeShader.compute.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f440a7a83056b48f18954c9311cb278d 3 | timeCreated: 1483657492 4 | licenseType: Pro 5 | ComputeShaderImporter: 6 | currentAPIMask: 131072 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/InstancedIndirectMaterial.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/InstancedIndirectMaterial.mat -------------------------------------------------------------------------------- /Assets/Physics/InstancedIndirectMaterial.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e2809ba4012e04529ba068367156e818 3 | timeCreated: 1490824695 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/InstancedIndirectSurfaceShader.shader: -------------------------------------------------------------------------------- 1 | Shader "Instanced/InstancedIndirectSurfaceShader" { 2 | Properties { 3 | _Color ("Color", Color) = (1,1,1,1) 4 | _Glossiness ("Smoothness", Range(0,1)) = 0.5 5 | _Metallic ("Metallic", Range(0,1)) = 0.0 6 | } 7 | SubShader { 8 | Tags { "RenderType"="Opaque" } 9 | LOD 200 10 | 11 | CGPROGRAM 12 | #include "Quaternion.cginc" 13 | // Physically based Standard lighting model, and enable shadows on all light types 14 | // And generate the shadow pass with instancing support 15 | #pragma surface surf Standard addshadow 16 | // #pragma surface surfStandard Standard fullforwardshadows addshadow 17 | // Use shader model 3.0 target, to get nicer looking lighting 18 | #pragma target 3.0 19 | 20 | // Enable instancing for this shader 21 | #pragma multi_compile_instancing 22 | #pragma instancing_options procedural:setup 23 | 24 | // Config maxcount. See manual page. 25 | // #pragma instancing_options 26 | 27 | fixed4 _Color; 28 | half _Glossiness; 29 | half _Metallic; 30 | 31 | struct Input { 32 | float2 uv_MainTex; 33 | }; 34 | 35 | 36 | #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 37 | StructuredBuffer positions; 38 | StructuredBuffer quaternions; 39 | StructuredBuffer previousPositions; 40 | StructuredBuffer previousQuaternions; 41 | float blendAlpha; 42 | #endif 43 | 44 | void setup() 45 | { 46 | #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 47 | //float4x4 rotation = quaternion_to_matrix(nlerp(previousQuaternions[unity_InstanceID], quaternions[unity_InstanceID], blendAlpha)); 48 | float4x4 rotation = quaternion_to_matrix(quaternions[unity_InstanceID]); 49 | //float3 position = lerp(previousPositions[unity_InstanceID], positions[unity_InstanceID], blendAlpha); 50 | float3 position = positions[unity_InstanceID]; 51 | float4x4 translation = { 52 | 1,0,0,position.x, 53 | 0,1,0,position.y, 54 | 0,0,1,position.z, 55 | 0,0,0,1 56 | }; 57 | unity_ObjectToWorld = mul(translation, rotation); 58 | 59 | 60 | // inverse transform matrix 61 | // taken from richardkettlewell's post on 62 | // https://forum.unity3d.com/threads/drawmeshinstancedindirect-example-comments-and-questions.446080/ 63 | 64 | float3x3 w2oRotation; 65 | w2oRotation[0] = unity_ObjectToWorld[1].yzx * unity_ObjectToWorld[2].zxy - unity_ObjectToWorld[1].zxy * unity_ObjectToWorld[2].yzx; 66 | w2oRotation[1] = unity_ObjectToWorld[0].zxy * unity_ObjectToWorld[2].yzx - unity_ObjectToWorld[0].yzx * unity_ObjectToWorld[2].zxy; 67 | w2oRotation[2] = unity_ObjectToWorld[0].yzx * unity_ObjectToWorld[1].zxy - unity_ObjectToWorld[0].zxy * unity_ObjectToWorld[1].yzx; 68 | 69 | float det = dot(unity_ObjectToWorld[0], w2oRotation[0]); 70 | 71 | w2oRotation = transpose(w2oRotation); 72 | 73 | w2oRotation *= rcp(det); 74 | 75 | float3 w2oPosition = mul(w2oRotation, -unity_ObjectToWorld._14_24_34); 76 | 77 | 78 | unity_WorldToObject._11_21_31_41 = float4(w2oRotation._11_21_31, 0.0f); 79 | unity_WorldToObject._12_22_32_42 = float4(w2oRotation._12_22_32, 0.0f); 80 | unity_WorldToObject._13_23_33_43 = float4(w2oRotation._13_23_33, 0.0f); 81 | unity_WorldToObject._14_24_34_44 = float4(w2oPosition, 1.0f); 82 | #endif 83 | } 84 | 85 | 86 | // Declare instanced properties inside a cbuffer. 87 | // Each instanced property is an array of by default 500(D3D)/128(GL) elements. Since D3D and GL imposes a certain limitation 88 | // of 64KB and 16KB respectively on the size of a cubffer, the default array size thus allows two matrix arrays in one cbuffer. 89 | // Use maxcount option on #pragma instancing_options directive to specify array size other than default (divided by 4 when used 90 | // for GL). 91 | //UNITY_INSTANCING_CBUFFER_START(Props) 92 | // UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) // Make _Color an instanced property (i.e. an array) 93 | //UNITY_INSTANCING_CBUFFER_END 94 | 95 | void surf (Input IN, inout SurfaceOutputStandard o) { 96 | // Albedo comes from a texture tinted by color 97 | fixed4 c = _Color; 98 | o.Albedo = c.rgb; 99 | // Metallic and smoothness come from slider variables 100 | o.Metallic = _Metallic; 101 | o.Smoothness = _Glossiness; 102 | o.Alpha = c.a; 103 | } 104 | 105 | ENDCG 106 | } 107 | FallBack "Diffuse" 108 | } 109 | -------------------------------------------------------------------------------- /Assets/Physics/InstancedIndirectSurfaceShader.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ae0df13cb207e4a81af0f927232cc227 3 | timeCreated: 1490824669 4 | licenseType: Pro 5 | ShaderImporter: 6 | defaultTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/InstancedIndirectSurfaceShaderNoRotation.shader: -------------------------------------------------------------------------------- 1 | Shader "Instanced/InstancedIndirectSurfaceShaderNoRotation" { 2 | Properties { 3 | _Color ("Color", Color) = (1,1,1,1) 4 | _Glossiness ("Smoothness", Range(0,1)) = 0.5 5 | _Metallic ("Metallic", Range(0,1)) = 0.0 6 | } 7 | SubShader { 8 | Tags { "RenderType"="Opaque" } 9 | LOD 200 10 | 11 | CGPROGRAM 12 | // Physically based Standard lighting model, and enable shadows on all light types 13 | // And generate the shadow pass with instancing support 14 | #pragma surface surf Standard addshadow 15 | // #pragma surface surfStandard Standard fullforwardshadows addshadow 16 | // Use shader model 3.0 target, to get nicer looking lighting 17 | #pragma target 3.0 18 | 19 | // Enable instancing for this shader 20 | #pragma multi_compile_instancing 21 | #pragma instancing_options procedural:setup 22 | 23 | // Config maxcount. See manual page. 24 | // #pragma instancing_options 25 | 26 | fixed4 _Color; 27 | half _Glossiness; 28 | half _Metallic; 29 | 30 | struct Input { 31 | float2 uv_MainTex; 32 | }; 33 | 34 | float4 scale; 35 | #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 36 | StructuredBuffer positions; 37 | 38 | #endif 39 | 40 | void setup() 41 | { 42 | #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 43 | float3 position = positions[unity_InstanceID]; 44 | float4x4 worldPositionAndScale = { 45 | scale.x,0,0,position.x, 46 | 0,scale.y,0,position.y, 47 | 0,0,scale.z,position.z, 48 | 0,0,0,1 49 | }; 50 | unity_ObjectToWorld = worldPositionAndScale; 51 | // inverse transform matrix 52 | // taken from richardkettlewell's post on 53 | // https://forum.unity3d.com/threads/drawmeshinstancedindirect-example-comments-and-questions.446080/ 54 | 55 | float3x3 w2oRotation; 56 | w2oRotation[0] = unity_ObjectToWorld[1].yzx * unity_ObjectToWorld[2].zxy - unity_ObjectToWorld[1].zxy * unity_ObjectToWorld[2].yzx; 57 | w2oRotation[1] = unity_ObjectToWorld[0].zxy * unity_ObjectToWorld[2].yzx - unity_ObjectToWorld[0].yzx * unity_ObjectToWorld[2].zxy; 58 | w2oRotation[2] = unity_ObjectToWorld[0].yzx * unity_ObjectToWorld[1].zxy - unity_ObjectToWorld[0].zxy * unity_ObjectToWorld[1].yzx; 59 | 60 | float det = dot(unity_ObjectToWorld[0], w2oRotation[0]); 61 | 62 | w2oRotation = transpose(w2oRotation); 63 | 64 | w2oRotation *= rcp(det); 65 | 66 | float3 w2oPosition = mul(w2oRotation, -unity_ObjectToWorld._14_24_34); 67 | 68 | unity_WorldToObject._11_21_31_41 = float4(w2oRotation._11_21_31, 0.0f); 69 | unity_WorldToObject._12_22_32_42 = float4(w2oRotation._12_22_32, 0.0f); 70 | unity_WorldToObject._13_23_33_43 = float4(w2oRotation._13_23_33, 0.0f); 71 | unity_WorldToObject._14_24_34_44 = float4(w2oPosition, 1.0f); 72 | #endif 73 | } 74 | 75 | 76 | // Declare instanced properties inside a cbuffer. 77 | // Each instanced property is an array of by default 500(D3D)/128(GL) elements. Since D3D and GL imposes a certain limitation 78 | // of 64KB and 16KB respectively on the size of a cubffer, the default array size thus allows two matrix arrays in one cbuffer. 79 | // Use maxcount option on #pragma instancing_options directive to specify array size other than default (divided by 4 when used 80 | // for GL). 81 | //UNITY_INSTANCING_CBUFFER_START(Props) 82 | // UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) // Make _Color an instanced property (i.e. an array) 83 | //UNITY_INSTANCING_CBUFFER_END 84 | 85 | void surf (Input IN, inout SurfaceOutputStandard o) { 86 | // Albedo comes from a texture tinted by color 87 | fixed4 c = _Color; 88 | o.Albedo = c.rgb; 89 | // Metallic and smoothness come from slider variables 90 | o.Metallic = _Metallic; 91 | o.Smoothness = _Glossiness; 92 | o.Alpha = c.a; 93 | } 94 | 95 | ENDCG 96 | } 97 | FallBack "Diffuse" 98 | } 99 | -------------------------------------------------------------------------------- /Assets/Physics/InstancedIndirectSurfaceShaderNoRotation.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 123856b5807caf744942bb236785a78b 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/Math.cginc: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* 3 | Project - Unity CJ Lib 4 | https://github.com/TheAllenChou/unity-cj-lib 5 | 6 | Author - Ming-Lun "Allen" Chou 7 | Web - http://AllenChou.net 8 | Twitter - @TheAllenChou 9 | */ 10 | /******************************************************************************/ 11 | 12 | #ifndef CJ_LIB_MATH 13 | #define CJ_LIB_MATH 14 | 15 | #define kPi (3.1415926535) 16 | #define kTwoPi (6.2831853071) 17 | #define kHalfPi (1.5707963267) 18 | #define kThirdPi (1.0471975511) 19 | #define kQuaterPi (0.7853981633) 20 | #define kFifthPi (0.6283185307) 21 | #define kSixthPi (0.5235987755) 22 | 23 | #define kSqrt2 (1.4142135623) 24 | #define kSqrt3 (1.7320508075) 25 | #define kSqrt2Inv (0.7071067811) 26 | #define kSqrt3Inv (0.5773502691) 27 | 28 | #define kEpsilon (0.0000000001) 29 | #define kEpsilonComp (0.9999999999) 30 | 31 | #define kRad2Deg (57.295779513) 32 | #define kDeg2Rad (0.0174532925) 33 | 34 | #include "Color.cginc" 35 | #include "Quaternion.cginc" 36 | #include "Vector.cginc" 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Assets/Physics/Math.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cbc2d2d27ca839e4a9a2e5662fd714ad 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/Particle.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/Particle.mat -------------------------------------------------------------------------------- /Assets/Physics/Particle.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d315fea00a36764c9226eb565d21116 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/ParticleForceLineMaterial.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/ParticleForceLineMaterial.mat -------------------------------------------------------------------------------- /Assets/Physics/ParticleForceLineMaterial.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 74605ee591d3be844b20a229dcfe0267 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/ParticleForceLineShader.shader: -------------------------------------------------------------------------------- 1 |  Shader "Instanced/ParticleForceLineShader" 2 | { 3 | Properties 4 | { 5 | _Color ("Color", Color) = (1, 1, 1, 1) 6 | } 7 | 8 | SubShader 9 | { 10 | Tags { "RenderType"="Opaque" } 11 | LOD 100 12 | 13 | Pass 14 | { 15 | CGPROGRAM 16 | #include "UnityCG.cginc" 17 | #pragma vertex vert 18 | #pragma fragment frag 19 | #pragma multi_compile_instancing 20 | #pragma instancing_options procedural:setup 21 | void setup() {} 22 | 23 | 24 | struct appdata 25 | { 26 | float4 vertex : POSITION; 27 | UNITY_VERTEX_INPUT_INSTANCE_ID 28 | }; 29 | 30 | struct v2f 31 | { 32 | float4 vertex : SV_POSITION; 33 | }; 34 | 35 | float4 _Color; 36 | 37 | 38 | StructuredBuffer positions; 39 | StructuredBuffer vectors; 40 | 41 | v2f vert(appdata v) 42 | { 43 | v2f o; 44 | 45 | UNITY_SETUP_INSTANCE_ID(v); 46 | #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 47 | int instance_id = UNITY_GET_INSTANCE_ID(v); 48 | float3 position = positions[instance_id]; 49 | float3 vect = vectors[instance_id]; 50 | //vect = float3(0,0,0); 51 | float3 endPoint = float3(50*vect.x * v.vertex.x, 50*vect.y * v.vertex.y, 50*vect.z * v.vertex.z); 52 | 53 | o.vertex = UnityObjectToClipPos(position + endPoint); 54 | #else 55 | o.vertex = UnityObjectToClipPos(v.vertex); 56 | #endif 57 | return o; 58 | } 59 | 60 | fixed4 frag(v2f i) : SV_Target 61 | { 62 | return _Color; 63 | } 64 | ENDCG 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Assets/Physics/ParticleForceLineShader.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 128fff63a3658b34e8166319b323076d 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/PrimitiveMeshFactory.cs: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* 3 | Project - Unity CJ Lib 4 | https://github.com/TheAllenChou/unity-cj-lib 5 | 6 | Author - Ming-Lun "Allen" Chou 7 | Web - http://AllenChou.net 8 | Twitter - @TheAllenChou 9 | */ 10 | /******************************************************************************/ 11 | 12 | using System; 13 | using System.Collections.Generic; 14 | using UnityEngine; 15 | 16 | namespace CjLib 17 | { 18 | // DO NOT modify nor keep references to the meshes returned by this factory 19 | // because they are from shared pools of cached meshes 20 | public class PrimitiveMeshFactory 21 | { 22 | 23 | // line 24 | // ------------------------------------------------------------------------ 25 | 26 | public static Mesh Line(Vector3 v0, Vector3 v1) 27 | { 28 | Mesh mesh = new Mesh(); 29 | 30 | Vector3[] aVert = { v0, v1 }; 31 | int[] aIndex = { 0, 1 }; 32 | 33 | mesh.vertices = aVert; 34 | mesh.SetIndices(aIndex, MeshTopology.Lines, 0); 35 | 36 | return mesh; 37 | } 38 | 39 | public static Mesh Lines(Vector3[] aVert) 40 | { 41 | if (aVert.Length <= 1) 42 | return null; 43 | 44 | Mesh mesh = new Mesh(); 45 | 46 | int[] aIndex = new int[aVert.Length]; 47 | for (int i = 0; i < aVert.Length; ++i) 48 | { 49 | aIndex[i] = i; 50 | } 51 | 52 | mesh.vertices = aVert; 53 | mesh.SetIndices(aIndex, MeshTopology.Lines, 0); 54 | 55 | return mesh; 56 | } 57 | 58 | public static Mesh LineStrip(Vector3[] aVert) 59 | { 60 | if (aVert.Length <= 1) 61 | return null; 62 | 63 | Mesh mesh = new Mesh(); 64 | 65 | int[] aIndex = new int[aVert.Length]; 66 | for (int i = 0; i < aVert.Length; ++i) 67 | { 68 | aIndex[i] = i; 69 | } 70 | 71 | mesh.vertices = aVert; 72 | mesh.SetIndices(aIndex, MeshTopology.LineStrip, 0); 73 | 74 | return mesh; 75 | } 76 | 77 | // ------------------------------------------------------------------------ 78 | // end: line 79 | 80 | 81 | // box 82 | // ------------------------------------------------------------------------ 83 | 84 | private static Mesh s_boxWireframeMesh; 85 | private static Mesh s_boxSolidColorMesh; 86 | private static Mesh s_boxFlatShadedMesh; 87 | 88 | public static Mesh BoxWireframe() 89 | { 90 | if (s_boxWireframeMesh == null) 91 | { 92 | s_boxWireframeMesh = new Mesh(); 93 | 94 | Vector3[] aVert = 95 | { 96 | new Vector3(-0.5f, -0.5f, -0.5f), 97 | new Vector3(-0.5f, 0.5f, -0.5f), 98 | new Vector3( 0.5f, 0.5f, -0.5f), 99 | new Vector3( 0.5f, -0.5f, -0.5f), 100 | new Vector3(-0.5f, -0.5f, 0.5f), 101 | new Vector3(-0.5f, 0.5f, 0.5f), 102 | new Vector3( 0.5f, 0.5f, 0.5f), 103 | new Vector3( 0.5f, -0.5f, 0.5f), 104 | }; 105 | 106 | int[] aIndex = 107 | { 108 | 0, 1, 109 | 1, 2, 110 | 2, 3, 111 | 3, 0, 112 | 2, 6, 113 | 6, 7, 114 | 7, 3, 115 | 7, 4, 116 | 4, 5, 117 | 5, 6, 118 | 5, 1, 119 | 1, 0, 120 | 0, 4, 121 | }; 122 | 123 | s_boxWireframeMesh.vertices = aVert; 124 | s_boxWireframeMesh.normals = aVert; // for GizmosUtil 125 | s_boxWireframeMesh.SetIndices(aIndex, MeshTopology.Lines, 0); 126 | } 127 | 128 | return s_boxWireframeMesh; 129 | } 130 | 131 | public static Mesh BoxSolidColor() 132 | { 133 | if (s_boxSolidColorMesh == null) 134 | { 135 | s_boxSolidColorMesh = new Mesh(); 136 | 137 | Vector3[] aVert = 138 | { 139 | new Vector3(-0.5f, -0.5f, -0.5f), 140 | new Vector3(-0.5f, 0.5f, -0.5f), 141 | new Vector3( 0.5f, 0.5f, -0.5f), 142 | new Vector3( 0.5f, -0.5f, -0.5f), 143 | new Vector3(-0.5f, -0.5f, 0.5f), 144 | new Vector3(-0.5f, 0.5f, 0.5f), 145 | new Vector3( 0.5f, 0.5f, 0.5f), 146 | new Vector3( 0.5f, -0.5f, 0.5f), 147 | }; 148 | 149 | int[] aIndex = 150 | { 151 | 0, 1, 2, 0, 2, 3, 152 | 3, 2, 6, 3, 6, 7, 153 | 7, 6, 5, 7, 5, 4, 154 | 4, 5, 1, 4, 1, 0, 155 | 1, 5, 6, 1, 6, 2, 156 | 0, 3, 7, 0, 7, 4, 157 | }; 158 | 159 | s_boxSolidColorMesh.vertices = aVert; 160 | s_boxSolidColorMesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 161 | } 162 | 163 | return s_boxSolidColorMesh; 164 | } 165 | 166 | public static Mesh BoxFlatShaded() 167 | { 168 | if (s_boxFlatShadedMesh == null) 169 | { 170 | s_boxFlatShadedMesh = new Mesh(); 171 | 172 | Vector3[] aRawVert = 173 | { 174 | new Vector3(-0.5f, -0.5f, -0.5f), 175 | new Vector3(-0.5f, 0.5f, -0.5f), 176 | new Vector3( 0.5f, 0.5f, -0.5f), 177 | new Vector3( 0.5f, -0.5f, -0.5f), 178 | new Vector3(-0.5f, -0.5f, 0.5f), 179 | new Vector3(-0.5f, 0.5f, 0.5f), 180 | new Vector3( 0.5f, 0.5f, 0.5f), 181 | new Vector3( 0.5f, -0.5f, 0.5f), 182 | }; 183 | 184 | Vector3[] aVert = 185 | { 186 | aRawVert[0], aRawVert[1], aRawVert[2], aRawVert[0], aRawVert[2], aRawVert[3], 187 | aRawVert[3], aRawVert[2], aRawVert[6], aRawVert[3], aRawVert[6], aRawVert[7], 188 | aRawVert[7], aRawVert[6], aRawVert[5], aRawVert[7], aRawVert[5], aRawVert[4], 189 | aRawVert[4], aRawVert[5], aRawVert[1], aRawVert[4], aRawVert[1], aRawVert[0], 190 | aRawVert[1], aRawVert[5], aRawVert[6], aRawVert[1], aRawVert[6], aRawVert[2], 191 | aRawVert[0], aRawVert[3], aRawVert[7], aRawVert[0], aRawVert[7], aRawVert[4], 192 | }; 193 | 194 | Vector3[] aRawNormal = 195 | { 196 | new Vector3( 0.0f, 0.0f, -1.0f), 197 | new Vector3( 1.0f, 0.0f, 0.0f), 198 | new Vector3( 0.0f, 0.0f, 1.0f), 199 | new Vector3(-1.0f, 0.0f, 0.0f), 200 | new Vector3( 0.0f, 1.0f, 0.0f), 201 | new Vector3( 0.0f, -1.0f, 0.0f), 202 | }; 203 | 204 | Vector3[] aNormal = 205 | { 206 | aRawNormal[0], aRawNormal[0], aRawNormal[0], aRawNormal[0], aRawNormal[0], aRawNormal[0], 207 | aRawNormal[1], aRawNormal[1], aRawNormal[1], aRawNormal[1], aRawNormal[1], aRawNormal[1], 208 | aRawNormal[2], aRawNormal[2], aRawNormal[2], aRawNormal[2], aRawNormal[2], aRawNormal[2], 209 | aRawNormal[3], aRawNormal[3], aRawNormal[3], aRawNormal[3], aRawNormal[3], aRawNormal[3], 210 | aRawNormal[4], aRawNormal[4], aRawNormal[4], aRawNormal[4], aRawNormal[4], aRawNormal[4], 211 | aRawNormal[5], aRawNormal[5], aRawNormal[5], aRawNormal[5], aRawNormal[5], aRawNormal[5], 212 | }; 213 | 214 | int[] aIndex = new int[aVert.Length]; 215 | for (int i = 0; i < aIndex.Length; ++i) 216 | { 217 | aIndex[i] = i; 218 | } 219 | 220 | s_boxFlatShadedMesh.vertices = aVert; 221 | s_boxFlatShadedMesh.normals = aNormal; 222 | s_boxFlatShadedMesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 223 | } 224 | 225 | return s_boxFlatShadedMesh; 226 | } 227 | 228 | // ------------------------------------------------------------------------ 229 | // end: box 230 | 231 | 232 | // rect 233 | // ------------------------------------------------------------------------ 234 | 235 | private static Mesh s_rectWireframeMesh; 236 | private static Mesh s_rectSolidColorMesh; 237 | private static Mesh s_rectFlatShadedMesh; 238 | 239 | // rectangle on the XZ plane centered at origin in object space, dimensions = (X dimension, Z dimension) 240 | public static Mesh RectWireframe() 241 | { 242 | if (s_rectWireframeMesh == null) 243 | { 244 | s_rectWireframeMesh = new Mesh(); 245 | 246 | Vector3[] aVert = 247 | { 248 | new Vector3(-0.5f, 0.0f, -0.5f), 249 | new Vector3(-0.5f, 0.0f, 0.5f), 250 | new Vector3( 0.5f, 0.0f, 0.5f), 251 | new Vector3( 0.5f, 0.0f, -0.5f), 252 | }; 253 | 254 | int[] aIndex = 255 | { 256 | 0, 1, 257 | 1, 2, 258 | 2, 3, 259 | 3, 0, 260 | }; 261 | 262 | s_rectWireframeMesh.vertices = aVert; 263 | s_rectWireframeMesh.normals = aVert; // for GizmosUtil 264 | s_rectWireframeMesh.SetIndices(aIndex, MeshTopology.Lines, 0); 265 | } 266 | 267 | return s_rectWireframeMesh; 268 | } 269 | 270 | // rectangle on the XZ plane centered at origin in object space, dimensions = (X dimension, Z dimension) 271 | public static Mesh RectSolidColor() 272 | { 273 | if (s_rectSolidColorMesh == null) 274 | { 275 | s_rectSolidColorMesh = new Mesh(); 276 | 277 | Vector3[] aVert = 278 | { 279 | new Vector3(-0.5f, 0.0f, -0.5f), 280 | new Vector3(-0.5f, 0.0f, 0.5f), 281 | new Vector3( 0.5f, 0.0f, 0.5f), 282 | new Vector3( 0.5f, 0.0f, -0.5f), 283 | }; 284 | 285 | int[] aIndex = 286 | { 287 | 0, 1, 2, 0, 2, 3, 288 | 0, 2, 1, 0, 3, 2, 289 | }; 290 | 291 | s_rectSolidColorMesh.vertices = aVert; 292 | s_rectSolidColorMesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 293 | } 294 | 295 | return s_rectSolidColorMesh; 296 | } 297 | 298 | // rectangle on the XZ plane centered at origin in object space, dimensions = (X dimension, Z dimension) 299 | public static Mesh RectFlatShaded() 300 | { 301 | if (s_rectFlatShadedMesh == null) 302 | { 303 | s_rectFlatShadedMesh = new Mesh(); 304 | 305 | Vector3[] aVert = 306 | { 307 | new Vector3(-0.5f, 0.0f, -0.5f), 308 | new Vector3(-0.5f, 0.0f, 0.5f), 309 | new Vector3( 0.5f, 0.0f, 0.5f), 310 | new Vector3( 0.5f, 0.0f, -0.5f), 311 | new Vector3(-0.5f, 0.0f, -0.5f), 312 | new Vector3(-0.5f, 0.0f, 0.5f), 313 | new Vector3( 0.5f, 0.0f, 0.5f), 314 | new Vector3( 0.5f, 0.0f, -0.5f), 315 | }; 316 | 317 | Vector3[] aNormal = 318 | { 319 | new Vector3(0.0f, 1.0f, 0.0f), 320 | new Vector3(0.0f, 1.0f, 0.0f), 321 | new Vector3(0.0f, 1.0f, 0.0f), 322 | new Vector3(0.0f, 1.0f, 0.0f), 323 | new Vector3(0.0f, -1.0f, 0.0f), 324 | new Vector3(0.0f, -1.0f, 0.0f), 325 | new Vector3(0.0f, -1.0f, 0.0f), 326 | new Vector3(0.0f, -1.0f, 0.0f), 327 | }; 328 | 329 | int[] aIndex = 330 | { 331 | 0, 1, 2, 0, 2, 3, 332 | 4, 6, 5, 4, 7, 6, 333 | }; 334 | 335 | s_rectFlatShadedMesh.vertices = aVert; 336 | s_rectFlatShadedMesh.normals = aNormal; 337 | s_rectFlatShadedMesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 338 | } 339 | 340 | return s_rectFlatShadedMesh; 341 | } 342 | 343 | // ------------------------------------------------------------------------ 344 | // end: rect 345 | 346 | 347 | // circle 348 | // ------------------------------------------------------------------------ 349 | 350 | private static Dictionary s_circleWireframeMeshPool; 351 | private static Dictionary s_circleSolidColorMeshPool; 352 | private static Dictionary s_circleFlatShadedMeshPool; 353 | 354 | // draw a circle on the XZ plane centered at origin in object space 355 | public static Mesh CircleWireframe(int numSegments) 356 | { 357 | if (numSegments <= 1) 358 | return null; 359 | 360 | if (s_circleWireframeMeshPool == null) 361 | s_circleWireframeMeshPool = new Dictionary(); 362 | 363 | Mesh mesh; 364 | if (!s_circleWireframeMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 365 | { 366 | mesh = new Mesh(); 367 | 368 | Vector3[] aVert = new Vector3[numSegments]; 369 | int[] aIndex = new int[numSegments + 1]; 370 | 371 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 372 | float angle = 0.0f; 373 | for (int i = 0; i < numSegments; ++i) 374 | { 375 | aVert[i] = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 376 | aIndex[i] = i; 377 | angle += angleIncrement; 378 | } 379 | aIndex[numSegments] = 0; 380 | 381 | mesh.vertices = aVert; 382 | mesh.normals = aVert; // for GizmosUtil 383 | mesh.SetIndices(aIndex, MeshTopology.LineStrip, 0); 384 | 385 | if (s_circleWireframeMeshPool.ContainsKey(numSegments)) 386 | s_circleWireframeMeshPool.Remove(numSegments); 387 | 388 | s_circleWireframeMeshPool.Add(numSegments, mesh); 389 | } 390 | 391 | return mesh; 392 | } 393 | 394 | // draw a circle on the XZ plane centered at origin in object space 395 | public static Mesh CircleSolidColor(int numSegments) 396 | { 397 | if (numSegments <= 1) 398 | return null; 399 | 400 | if (s_circleSolidColorMeshPool == null) 401 | s_circleSolidColorMeshPool = new Dictionary(); 402 | 403 | Mesh mesh; 404 | if (!s_circleSolidColorMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 405 | { 406 | mesh = new Mesh(); 407 | 408 | Vector3[] aVert = new Vector3[numSegments + 1]; 409 | int[] aIndex = new int[numSegments * 6]; 410 | 411 | int iIndex = 0; 412 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 413 | float angle = 0.0f; 414 | for (int i = 0; i < numSegments; ++i) 415 | { 416 | aVert[i] = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 417 | angle += angleIncrement; 418 | 419 | aIndex[iIndex++] = numSegments; 420 | aIndex[iIndex++] = (i + 1) % numSegments; 421 | aIndex[iIndex++] = i; 422 | aIndex[iIndex++] = numSegments; 423 | aIndex[iIndex++] = i; 424 | aIndex[iIndex++] = (i + 1) % numSegments; 425 | 426 | } 427 | aVert[numSegments] = Vector3.zero; 428 | 429 | mesh.vertices = aVert; 430 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 431 | 432 | if (s_circleSolidColorMeshPool.ContainsKey(numSegments)) 433 | s_circleSolidColorMeshPool.Remove(numSegments); 434 | 435 | s_circleSolidColorMeshPool.Add(numSegments, mesh); 436 | } 437 | 438 | return mesh; 439 | } 440 | 441 | // draw a circle on the XZ plane centered at origin in object space 442 | public static Mesh CircleFlatShaded(int numSegments) 443 | { 444 | if (numSegments <= 1) 445 | return null; 446 | 447 | if (s_circleFlatShadedMeshPool == null) 448 | s_circleFlatShadedMeshPool = new Dictionary(); 449 | 450 | Mesh mesh; 451 | if (!s_circleFlatShadedMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 452 | { 453 | mesh = new Mesh(); 454 | 455 | Vector3[] aVert = new Vector3[(numSegments + 1) * 2]; 456 | Vector3[] aNormal = new Vector3[aVert.Length]; 457 | int[] aIndex = new int[numSegments * 6]; 458 | 459 | int iIndex = 0; 460 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 461 | float angle = 0.0f; 462 | for (int i = 0; i < numSegments; ++i) 463 | { 464 | aVert[i] = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 465 | angle += angleIncrement; 466 | 467 | aNormal[i] = new Vector3(0.0f, 1.0f, 0.0f); 468 | 469 | aIndex[iIndex++] = numSegments; 470 | aIndex[iIndex++] = (i + 1) % numSegments; 471 | aIndex[iIndex++] = i; 472 | } 473 | aVert[numSegments] = Vector3.zero; 474 | aNormal[numSegments] = new Vector3(0.0f, 1.0f, 0.0f); 475 | angle = 0.0f; 476 | for (int i = 0; i < numSegments; ++i) 477 | { 478 | aVert[i + numSegments + 1] = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 479 | angle -= angleIncrement; 480 | 481 | aNormal[i + numSegments + 1] = new Vector3(0.0f, -1.0f, 0.0f); 482 | 483 | aIndex[iIndex++] = numSegments * 2 + 1; 484 | aIndex[iIndex++] = ((i + 1) % numSegments) + numSegments + 1; 485 | aIndex[iIndex++] = i + (numSegments + 1); 486 | } 487 | aVert[numSegments * 2 + 1] = Vector3.zero; 488 | aNormal[numSegments * 2 + 1] = new Vector3(0.0f, -1.0f, 0.0f); 489 | 490 | mesh.vertices = aVert; 491 | mesh.normals = aNormal; 492 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 493 | 494 | if (s_circleFlatShadedMeshPool.ContainsKey(numSegments)) 495 | s_circleFlatShadedMeshPool.Remove(numSegments); 496 | 497 | s_circleFlatShadedMeshPool.Add(numSegments, mesh); 498 | } 499 | 500 | return mesh; 501 | } 502 | 503 | // ------------------------------------------------------------------------ 504 | // end: circle 505 | 506 | 507 | // cylinder 508 | // ------------------------------------------------------------------------ 509 | 510 | private static Dictionary s_cylinderWireframeMeshPool; 511 | private static Dictionary s_cylinderSolidColorMeshPool; 512 | private static Dictionary s_cylinderFlatShadedMeshPool; 513 | private static Dictionary s_cylinderSmoothShadedMeshPool; 514 | 515 | public static Mesh CylinderWireframe(int numSegments) 516 | { 517 | if (numSegments <= 1) 518 | return null; 519 | 520 | if (s_cylinderWireframeMeshPool == null) 521 | s_cylinderWireframeMeshPool = new Dictionary(); 522 | 523 | Mesh mesh; 524 | if (!s_cylinderWireframeMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 525 | { 526 | mesh = new Mesh(); 527 | 528 | Vector3[] aVert = new Vector3[numSegments * 2]; 529 | int[] aIndex = new int[numSegments * 6]; 530 | 531 | Vector3 bottom = new Vector3(0.0f, -0.5f, 0.0f); 532 | Vector3 top = new Vector3(0.0f, 0.5f, 0.0f); 533 | 534 | int iIndex = 0; 535 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 536 | float angle = 0.0f; 537 | for (int i = 0; i < numSegments; ++i) 538 | { 539 | Vector3 offset = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 540 | aVert[i] = bottom + offset; 541 | aVert[numSegments + i] = top + offset; 542 | 543 | aIndex[iIndex++] = i; 544 | aIndex[iIndex++] = ((i + 1) % numSegments); 545 | 546 | aIndex[iIndex++] = i; 547 | aIndex[iIndex++] = numSegments + i; 548 | 549 | aIndex[iIndex++] = numSegments + i; 550 | aIndex[iIndex++] = numSegments + ((i + 1) % numSegments); 551 | 552 | angle += angleIncrement; 553 | } 554 | 555 | mesh.vertices = aVert; 556 | mesh.normals = aVert; // for GizmosUtil 557 | mesh.SetIndices(aIndex, MeshTopology.Lines, 0); 558 | 559 | if (s_cylinderWireframeMeshPool.ContainsKey(numSegments)) 560 | s_cylinderWireframeMeshPool.Remove(numSegments); 561 | 562 | s_cylinderWireframeMeshPool.Add(numSegments, mesh); 563 | } 564 | 565 | return mesh; 566 | } 567 | 568 | public static Mesh CylinderSolidColor(int numSegments) 569 | { 570 | if (numSegments <= 1) 571 | return null; 572 | 573 | if (s_cylinderSolidColorMeshPool == null) 574 | s_cylinderSolidColorMeshPool = new Dictionary(); 575 | 576 | Mesh mesh; 577 | if (!s_cylinderSolidColorMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 578 | { 579 | mesh = new Mesh(); 580 | 581 | Vector3[] aVert = new Vector3[numSegments * 2 + 2]; 582 | int[] aIndex = new int[numSegments * 12]; 583 | 584 | Vector3 bottom = new Vector3(0.0f, -0.5f, 0.0f); 585 | Vector3 top = new Vector3(0.0f, 0.5f, 0.0f); 586 | 587 | int iBottomCapStart = 0; 588 | int iTopCapStart = numSegments; 589 | int iBottom = numSegments * 2; 590 | int iTop = numSegments * 2 + 1; 591 | 592 | aVert[iBottom] = bottom; 593 | aVert[iTop] = top; 594 | 595 | int iIndex = 0; 596 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 597 | float angle = 0.0f; 598 | for (int i = 0; i < numSegments; ++i) 599 | { 600 | Vector3 offset = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 601 | aVert[iBottomCapStart + i] = bottom + offset; 602 | aVert[iTopCapStart + i] = top + offset; 603 | 604 | aIndex[iIndex++] = iBottom; 605 | aIndex[iIndex++] = iBottomCapStart + i; 606 | aIndex[iIndex++] = iBottomCapStart + ((i + 1) % numSegments); 607 | 608 | aIndex[iIndex++] = iBottomCapStart + i; 609 | aIndex[iIndex++] = iTopCapStart + ((i + 1) % numSegments); 610 | aIndex[iIndex++] = iBottomCapStart + ((i + 1) % numSegments); 611 | 612 | aIndex[iIndex++] = iBottomCapStart + i; 613 | aIndex[iIndex++] = iTopCapStart + i; 614 | aIndex[iIndex++] = iTopCapStart + ((i + 1) % numSegments); 615 | 616 | aIndex[iIndex++] = iTop; 617 | aIndex[iIndex++] = iTopCapStart + ((i + 1) % numSegments); 618 | aIndex[iIndex++] = iTopCapStart + i; 619 | 620 | angle += angleIncrement; 621 | } 622 | 623 | mesh.vertices = aVert; 624 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 625 | 626 | if (s_cylinderSolidColorMeshPool.ContainsKey(numSegments)) 627 | s_cylinderSolidColorMeshPool.Remove(numSegments); 628 | 629 | s_cylinderSolidColorMeshPool.Add(numSegments, mesh); 630 | } 631 | 632 | return mesh; 633 | } 634 | 635 | public static Mesh CylinderFlatShaded(int numSegments) 636 | { 637 | if (numSegments <= 1) 638 | return null; 639 | 640 | if (s_cylinderFlatShadedMeshPool == null) 641 | s_cylinderFlatShadedMeshPool = new Dictionary(); 642 | 643 | Mesh mesh; 644 | if (!s_cylinderFlatShadedMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 645 | { 646 | mesh = new Mesh(); 647 | 648 | Vector3[] aVert = new Vector3[numSegments * 6 + 2]; 649 | Vector3[] aNormal = new Vector3[aVert.Length]; 650 | int[] aIndex = new int[numSegments * 12]; 651 | 652 | Vector3 bottom = new Vector3(0.0f, -0.5f, 0.0f); 653 | Vector3 top = new Vector3(0.0f, 0.5f, 0.0f); 654 | 655 | int iBottomCapStart = 0; 656 | int iTopCapStart = numSegments; 657 | int iSideStart = numSegments * 2; 658 | int iBottom = numSegments * 6; 659 | int iTop = numSegments * 6 + 1; 660 | 661 | aVert[iBottom] = bottom; 662 | aVert[iTop] = top; 663 | 664 | aNormal[iBottom] = new Vector3(0.0f, -1.0f, 0.0f); 665 | aNormal[iTop] = new Vector3(0.0f, 1.0f, 0.0f); 666 | 667 | int iIndex = 0; 668 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 669 | float angle = 0.0f; 670 | for (int i = 0; i < numSegments; ++i) 671 | { 672 | // caps 673 | Vector3 offset = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 674 | aVert[iBottomCapStart + i] = bottom + offset; 675 | aVert[iTopCapStart + i] = top + offset; 676 | 677 | aNormal[iBottomCapStart + i] = new Vector3(0.0f, -1.0f, 0.0f); 678 | aNormal[iTopCapStart + i] = new Vector3(0.0f, 1.0f, 0.0f); 679 | 680 | aIndex[iIndex++] = iBottom; 681 | aIndex[iIndex++] = iBottomCapStart + i; 682 | aIndex[iIndex++] = iBottomCapStart + ((i + 1) % numSegments); 683 | 684 | aIndex[iIndex++] = iTop; 685 | aIndex[iIndex++] = iTopCapStart + ((i + 1) % numSegments); 686 | aIndex[iIndex++] = iTopCapStart + i; 687 | 688 | angle += angleIncrement; 689 | 690 | // sides 691 | Vector3 offsetNext = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 692 | aVert[iSideStart + i * 4 ] = bottom + offset; 693 | aVert[iSideStart + i * 4 + 1] = top + offset; 694 | aVert[iSideStart + i * 4 + 2] = bottom + offsetNext; 695 | aVert[iSideStart + i * 4 + 3] = top + offsetNext; 696 | 697 | Vector3 sideNormal = Vector3.Cross(top - bottom, offsetNext - offset).normalized; 698 | aNormal[iSideStart + i * 4 ] = sideNormal; 699 | aNormal[iSideStart + i * 4 + 1] = sideNormal; 700 | aNormal[iSideStart + i * 4 + 2] = sideNormal; 701 | aNormal[iSideStart + i * 4 + 3] = sideNormal; 702 | 703 | aIndex[iIndex++] = iSideStart + i * 4; 704 | aIndex[iIndex++] = iSideStart + i * 4 + 3; 705 | aIndex[iIndex++] = iSideStart + i * 4 + 2; 706 | 707 | aIndex[iIndex++] = iSideStart + i * 4; 708 | aIndex[iIndex++] = iSideStart + i * 4 + 1; 709 | aIndex[iIndex++] = iSideStart + i * 4 + 3; 710 | } 711 | 712 | mesh.vertices = aVert; 713 | mesh.normals = aNormal; 714 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 715 | 716 | if (s_cylinderFlatShadedMeshPool.ContainsKey(numSegments)) 717 | s_cylinderFlatShadedMeshPool.Remove(numSegments); 718 | 719 | s_cylinderFlatShadedMeshPool.Add(numSegments, mesh); 720 | } 721 | 722 | return mesh; 723 | } 724 | 725 | public static Mesh CylinderSmoothShaded(int numSegments) 726 | { 727 | if (numSegments <= 1) 728 | return null; 729 | 730 | if (s_cylinderSmoothShadedMeshPool == null) 731 | s_cylinderSmoothShadedMeshPool = new Dictionary(); 732 | 733 | Mesh mesh; 734 | if (!s_cylinderSmoothShadedMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 735 | { 736 | mesh = new Mesh(); 737 | 738 | Vector3[] aVert = new Vector3[numSegments * 4 + 2]; 739 | Vector3[] aNormal = new Vector3[aVert.Length]; 740 | int[] aIndex = new int[numSegments * 12]; 741 | 742 | Vector3 bottom = new Vector3(0.0f, -0.5f, 0.0f); 743 | Vector3 top = new Vector3(0.0f, 0.5f, 0.0f); 744 | 745 | int iBottomCapStart = 0; 746 | int iTopCapStart = numSegments; 747 | int iSideStart = numSegments * 2; 748 | int iBottom = numSegments * 4; 749 | int iTop = numSegments * 4 + 1; 750 | 751 | aVert[iBottom] = bottom; 752 | aVert[iTop] = top; 753 | 754 | aNormal[iBottom] = new Vector3(0.0f, -1.0f, 0.0f); 755 | aNormal[iTop] = new Vector3(0.0f, 1.0f, 0.0f); 756 | 757 | int iIndex = 0; 758 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 759 | float angle = 0.0f; 760 | for (int i = 0; i < numSegments; ++i) 761 | { 762 | // caps 763 | Vector3 offset = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 764 | aVert[iBottomCapStart + i] = bottom + offset; 765 | aVert[iTopCapStart + i] = top + offset; 766 | 767 | aNormal[iBottomCapStart + i] = new Vector3(0.0f, -1.0f, 0.0f); 768 | aNormal[iTopCapStart + i] = new Vector3(0.0f, 1.0f, 0.0f); 769 | 770 | aIndex[iIndex++] = iBottom; 771 | aIndex[iIndex++] = iBottomCapStart + i; 772 | aIndex[iIndex++] = iBottomCapStart + ((i + 1) % numSegments); 773 | 774 | aIndex[iIndex++] = iTop; 775 | aIndex[iIndex++] = iTopCapStart + ((i + 1) % numSegments); 776 | aIndex[iIndex++] = iTopCapStart + i; 777 | 778 | angle += angleIncrement; 779 | 780 | // sides 781 | aVert[iSideStart + i * 2 ] = bottom + offset; 782 | aVert[iSideStart + i * 2 + 1] = top + offset; 783 | 784 | aNormal[iSideStart + i * 2 ] = offset; 785 | aNormal[iSideStart + i * 2 + 1] = offset; 786 | 787 | aIndex[iIndex++] = iSideStart + i * 2; 788 | aIndex[iIndex++] = iSideStart + ((i * 2 + 3) % (numSegments * 2)); 789 | aIndex[iIndex++] = iSideStart + ((i * 2 + 2) % (numSegments * 2)); 790 | 791 | aIndex[iIndex++] = iSideStart + i * 2; 792 | aIndex[iIndex++] = iSideStart + ((i * 2 + 1) % (numSegments * 2)); 793 | aIndex[iIndex++] = iSideStart + ((i * 2 + 3) % (numSegments * 2)); 794 | } 795 | 796 | mesh.vertices = aVert; 797 | mesh.normals = aNormal; 798 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 799 | 800 | if (s_cylinderSmoothShadedMeshPool.ContainsKey(numSegments)) 801 | s_cylinderSmoothShadedMeshPool.Remove(numSegments); 802 | 803 | s_cylinderSmoothShadedMeshPool.Add(numSegments, mesh); 804 | } 805 | 806 | return mesh; 807 | } 808 | 809 | // ------------------------------------------------------------------------ 810 | // end: cylinder 811 | 812 | 813 | // sphere 814 | // ------------------------------------------------------------------------ 815 | 816 | private static Dictionary s_sphereWireframeMeshPool; 817 | private static Dictionary s_sphereSolidColorMeshPool; 818 | private static Dictionary s_sphereFlatShadedMeshPool; 819 | private static Dictionary s_sphereSmoothShadedMeshPool; 820 | 821 | public static Mesh SphereWireframe(int latSegments, int longSegments) 822 | { 823 | if (latSegments <= 0 || longSegments <= 1) 824 | return null; 825 | 826 | if (s_sphereWireframeMeshPool == null) 827 | s_sphereWireframeMeshPool = new Dictionary(); 828 | 829 | int meshKey = (latSegments << 16 ^ longSegments); 830 | Mesh mesh; 831 | if (!s_sphereWireframeMeshPool.TryGetValue(meshKey, out mesh) || mesh == null) 832 | { 833 | mesh = new Mesh(); 834 | 835 | Vector3[] aVert = new Vector3[longSegments * (latSegments - 1) + 2]; 836 | int[] aIndex = new int[(longSegments * (latSegments * 2 - 1)) * 2]; 837 | 838 | Vector3 top = new Vector3(0.0f, 1.0f, 0.0f); 839 | Vector3 bottom = new Vector3(0.0f, -1.0f, 0.0f); 840 | int iTop = aVert.Length - 2; 841 | int iBottom = aVert.Length - 1; 842 | aVert[iTop] = top; 843 | aVert[iBottom] = bottom; 844 | 845 | float[] aLatSin = new float[latSegments]; 846 | float[] aLatCos = new float[latSegments]; 847 | { 848 | float latAngleIncrement = Mathf.PI / latSegments; 849 | float latAngle = 0.0f; 850 | for (int iLat = 0; iLat < latSegments; ++iLat) 851 | { 852 | latAngle += latAngleIncrement; 853 | aLatSin[iLat] = Mathf.Sin(latAngle); 854 | aLatCos[iLat] = Mathf.Cos(latAngle); 855 | } 856 | } 857 | 858 | float[] aLongSin = new float[longSegments]; 859 | float[] aLongCos = new float[longSegments]; 860 | { 861 | float longAngleIncrement = 2.0f * Mathf.PI / longSegments; 862 | float longAngle = 0.0f; 863 | for (int iLong = 0; iLong < longSegments; ++iLong) 864 | { 865 | longAngle += longAngleIncrement; 866 | aLongSin[iLong] = Mathf.Sin(longAngle); 867 | aLongCos[iLong] = Mathf.Cos(longAngle); 868 | } 869 | } 870 | 871 | int iVert = 0; 872 | int iIndex = 0; 873 | for (int iLong = 0; iLong < longSegments; ++iLong) 874 | { 875 | float longSin = aLongSin[iLong]; 876 | float longCos = aLongCos[iLong]; 877 | 878 | for (int iLat = 0; iLat < latSegments - 1; ++iLat) 879 | { 880 | float latSin = aLatSin[iLat]; 881 | float latCos = aLatCos[iLat]; 882 | 883 | aVert[iVert] = new Vector3(longCos * latSin, latCos, longSin * latSin); 884 | 885 | if (iLat == 0) 886 | { 887 | aIndex[iIndex++] = iTop; 888 | aIndex[iIndex++] = iVert; 889 | } 890 | else 891 | { 892 | aIndex[iIndex++] = iVert - 1; 893 | aIndex[iIndex++] = iVert; 894 | } 895 | 896 | aIndex[iIndex++] = iVert; 897 | aIndex[iIndex++] = (iVert + latSegments - 1) % (longSegments * (latSegments - 1)); 898 | 899 | if (iLat == latSegments - 2) 900 | { 901 | aIndex[iIndex++] = iVert; 902 | aIndex[iIndex++] = iBottom; 903 | } 904 | 905 | ++iVert; 906 | } 907 | } 908 | 909 | mesh.vertices = aVert; 910 | mesh.normals = aVert; // for GizmosUtil 911 | mesh.SetIndices(aIndex, MeshTopology.Lines, 0); 912 | 913 | if (s_sphereWireframeMeshPool.ContainsKey(meshKey)) 914 | s_sphereWireframeMeshPool.Remove(meshKey); 915 | 916 | s_sphereWireframeMeshPool.Add(meshKey, mesh); 917 | } 918 | 919 | return mesh; 920 | } 921 | 922 | public static Mesh SphereSolidColor(int latSegments, int longSegments) 923 | { 924 | if (latSegments <= 0 || longSegments <= 1) 925 | return null; 926 | 927 | if (s_sphereSolidColorMeshPool == null) 928 | s_sphereSolidColorMeshPool = new Dictionary(); 929 | 930 | int meshKey = (latSegments << 16 ^ longSegments); 931 | Mesh mesh; 932 | if (!s_sphereSolidColorMeshPool.TryGetValue(meshKey, out mesh) || mesh == null) 933 | { 934 | mesh = new Mesh(); 935 | 936 | Vector3[] aVert = new Vector3[longSegments * (latSegments - 1) + 2]; 937 | int[] aIndex = new int[(longSegments * (latSegments - 1) * 2) * 3]; 938 | 939 | Vector3 top = new Vector3(0.0f, 1.0f, 0.0f); 940 | Vector3 bottom = new Vector3(0.0f, -1.0f, 0.0f); 941 | int iTop = aVert.Length - 2; 942 | int iBottom = aVert.Length - 1; 943 | aVert[iTop] = top; 944 | aVert[iBottom] = bottom; 945 | 946 | float[] aLatSin = new float[latSegments]; 947 | float[] aLatCos = new float[latSegments]; 948 | { 949 | float latAngleIncrement = Mathf.PI / latSegments; 950 | float latAngle = 0.0f; 951 | for (int iLat = 0; iLat < latSegments; ++iLat) 952 | { 953 | latAngle += latAngleIncrement; 954 | aLatSin[iLat] = Mathf.Sin(latAngle); 955 | aLatCos[iLat] = Mathf.Cos(latAngle); 956 | } 957 | } 958 | 959 | float[] aLongSin = new float[longSegments]; 960 | float[] aLongCos = new float[longSegments]; 961 | { 962 | float longAngleIncrement = 2.0f * Mathf.PI / longSegments; 963 | float longAngle = 0.0f; 964 | for (int iLong = 0; iLong < longSegments; ++iLong) 965 | { 966 | longAngle += longAngleIncrement; 967 | aLongSin[iLong] = Mathf.Sin(longAngle); 968 | aLongCos[iLong] = Mathf.Cos(longAngle); 969 | } 970 | } 971 | 972 | int iVert = 0; 973 | int iIndex = 0; 974 | for (int iLong = 0; iLong < longSegments; ++iLong) 975 | { 976 | float longSin = aLongSin[iLong]; 977 | float longCos = aLongCos[iLong]; 978 | 979 | for (int iLat = 0; iLat < latSegments - 1; ++iLat) 980 | { 981 | float latSin = aLatSin[iLat]; 982 | float latCos = aLatCos[iLat]; 983 | 984 | aVert[iVert] = new Vector3(longCos * latSin, latCos, longSin * latSin); 985 | 986 | if (iLat == 0) 987 | { 988 | aIndex[iIndex++] = iTop; 989 | aIndex[iIndex++] = (iVert + latSegments - 1) % (longSegments * (latSegments - 1)); 990 | aIndex[iIndex++] = iVert; 991 | } 992 | 993 | if (iLat < latSegments - 2) 994 | { 995 | aIndex[iIndex++] = iVert + 1; 996 | aIndex[iIndex++] = iVert; 997 | aIndex[iIndex++] = (iVert + latSegments - 1) % (longSegments * (latSegments - 1)); 998 | 999 | aIndex[iIndex++] = iVert + 1; 1000 | aIndex[iIndex++] = (iVert + latSegments - 1) % (longSegments * (latSegments - 1)); 1001 | aIndex[iIndex++] = (iVert + latSegments) % (longSegments * (latSegments - 1)); 1002 | } 1003 | 1004 | if (iLat == latSegments - 2) 1005 | { 1006 | aIndex[iIndex++] = iVert; 1007 | aIndex[iIndex++] = (iVert + latSegments - 1) % (longSegments * (latSegments - 1)); 1008 | aIndex[iIndex++] = iBottom; 1009 | } 1010 | 1011 | ++iVert; 1012 | } 1013 | } 1014 | 1015 | mesh.vertices = aVert; 1016 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 1017 | 1018 | if (s_sphereSolidColorMeshPool.ContainsKey(meshKey)) 1019 | s_sphereSolidColorMeshPool.Remove(meshKey); 1020 | 1021 | s_sphereSolidColorMeshPool.Add(meshKey, mesh); 1022 | } 1023 | 1024 | return mesh; 1025 | } 1026 | 1027 | public static Mesh SphereFlatShaded(int latSegments, int longSegments) 1028 | { 1029 | if (latSegments <= 1 || longSegments <= 1) 1030 | return null; 1031 | 1032 | if (s_sphereFlatShadedMeshPool == null) 1033 | s_sphereFlatShadedMeshPool = new Dictionary(); 1034 | 1035 | int meshKey = (latSegments << 16 ^ longSegments); 1036 | Mesh mesh; 1037 | if (!s_sphereFlatShadedMeshPool.TryGetValue(meshKey, out mesh) || mesh == null) 1038 | { 1039 | mesh = new Mesh(); 1040 | 1041 | int numVertsPerLong = (latSegments - 2) * 4 + 6; 1042 | int numTrisPerLong = (latSegments - 2) * 2 + 2; 1043 | 1044 | Vector3[] aVert = new Vector3[longSegments * numVertsPerLong]; 1045 | Vector3[] aNormal = new Vector3[aVert.Length]; 1046 | int[] aIndex = new int[longSegments * numTrisPerLong * 3]; 1047 | 1048 | Vector3 top = new Vector3(0.0f, 1.0f, 0.0f); 1049 | Vector3 bottom = new Vector3(0.0f, -1.0f, 0.0f); 1050 | 1051 | float[] aLatSin = new float[latSegments]; 1052 | float[] aLatCos = new float[latSegments]; 1053 | { 1054 | float latAngleIncrement = Mathf.PI / latSegments; 1055 | float latAngle = 0.0f; 1056 | for (int iLat = 0; iLat < latSegments; ++iLat) 1057 | { 1058 | latAngle += latAngleIncrement; 1059 | aLatSin[iLat] = Mathf.Sin(latAngle); 1060 | aLatCos[iLat] = Mathf.Cos(latAngle); 1061 | } 1062 | } 1063 | 1064 | float[] aLongSin = new float[longSegments]; 1065 | float[] aLongCos = new float[longSegments]; 1066 | { 1067 | float longAngleIncrement = 2.0f * Mathf.PI / longSegments; 1068 | float longAngle = 0.0f; 1069 | for (int iLong = 0; iLong < longSegments; ++iLong) 1070 | { 1071 | longAngle += longAngleIncrement; 1072 | aLongSin[iLong] = Mathf.Sin(longAngle); 1073 | aLongCos[iLong] = Mathf.Cos(longAngle); 1074 | } 1075 | } 1076 | 1077 | int iVert = 0; 1078 | int iNormal = 0; 1079 | int iIndex = 0; 1080 | for (int iLong = 0; iLong < longSegments; ++iLong) 1081 | { 1082 | float longSin = aLongSin[iLong]; 1083 | float longCos = aLongCos[iLong]; 1084 | float longSinNext = aLongSin[(iLong + 1) % longSegments]; 1085 | float longCosNext = aLongCos[(iLong + 1) % longSegments]; 1086 | 1087 | int iTop = iVert; 1088 | 1089 | aVert[iVert++] = top; 1090 | aVert[iVert++] = new Vector3(longCos * aLatSin[0], aLatCos[0], longSin * aLatSin[0]); 1091 | aVert[iVert++] = new Vector3(longCosNext * aLatSin[0], aLatCos[0], longSinNext * aLatSin[0]); 1092 | 1093 | int iBottom = iVert; 1094 | 1095 | aVert[iVert++] = bottom; 1096 | aVert[iVert++] = new Vector3(longCos * aLatSin[latSegments - 2], aLatCos[latSegments - 2], longSin * aLatSin[latSegments - 2]); 1097 | aVert[iVert++] = new Vector3(longCosNext * aLatSin[latSegments - 2], aLatCos[latSegments - 2], longSinNext * aLatSin[latSegments - 2]); 1098 | 1099 | Vector3 topNormal = Vector3.Cross(aVert[iTop + 2] - aVert[iTop], aVert[iTop + 1] - aVert[iTop]).normalized; 1100 | aNormal[iNormal++] = topNormal; 1101 | aNormal[iNormal++] = topNormal; 1102 | aNormal[iNormal++] = topNormal; 1103 | 1104 | Vector3 bottomNormal = Vector3.Cross(aVert[iBottom + 1] - aVert[iBottom], aVert[iBottom + 2] - aVert[iBottom]).normalized; 1105 | aNormal[iNormal++] = bottomNormal; 1106 | aNormal[iNormal++] = bottomNormal; 1107 | aNormal[iNormal++] = bottomNormal; 1108 | 1109 | aIndex[iIndex++] = iTop; 1110 | aIndex[iIndex++] = iTop + 2; 1111 | aIndex[iIndex++] = iTop + 1; 1112 | 1113 | aIndex[iIndex++] = iBottom; 1114 | aIndex[iIndex++] = iBottom + 1; 1115 | aIndex[iIndex++] = iBottom + 2; 1116 | 1117 | for (int iLat = 0; iLat < latSegments - 2; ++iLat) 1118 | { 1119 | float latSin = aLatSin[iLat]; 1120 | float latCos = aLatCos[iLat]; 1121 | float latSinNext = aLatSin[iLat + 1]; 1122 | float latCosNext = aLatCos[iLat + 1]; 1123 | 1124 | int iQuadStart = iVert; 1125 | 1126 | aVert[iVert++] = new Vector3(longCos * latSin, latCos, longSin * latSin); 1127 | aVert[iVert++] = new Vector3(longCosNext * latSin, latCos, longSinNext * latSin); 1128 | aVert[iVert++] = new Vector3(longCosNext * latSinNext, latCosNext, longSinNext * latSinNext); 1129 | aVert[iVert++] = new Vector3(longCos * latSinNext, latCosNext, longSin * latSinNext); 1130 | 1131 | Vector3 quadNormal = Vector3.Cross(aVert[iQuadStart + 1] - aVert[iQuadStart], aVert[iQuadStart + 2] - aVert[iQuadStart]).normalized; 1132 | aNormal[iNormal++] = quadNormal; 1133 | aNormal[iNormal++] = quadNormal; 1134 | aNormal[iNormal++] = quadNormal; 1135 | aNormal[iNormal++] = quadNormal; 1136 | 1137 | aIndex[iIndex++] = iQuadStart; 1138 | aIndex[iIndex++] = iQuadStart + 1; 1139 | aIndex[iIndex++] = iQuadStart + 2; 1140 | 1141 | aIndex[iIndex++] = iQuadStart; 1142 | aIndex[iIndex++] = iQuadStart + 2; 1143 | aIndex[iIndex++] = iQuadStart + 3; 1144 | } 1145 | } 1146 | 1147 | mesh.vertices = aVert; 1148 | mesh.normals = aNormal; 1149 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 1150 | 1151 | if (s_sphereFlatShadedMeshPool.ContainsKey(meshKey)) 1152 | s_sphereFlatShadedMeshPool.Remove(meshKey); 1153 | 1154 | s_sphereFlatShadedMeshPool.Add(meshKey, mesh); 1155 | } 1156 | 1157 | return mesh; 1158 | } 1159 | 1160 | public static Mesh SphereSmoothShaded(int latSegments, int longSegments) 1161 | { 1162 | if (latSegments <= 1 || longSegments <= 1) 1163 | return null; 1164 | 1165 | if (s_sphereSmoothShadedMeshPool == null) 1166 | s_sphereSmoothShadedMeshPool = new Dictionary(); 1167 | 1168 | int meshKey = (latSegments << 16 ^ longSegments); 1169 | Mesh mesh; 1170 | if (!s_sphereSmoothShadedMeshPool.TryGetValue(meshKey, out mesh) || mesh == null) 1171 | { 1172 | mesh = new Mesh(); 1173 | 1174 | int numVertsPerLong = (latSegments - 1); 1175 | int numTrisPerLong = (latSegments - 2) * 2 + 2; 1176 | 1177 | Vector3[] aVert = new Vector3[longSegments * numVertsPerLong + 2]; 1178 | Vector3[] aNormal = new Vector3[aVert.Length]; 1179 | int[] aIndex = new int[longSegments * numTrisPerLong * 3]; 1180 | 1181 | Vector3 top = new Vector3(0.0f, 1.0f, 0.0f); 1182 | Vector3 bottom = new Vector3(0.0f, -1.0f, 0.0f); 1183 | 1184 | int iTop = longSegments * numVertsPerLong; 1185 | int iBottom = iTop + 1; 1186 | 1187 | aVert[iTop] = top; 1188 | aVert[iBottom] = bottom; 1189 | 1190 | aNormal[iTop] = new Vector3(0.0f, 1.0f, 0.0f); 1191 | aNormal[iBottom] = new Vector3(0.0f, -1.0f, 0.0f); 1192 | 1193 | float[] aLatSin = new float[latSegments]; 1194 | float[] aLatCos = new float[latSegments]; 1195 | { 1196 | float latAngleIncrement = Mathf.PI / latSegments; 1197 | float latAngle = 0.0f; 1198 | for (int iLat = 0; iLat < latSegments; ++iLat) 1199 | { 1200 | latAngle += latAngleIncrement; 1201 | aLatSin[iLat] = Mathf.Sin(latAngle); 1202 | aLatCos[iLat] = Mathf.Cos(latAngle); 1203 | } 1204 | } 1205 | 1206 | float[] aLongSin = new float[longSegments]; 1207 | float[] aLongCos = new float[longSegments]; 1208 | { 1209 | float longAngleIncrement = 2.0f * Mathf.PI / longSegments; 1210 | float longAngle = 0.0f; 1211 | for (int iLong = 0; iLong < longSegments; ++iLong) 1212 | { 1213 | longAngle += longAngleIncrement; 1214 | aLongSin[iLong] = Mathf.Sin(longAngle); 1215 | aLongCos[iLong] = Mathf.Cos(longAngle); 1216 | } 1217 | } 1218 | 1219 | int iVert = 0; 1220 | int iNormal = 0; 1221 | int iIndex = 0; 1222 | for (int iLong = 0; iLong < longSegments; ++iLong) 1223 | { 1224 | float longSin = aLongSin[iLong]; 1225 | float longCos = aLongCos[iLong]; 1226 | 1227 | for (int iLat = 0; iLat < latSegments - 1; ++iLat) 1228 | { 1229 | float latSin = aLatSin[iLat]; 1230 | float latCos = aLatCos[iLat]; 1231 | 1232 | Vector3 vert = new Vector3(longCos * latSin, latCos, longSin * latSin); 1233 | 1234 | aVert[iVert++] = vert; 1235 | 1236 | aNormal[iNormal++] = vert; 1237 | 1238 | int iQuad0 = iVert - 1; 1239 | int iQuad1 = iQuad0 + 1; 1240 | int iQuad2 = (iQuad0 + numVertsPerLong) % (longSegments * numVertsPerLong); 1241 | int iQuad3 = (iQuad0 + numVertsPerLong + 1) % (longSegments * numVertsPerLong); 1242 | 1243 | if (latSegments == 2) 1244 | { 1245 | aIndex[iIndex++] = iTop; 1246 | aIndex[iIndex++] = iQuad2; 1247 | aIndex[iIndex++] = iQuad0; 1248 | 1249 | aIndex[iIndex++] = iBottom; 1250 | aIndex[iIndex++] = iQuad1; 1251 | aIndex[iIndex++] = iQuad3; 1252 | } 1253 | else if (iLat < latSegments - 2) 1254 | { 1255 | if (iLat == 0) 1256 | { 1257 | aIndex[iIndex++] = iTop; 1258 | aIndex[iIndex++] = iQuad2; 1259 | aIndex[iIndex++] = iQuad0; 1260 | } 1261 | else if (iLat == latSegments - 3) 1262 | { 1263 | aIndex[iIndex++] = iBottom; 1264 | aIndex[iIndex++] = iQuad1; 1265 | aIndex[iIndex++] = iQuad3; 1266 | } 1267 | 1268 | aIndex[iIndex++] = iQuad0; 1269 | aIndex[iIndex++] = iQuad3; 1270 | aIndex[iIndex++] = iQuad1; 1271 | 1272 | aIndex[iIndex++] = iQuad0; 1273 | aIndex[iIndex++] = iQuad2; 1274 | aIndex[iIndex++] = iQuad3; 1275 | } 1276 | } 1277 | } 1278 | 1279 | mesh.vertices = aVert; 1280 | mesh.normals = aNormal; 1281 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 1282 | 1283 | if (s_sphereSmoothShadedMeshPool.ContainsKey(meshKey)) 1284 | s_sphereSmoothShadedMeshPool.Remove(meshKey); 1285 | 1286 | s_sphereSmoothShadedMeshPool.Add(meshKey, mesh); 1287 | } 1288 | 1289 | return mesh; 1290 | } 1291 | 1292 | // ------------------------------------------------------------------------ 1293 | // end: sphere 1294 | 1295 | 1296 | // capsule 1297 | // ------------------------------------------------------------------------ 1298 | 1299 | private static Dictionary s_capsuleWireframeMeshPool; 1300 | private static Dictionary s_capsuleSolidColorMeshPool; 1301 | private static Dictionary s_capsuleFlatShadedMeshPool; 1302 | private static Dictionary s_capsuleSmoothShadedMeshPool; 1303 | 1304 | public static Mesh CapsuleWireframe(int latSegmentsPerCap, int longSegmentsPerCap, bool caps = true, bool topCapOnly = false, bool sides = true) 1305 | { 1306 | if (latSegmentsPerCap <= 0 || longSegmentsPerCap <= 1) 1307 | return null; 1308 | 1309 | if (!caps && !sides) 1310 | return null; 1311 | 1312 | if (s_capsuleWireframeMeshPool == null) 1313 | s_capsuleWireframeMeshPool = new Dictionary(); 1314 | 1315 | int meshKey = (latSegmentsPerCap << 12 ^ longSegmentsPerCap ^ (caps ? 1 << 28 : 0) ^ (topCapOnly ? 1 << 29 : 0) ^ (sides ? 1 << 30 : 0)); 1316 | Mesh mesh; 1317 | if (!s_capsuleWireframeMeshPool.TryGetValue(meshKey, out mesh) || mesh == null) 1318 | { 1319 | mesh = new Mesh(); 1320 | 1321 | Vector3[] aVert = new Vector3[longSegmentsPerCap * latSegmentsPerCap * 2 + 2]; 1322 | int[] aIndex = new int[longSegmentsPerCap * (latSegmentsPerCap * 4 + 1) * 2]; 1323 | 1324 | Vector3 top = new Vector3(0.0f, 1.5f, 0.0f); 1325 | Vector3 bottom = new Vector3(0.0f, -1.5f, 0.0f); 1326 | int iTop = aVert.Length - 2; 1327 | int iBottom = aVert.Length - 1; 1328 | aVert[iTop] = top; 1329 | aVert[iBottom] = bottom; 1330 | 1331 | float[] aLatSin = new float[latSegmentsPerCap]; 1332 | float[] aLatCos = new float[latSegmentsPerCap]; 1333 | { 1334 | float latAngleIncrement = 0.5f * Mathf.PI / latSegmentsPerCap; 1335 | float latAngle = 0.0f; 1336 | for (int iLat = 0; iLat < latSegmentsPerCap; ++iLat) 1337 | { 1338 | latAngle += latAngleIncrement; 1339 | aLatSin[iLat] = Mathf.Sin(latAngle); 1340 | aLatCos[iLat] = Mathf.Cos(latAngle); 1341 | } 1342 | } 1343 | 1344 | float[] aLongSin = new float[longSegmentsPerCap]; 1345 | float[] aLongCos = new float[longSegmentsPerCap]; 1346 | { 1347 | float longAngleIncrement = 2.0f * Mathf.PI / longSegmentsPerCap; 1348 | float longAngle = 0.0f; 1349 | for (int iLong = 0; iLong < longSegmentsPerCap; ++iLong) 1350 | { 1351 | longAngle += longAngleIncrement; 1352 | aLongSin[iLong] = Mathf.Sin(longAngle); 1353 | aLongCos[iLong] = Mathf.Cos(longAngle); 1354 | } 1355 | } 1356 | 1357 | int iVert = 0; 1358 | int iIndex = 0; 1359 | for (int iLong = 0; iLong < longSegmentsPerCap; ++iLong) 1360 | { 1361 | float longSin = aLongSin[iLong]; 1362 | float longCos = aLongCos[iLong]; 1363 | 1364 | for (int iLat = 0; iLat < latSegmentsPerCap; ++iLat) 1365 | { 1366 | float latSin = aLatSin[iLat]; 1367 | float latCos = aLatCos[iLat]; 1368 | 1369 | aVert[iVert ] = new Vector3(longCos * latSin, latCos + 0.5f, longSin * latSin); 1370 | aVert[iVert + 1] = new Vector3(longCos * latSin, -latCos - 0.5f, longSin * latSin); 1371 | 1372 | if (caps) 1373 | { 1374 | if (iLat == 0) 1375 | { 1376 | aIndex[iIndex++] = iTop; 1377 | aIndex[iIndex++] = iVert; 1378 | 1379 | if (!topCapOnly) 1380 | { 1381 | aIndex[iIndex++] = iBottom; 1382 | aIndex[iIndex++] = iVert + 1; 1383 | } 1384 | } 1385 | else 1386 | { 1387 | aIndex[iIndex++] = iVert - 2; 1388 | aIndex[iIndex++] = iVert; 1389 | 1390 | if (!topCapOnly) 1391 | { 1392 | aIndex[iIndex++] = iVert - 1; 1393 | aIndex[iIndex++] = iVert + 1; 1394 | } 1395 | } 1396 | } 1397 | 1398 | if (caps || iLat == latSegmentsPerCap - 1) 1399 | { 1400 | aIndex[iIndex++] = iVert; 1401 | aIndex[iIndex++] = (iVert + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1402 | 1403 | if (!topCapOnly) 1404 | { 1405 | aIndex[iIndex++] = iVert + 1; 1406 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1407 | } 1408 | } 1409 | 1410 | if (sides && iLat == latSegmentsPerCap - 1) 1411 | { 1412 | aIndex[iIndex++] = iVert; 1413 | aIndex[iIndex++] = iVert + 1; 1414 | } 1415 | 1416 | iVert += 2; 1417 | } 1418 | } 1419 | 1420 | Array.Resize(ref aIndex, iIndex); 1421 | 1422 | mesh.vertices = aVert; 1423 | mesh.normals = aVert; // for GizmosUtil 1424 | mesh.SetIndices(aIndex, MeshTopology.Lines, 0); 1425 | 1426 | if (s_capsuleWireframeMeshPool.ContainsKey(meshKey)) 1427 | s_capsuleWireframeMeshPool.Remove(meshKey); 1428 | 1429 | s_capsuleWireframeMeshPool.Add(meshKey, mesh); 1430 | } 1431 | 1432 | return mesh; 1433 | } 1434 | 1435 | public static Mesh CapsuleSolidColor(int latSegmentsPerCap, int longSegmentsPerCap, bool caps = true, bool topCapOnly = false, bool sides = true) 1436 | { 1437 | if (latSegmentsPerCap <= 0 || longSegmentsPerCap <= 1) 1438 | return null; 1439 | 1440 | if (!caps && !sides) 1441 | return null; 1442 | 1443 | if (s_capsuleSolidColorMeshPool == null) 1444 | s_capsuleSolidColorMeshPool = new Dictionary(); 1445 | 1446 | int meshKey = (latSegmentsPerCap << 12 ^ longSegmentsPerCap ^ (caps ? 1 << 28 : 0) ^ (topCapOnly ? 1 << 29 : 0) ^ (sides ? 1 << 30 : 0)); 1447 | Mesh mesh; 1448 | if (!s_capsuleSolidColorMeshPool.TryGetValue(meshKey, out mesh) || mesh == null) 1449 | { 1450 | mesh = new Mesh(); 1451 | 1452 | Vector3[] aVert = new Vector3[longSegmentsPerCap * latSegmentsPerCap * 2 + 2]; 1453 | int[] aIndex = new int[longSegmentsPerCap * (latSegmentsPerCap * 4) * 3]; 1454 | 1455 | Vector3 top = new Vector3(0.0f, 1.5f, 0.0f); 1456 | Vector3 bottom = new Vector3(0.0f, -1.5f, 0.0f); 1457 | int iTop = aVert.Length - 2; 1458 | int iBottom = aVert.Length - 1; 1459 | aVert[iTop] = top; 1460 | aVert[iBottom] = bottom; 1461 | 1462 | float[] aLatSin = new float[latSegmentsPerCap]; 1463 | float[] aLatCos = new float[latSegmentsPerCap]; 1464 | { 1465 | float latAngleIncrement = 0.5f * Mathf.PI / latSegmentsPerCap; 1466 | float latAngle = 0.0f; 1467 | for (int iLat = 0; iLat < latSegmentsPerCap; ++iLat) 1468 | { 1469 | latAngle += latAngleIncrement; 1470 | aLatSin[iLat] = Mathf.Sin(latAngle); 1471 | aLatCos[iLat] = Mathf.Cos(latAngle); 1472 | } 1473 | } 1474 | 1475 | float[] aLongSin = new float[longSegmentsPerCap]; 1476 | float[] aLongCos = new float[longSegmentsPerCap]; 1477 | { 1478 | float longAngleIncrement = 2.0f * Mathf.PI / longSegmentsPerCap; 1479 | float longAngle = 0.0f; 1480 | for (int iLong = 0; iLong < longSegmentsPerCap; ++iLong) 1481 | { 1482 | longAngle += longAngleIncrement; 1483 | aLongSin[iLong] = Mathf.Sin(longAngle); 1484 | aLongCos[iLong] = Mathf.Cos(longAngle); 1485 | } 1486 | } 1487 | 1488 | int iVert = 0; 1489 | int iIndex = 0; 1490 | for (int iLong = 0; iLong < longSegmentsPerCap; ++iLong) 1491 | { 1492 | float longSin = aLongSin[iLong]; 1493 | float longCos = aLongCos[iLong]; 1494 | 1495 | for (int iLat = 0; iLat < latSegmentsPerCap; ++iLat) 1496 | { 1497 | float latSin = aLatSin[iLat]; 1498 | float latCos = aLatCos[iLat]; 1499 | 1500 | aVert[iVert ] = new Vector3(longCos * latSin, latCos + 0.5f, longSin * latSin); 1501 | aVert[iVert + 1] = new Vector3(longCos * latSin, -latCos - 0.5f, longSin * latSin); 1502 | 1503 | if (iLat == 0) 1504 | { 1505 | if (caps) 1506 | { 1507 | aIndex[iIndex++] = iTop; 1508 | aIndex[iIndex++] = (iVert + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1509 | aIndex[iIndex++] = iVert; 1510 | 1511 | if (!topCapOnly) 1512 | { 1513 | aIndex[iIndex++] = iBottom; 1514 | aIndex[iIndex++] = iVert + 1; 1515 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1516 | } 1517 | } 1518 | } 1519 | else 1520 | { 1521 | if (caps) 1522 | { 1523 | aIndex[iIndex++] = iVert - 2; 1524 | aIndex[iIndex++] = (iVert + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1525 | aIndex[iIndex++] = iVert; 1526 | 1527 | aIndex[iIndex++] = iVert - 2; 1528 | aIndex[iIndex++] = (iVert - 2 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1529 | aIndex[iIndex++] = (iVert + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1530 | 1531 | if (!topCapOnly) 1532 | { 1533 | aIndex[iIndex++] = iVert - 1; 1534 | aIndex[iIndex++] = iVert + 1; 1535 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1536 | 1537 | aIndex[iIndex++] = iVert - 1; 1538 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1539 | aIndex[iIndex++] = (iVert - 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1540 | } 1541 | } 1542 | 1543 | if (sides && iLat == latSegmentsPerCap - 1) 1544 | { 1545 | aIndex[iIndex++] = iVert; 1546 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1547 | aIndex[iIndex++] = iVert + 1; 1548 | 1549 | aIndex[iIndex++] = iVert; 1550 | aIndex[iIndex++] = (iVert+ latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1551 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1552 | } 1553 | } 1554 | 1555 | iVert += 2; 1556 | } 1557 | } 1558 | 1559 | Array.Resize(ref aIndex, iIndex); 1560 | 1561 | mesh.vertices = aVert; 1562 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 1563 | 1564 | if (s_capsuleSolidColorMeshPool.ContainsKey(meshKey)) 1565 | s_capsuleSolidColorMeshPool.Remove(meshKey); 1566 | 1567 | s_capsuleSolidColorMeshPool.Add(meshKey, mesh); 1568 | } 1569 | 1570 | return mesh; 1571 | } 1572 | 1573 | public static Mesh CapsuleFlatShaded(int latSegmentsPerCap, int longSegmentsPerCap, bool caps = true, bool topCapOnly = false, bool sides = true) 1574 | { 1575 | if (latSegmentsPerCap <= 0 || longSegmentsPerCap <= 1) 1576 | return null; 1577 | 1578 | if (!caps && !sides) 1579 | return null; 1580 | 1581 | if (s_capsuleFlatShadedMeshPool == null) 1582 | s_capsuleFlatShadedMeshPool = new Dictionary(); 1583 | 1584 | int meshKey = (latSegmentsPerCap << 12 ^ longSegmentsPerCap ^ (caps ? 1 << 28 : 0) ^ (topCapOnly ? 1 << 29 : 0) ^ (sides ? 1 << 30 : 0)); 1585 | Mesh mesh; 1586 | if (!s_capsuleFlatShadedMeshPool.TryGetValue(meshKey, out mesh) || mesh == null) 1587 | { 1588 | mesh = new Mesh(); 1589 | 1590 | Vector3[] aVert = new Vector3[longSegmentsPerCap * (latSegmentsPerCap - 1) * 8 + longSegmentsPerCap * 10]; 1591 | Vector3[] aNormal = new Vector3[aVert.Length]; 1592 | int[] aIndex = new int[longSegmentsPerCap * (latSegmentsPerCap * 4) * 3]; 1593 | 1594 | Vector3 top = new Vector3(0.0f, 1.5f, 0.0f); 1595 | Vector3 bottom = new Vector3(0.0f, -1.5f, 0.0f); 1596 | int iTop = aVert.Length - 2; 1597 | int iBottom = aVert.Length - 1; 1598 | aVert[iTop] = top; 1599 | aVert[iBottom] = bottom; 1600 | 1601 | aNormal[iTop] = new Vector3(0.0f, 1.0f, 0.0f); 1602 | aNormal[iBottom] = new Vector3(0.0f, -1.0f, 0.0f); 1603 | 1604 | float[] aLatSin = new float[latSegmentsPerCap]; 1605 | float[] aLatCos = new float[latSegmentsPerCap]; 1606 | { 1607 | float latAngleIncrement = 0.5f * Mathf.PI / latSegmentsPerCap; 1608 | float latAngle = 0.0f; 1609 | for (int iLat = 0; iLat < latSegmentsPerCap; ++iLat) 1610 | { 1611 | latAngle += latAngleIncrement; 1612 | aLatSin[iLat] = Mathf.Sin(latAngle); 1613 | aLatCos[iLat] = Mathf.Cos(latAngle); 1614 | } 1615 | } 1616 | 1617 | float[] aLongSin = new float[longSegmentsPerCap]; 1618 | float[] aLongCos = new float[longSegmentsPerCap]; 1619 | { 1620 | float longAngleIncrement = 2.0f * Mathf.PI / longSegmentsPerCap; 1621 | float longAngle = 0.0f; 1622 | for (int iLong = 0; iLong < longSegmentsPerCap; ++iLong) 1623 | { 1624 | longAngle += longAngleIncrement; 1625 | aLongSin[iLong] = Mathf.Sin(longAngle); 1626 | aLongCos[iLong] = Mathf.Cos(longAngle); 1627 | } 1628 | } 1629 | 1630 | int iVert = 0; 1631 | int iNormal = 0; 1632 | int iIndex = 0; 1633 | for (int iLong = 0; iLong < longSegmentsPerCap; ++iLong) 1634 | { 1635 | float longSin = aLongSin[iLong]; 1636 | float longCos = aLongCos[iLong]; 1637 | float longSinNext = aLongSin[(iLong + 1) % longSegmentsPerCap]; 1638 | float longCosNext = aLongCos[(iLong + 1) % longSegmentsPerCap]; 1639 | 1640 | for (int iLat = 0; iLat < latSegmentsPerCap; ++iLat) 1641 | { 1642 | float latSin = aLatSin[iLat]; 1643 | float latCos = aLatCos[iLat]; 1644 | 1645 | if (caps && iLat < latSegmentsPerCap - 1) 1646 | { 1647 | if (iLat == 0) 1648 | { 1649 | int iTopTriStart = iVert; 1650 | 1651 | aVert[iVert++] = top; 1652 | aVert[iVert++] = new Vector3(longCos * latSin, latCos + 0.5f, longSin * latSin); 1653 | aVert[iVert++] = new Vector3(longCosNext * latSin, latCos + 0.5f, longSinNext * latSin); 1654 | 1655 | Vector3 topTriNormal = Vector3.Cross(aVert[iTopTriStart + 2] - aVert[iTopTriStart], aVert[iTopTriStart + 1] - aVert[iTopTriStart]); 1656 | aNormal[iNormal++] = topTriNormal; 1657 | aNormal[iNormal++] = topTriNormal; 1658 | aNormal[iNormal++] = topTriNormal; 1659 | 1660 | aIndex[iIndex++] = iTopTriStart; 1661 | aIndex[iIndex++] = iTopTriStart + 2; 1662 | aIndex[iIndex++] = iTopTriStart + 1; 1663 | 1664 | if (!topCapOnly) 1665 | { 1666 | int iBottomTriStart = iVert; 1667 | 1668 | aVert[iVert++] = bottom; 1669 | aVert[iVert++] = new Vector3(longCos * latSin, -latCos - 0.5f, longSin * latSin); 1670 | aVert[iVert++] = new Vector3(longCosNext * latSin, -latCos - 0.5f, longSinNext * latSin); 1671 | 1672 | Vector3 bottomTriNormal = Vector3.Cross(aVert[iBottomTriStart + 1] - aVert[iBottomTriStart], aVert[iBottomTriStart + 2] - aVert[iBottomTriStart]).normalized; 1673 | aNormal[iNormal++] = bottomTriNormal; 1674 | aNormal[iNormal++] = bottomTriNormal; 1675 | aNormal[iNormal++] = bottomTriNormal; 1676 | 1677 | aIndex[iIndex++] = iBottomTriStart; 1678 | aIndex[iIndex++] = iBottomTriStart + 1; 1679 | aIndex[iIndex++] = iBottomTriStart + 2; 1680 | } 1681 | } 1682 | 1683 | float latSinNext = aLatSin[iLat + 1]; 1684 | float latCosNext = aLatCos[iLat + 1]; 1685 | 1686 | if (caps) 1687 | { 1688 | int iTopQuadStart = iVert; 1689 | 1690 | aVert[iVert++] = new Vector3(longCos * latSin, latCos + 0.5f, longSin * latSin); 1691 | aVert[iVert++] = new Vector3(longCos * latSinNext, latCosNext + 0.5f, longSin * latSinNext); 1692 | aVert[iVert++] = new Vector3(longCosNext * latSinNext, latCosNext + 0.5f, longSinNext * latSinNext); 1693 | aVert[iVert++] = new Vector3(longCosNext * latSin, latCos + 0.5f, longSinNext * latSin); 1694 | 1695 | Vector3 topQuadNormal = Vector3.Cross(aVert[iTopQuadStart + 3] - aVert[iTopQuadStart], aVert[iTopQuadStart + 1] - aVert[iTopQuadStart]); 1696 | aNormal[iNormal++] = topQuadNormal; 1697 | aNormal[iNormal++] = topQuadNormal; 1698 | aNormal[iNormal++] = topQuadNormal; 1699 | aNormal[iNormal++] = topQuadNormal; 1700 | 1701 | aIndex[iIndex++] = iTopQuadStart; 1702 | aIndex[iIndex++] = iTopQuadStart + 2; 1703 | aIndex[iIndex++] = iTopQuadStart + 1; 1704 | 1705 | aIndex[iIndex++] = iTopQuadStart; 1706 | aIndex[iIndex++] = iTopQuadStart + 3; 1707 | aIndex[iIndex++] = iTopQuadStart + 2; 1708 | 1709 | if (!topCapOnly) 1710 | { 1711 | int iBottomQuadStart = iVert; 1712 | 1713 | aVert[iVert++] = new Vector3(longCos * latSin, -latCos - 0.5f, longSin * latSin); 1714 | aVert[iVert++] = new Vector3(longCos * latSinNext, -latCosNext - 0.5f, longSin * latSinNext); 1715 | aVert[iVert++] = new Vector3(longCosNext * latSinNext, -latCosNext - 0.5f, longSinNext * latSinNext); 1716 | aVert[iVert++] = new Vector3(longCosNext * latSin, -latCos - 0.5f, longSinNext * latSin); 1717 | 1718 | Vector3 bottomQuadNormal = Vector3.Cross(aVert[iBottomQuadStart + 1] - aVert[iBottomQuadStart], aVert[iBottomQuadStart + 3] - aVert[iBottomQuadStart]); 1719 | aNormal[iNormal++] = bottomQuadNormal; 1720 | aNormal[iNormal++] = bottomQuadNormal; 1721 | aNormal[iNormal++] = bottomQuadNormal; 1722 | aNormal[iNormal++] = bottomQuadNormal; 1723 | 1724 | aIndex[iIndex++] = iBottomQuadStart; 1725 | aIndex[iIndex++] = iBottomQuadStart + 1; 1726 | aIndex[iIndex++] = iBottomQuadStart + 2; 1727 | 1728 | aIndex[iIndex++] = iBottomQuadStart; 1729 | aIndex[iIndex++] = iBottomQuadStart + 2; 1730 | aIndex[iIndex++] = iBottomQuadStart + 3; 1731 | } 1732 | } 1733 | } 1734 | else if (sides && iLat == latSegmentsPerCap - 1) 1735 | { 1736 | int iSideQuadStart = iVert; 1737 | 1738 | aVert[iVert++] = new Vector3(longCos * latSin, latCos + 0.5f, longSin * latSin); 1739 | aVert[iVert++] = new Vector3(longCos * latSin, -latCos - 0.5f, longSin * latSin); 1740 | aVert[iVert++] = new Vector3(longCosNext * latSin, -latCos - 0.5f, longSinNext * latSin); 1741 | aVert[iVert++] = new Vector3(longCosNext * latSin, latCos + 0.5f, longSinNext * latSin); 1742 | 1743 | Vector3 sideNormal = Vector3.Cross(aVert[iSideQuadStart + 3] - aVert[iSideQuadStart], aVert[iSideQuadStart + 1] - aVert[iSideQuadStart]).normalized; 1744 | aNormal[iNormal++] = sideNormal; 1745 | aNormal[iNormal++] = sideNormal; 1746 | aNormal[iNormal++] = sideNormal; 1747 | aNormal[iNormal++] = sideNormal; 1748 | 1749 | aIndex[iIndex++] = iSideQuadStart; 1750 | aIndex[iIndex++] = iSideQuadStart + 2; 1751 | aIndex[iIndex++] = iSideQuadStart + 1; 1752 | 1753 | aIndex[iIndex++] = iSideQuadStart; 1754 | aIndex[iIndex++] = iSideQuadStart + 3; 1755 | aIndex[iIndex++] = iSideQuadStart + 2; 1756 | } 1757 | } 1758 | } 1759 | 1760 | Array.Resize(ref aIndex, iIndex); 1761 | 1762 | mesh.vertices = aVert; 1763 | mesh.normals = aNormal; 1764 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 1765 | 1766 | if (s_capsuleFlatShadedMeshPool.ContainsKey(meshKey)) 1767 | s_capsuleFlatShadedMeshPool.Remove(meshKey); 1768 | 1769 | s_capsuleFlatShadedMeshPool.Add(meshKey, mesh); 1770 | } 1771 | 1772 | return mesh; 1773 | } 1774 | 1775 | public static Mesh CapsuleSmoothShaded(int latSegmentsPerCap, int longSegmentsPerCap, bool caps = true, bool topCapOnly = false, bool sides = true) 1776 | { 1777 | if (latSegmentsPerCap <= 0 || longSegmentsPerCap <= 1) 1778 | return null; 1779 | 1780 | if (!caps && !sides) 1781 | return null; 1782 | 1783 | if (s_capsuleSmoothShadedMeshPool == null) 1784 | s_capsuleSmoothShadedMeshPool = new Dictionary(); 1785 | 1786 | int meshKey = (latSegmentsPerCap << 12 ^ longSegmentsPerCap ^ (caps ? 1 << 28 : 0) ^ (topCapOnly ? 1 << 29 : 0) ^ (sides ? 1 << 30 : 0)); 1787 | Mesh mesh; 1788 | if (!s_capsuleSmoothShadedMeshPool.TryGetValue(meshKey, out mesh) || mesh == null) 1789 | { 1790 | mesh = new Mesh(); 1791 | 1792 | Vector3[] aVert = new Vector3[longSegmentsPerCap * latSegmentsPerCap * 2 + 2]; 1793 | Vector3[] aNormal = new Vector3[aVert.Length]; 1794 | int[] aIndex = new int[longSegmentsPerCap * (latSegmentsPerCap * 4) * 3]; 1795 | 1796 | Vector3 top = new Vector3(0.0f, 1.5f, 0.0f); 1797 | Vector3 bottom = new Vector3(0.0f, -1.5f, 0.0f); 1798 | int iTop = aVert.Length - 2; 1799 | int iBottom = aVert.Length - 1; 1800 | aVert[iTop] = top; 1801 | aVert[iBottom] = bottom; 1802 | 1803 | aNormal[iTop] = new Vector3(0.0f, 1.0f, 0.0f); 1804 | aNormal[iBottom] = new Vector3(0.0f, -1.0f, 0.0f); 1805 | 1806 | float[] aLatSin = new float[latSegmentsPerCap]; 1807 | float[] aLatCos = new float[latSegmentsPerCap]; 1808 | { 1809 | float latAngleIncrement = 0.5f * Mathf.PI / latSegmentsPerCap; 1810 | float latAngle = 0.0f; 1811 | for (int iLat = 0; iLat < latSegmentsPerCap; ++iLat) 1812 | { 1813 | latAngle += latAngleIncrement; 1814 | aLatSin[iLat] = Mathf.Sin(latAngle); 1815 | aLatCos[iLat] = Mathf.Cos(latAngle); 1816 | } 1817 | } 1818 | 1819 | float[] aLongSin = new float[longSegmentsPerCap]; 1820 | float[] aLongCos = new float[longSegmentsPerCap]; 1821 | { 1822 | float longAngleIncrement = 2.0f * Mathf.PI / longSegmentsPerCap; 1823 | float longAngle = 0.0f; 1824 | for (int iLong = 0; iLong < longSegmentsPerCap; ++iLong) 1825 | { 1826 | longAngle += longAngleIncrement; 1827 | aLongSin[iLong] = Mathf.Sin(longAngle); 1828 | aLongCos[iLong] = Mathf.Cos(longAngle); 1829 | } 1830 | } 1831 | 1832 | int iVert = 0; 1833 | int iNormal = 0; 1834 | int iIndex = 0; 1835 | for (int iLong = 0; iLong < longSegmentsPerCap; ++iLong) 1836 | { 1837 | float longSin = aLongSin[iLong]; 1838 | float longCos = aLongCos[iLong]; 1839 | 1840 | for (int iLat = 0; iLat < latSegmentsPerCap; ++iLat) 1841 | { 1842 | float latSin = aLatSin[iLat]; 1843 | float latCos = aLatCos[iLat]; 1844 | 1845 | aVert[iVert ] = new Vector3(longCos * latSin, latCos + 0.5f, longSin * latSin); 1846 | aVert[iVert + 1] = new Vector3(longCos * latSin, -latCos - 0.5f, longSin * latSin); 1847 | 1848 | aNormal[iNormal ] = new Vector3(longCos * latSin, latCos, longSin * latSin); 1849 | aNormal[iNormal + 1] = new Vector3(longCos * latSin, -latCos, longSin * latSin); 1850 | 1851 | if (caps && iLat == 0) 1852 | { 1853 | aIndex[iIndex++] = iTop; 1854 | aIndex[iIndex++] = (iVert + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1855 | aIndex[iIndex++] = iVert; 1856 | 1857 | if (!topCapOnly) 1858 | { 1859 | aIndex[iIndex++] = iBottom; 1860 | aIndex[iIndex++] = iVert + 1; 1861 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1862 | } 1863 | } 1864 | else 1865 | { 1866 | if (caps) 1867 | { 1868 | aIndex[iIndex++] = iVert - 2; 1869 | aIndex[iIndex++] = (iVert + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1870 | aIndex[iIndex++] = iVert; 1871 | 1872 | aIndex[iIndex++] = iVert - 2; 1873 | aIndex[iIndex++] = (iVert - 2 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1874 | aIndex[iIndex++] = (iVert + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1875 | 1876 | if (!topCapOnly) 1877 | { 1878 | aIndex[iIndex++] = iVert - 1; 1879 | aIndex[iIndex++] = iVert + 1; 1880 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1881 | 1882 | aIndex[iIndex++] = iVert - 1; 1883 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1884 | aIndex[iIndex++] = (iVert - 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1885 | } 1886 | } 1887 | 1888 | if (sides && iLat == latSegmentsPerCap - 1) 1889 | { 1890 | aIndex[iIndex++] = iVert; 1891 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1892 | aIndex[iIndex++] = iVert + 1; 1893 | 1894 | aIndex[iIndex++] = iVert; 1895 | aIndex[iIndex++] = (iVert+ latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1896 | aIndex[iIndex++] = (iVert + 1 + latSegmentsPerCap * 2) % (longSegmentsPerCap * latSegmentsPerCap * 2); 1897 | } 1898 | } 1899 | 1900 | iVert += 2; 1901 | iNormal += 2; 1902 | } 1903 | } 1904 | 1905 | Array.Resize(ref aIndex, iIndex); 1906 | 1907 | mesh.vertices = aVert; 1908 | mesh.normals = aNormal; 1909 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 1910 | 1911 | if (s_capsuleSmoothShadedMeshPool.ContainsKey(meshKey)) 1912 | s_capsuleSmoothShadedMeshPool.Remove(meshKey); 1913 | 1914 | s_capsuleSmoothShadedMeshPool.Add(meshKey, mesh); 1915 | } 1916 | 1917 | return mesh; 1918 | } 1919 | 1920 | private static Dictionary s_capsule2dWireframeMeshPool; 1921 | private static Dictionary s_capsule2dSolidColorMeshPool; 1922 | private static Dictionary s_capsule2dFlatShadedMeshPool; 1923 | 1924 | public static Mesh Capsule2DWireframe(int capSegments) 1925 | { 1926 | if (capSegments <= 0) 1927 | return null; 1928 | 1929 | if (s_capsule2dWireframeMeshPool == null) 1930 | s_capsule2dWireframeMeshPool = new Dictionary(); 1931 | 1932 | Mesh mesh; 1933 | if (!s_capsule2dWireframeMeshPool.TryGetValue(capSegments, out mesh) || mesh == null) 1934 | { 1935 | mesh = new Mesh(); 1936 | 1937 | Vector3[] aVert = new Vector3[(capSegments + 1) * 2]; 1938 | int[] aIndex = new int[(capSegments + 1) * 4]; 1939 | 1940 | int iVert = 0; 1941 | int iIndex = 0; 1942 | float angleIncrement = Mathf.PI / capSegments; 1943 | float angle = 0.0f; 1944 | for (int i = 0; i < capSegments; ++i) 1945 | { 1946 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) + 0.5f, 0.0f); 1947 | angle += angleIncrement; 1948 | } 1949 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) + 0.5f, 0.0f); 1950 | for (int i = 0; i < capSegments; ++i) 1951 | { 1952 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) - 0.5f, 0.0f); 1953 | angle += angleIncrement; 1954 | } 1955 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) - 0.5f, 0.0f); 1956 | 1957 | for (int i = 0; i < aVert.Length - 1; ++i) 1958 | { 1959 | aIndex[iIndex++] = i; 1960 | aIndex[iIndex++] = (i + 1) % aVert.Length; 1961 | } 1962 | 1963 | mesh.vertices = aVert; 1964 | mesh.normals = aVert; // for GizmosUtil 1965 | mesh.SetIndices(aIndex, MeshTopology.LineStrip, 0); 1966 | 1967 | if (s_capsule2dWireframeMeshPool.ContainsKey(capSegments)) 1968 | s_capsule2dWireframeMeshPool.Remove(capSegments); 1969 | 1970 | s_capsule2dWireframeMeshPool.Add(capSegments, mesh); 1971 | } 1972 | 1973 | return mesh; 1974 | } 1975 | 1976 | public static Mesh Capsule2DSolidColor(int capSegments) 1977 | { 1978 | if (capSegments <= 0) 1979 | return null; 1980 | 1981 | if (s_capsule2dSolidColorMeshPool == null) 1982 | s_capsule2dSolidColorMeshPool = new Dictionary(); 1983 | 1984 | Mesh mesh; 1985 | if (!s_capsule2dSolidColorMeshPool.TryGetValue(capSegments, out mesh) || mesh == null) 1986 | { 1987 | mesh = new Mesh(); 1988 | 1989 | Vector3[] aVert = new Vector3[(capSegments + 1) * 2]; 1990 | int[] aIndex = new int[(capSegments + 1) * 12]; 1991 | 1992 | int iVert = 0; 1993 | int iIndex = 0; 1994 | float angleIncrement = Mathf.PI / capSegments; 1995 | float angle = 0.0f; 1996 | for (int i = 0; i < capSegments; ++i) 1997 | { 1998 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) + 0.5f, 0.0f); 1999 | angle += angleIncrement; 2000 | } 2001 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) + 0.5f, 0.0f); 2002 | for (int i = 0; i < capSegments; ++i) 2003 | { 2004 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) - 0.5f, 0.0f); 2005 | angle += angleIncrement; 2006 | } 2007 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) - 0.5f, 0.0f); 2008 | 2009 | for (int i = 1; i < aVert.Length; ++i) 2010 | { 2011 | aIndex[iIndex++] = 0; 2012 | aIndex[iIndex++] = (i + 1) % aVert.Length; 2013 | aIndex[iIndex++] = i; 2014 | 2015 | aIndex[iIndex++] = 0; 2016 | aIndex[iIndex++] = i; 2017 | aIndex[iIndex++] = (i + 1) % aVert.Length; 2018 | } 2019 | 2020 | mesh.vertices = aVert; 2021 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 2022 | 2023 | if (s_capsule2dSolidColorMeshPool.ContainsKey(capSegments)) 2024 | s_capsule2dSolidColorMeshPool.Remove(capSegments); 2025 | 2026 | s_capsule2dSolidColorMeshPool.Add(capSegments, mesh); 2027 | } 2028 | 2029 | return mesh; 2030 | } 2031 | 2032 | public static Mesh Capsule2DFlatShaded(int capSegments) 2033 | { 2034 | if (capSegments <= 0) 2035 | return null; 2036 | 2037 | if (s_capsule2dFlatShadedMeshPool == null) 2038 | s_capsule2dFlatShadedMeshPool = new Dictionary(); 2039 | 2040 | Mesh mesh; 2041 | if (!s_capsule2dFlatShadedMeshPool.TryGetValue(capSegments, out mesh) || mesh == null) 2042 | { 2043 | mesh = new Mesh(); 2044 | 2045 | int numVertsPerSide = (capSegments + 1) * 2; 2046 | Vector3[] aVert = new Vector3[numVertsPerSide * 2]; 2047 | Vector3[] aNormal = new Vector3[aVert.Length]; 2048 | int[] aIndex = new int[numVertsPerSide * 6]; 2049 | 2050 | int iVert = 0; 2051 | int iNormal = 0; 2052 | int iIndex = 0; 2053 | float angleIncrement = Mathf.PI / capSegments; 2054 | float angle = 0.0f; 2055 | for (int iSide = 0; iSide < 2; ++iSide) 2056 | { 2057 | for (int i = 0; i < capSegments; ++i) 2058 | { 2059 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) + 0.5f, 0.0f); 2060 | angle += angleIncrement; 2061 | } 2062 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) + 0.5f, 0.0f); 2063 | for (int i = 0; i < capSegments; ++i) 2064 | { 2065 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) - 0.5f, 0.0f); 2066 | angle += angleIncrement; 2067 | } 2068 | aVert[iVert++] = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle) - 0.5f, 0.0f); 2069 | 2070 | Vector3 sideNormal = new Vector3(0.0f, 0.0f, (iSide == 0) ? -1.0f : 1.0f); 2071 | for (int i = 0; i < numVertsPerSide; ++i) 2072 | { 2073 | aNormal[iNormal++] = sideNormal; 2074 | } 2075 | } 2076 | 2077 | for (int i = 1; i < numVertsPerSide; ++i) 2078 | { 2079 | aIndex[iIndex++] = 0; 2080 | aIndex[iIndex++] = (i + 1) % numVertsPerSide; 2081 | aIndex[iIndex++] = i; 2082 | 2083 | aIndex[iIndex++] = numVertsPerSide; 2084 | aIndex[iIndex++] = numVertsPerSide + i; 2085 | aIndex[iIndex++] = numVertsPerSide + ((i + 1) % numVertsPerSide); 2086 | } 2087 | 2088 | mesh.vertices = aVert; 2089 | mesh.normals = aNormal; 2090 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 2091 | 2092 | if (s_capsule2dFlatShadedMeshPool.ContainsKey(capSegments)) 2093 | s_capsule2dFlatShadedMeshPool.Remove(capSegments); 2094 | 2095 | s_capsule2dFlatShadedMeshPool.Add(capSegments, mesh); 2096 | } 2097 | 2098 | return mesh; 2099 | } 2100 | 2101 | // ------------------------------------------------------------------------ 2102 | // end: capsule 2103 | 2104 | 2105 | // cone 2106 | // ------------------------------------------------------------------------ 2107 | 2108 | private static Dictionary s_coneWireframeMeshPool; 2109 | private static Dictionary s_coneSolidColorMeshPool; 2110 | private static Dictionary s_coneFlatShadedMeshPool; 2111 | private static Dictionary s_coneSmoothhadedMeshPool; 2112 | 2113 | public static Mesh ConeWireframe(int numSegments) 2114 | { 2115 | if (numSegments <= 1) 2116 | return null; 2117 | 2118 | if (s_coneWireframeMeshPool == null) 2119 | s_coneWireframeMeshPool = new Dictionary(); 2120 | 2121 | Mesh mesh; 2122 | if (!s_coneWireframeMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 2123 | { 2124 | mesh = new Mesh(); 2125 | 2126 | Vector3[] aVert = new Vector3[numSegments + 1]; 2127 | int[] aIndex = new int[numSegments * 4]; 2128 | 2129 | int iTop = numSegments; 2130 | 2131 | aVert[iTop] = new Vector3(0.0f, 1.0f, 0.0f); 2132 | 2133 | int iIndex = 0; 2134 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 2135 | float angle = 0.0f; 2136 | for (int i = 0; i < numSegments; ++i) 2137 | { 2138 | aVert[i] = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 2139 | 2140 | aIndex[iIndex++] = i; 2141 | aIndex[iIndex++] = (i + 1) % numSegments; 2142 | 2143 | aIndex[iIndex++] = i; 2144 | aIndex[iIndex++] = iTop; 2145 | 2146 | angle += angleIncrement; 2147 | } 2148 | 2149 | mesh.vertices = aVert; 2150 | mesh.normals = aVert; // for GizmosUtil 2151 | mesh.SetIndices(aIndex, MeshTopology.Lines, 0); 2152 | 2153 | if (s_coneWireframeMeshPool.ContainsKey(numSegments)) 2154 | s_coneWireframeMeshPool.Remove(numSegments); 2155 | 2156 | s_coneWireframeMeshPool.Add(numSegments, mesh); 2157 | } 2158 | 2159 | return mesh; 2160 | } 2161 | 2162 | public static Mesh ConeSolidColor(int numSegments) 2163 | { 2164 | if (numSegments <= 1) 2165 | return null; 2166 | 2167 | if (s_coneSolidColorMeshPool == null) 2168 | s_coneSolidColorMeshPool = new Dictionary(); 2169 | 2170 | Mesh mesh; 2171 | if (!s_coneSolidColorMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 2172 | { 2173 | mesh = new Mesh(); 2174 | 2175 | Vector3[] aVert = new Vector3[numSegments + 1]; 2176 | int[] aIndex = new int[numSegments * 3 + (numSegments - 2) * 3]; 2177 | 2178 | int iTop = numSegments; 2179 | 2180 | aVert[iTop] = new Vector3(0.0f, 1.0f, 0.0f); 2181 | 2182 | int iIndex = 0; 2183 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 2184 | float angle = 0.0f; 2185 | for (int i = 0; i < numSegments; ++i) 2186 | { 2187 | aVert[i] = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 2188 | 2189 | aIndex[iIndex++] = iTop; 2190 | aIndex[iIndex++] = (i + 1) % numSegments; 2191 | aIndex[iIndex++] = i; 2192 | 2193 | if (i >= 2) 2194 | { 2195 | aIndex[iIndex++] = 0; 2196 | aIndex[iIndex++] = i - 1; 2197 | aIndex[iIndex++] = i; 2198 | } 2199 | 2200 | angle += angleIncrement; 2201 | } 2202 | 2203 | mesh.vertices = aVert; 2204 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 2205 | 2206 | if (s_coneSolidColorMeshPool.ContainsKey(numSegments)) 2207 | s_coneSolidColorMeshPool.Remove(numSegments); 2208 | 2209 | s_coneSolidColorMeshPool.Add(numSegments, mesh); 2210 | } 2211 | 2212 | return mesh; 2213 | } 2214 | 2215 | public static Mesh ConeFlatShaded(int numSegments) 2216 | { 2217 | if (numSegments <= 1) 2218 | return null; 2219 | 2220 | if (s_coneFlatShadedMeshPool == null) 2221 | s_coneFlatShadedMeshPool = new Dictionary(); 2222 | 2223 | Mesh mesh; 2224 | if (!s_coneFlatShadedMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 2225 | { 2226 | mesh = new Mesh(); 2227 | 2228 | Vector3[] aVert = new Vector3[numSegments * 3 + numSegments]; 2229 | Vector3[] aNormal = new Vector3[aVert.Length]; 2230 | int[] aIndex = new int[numSegments * 3 + (numSegments - 2) * 3]; 2231 | 2232 | Vector3 top = new Vector3(0.0f, 1.0f, 0.0f); 2233 | 2234 | Vector3[] aBaseVert = new Vector3[numSegments]; 2235 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 2236 | float angle = 0.0f; 2237 | for (int i = 0; i < numSegments; ++i) 2238 | { 2239 | aBaseVert[i] = Mathf.Cos(angle) * Vector3.right + Mathf.Sin(angle) * Vector3.forward; 2240 | angle += angleIncrement; 2241 | } 2242 | 2243 | int iVert = 0; 2244 | int iIndex = 0; 2245 | int iNormal = 0; 2246 | for (int i = 0; i < numSegments; ++i) 2247 | { 2248 | int iSideTriStart = iVert; 2249 | 2250 | aVert[iVert++] = top; 2251 | aVert[iVert++] = aBaseVert[i]; 2252 | aVert[iVert++] = aBaseVert[(i + 1) % numSegments]; 2253 | 2254 | Vector3 sideTriNormal = Vector3.Cross(aVert[iSideTriStart + 2] - aVert[iSideTriStart], aVert[iSideTriStart + 1] - aVert[iSideTriStart]).normalized; 2255 | aNormal[iNormal++] = sideTriNormal; 2256 | aNormal[iNormal++] = sideTriNormal; 2257 | aNormal[iNormal++] = sideTriNormal; 2258 | 2259 | aIndex[iIndex++] = iSideTriStart; 2260 | aIndex[iIndex++] = iSideTriStart + 2; 2261 | aIndex[iIndex++] = iSideTriStart + 1; 2262 | } 2263 | 2264 | int iBaseStart = iVert; 2265 | for (int i = 0; i < numSegments; ++i) 2266 | { 2267 | aVert[iVert++] = aBaseVert[i]; 2268 | 2269 | aNormal[iNormal++] = new Vector3(0.0f, -1.0f, 0.0f); 2270 | 2271 | if (i >= 2) 2272 | { 2273 | aIndex[iIndex++] = iBaseStart; 2274 | aIndex[iIndex++] = iBaseStart + i - 1; 2275 | aIndex[iIndex++] = iBaseStart + i; 2276 | } 2277 | } 2278 | 2279 | mesh.vertices = aVert; 2280 | mesh.normals = aNormal; 2281 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 2282 | 2283 | if (s_coneFlatShadedMeshPool.ContainsKey(numSegments)) 2284 | s_coneFlatShadedMeshPool.Remove(numSegments); 2285 | 2286 | s_coneFlatShadedMeshPool.Add(numSegments, mesh); 2287 | } 2288 | 2289 | return mesh; 2290 | } 2291 | 2292 | public static Mesh ConeSmoothShaded(int numSegments) 2293 | { 2294 | if (numSegments <= 1) 2295 | return null; 2296 | 2297 | if (s_coneSmoothhadedMeshPool == null) 2298 | s_coneSmoothhadedMeshPool = new Dictionary(); 2299 | 2300 | Mesh mesh; 2301 | if (!s_coneSmoothhadedMeshPool.TryGetValue(numSegments, out mesh) || mesh == null) 2302 | { 2303 | mesh = new Mesh(); 2304 | 2305 | Vector3[] aVert = new Vector3[numSegments * 2 + 1]; 2306 | Vector3[] aNormal = new Vector3[aVert.Length]; 2307 | int[] aIndex = new int[numSegments * 3 + (numSegments - 2) * 3]; 2308 | 2309 | int iTop = aVert.Length - 1; 2310 | 2311 | aVert[iTop] = new Vector3(0.0f, 1.0f, 0.0f); 2312 | aNormal[iTop] = new Vector3(0.0f, 0.0f, 0.0f); 2313 | 2314 | float sqrt2Inv = Mathf.Sqrt(0.5f); 2315 | 2316 | int iIndex = 0; 2317 | float angleIncrement = 2.0f * Mathf.PI / numSegments; 2318 | float angle = 0.0f; 2319 | for (int i = 0; i < numSegments; ++i) 2320 | { 2321 | float cos = Mathf.Cos(angle); 2322 | float sin = Mathf.Sin(angle); 2323 | 2324 | Vector3 baseVert = cos * Vector3.right + sin * Vector3.forward; 2325 | aVert[i] = baseVert; 2326 | aVert[numSegments + i] = baseVert; 2327 | 2328 | aNormal[i] = new Vector3(cos * sqrt2Inv, sqrt2Inv, sin * sqrt2Inv); 2329 | aNormal[numSegments + i] = new Vector3(0.0f, -1.0f, 0.0f); 2330 | 2331 | aIndex[iIndex++] = iTop; 2332 | aIndex[iIndex++] = (i + 1) % numSegments; 2333 | aIndex[iIndex++] = i; 2334 | 2335 | if (i >= 2) 2336 | { 2337 | aIndex[iIndex++] = numSegments; 2338 | aIndex[iIndex++] = numSegments + i - 1; 2339 | aIndex[iIndex++] = numSegments + i; 2340 | } 2341 | 2342 | angle += angleIncrement; 2343 | } 2344 | 2345 | mesh.vertices = aVert; 2346 | mesh.normals = aNormal; 2347 | mesh.SetIndices(aIndex, MeshTopology.Triangles, 0); 2348 | 2349 | if (s_coneSmoothhadedMeshPool.ContainsKey(numSegments)) 2350 | s_coneSmoothhadedMeshPool.Remove(numSegments); 2351 | 2352 | s_coneSmoothhadedMeshPool.Add(numSegments, mesh); 2353 | } 2354 | 2355 | return mesh; 2356 | } 2357 | 2358 | // ------------------------------------------------------------------------ 2359 | // end: cone 2360 | } 2361 | } 2362 | -------------------------------------------------------------------------------- /Assets/Physics/PrimitiveMeshFactory.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 969b491eb2368ea46996b97698ed6f21 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Physics/Quaternion.cginc: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* 3 | Project - Unity CJ Lib 4 | https://github.com/TheAllenChou/unity-cj-lib 5 | 6 | Author - Ming-Lun "Allen" Chou 7 | Web - http://AllenChou.net 8 | Twitter - @TheAllenChou 9 | */ 10 | /******************************************************************************/ 11 | 12 | #ifndef CJ_LIB_QUATERNION 13 | #define CJ_LIB_QUATERNION 14 | 15 | #include "Math.cginc" 16 | 17 | #define kUnitQuat (float4(0.0, 0.0, 0.0, 1.0)) 18 | 19 | inline float4 quat_conj(float4 q) 20 | { 21 | return float4(-q.xyz, q.w); 22 | } 23 | 24 | // q must be unit quaternion 25 | inline float4 quat_pow(float4 q, float p) 26 | { 27 | float r = length(q.xyz); 28 | if (r < kEpsilon) 29 | return kUnitQuat; 30 | 31 | float t = p * atan2(q.w, r); 32 | 33 | return float4(sin(t) * q.xyz / r, cos(t)); 34 | } 35 | 36 | inline float4 quat_axis_angle(float3 v, float a) 37 | { 38 | float h = 0.5 * a; 39 | return float4(sin(h) * normalize(v), cos(h)); 40 | } 41 | 42 | inline float4 quat_concat(float4 q1, float4 q2) 43 | { 44 | return float4(q1.w * q2.xyz + q2.w * q1.xyz + cross(q1.xyz, q2.xyz), q1.w * q2.w - dot(q1.xyz, q2.xyz)); 45 | } 46 | 47 | inline float3 quat_mul(float4 q, float3 v) 48 | { 49 | return dot(q.xyz, v) * q.xyz + q.w * q.w * v + 2.0 * q.w * cross(q.xyz, v) - cross(cross(q.xyz, v), q.xyz); 50 | } 51 | 52 | // both a & b must be unit quaternions 53 | inline float4 slerp(float4 a, float4 b, float t) 54 | { 55 | float d = dot(a, b); 56 | if (d > 0.99999) 57 | { 58 | return lerp(a, b, t); 59 | } 60 | 61 | float r = acos(saturate(d)); 62 | return (sin((1.0 - t) * r) * a + sin(t * r) * b) / sin(r); 63 | } 64 | 65 | inline float4 nlerp(float4 a, float b, float t) 66 | { 67 | return normalize(lerp(a, b, t)); 68 | } 69 | 70 | float4x4 quaternion_to_matrix(float4 quat) 71 | { 72 | float4x4 m = float4x4(float4(0, 0, 0, 0), float4(0, 0, 0, 0), float4(0, 0, 0, 0), float4(0, 0, 0, 0)); 73 | 74 | float x = quat.x, y = quat.y, z = quat.z, w = quat.w; 75 | float x2 = x + x, y2 = y + y, z2 = z + z; 76 | float xx = x * x2, xy = x * y2, xz = x * z2; 77 | float yy = y * y2, yz = y * z2, zz = z * z2; 78 | float wx = w * x2, wy = w * y2, wz = w * z2; 79 | 80 | m[0][0] = 1.0 - (yy + zz); 81 | m[0][1] = xy - wz; 82 | m[0][2] = xz + wy; 83 | 84 | m[1][0] = xy + wz; 85 | m[1][1] = 1.0 - (xx + zz); 86 | m[1][2] = yz - wx; 87 | 88 | m[2][0] = xz - wy; 89 | m[2][1] = yz + wx; 90 | m[2][2] = 1.0 - (xx + yy); 91 | 92 | m[3][3] = 1.0; 93 | 94 | return m; 95 | } 96 | 97 | float3x3 quaternion_to_matrix3x3(float4 quat) 98 | { 99 | float3x3 m = float3x3(float3(0, 0, 0), float3(0, 0, 0), float3(0, 0, 0)); 100 | 101 | float x = quat.x, y = quat.y, z = quat.z, w = quat.w; 102 | float x2 = x + x, y2 = y + y, z2 = z + z; 103 | float xx = x * x2, xy = x * y2, xz = x * z2; 104 | float yy = y * y2, yz = y * z2, zz = z * z2; 105 | float wx = w * x2, wy = w * y2, wz = w * z2; 106 | 107 | m[0][0] = 1.0 - (yy + zz); 108 | m[0][1] = xy - wz; 109 | m[0][2] = xz + wy; 110 | 111 | m[1][0] = xy + wz; 112 | m[1][1] = 1.0 - (xx + zz); 113 | m[1][2] = yz - wx; 114 | 115 | m[2][0] = xz - wy; 116 | m[2][1] = yz + wx; 117 | m[2][2] = 1.0 - (xx + yy); 118 | 119 | return m; 120 | } 121 | #endif 122 | -------------------------------------------------------------------------------- /Assets/Physics/Quaternion.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e4acf9f8acb3a9b408dcca8bc0f064ff 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/RailgunBasicShader.shader: -------------------------------------------------------------------------------- 1 | // Upgrade NOTE: upgraded instancing buffer 'Props' to new syntax. 2 | 3 | Shader "Railgun/RailgunBasicShader" { 4 | Properties { 5 | _Color ("Color", Color) = (1,1,1,1) 6 | _MainTex ("Albedo (RGB)", 2D) = "white" {} 7 | } 8 | SubShader { 9 | Tags { "RenderType"="Opaque" } 10 | LOD 200 11 | Stencil { 12 | Ref 0 13 | Comp Always 14 | Pass Replace 15 | } 16 | CGPROGRAM 17 | // Physically based Standard lighting model, and enable shadows on all light types 18 | // And generate the shadow pass with instancing support 19 | #pragma surface surf Lambert fullforwardshadows addshadow 20 | 21 | // Use shader model 3.0 target, to get nicer looking lighting 22 | #pragma target 3.0 23 | 24 | // Enable instancing for this shader 25 | #pragma multi_compile_instancing 26 | 27 | // Config maxcount. See manual page. 28 | // #pragma instancing_options 29 | 30 | sampler2D _MainTex; 31 | 32 | struct Input { 33 | float2 uv_MainTex; 34 | }; 35 | 36 | 37 | // Declare instanced properties inside a cbuffer. 38 | // Each instanced property is an array of by default 500(D3D)/128(GL) elements. Since D3D and GL imposes a certain limitation 39 | // of 64KB and 16KB respectively on the size of a cubffer, the default array size thus allows two matrix arrays in one cbuffer. 40 | // Use maxcount option on #pragma instancing_options directive to specify array size other than default (divided by 4 when used 41 | // for GL). 42 | UNITY_INSTANCING_BUFFER_START(Props) 43 | UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) // Make _Color an instanced property (i.e. an array) 44 | #define _Color_arr Props 45 | UNITY_INSTANCING_BUFFER_END(Props) 46 | 47 | void surf (Input IN, inout SurfaceOutput o) { 48 | // Albedo comes from a texture tinted by color 49 | fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(_Color_arr, _Color); 50 | o.Albedo = c.rgb; 51 | o.Alpha = c.a; 52 | } 53 | ENDCG 54 | } 55 | FallBack "Diffuse" 56 | } 57 | -------------------------------------------------------------------------------- /Assets/Physics/RailgunBasicShader.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ae027796e14a164458f76f55a781c59e 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/SlowMotion.prefab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/SlowMotion.prefab -------------------------------------------------------------------------------- /Assets/Physics/SlowMotion.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 82a24ea90b29c47b18a981c299990688 3 | timeCreated: 1491775042 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 100100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/StressTest.prefab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/StressTest.prefab -------------------------------------------------------------------------------- /Assets/Physics/StressTest.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 458d096163c464b3f91222b6ae1804a7 3 | timeCreated: 1491775168 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 100100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/TangentialForceTest.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | public class TangentialForceTest : MonoBehaviour 7 | { 8 | public GameObject m_particleOne; 9 | public GameObject m_particleTwo; 10 | public GameObject m_particleOneVelocity; 11 | public GameObject m_particleTwoVelocity; 12 | public Material m_velocityMaterial; 13 | public Material m_tangentialMaterial; 14 | public Material m_springMaterial; 15 | public Material m_dampingMaterial; 16 | public float m_tangentialScalar; 17 | public float m_springForceScalar; 18 | public float m_dampingForceScalar; 19 | 20 | struct MeshAndMat { 21 | public Mesh m_mesh; 22 | public Material m_material; 23 | } 24 | private List m_drawThese; 25 | void Awake() { 26 | Application.targetFrameRate = 60; 27 | } 28 | void OnEnable() { 29 | m_drawThese = new List(); 30 | Camera.onPreCull += Render; 31 | } 32 | void OnDisable() { 33 | m_drawThese.Clear(); 34 | m_drawThese = null; 35 | Camera.onPreCull -= Render; 36 | } 37 | void Render(Camera c) 38 | { 39 | foreach (var mm in m_drawThese) { 40 | Graphics.DrawMesh(mm.m_mesh, Matrix4x4.identity, mm.m_material, 1, c, 0, null, false, false, false); 41 | //Graphics.DrawMesh(mesh, Matrix4x4.identity, m, 1, Camera.main, 0, null, false, false, false); 42 | } 43 | } 44 | void DrawLine(Vector3 start, Vector3 end, Material m) { 45 | var mesh = CjLib.PrimitiveMeshFactory.Line(start,end); 46 | var meshAndMat = new MeshAndMat(); 47 | meshAndMat.m_mesh = mesh; 48 | meshAndMat.m_material = m; 49 | m_drawThese.Add(meshAndMat); 50 | } 51 | void Update() { 52 | m_drawThese.Clear(); 53 | //draw velocities 54 | var posOne = m_particleOne.transform.position; 55 | var velOne = m_particleOneVelocity.transform.position - posOne; 56 | DrawLine(posOne, posOne + velOne, m_velocityMaterial); 57 | 58 | var posTwo = m_particleTwo.transform.position; 59 | var velTwo = m_particleTwoVelocity.transform.position - posTwo; 60 | DrawLine(posTwo, posTwo + velTwo, m_velocityMaterial); 61 | 62 | // draw spring force vector 63 | var springIJ = m_springForceScalar * SpringForceVector(posOne, posTwo); 64 | var springJI = m_springForceScalar * SpringForceVector(posTwo, posOne); 65 | DrawLine(posOne, posOne + springIJ, m_springMaterial); 66 | DrawLine(posTwo, posTwo + springJI, m_springMaterial); 67 | 68 | // draw damping force vector 69 | var dampingIJ = m_dampingForceScalar * DampingForceVector(velOne, velTwo); 70 | var dampingJI = m_dampingForceScalar * DampingForceVector(velTwo, velOne); 71 | DrawLine(posOne, posOne + dampingIJ, m_dampingMaterial); 72 | DrawLine(posTwo, posTwo + dampingJI, m_dampingMaterial); 73 | 74 | //draw tangentialforce vector 75 | var vijt = m_tangentialScalar * TangentialForceVector(posOne, posTwo, velOne, velTwo); 76 | var vjit = m_tangentialScalar * TangentialForceVector(posTwo, posOne, velTwo, velOne); 77 | DrawLine(posOne, posOne + vijt, m_tangentialMaterial); 78 | DrawLine(posTwo, posTwo + vjit, m_tangentialMaterial); 79 | } 80 | 81 | Vector3 TangentialForceVector(Vector3 pi, Vector3 pj, Vector3 vi, Vector3 vj) { 82 | var pij = pj - pi; 83 | var vij = vj - vi; 84 | var pijn = pij.normalized; 85 | var vijt = vij - pijn * Vector3.Dot(vij, pijn); 86 | return vijt; 87 | } 88 | Vector3 SpringForceVector(Vector3 pi, Vector3 pj) { 89 | var pij = pj - pi; 90 | var pijn = pij.normalized; 91 | float diameter = 1.0f; 92 | float penetration = pij.magnitude; 93 | if (diameter >= penetration) 94 | return -1.0f * (diameter - penetration) * pijn; 95 | return Vector3.zero; 96 | } 97 | 98 | Vector3 DampingForceVector(Vector3 vi, Vector3 vj) { 99 | var vij = vj - vi; 100 | return vij; 101 | } 102 | } -------------------------------------------------------------------------------- /Assets/Physics/TangentialForceTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d6e865bea23e5c4418b2b849482d5b8f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4a28716fae729b2448897f10aeec893d 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Black.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/TangentialTest/Black.mat -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Black.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 18dea195432d4ba42bd75d8c434ebf1c 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Blue.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/TangentialTest/Blue.mat -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Blue.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9cca366ef0be29349a496ebc9eab1fa3 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Green.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/TangentialTest/Green.mat -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Green.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 68e2e4a1656876840ac8ef7fa1627909 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Red.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/TangentialTest/Red.mat -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Red.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4115be732b64fde4f94071018cf31a98 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/TangentialTest.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/TangentialTest/TangentialTest.unity -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/TangentialTest.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: caae4c78a46671d4b83c144dfbde19ba 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Transparent.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/TangentialTest/Transparent.mat -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Transparent.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f102406929843f44f8fc8fc1241ed1b1 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Yellow.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/TangentialTest/Yellow.mat -------------------------------------------------------------------------------- /Assets/Physics/TangentialTest/Yellow.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b3e2c4f56d5aa0645be375e0483dd03c 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 2100000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Physics/TowerFall.prefab: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/TowerFall.prefab -------------------------------------------------------------------------------- /Assets/Physics/TowerFall.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e55c0bc22c5824e6897cde7000b5eab7 3 | timeCreated: 1491775082 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 100100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/Vector.cginc: -------------------------------------------------------------------------------- 1 | /******************************************************************************/ 2 | /* 3 | Project - Unity CJ Lib 4 | https://github.com/TheAllenChou/unity-cj-lib 5 | 6 | Author - Ming-Lun "Allen" Chou 7 | Web - http://AllenChou.net 8 | Twitter - @TheAllenChou 9 | */ 10 | /******************************************************************************/ 11 | 12 | #ifndef CJ_LIB_VECTOR 13 | #define CJ_LIB_VECTOR 14 | 15 | #include "Math.cginc" 16 | 17 | inline float3 find_ortho(float3 v) 18 | { 19 | if (v.x >= kSqrt3Inv) 20 | return float3(v.y, -v.x, 0.0); 21 | else 22 | return float3(0.0, v.z, -v.y); 23 | } 24 | 25 | // both a & b must be unit vectors 26 | inline float3 slerp(float3 a, float3 b, float t) 27 | { 28 | float d = dot(a, b); 29 | if (d > 0.99999) 30 | { 31 | return lerp(a, b, t); 32 | } 33 | 34 | float r = acos(saturate(d)); 35 | return (sin((1.0 - t) * r) * a + sin(t * r) * b) / sin(r); 36 | } 37 | 38 | inline float3 nlerp(float3 a, float b, float t) 39 | { 40 | return normalize(lerp(a, b, t)); 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /Assets/Physics/Vector.cginc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fa89081643259a543bf0f9f2dc1300cc 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Assets/Physics/physics.unity: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/Assets/Physics/physics.unity -------------------------------------------------------------------------------- /Assets/Physics/physics.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 935105dad292541c1b194f2200da57a6 3 | timeCreated: 1483658473 4 | licenseType: Pro 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.ads": "2.0.8", 4 | "com.unity.analytics": "2.0.16", 5 | "com.unity.package-manager-ui": "1.9.9", 6 | "com.unity.purchasing": "2.0.1", 7 | "com.unity.textmeshpro": "1.2.1", 8 | "com.unity.modules.ai": "1.0.0", 9 | "com.unity.modules.animation": "1.0.0", 10 | "com.unity.modules.assetbundle": "1.0.0", 11 | "com.unity.modules.audio": "1.0.0", 12 | "com.unity.modules.cloth": "1.0.0", 13 | "com.unity.modules.director": "1.0.0", 14 | "com.unity.modules.imageconversion": "1.0.0", 15 | "com.unity.modules.imgui": "1.0.0", 16 | "com.unity.modules.jsonserialize": "1.0.0", 17 | "com.unity.modules.particlesystem": "1.0.0", 18 | "com.unity.modules.physics": "1.0.0", 19 | "com.unity.modules.physics2d": "1.0.0", 20 | "com.unity.modules.screencapture": "1.0.0", 21 | "com.unity.modules.terrain": "1.0.0", 22 | "com.unity.modules.terrainphysics": "1.0.0", 23 | "com.unity.modules.tilemap": "1.0.0", 24 | "com.unity.modules.ui": "1.0.0", 25 | "com.unity.modules.uielements": "1.0.0", 26 | "com.unity.modules.umbra": "1.0.0", 27 | "com.unity.modules.unityanalytics": "1.0.0", 28 | "com.unity.modules.unitywebrequest": "1.0.0", 29 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 30 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 31 | "com.unity.modules.unitywebrequesttexture": "1.0.0", 32 | "com.unity.modules.unitywebrequestwww": "1.0.0", 33 | "com.unity.modules.vehicles": "1.0.0", 34 | "com.unity.modules.video": "1.0.0", 35 | "com.unity.modules.vr": "1.0.0", 36 | "com.unity.modules.wind": "1.0.0", 37 | "com.unity.modules.xr": "1.0.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/AudioManager.asset -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/ClusterInputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/DynamicsManager.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/EditorBuildSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/EditorSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/GraphicsSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/InputManager.asset -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/NavMeshAreas.asset -------------------------------------------------------------------------------- /ProjectSettings/NetworkManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/NetworkManager.asset -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/Physics2DSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/PresetManager.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/ProjectSettings.asset -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2018.2.0f2 2 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/QualitySettings.asset -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/TagManager.asset -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/TimeManager.asset -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jknightdoeswork/gpu-physics-unity/224fc1ca4f2de93aae2e3db86ae3f2ffa3bffcb9/ProjectSettings/UnityConnectSettings.asset -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A GPU Accelerated Voxel Physics Solver for Unity 2 | 3 | Read more at 4 | 5 | [http://www.00jknight.com/blog/gpu-accelerated-voxel-physics-solver](http://www.00jknight.com/blog/gpu-accelerated-voxel-physics-solver) 6 | 7 | ![gif](https://thumbs.gfycat.com/MammothInfantileDunlin-size_restricted.gif "Gif") 8 | 9 | 64,000 cubes 10 | 11 | ![gif](https://fat.gfycat.com/JovialKnobbyBrahmanbull.gif "Gif") 12 | 13 | 1024 cubes 14 | 15 | A Unity Command Buffer is used by GPUPhysics.cs to dispatch the compute and render shaders. 16 | 17 | This has been designed such that no per voxel data is transferred between the GPU and the CPU at runtime. 18 | 19 | Speed will likely by further through research and optimization of the per particle Kernels within the Compute Shader. 20 | 21 | LICENSE 22 | 23 | You can use this software in a commercial game, but you cannot sell this software on the Unity Asset Store or any other platform that sells software tools for developers. 24 | 25 | 26 | Further Improvements 27 | 28 | Build the Voxel Grid around the bounds of the simulation dynamically 29 | - auto apply the "renderer bounds" and the "gridDimensions" 30 | - does "renderer bounds" even do anything? - looks like not 31 | 32 | Eliminate the Voxel Grid Clear Step 33 | 34 | Establish the pattern for collision with solid objects 35 | 36 | Find out why the Damping force and Tangential forces described in Takahiro Harada's 37 | system do not seem to have good effects 38 | 39 | Determine if a better shadow pass can be constructed to speed up shadows 40 | 41 | Find out how to reliably render through CommandBuffer.DrawMeshInstancedIndirect (Unity bugs?) 42 | 43 | Optimize the thread grouping 44 | 45 | -------------------------------------------------------------------------------- /gpuphysics.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gpuphysics", "Assembly-CSharp.csproj", "{E879FE27-66DB-210B-114E-A5E451B4A131}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {E879FE27-66DB-210B-114E-A5E451B4A131}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {E879FE27-66DB-210B-114E-A5E451B4A131}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {E879FE27-66DB-210B-114E-A5E451B4A131}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {E879FE27-66DB-210B-114E-A5E451B4A131}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | --------------------------------------------------------------------------------