예제 #1
0
    public void Initialise(int numParticles, float waveParticleKillThreshold)
    {
        _particleContainerSize     = numParticles;
        _waveParticleKillThreshold = waveParticleKillThreshold;
        _splatTexture = null;

        // TODO: write Compute shader to clear this buffer
        _waveParticlesBuffer = new ComputeBuffer((int)_particleContainerSize, WaveParticle.STRIDE);

        _gpuCommitParticles    = Resources.Load <ComputeShader>(COMMIT_PARTICLES);
        _gpuSplatParticles     = Resources.Load <ComputeShader>(SPLAT_PARTICLES);
        _gpuSubdivideParticles = Resources.Load <ComputeShader>(SUBDIVIDE_PARTICLES);

        kernel_CommmitParticles       = _gpuCommitParticles.FindKernel(COMMIT_PARTICLES);
        kernel_SplatParticles         = _gpuSplatParticles.FindKernel(SPLAT_PARTICLES);
        kernel_SubdivideParticles     = _gpuSubdivideParticles.FindKernel(SUBDIVIDE_PARTICLES);
        kernel_AddSubdividedParticles = _gpuSubdivideParticles.FindKernel(ADD_SUBDIVIDED_PARTICLES);

        _particleEvents = new EventElement[_particleContainerSize];
        for (int i = 0; i < _particleEvents.Length; i++)
        {
            _particleEvents[i] = EventElement.getDeadEvent();
        }
        for (int i = 0; i < _subdivisionEvents.Length; i++)
        {
            _subdivisionEvents[i] = _NullParticleIndex;
        }

        _pendingParticles = new WaveParticle[numParticles / 10];

        downsampleMaterial = new Material(Shader.Find("Unlit/DownSampleTexture"));
        DOWNSAMPLE_ANTI_ALIAS_FACTOR_ID = Shader.PropertyToID("_antiAliasFactor");
        DOWNSAMPLE_TEXTURE_WIDTH_ID     = Shader.PropertyToID("_textureWidth");
        DOWNSAMPLE_TEXTURE_HEIGHT_ID    = Shader.PropertyToID("_textureHeight");
    }
