Пример #1
0
        private void OnFrameUpdate(ThreadContext context)
        {
            updatePasses.Enabled = true; //!RenderContext.IsPaused;

            // Add new updater to the current list
            foreach (var particleUpdater in Updaters)
            {
                ParticleUpdaterState particleUpdaterState = null;
                foreach (ParticleUpdaterState state in currentUpdaters)
                {
                    if (ReferenceEquals(state.UserState, particleUpdater))
                    {
                        particleUpdaterState = state;
                        break;
                    }
                }
                if (particleUpdaterState == null)
                {
                    currentUpdaters.Add(new ParticleUpdaterState()
                    {
                        UserState = particleUpdater, StructureSize = StructureSize
                    });
                }
            }

            // Get updater to remove from current list
            foreach (var particleUpdater in currentUpdaters)
            {
                ParticleEmitterComponent particleUpdaterState = null;
                foreach (ParticleEmitterComponent state in Updaters)
                {
                    if (ReferenceEquals(state, particleUpdater.UserState))
                    {
                        particleUpdaterState = state;
                        break;
                    }
                }
                if (particleUpdaterState == null)
                {
                    updatersToRemove.Add(particleUpdater);
                }
            }

            // Remove from the current list
            foreach (var particleUpdaterState in updatersToRemove)
            {
                currentUpdaters.Remove(particleUpdaterState);

                // Remove the mesh to be rendered
                meshesToRender.RemoveMesh(particleUpdaterState.MeshUpdater);

                // Dispose the previous particule updater as it is no longer used
                particleUpdaterState.DisposeBuffers();
            }

            // Reallocate global buffers if needed
            if (updatersCount > capacityCount)
            {
                CapacityCount = updatersCount;
                OnCapacityCountChange();
            }

            int particleUpdaterIndex = 1;

            currentParticleCount = 0;
            // Update start index into global buffers for all CPU/GPU static buffers.
            int startIndex = 0;

            for (int i = 0; i < currentUpdaters.Count; i++)
            {
                var currentState = currentUpdaters[i];
                var userState    = currentState.UserState;

                if (!userState.IsDynamicEmitter)
                {
                    // If there is a change from dynamic type to CPU/GPU static buffer, we need to deallocate previous Append/ConsumeBuffers
                    if (currentState.IsDynamicEmitter)
                    {
                        currentState.DisposeBuffers();
                    }
                }
                else if (userState.Count > currentState.Count)
                {
                    // This is a dynamic buffer and the new buffer is larger than previous one
                    // or we simply need to allocate new consume/append buffers
                    currentState.AllocateBuffers(context.GraphicsDevice);
                }

                // Create Effect shader
                if (!ReferenceEquals(userState.Shader, currentState.Shader) || currentState.Count != userState.Count)
                {
                    // Remove the effect pass
                    updatePasses.RemovePass(currentState.EffectPass);

                    // Dispose previous effects
                    currentState.DisposeEffects();

                    // Remove mesh
                    if (currentState.MeshUpdater != null)
                    {
                        meshesToRender.RemoveMesh(currentState.MeshUpdater);
                        currentState.MeshUpdater = null;
                    }

                    // Compile new shader
                    if (userState.Shader != null)
                    {
                        string name = userState.Name ?? string.Format("{0}{1}", userState.Shader.ClassName, particleUpdaterIndex++);

                        currentState.EffectPass = new RenderPass(name);
                        updatePasses.AddPass(currentState.EffectPass);

                        // Calculate the best dispatch thread count
                        int dispatchCount = MaximumThreadPerGroup;
                        while (dispatchCount > 0)
                        {
                            // If the maximum count is a multiple of the current dispatchCount use it
                            if ((userState.Count & (dispatchCount - 1)) == 0)
                            {
                                break;
                            }
                            dispatchCount >>= 1;
                        }

                        // Compile the new shader for this count
                        currentState.EffectUpdater = this.EffectSystemOld.BuildEffect(name).Using(
                            new ComputeShaderPlugin(userState.Shader, dispatchCount, 1, 1)
                        {
                            RenderPass = currentState.EffectPass,
                            Macros     = { new ShaderMacro("PARTICLE_STRUCT", StructureName) }
                        });

                        // Instantiate the mesh updater
                        var meshParams = new ParameterCollection(name);
                        currentState.MeshUpdater = new EffectMesh(currentState.EffectUpdater, new Mesh {
                            Parameters = meshParams
                        }).Dispatch(userState.Count / dispatchCount, 1, 1);
                        currentState.MeshUpdater.Parameters.AddSources(Parameters);
                        currentState.MeshUpdater.Parameters.AddSources(MainPlugin.ViewParameters);
                        currentState.MeshUpdater.Parameters.AddSources(userState.Parameters);

                        // Setup Append/Consume
                        if (userState.IsDynamicEmitter)
                        {
                            currentState.MeshUpdater.Parameters.Set(ParticleBaseKeys.ParticleInputBuffer, currentState.ConsumeBuffer);
                            currentState.MeshUpdater.Parameters.Set(ParticleBaseKeys.ParticleOutputBuffer, currentState.AppendBuffer);
                            currentState.MeshUpdater.Parameters.Set(ParticleBaseKeys.ParticleStartIndex, (uint)0);
                        }
                        else
                        {
                            // Setup update on global buffer
                            currentState.MeshUpdater.Parameters.Set(ParticleBaseKeys.ParticleGlobalBuffer, globalBuffer);
                            currentState.MeshUpdater.Parameters.Set(ParticleBaseKeys.ParticleStartIndex, (uint)startIndex);
                        }

                        // Add this updater to the rendering list
                        meshesToRender.AddMesh(currentState.MeshUpdater);
                    }
                }

                // Setup Append/Consume
                if (currentState.MeshUpdater != null && !userState.IsDynamicEmitter && currentState.StartIndex != startIndex)
                {
                    // Setup update on global buffer
                    currentState.MeshUpdater.Parameters.Set(ParticleBaseKeys.ParticleStartIndex, (uint)startIndex);
                }

                // Transfer CPU buffer to GPU
                if (!ReferenceEquals(userState.ParticleData, currentState.ParticleData) ||
                    userState.UpdateNextBuffer ||
                    userState.Type == ParticleEmitterType.CpuDynamic ||
                    currentState.StartIndex != startIndex ||
                    currentState.Count != userState.Count
                    )
                {
                    // Update the data if necessary
                    userState.OnUpdateData();

                    if (userState.ParticleData != null)
                    {
                        var handle = GCHandle.Alloc(userState.ParticleData, GCHandleType.Pinned);
                        globalBuffer.SetData(context.GraphicsDevice, new DataPointer(handle.AddrOfPinnedObject(), userState.Count * StructureSize), startIndex * StructureSize);
                        handle.Free();
                    }
                    userState.UpdateNextBuffer = false;
                }

                // Replicate the shader to the current state
                currentState.Type   = userState.Type;
                currentState.Shader = userState.Shader;
                currentState.Count  = userState.Count;
                currentState.ParticleElementSize = userState.ParticleElementSize;
                currentState.ParticleData        = userState.ParticleData;
                currentState.StartIndex          = startIndex;

                // Copy Maximum count to current state
                currentParticleCount += userState.Count;

                // Update start index
                startIndex += userState.Count;
            }

            // Add mesh to the render list
            if (updatersCount > 0)
            {
                if (!isParticleRenderingEnabled)
                {
                    isParticleRenderingEnabled = true;

                    meshesToRender.AddMesh(effectMeshRender);
                    meshesToRender.AddMesh(effectMeshCopyToSortBuffer);
                }
            }
            else
            {
                isParticleRenderingEnabled = false;
                meshesToRender.RemoveMesh(effectMeshRender);
                meshesToRender.RemoveMesh(effectMeshCopyToSortBuffer);
            }

            // Prepare mesh for rendering
            PrepareForRendering();
        }