/// <summary> /// 初期化 /// </summary> protected virtual void Initialize() { particleNum = (particleMax / THREAD_NUM_X) * THREAD_NUM_X; emitNum = (emitMax / THREAD_NUM_X) * THREAD_NUM_X; //Debug.Log("particleNum " + particleNum + " emitNum " + emitNum + " THREAD_NUM_X " + THREAD_NUM_X); particleBuffer = new ComputeBuffer(particleNum, Marshal.SizeOf(typeof(T)), ComputeBufferType.Default); particleActiveBuffer = new ComputeBuffer(particleNum, Marshal.SizeOf(typeof(int)), ComputeBufferType.Append); particleActiveBuffer.SetCounterValue(0); particlePoolBuffer = new ComputeBuffer(particleNum, Marshal.SizeOf(typeof(int)), ComputeBufferType.Append); particlePoolBuffer.SetCounterValue(0); particleActiveCountBuffer = new ComputeBuffer(4, Marshal.SizeOf(typeof(int)), ComputeBufferType.IndirectArguments); particlePoolCountBuffer = new ComputeBuffer(4, Marshal.SizeOf(typeof(int)), ComputeBufferType.IndirectArguments); particlePoolCountBuffer.SetData(particleCounts); initKernel = cs.FindKernel("Init"); emitKernel = cs.FindKernel("Emit"); updateKernel = cs.FindKernel("Update"); cspropid_Particles = ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._Particles); cspropid_DeadList = ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._DeadList); cspropid_ActiveList = ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._ActiveList); cspropid_ParticlePool = ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._ParticlePool); cspropid_EmitNum = ShaderDefines.GetIntPropertyID(ShaderDefines.IntID._EmitNum); //Debug.Log("initKernel " + initKernel + " emitKernel " + emitKernel + " updateKernel " + updateKernel); cs.SetBuffer(initKernel, cspropid_Particles, particleBuffer); cs.SetBuffer(initKernel, cspropid_DeadList, particlePoolBuffer); cs.Dispatch(initKernel, particleNum / THREAD_NUM_X, 1, 1); isInitialized = true; }
// パーティクルの発生処理 public void EmitParticle(Vector3 _position) { // 使用できるパーティクル数を取得 ComputeBuffer.CopyCount(m_particlePoolBuffer, m_particlePoolCountsBuffer, 0); m_particlePoolCountsBuffer.GetData(m_particleCounts); m_particlePoolNum = m_particleCounts[0]; // エミット数未満ならエミット処理をしない if (m_particleCounts[0] < m_numEmitParticles) { return; } // 変数を設定 _computeShader.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._elapsedTime), Time.time); _computeShader.SetVector(ShaderDefines.GetVectorPropertyID(ShaderDefines.VectorID._position), _position); _computeShader.SetVector(ShaderDefines.GetVectorPropertyID(ShaderDefines.VectorID._range), _range); _computeShader.SetVector(ShaderDefines.GetVectorPropertyID(ShaderDefines.VectorID._minVelocity), _minVelocity); _computeShader.SetVector(ShaderDefines.GetVectorPropertyID(ShaderDefines.VectorID._maxVelocity), _maxVelocity); _computeShader.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._startScale), _startScale); _computeShader.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._endScale), _endScale); _computeShader.SetVector(ShaderDefines.GetVectorPropertyID(ShaderDefines.VectorID._color), _color); _computeShader.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._lifeTime), _lifeTime); // バッファを設定 _computeShader.SetBuffer(m_emitKernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._particlePoolBuffer), m_particlePoolBuffer); _computeShader.SetBuffer(m_emitKernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._particlesBuffer), m_particlesBuffer); // エミットカーネルを実行 _computeShader.Dispatch(m_emitKernel, m_numEmitParticles / THREAD_NUM_X, 1, 1); }
// 初期化処理 private void Initialize() { // パーティクル数をスレッド数の倍数にする m_numParticles = Mathf.CeilToInt(_numMaxParticles / (float)THREAD_NUM_X) * THREAD_NUM_X; // エミット数をスレッド数の倍数にする m_numEmitParticles = Mathf.CeilToInt(_numMaxEmitParticles / (float)THREAD_NUM_X) * THREAD_NUM_X; // バッファを生成 m_particlesBuffer = new ComputeBuffer(m_numParticles, Marshal.SizeOf(typeof(GPUParticleData)), ComputeBufferType.Default); m_activeParticlesBuffer = new ComputeBuffer(m_numParticles, Marshal.SizeOf(typeof(int)), ComputeBufferType.Append); m_particlePoolBuffer = new ComputeBuffer(m_numParticles, Marshal.SizeOf(typeof(int)), ComputeBufferType.Append); m_activeParticleCountsBuffer = new ComputeBuffer(4, Marshal.SizeOf(typeof(int)), ComputeBufferType.IndirectArguments); m_particlePoolCountsBuffer = new ComputeBuffer(4, Marshal.SizeOf(typeof(int)), ComputeBufferType.IndirectArguments); // バッファにデータを渡す m_activeParticleCountsBuffer.SetData(m_particleCounts); m_particlePoolCountsBuffer.SetData(m_particleCounts); // カーネルを設定 m_initKernel = _computeShader.FindKernel("Init"); m_emitKernel = _computeShader.FindKernel("Emit"); m_updateKernel = _computeShader.FindKernel("Update"); // 変数を設定 _computeShader.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._gravity), _gravity); // バッファを設定 _computeShader.SetBuffer(m_initKernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._particlesBuffer), m_particlesBuffer); _computeShader.SetBuffer(m_initKernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._deadParticlesBuffer), m_particlePoolBuffer); // 初期化カーネルを実行 _computeShader.Dispatch(m_initKernel, m_numParticles / THREAD_NUM_X, 1, 1); }
// public関数 #region public method public void PutFootsteps(Vector3 _position) { // バッファを設定 _computeShader.SetBuffer(m_putKernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._verticesBuffer), m_verticesBuffer); // 変数を設定 _computeShader.SetVector(ShaderDefines.GetVectorPropertyID(ShaderDefines.VectorID._playerPosition), new Vector2(_position.x, _position.z)); // カーネルの実行 _computeShader.Dispatch(m_putKernel, m_numThreadGroups * m_numThreadGroups, 1, 1); }
// シェーダーの値の設定 private void SetMaterialParam() { // テクスチャを設定 _shaderMaterial.SetTexture(ShaderDefines.GetTexturePropertyID(ShaderDefines.TextureID._mainTexture), _texture); // バッファを設定 _shaderMaterial.SetBuffer(ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._meshIndicesBuffer), m_meshIndicesBuffer); _shaderMaterial.SetBuffer(ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._meshVertexDatasBuffer), m_meshVertexDatasBuffer); _shaderMaterial.SetBuffer(ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._particlesBuffer), m_particlesBuffer); // パスを設定 _shaderMaterial.SetPass(0); }
// 描画処理 private void OnRenderObjectInternal() { // カリングを行うか判定 if (_isCulling) { // カメラを取得 Camera cam = Camera.current; // カメラが存在するか判定 if (!m_cameraDatas.ContainsKey(cam)) { // このフレームは登録だけ m_cameraDatas[cam] = null; } else { // カメラのカリングデータを取得 CullingData data = m_cameraDatas[cam]; // カリングデータが存在するか判定 if (data != null) { // シェーダーの値の設定 SetMaterialParam(); // バッファを設定 _shaderMaterial.SetBuffer(ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._inViewParticlesBuffer), data.GetInViewParticlesBuffer()); // キーワードを有効化 _shaderMaterial.EnableKeyword("GPUPARTICLE_CULLING_ON"); // 描画処理 Graphics.DrawProceduralIndirect(MeshTopology.Triangles, data.GetInViewCountsBuffer()); } } } else { // シェーダーの値の設定 SetMaterialParam(); // バッファを設定 _shaderMaterial.SetBuffer(ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._activeParticlesBuffer), m_activeParticlesBuffer); // キーワードを無効化 _shaderMaterial.DisableKeyword("GPUPARTICLE_CULLING_ON"); // 描画処理 Graphics.DrawProceduralIndirect(MeshTopology.Triangles, m_activeCountBuffer); } }
// 地形描画 void RenderTerrain() { // テクスチャを設定 _shaderMaterial.SetTexture(ShaderDefines.GetTexturePropertyID(ShaderDefines.TextureID._mainTexture), _texture); // 変数を設定 _shaderMaterial.SetInt(ShaderDefines.GetIntPropertyID(ShaderDefines.IntID._numVertices), _numVertices); _shaderMaterial.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._height), _height); // バッファの設定 _shaderMaterial.SetBuffer(ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._verticesBuffer), m_verticesBuffer); // 描画処理 Graphics.DrawMeshInstancedIndirect(_mesh, 0, _shaderMaterial, new Bounds(Vector3.zero, new Vector3(1000.0f, 1000.0f, 1000.0f)), m_argsBuffer); }
// 頂点の計算 void CalculateVertex() { // バッファを設定 _computeShader.SetBuffer(m_calculateKernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._verticesBuffer), m_verticesBuffer); // 変数を設定 _computeShader.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._fieldSize), FIELD_SIZE); _computeShader.SetInt(ShaderDefines.GetIntPropertyID(ShaderDefines.IntID._numVertices), _numVertices); _computeShader.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._distance), m_distance); _computeShader.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._height), _height); _computeShader.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._smoothness), _smoothness * _numVertices); _computeShader.SetVector(ShaderDefines.GetVectorPropertyID(ShaderDefines.VectorID._offset), new Vector2(_offsetX, _offsetY)); // カーネルの実行 _computeShader.Dispatch(m_calculateKernel, m_numThreadGroups, 1, m_numThreadGroups); }
// パーティクルの更新処理 private void UpdateParticle() { // バッファのカウンターをリセット m_activeParticlesBuffer.SetCounterValue(0); // 変数を設定 _computeShader.SetFloat(ShaderDefines.GetFloatPropertyID(ShaderDefines.FloatID._deltaTime), Time.deltaTime); // バッファを設定 _computeShader.SetBuffer(m_updateKernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._particlesBuffer), m_particlesBuffer); _computeShader.SetBuffer(m_updateKernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._deadParticlesBuffer), m_particlePoolBuffer); _computeShader.SetBuffer(m_updateKernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._activeParticlesBuffer), m_activeParticlesBuffer); // 更新カーネルを実行 _computeShader.Dispatch(m_updateKernel, m_numParticles / THREAD_NUM_X, 1, 1); // 使用中のパーティクル数を取得 ComputeBuffer.CopyCount(m_activeParticlesBuffer, m_activeParticleCountsBuffer, 0); }
// 更新処理 public void Update(ComputeShader _computeShader, Camera _camera, int _numParticles, ComputeBuffer _particlesBuffer, ComputeBuffer _activeParticlesBuffer) { // 視錘台カリングを行うカーネル int kernel = _computeShader.FindKernel("FrustumCulling"); // 視錘台の計算 CalculateFrustumPlanes(_camera.projectionMatrix * _camera.worldToCameraMatrix, ref m_planes); // 視錘台の法線を分解 for (int i = 0; i < 4; i++) { Debug.DrawRay(_camera.transform.position, m_planes[i].normal * 10f, Color.yellow); m_normalsFloat[i + 0] = m_planes[i].normal.x; m_normalsFloat[i + 4] = m_planes[i].normal.y; m_normalsFloat[i + 8] = m_planes[i].normal.z; } // バッファのカウンターをリセット m_inViewParticlesBuffer.SetCounterValue(0); // カメラの座標 Vector3 cameraPosition = _camera.transform.position; // 変数を設定 _computeShader.SetInt(ShaderDefines.GetIntPropertyID(ShaderDefines.IntID._numParticles), _numParticles); _computeShader.SetFloats(ShaderDefines.GetVectorPropertyID(ShaderDefines.VectorID._cameraPosition), cameraPosition.x, cameraPosition.y, cameraPosition.z); _computeShader.SetFloats(ShaderDefines.GetVectorPropertyID(ShaderDefines.VectorID._cameraFrustumNormals), m_normalsFloat); // バッファを設定 _computeShader.SetBuffer(kernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._particlesBuffer), _particlesBuffer); _computeShader.SetBuffer(kernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._activeParticlesBuffer), _activeParticlesBuffer); _computeShader.SetBuffer(kernel, ShaderDefines.GetBufferPropertyID(ShaderDefines.BufferID._inViewParticlesBuffer), m_inViewParticlesBuffer); // カーネルを実行 _computeShader.Dispatch(kernel, Mathf.CeilToInt((float)_activeParticlesBuffer.count / NUM_THREAD_X), 1, 1); // バッファにデータを渡す m_inViewCountsBuffer.SetData(m_inViewCounts); // 視界内のパーティクル数を取得 ComputeBuffer.CopyCount(m_inViewParticlesBuffer, m_inViewCountsBuffer, 4); }