예제 #2
0
    /// <summary>
    /// Apply the subdivisions based on which particles need subdividing this frame.
    ///
    /// This happens in two Compute Shader steps:
    ///
    ///   - The first takes all particles to be subdived and calculates the details of which particles will be created
    ///
    ///   - The second takes all the newly created particles and adds them to the total pool of Wave Particles
    ///     It also creates a buffer of data that can be used to calculate future subdivision events that will occur
    ///     as a result of the new wave particles.
    ///
    /// </summary>
    /// <param name="currentFrame"></param>
    public void calculateSubdivisions(int currentFrame)
    {
        // Commit all pending particles that are stored in CPU memory to the GPU.
        commitParticles();

        ///
        /// Count the number of subdivisions that will applied this frame.
        ///
        int numSubdivisions = 0;

        {
            int particleIndex = _subdivisionEvents[currentFrame];
            while (particleIndex != _NullParticleIndex)
            {
                numSubdivisions++;
                particleIndex = _particleEvents[particleIndex].frontIndex;
            }
        }

        // If no subdivisions are required, return
        if (numSubdivisions == 0)
        {
            return;
        }

        ///
        /// Get the indices of all the particles that will be subdivided this frame.
        ///
        int[] particleIndicesToSubdivide = new int[numSubdivisions];
        {
            int particleIndex = _subdivisionEvents[currentFrame];
            for (int i = 0; i < particleIndicesToSubdivide.Length; i++)
            {
                particleIndicesToSubdivide[i] = particleIndex;
                particleIndex = _particleEvents[particleIndex].frontIndex;
                _particleEvents[particleIndicesToSubdivide[i]] = EventElement.getDeadEvent();
            }
            _subdivisionEvents[currentFrame] = _NullParticleIndex;
        }

        ///
        /// Create buffers for storing particles to be subdivided and the resulting subdivisions.
        ///
        ComputeBuffer particleIndicesToSubdivideBuffer = new ComputeBuffer(numSubdivisions, sizeof(int));

        particleIndicesToSubdivideBuffer.SetData(particleIndicesToSubdivide);
        // Create an append buffer for the newly created particles
        ComputeBuffer particlesToAddBuffer = new ComputeBuffer(numSubdivisions * 3, WaveParticle.STRIDE, ComputeBufferType.Append);

        particlesToAddBuffer.SetCounterValue(0);

        // Load particles to be subdivided into this buffer, and copy it out to get future subdivision details???
        _gpuSubdivideParticles.SetInt(NUM_SUBDIVISIONS, numSubdivisions);
        _gpuSubdivideParticles.SetFloat(KILL_THRESHOLD, _waveParticleKillThreshold);
        _gpuSubdivideParticles.SetBuffer(kernel_SubdivideParticles, PARTICLE_INDICES_TO_SUBDIVIDE_BUFFER, particleIndicesToSubdivideBuffer);
        _gpuSubdivideParticles.SetBuffer(kernel_SubdivideParticles, WAVE_PARTICLE_BUFFER, _waveParticlesBuffer);
        _gpuSubdivideParticles.SetBuffer(kernel_SubdivideParticles, PARTICLES_TO_ADD_APPEND_BUFFER, particlesToAddBuffer);
        _gpuSubdivideParticles.Dispatch(kernel_SubdivideParticles, (numSubdivisions + THREAD_GROUPS_X) / THREAD_GROUPS_X, 1, 1);

        int           numParticlesToAdd     = particlesToAddBuffer.count;
        ComputeBuffer subdivisionDataBuffer = new ComputeBuffer(numParticlesToAdd, sizeof(int) * 2);

        _gpuSubdivideParticles.SetInt(CURRENT_HEAD, _currentHead);
        _gpuSubdivideParticles.SetInt(PARTICLE_CONTAINER_SIZE, _particleContainerSize);
        _gpuSubdivideParticles.SetInt(FRAME_CYCLE_LENGTH, WaveParticle.FRAME_CYCLE_LENGTH);
        _gpuSubdivideParticles.SetInt(NUM_PARTICLES_TO_ADD, numParticlesToAdd);
        _gpuSubdivideParticles.SetFloat(WAVE_PARTICLE_RADIUS, WaveParticle.RADIUS);
        _gpuSubdivideParticles.SetFloat(FIXED_DELTA_TIME, Time.fixedDeltaTime);
        _gpuSubdivideParticles.SetFloat(PARTICLE_SPEED, WaveParticle.PARTICLE_SPEED);

        _gpuSubdivideParticles.SetBuffer(kernel_AddSubdividedParticles, PARTICLES_TO_ADD_CONSUME_BUFFER, particlesToAddBuffer);
        _gpuSubdivideParticles.SetBuffer(kernel_AddSubdividedParticles, SUBDIVISION_DATA, subdivisionDataBuffer);
        _gpuSubdivideParticles.SetBuffer(kernel_AddSubdividedParticles, WAVE_PARTICLE_BUFFER, _waveParticlesBuffer);

        _gpuSubdivideParticles.Dispatch(kernel_AddSubdividedParticles, (numParticlesToAdd + THREAD_GROUPS_X) / THREAD_GROUPS_X, 1, 1);

        _currentHead           = (_currentHead + numParticlesToAdd) % _particleContainerSize;
        int[,] subdivisionData = new int[numParticlesToAdd, 2];
        subdivisionDataBuffer.GetData(subdivisionData);
        for (int i = 0; i < numParticlesToAdd; i++)
        {
            int particleIndex    = subdivisionData[i, 0];
            int subdivisionFrame = subdivisionData[i, 1];
            addSubdivisionEvent(particleIndex, subdivisionFrame);
        }

        subdivisionDataBuffer.Release();
        particlesToAddBuffer.Release();
        particleIndicesToSubdivideBuffer.Release();
    }