/// <summary> /// 密度計算 /// </summary> void ComputeDensity() { int kernelIdx = _particleComputeShader.FindKernel(CS_NAMES.COMPUTE_DENSITY_KERNEL); _particleComputeShader.SetBuffer(kernelIdx, CS_NAMES.PARTICLE_READ_BUFFER, _particleBuffer.Current); _particleComputeShader.SetBuffer(kernelIdx, CS_NAMES.PARTICLE_WRITE_BUFFER, _particleBuffer.Other); _particleComputeShader.SetBuffer(kernelIdx, CS_NAMES.CELL_START_END_BUFFER, _cellStartEndBuffer); _particleComputeShader.Dispatch(kernelIdx, _groupNum.x, _groupNum.y, _groupNum.z); _particleBuffer.Swap(); }
// SORT. private static void Sort() { Debug.Assert(sTotalParticleCount <= sMergedParticleCount); Debug.Assert(Mathf.IsPowerOfTwo(sMergedParticleCount)); // DISPATCH SORT BUFFER. for (int k = 2; k <= sMergedParticleCount; k <<= 1) // Major steps. { for (int j = k >> 1; j > 0; j = j >> 1) // Minor steps. { // SWAP AND BIND BUFFERS. sSortElementSwapBuffer.Swap(); sComputeShader.SetBuffer(sKernelSort, "gSortElementBufferIN", sSortElementSwapBuffer.GetInputBuffer()); sComputeShader.SetBuffer(sKernelSort, "gSortElementBufferOUT", sSortElementSwapBuffer.GetOutputBuffer()); sComputeShader.SetInt("gK", k); sComputeShader.SetInt("gJ", j); sComputeShader.SetInt("gMaxParticleCount", sMergedParticleCount); // DISPATCH. sComputeShader.Dispatch(sKernelSort, (int)Mathf.Ceil(sMergedParticleCount / 64.0f), 1, 1); } } }
// FETCH COLLISION RESULTS. private static void FetchCollisionResults() { List <GPUParticleSphereCollider> sphereColliderList = GPUParticleSphereCollider.GetGPUParticleSphereColliderList(); // Return early if null or zero GPUParticleSphereCollider. if (sphereColliderList == null) { return; } if (sphereColliderList.Count == 0) { return; } Debug.Assert(sphereColliderList.Count < sMaxSphereColliderCount); // Reset data. // TODO: Might not need to reset all this data!! int[] data = new int[sMaxGPUColliderCount]; for (int i = 0; i < data.GetLength(0); ++i) { data[i] = 0; } sGPUColliderResultSwapBuffer.GetInputBuffer().SetData(data); sGPUColliderResultSwapBuffer.GetOutputBuffer().SetData(data); int count = 0; bool initZero = true; foreach (KeyValuePair <GPUParticleSystem, GPUParticleSystem> it in sGPUParticleSystemDictionary) { GPUParticleSystem system = it.Value; if (!system.gameObject.activeInHierarchy) { continue; } sGPUColliderResultSwapBuffer.Swap(); sComputeShader.SetBuffer(sKernelResult, "gGPUColliderResultBufferIN", sGPUColliderResultSwapBuffer.GetInputBuffer()); sComputeShader.SetBuffer(sKernelResult, "gGPUColliderResultBufferOUT", sGPUColliderResultSwapBuffer.GetOutputBuffer()); sComputeShader.SetInt("gGPUColliderCount", sphereColliderList.Count); sComputeShader.SetBuffer(sKernelResult, "gSphereColliderResultBufferREAD", system.GetSphereColliderResultBuffer()); sComputeShader.SetBool("gInitZero", initZero); initZero = false; // DISPATCH. sComputeShader.Dispatch(sKernelResult, (int)Mathf.Ceil(sMaxSphereColliderCount / 64.0f), 1, 1); count++; } // GET DATA FROM GPU TO CPU. int[] collisionData = new int[sphereColliderList.Count]; sGPUColliderResultSwapBuffer.GetOutputBuffer().GetData(collisionData); // UPDATE COLLIDERS. for (int i = 0; i < sphereColliderList.Count; ++i) { GPUParticleSphereCollider collider = sphereColliderList[i]; if (GPUParticleSphereCollider.SKIPFRAME) { GPUParticleSphereCollider.SKIPFRAME = false; collider.SetCollisionsThisFrame(0); } else { collider.SetCollisionsThisFrame(collisionData[i]); } } }
// UPDATE. private void UpdateSystem() { // SWAP INPUT/OUTPUT. mPositionBuffer.Swap(); mVelocityBuffer.Swap(); mLifetimeBuffer.Swap(); // BIND INPUT BUFFERS. sComputeShader.SetBuffer(sKernelUpdate, "gPositionIN", mPositionBuffer.GetInputBuffer()); sComputeShader.SetBuffer(sKernelUpdate, "gVelocityIN", mVelocityBuffer.GetInputBuffer()); sComputeShader.SetBuffer(sKernelUpdate, "gLifetimeIN", mLifetimeBuffer.GetInputBuffer()); // BIND OUTPUT BUFFERS. sComputeShader.SetBuffer(sKernelUpdate, "gPositionOUT", mPositionBuffer.GetOutputBuffer()); sComputeShader.SetBuffer(sKernelUpdate, "gVelocityOUT", mVelocityBuffer.GetOutputBuffer()); sComputeShader.SetBuffer(sKernelUpdate, "gLifetimeOUT", mLifetimeBuffer.GetOutputBuffer()); sComputeShader.SetBuffer(sKernelUpdate, "gColorOUT", mColorBuffer); sComputeShader.SetBuffer(sKernelUpdate, "gHaloOUT", mHaloBuffer); sComputeShader.SetBuffer(sKernelUpdate, "gScaleOUT", mScaleBuffer); sComputeShader.SetBuffer(sKernelUpdate, "gTransparencyOUT", mTransperancyBuffer); // BIND VALUE OF LIFETIME BUFFERS. sComputeShader.SetInt("gColorLifetimeCount", mDescriptor.ColorOverLifetime.Length()); sComputeShader.SetBuffer(sKernelUpdate, "gColorLifetimeBuffer", mColorLifetimePointsBuffer); sComputeShader.SetInt("gHaloLifetimeCount", mDescriptor.HaloOverLifetime.Length()); sComputeShader.SetBuffer(sKernelUpdate, "gHaloLifetimeBuffer", mHaloLifetimePointsBuffer); sComputeShader.SetInt("gScaleLifetimeCount", mDescriptor.ScaleOverLifetime.Length()); sComputeShader.SetBuffer(sKernelUpdate, "gScaleLifetimeBuffer", mScaleLifetimePointsBuffer); sComputeShader.SetInt("gTransparencyLifetimeCount", mDescriptor.OpacityOverLifetime.Length()); sComputeShader.SetBuffer(sKernelUpdate, "gTransparencyLifetimeBuffer", mTransparencyLifetimePointsBuffer); // SET META DATA. sComputeShader.SetInt("gMaxParticleCount", mMaxParticleCount); sComputeShader.SetFloat("gDeltaTime", Time.deltaTime); sComputeShader.SetFloats("gConstantAcceleration", new float[] { mDescriptor.ConstantAcceleration.x, mDescriptor.ConstantAcceleration.y, mDescriptor.ConstantAcceleration.z }); sComputeShader.SetFloat("gConstantDrag", mDescriptor.ConstantDrag); // ACCELERATOR. Dictionary <GPUParticleAttractor, GPUParticleAttractor> attractorDictionary = GPUParticleAttractor.GetGPUParticleAttractorDictionary(); if (attractorDictionary == null) { sComputeShader.SetInt("gAttractorCount", 0); } else { Debug.Assert(attractorDictionary.Count < sMaxAttractorCount); float[] attractorArray = new float[attractorDictionary.Count * 8]; int i = 0; int count = 0; foreach (KeyValuePair <GPUParticleAttractor, GPUParticleAttractor> it in attractorDictionary) { GPUParticleAttractor attractor = it.Value; //Skip if inactive. if (!attractor.gameObject.activeInHierarchy) { continue; } float scale = Mathf.Max(Mathf.Max(attractor.transform.localScale.x, attractor.transform.localScale.y), attractor.transform.localScale.z); attractorArray[i++] = attractor.transform.position.x; attractorArray[i++] = attractor.transform.position.y; attractorArray[i++] = attractor.transform.position.z; attractorArray[i++] = attractor.Power; attractorArray[i++] = scale * attractor.Min; attractorArray[i++] = scale * attractor.Max; attractorArray[i++] = 0.0f; //Padding attractorArray[i++] = 0.0f; //Padding count++; } sGPUParticleAttractorBuffer.SetData(attractorArray); sComputeShader.SetInt("gAttractorCount", count); sComputeShader.SetBuffer(sKernelUpdate, "gAttractorBuffer", sGPUParticleAttractorBuffer); } // Vector Fields. Dictionary <GPUParticleVectorField, GPUParticleVectorField> vectorFieldDictionary = GPUParticleVectorField.GetGPUParticleAttractorDictionary(); if (vectorFieldDictionary == null) { sComputeShader.SetInt("gVectorFieldCount", 0); } else { Debug.Assert(vectorFieldDictionary.Count < sMaxVectorFieldCount); float[] vectorFieldArray = new float[vectorFieldDictionary.Count * 8]; int i = 0; int count = 0; foreach (KeyValuePair <GPUParticleVectorField, GPUParticleVectorField> it in vectorFieldDictionary) { GPUParticleVectorField vectorField = it.Value; //Skip if inactive. if (!vectorField.gameObject.activeInHierarchy) { continue; } float scale = Mathf.Max(Mathf.Max(vectorField.transform.localScale.x, vectorField.transform.localScale.y), vectorField.transform.localScale.z); Vector3 vector = vectorField.RelativeVectorField ? vectorField.VectorRelative : vectorField.Vector; vectorFieldArray[i++] = vectorField.transform.position.x; vectorFieldArray[i++] = vectorField.transform.position.y; vectorFieldArray[i++] = vectorField.transform.position.z; vectorFieldArray[i++] = vector.x; vectorFieldArray[i++] = vector.y; vectorFieldArray[i++] = vector.z; vectorFieldArray[i++] = scale * vectorField.Min; vectorFieldArray[i++] = scale * vectorField.Max; count++; } sGPUParticleVectorFieldBuffer.SetData(vectorFieldArray); sComputeShader.SetInt("gVectorFieldCount", count); sComputeShader.SetBuffer(sKernelUpdate, "gVectorFieldBuffer", sGPUParticleVectorFieldBuffer); } // SPHERE COLLIDER. List <GPUParticleSphereCollider> sphereColliderList = GPUParticleSphereCollider.GetGPUParticleSphereColliderList(); if (sphereColliderList == null) { sComputeShader.SetInt("gSphereColliderCount", 0); } else { Debug.Assert(sphereColliderList.Count < sMaxSphereColliderCount); // Reset result buffer. int[] resetArray = new int[sphereColliderList.Count]; for (int i = 0; i < sphereColliderList.Count; ++i) { resetArray[i] = 0; } mSphereColliderResultBuffer.SetData(resetArray); // Update sphere collider buffer. float[] sphereColliderArray = new float[sphereColliderList.Count * 4]; int count = 0; for (int i = 0, j = 0; i < sphereColliderList.Count; ++i) { GPUParticleSphereCollider sphereCollider = sphereColliderList[i]; //Skip if inactive. if (!sphereCollider.gameObject.activeInHierarchy) { continue; } float scale = Mathf.Max(Mathf.Max(sphereCollider.transform.localScale.x, sphereCollider.transform.localScale.y), sphereCollider.transform.localScale.z); sphereColliderArray[j++] = sphereCollider.transform.position.x; sphereColliderArray[j++] = sphereCollider.transform.position.y; sphereColliderArray[j++] = sphereCollider.transform.position.z; sphereColliderArray[j++] = scale * sphereCollider.Radius; count++; } sGPUParticleSphereColliderBuffer.SetData(sphereColliderArray); sComputeShader.SetInt("gSphereColliderCount", count); sComputeShader.SetBuffer(sKernelUpdate, "gSphereColliderBuffer", sGPUParticleSphereColliderBuffer); sComputeShader.SetBuffer(sKernelUpdate, "gSphereColliderResultBufferWRITE", mSphereColliderResultBuffer); } // DISPATCH. sComputeShader.Dispatch(sKernelUpdate, (int)Mathf.Ceil(mMaxParticleCount / 64.0f), 1, 1); }
/// <summary> /// Swap to switch read and write buffer. /// </summary> public void Swap() { mSwapBuffer.Swap(); }