#pragma kernel CSMain ${VFXPragmaOnlyRenderers} ${VFXPragmaRequire} ${VFXGlobalInclude} ${VFXGlobalDeclaration} ${VFXInclude("Shaders/VFXParticleCommon.template")} #define USE_DEAD_LIST (VFX_USE_ALIVE_CURRENT && !HAS_STRIPS) #define instancingPrefixSumOffset 0 RWByteAddressBuffer attributeBuffer; ByteAddressBuffer sourceAttributeBuffer; #if !VFX_USE_SPAWNER_FROM_GPU StructuredBuffer spawnBuffer; #define EVENT_PREFIX_SUM(index) spawnBuffer[index] #define SPAWNCOUNT_PREFIX_SUM_OFFSET instancingActiveCount #endif CBUFFER_START(initParamsConst) uint dispatchWidth; ${VFXInstancingConstants} CBUFFER_END #if USE_DEAD_LIST RWStructuredBuffer deadList; #endif #if VFX_USE_SPAWNER_FROM_GPU StructuredBuffer eventList; #endif #if HAS_STRIPS RWStructuredBuffer stripDataBuffer; #endif ${VFXPerPassInclude} ${VFXGeneratedBlockFunction} #if HAS_STRIPS bool GetParticleIndex(inout uint particleIndex, uint stripIndex, uint instanceIndex) { uint relativeIndex; uint bufferIndex = STRIP_DATA_INDEX(instanceIndex, stripIndex); InterlockedAdd(STRIP_DATA(STRIP_NEXT_INDEX, bufferIndex), 1, relativeIndex); bool isFull = relativeIndex >= PARTICLE_PER_STRIP_COUNT; if (isFull) { InterlockedAdd(STRIP_DATA(STRIP_NEXT_INDEX, bufferIndex), -1); // Remove previous increment } else { particleIndex = stripIndex * PARTICLE_PER_STRIP_COUNT + ((STRIP_DATA(STRIP_FIRST_INDEX, bufferIndex) + relativeIndex) % PARTICLE_PER_STRIP_COUNT); } return !isFull; } #endif [numthreads(NB_THREADS_PER_GROUP,1,1)] void CSMain(uint3 groupId : SV_GroupID, uint3 groupThreadId : SV_GroupThreadID) { uint id = groupThreadId.x + groupId.x * NB_THREADS_PER_GROUP; #if !VFX_USE_SPAWNER_FROM_GPU id += groupId.y * dispatchWidth * NB_THREADS_PER_GROUP; #endif ${VFXInitInstancingCompute} ${VFXLoadContextData} uint systemSeed = contextData.systemSeed; ${VFXLoadGraphValues} #if VFX_USE_SPAWNER_FROM_GPU uint elementCount = eventList[VFXGetEventListBufferElementCount(instanceActiveIndex)]; uint totalAccumulatedElementCount = eventList[VFXGetEventListBufferAccumulatedCount(instanceActiveIndex)]; uint maxThreadId = min(contextData.maxParticleCount, elementCount); uint currentSpawnIndex = totalAccumulatedElementCount - elementCount; #else uint nbEvents = EVENT_PREFIX_SUM(instanceActiveIndex); [branch] if (instanceActiveIndex > 0u) { nbEvents -= EVENT_PREFIX_SUM(instanceActiveIndex - 1); } uint maxThreadId = instancingPrefixSum[instancingPrefixSumOffset + instanceCurrentIndex]; [branch] if (instanceCurrentIndex > instancingCurrentOffset) { maxThreadId -= instancingPrefixSum[instancingPrefixSumOffset + instanceCurrentIndex - 1]; } uint currentSpawnIndex = contextData.initSpawnIndex; #endif #if USE_DEAD_LIST maxThreadId = min(maxThreadId, deadList[DEAD_LIST_COUNT_COPY_OFFSET + instanceIndex]); #endif if (index < maxThreadId) { #if VFX_USE_SPAWNER_FROM_GPU int sourceIndex = eventList[VFXGetEventListBufferIndex(id, instanceActiveIndex)]; #endif uint startEventIndex = 0u; //tmp for GPU Events #if !VFX_USE_SPAWNER_FROM_GPU int sourceIndex = 0; startEventIndex = 0; [branch] if (instanceActiveIndex > 0u) { startEventIndex = EVENT_PREFIX_SUM(instanceActiveIndex - 1); } uint sourceSearchBegin = startEventIndex + SPAWNCOUNT_PREFIX_SUM_OFFSET; uint sourceSearchEnd = sourceSearchBegin + nbEvents; sourceIndex = BinarySearchPrefixSum(index, spawnBuffer, sourceSearchBegin, sourceSearchEnd) - sourceSearchBegin; #endif VFXAttributes attributes = (VFXAttributes)0; VFXSourceAttributes sourceAttributes = (VFXSourceAttributes)0; ${VFXLoadAttributes} uint particleIndex = index + currentSpawnIndex; #if VFX_USE_PARTICLEID_CURRENT attributes.particleId = particleIndex; #endif #if VFX_USE_SEED_CURRENT attributes.seed = WangHash(particleIndex ^ systemSeed); #endif #if VFX_USE_SPAWNINDEX_CURRENT attributes.spawnIndex = id; #endif #if HAS_STRIPS #if !VFX_USE_SPAWNER_FROM_GPU ${VFXLoadParameter:{stripIndex}} #else uint stripIndex = sourceIndex; #endif stripIndex = min(stripIndex, STRIP_COUNT); if (!GetParticleIndex(particleIndex, stripIndex, instanceIndex)) return; const StripData stripData = GetStripDataFromStripIndex(stripIndex, instanceIndex); InitStripAttributesWithSpawn(maxThreadId, particleIndex, attributes, stripData); // TODO Change seed to be sure we're deterministic on random with strip #endif ${VFXProcessBlocks} #if VFX_USE_ALIVE_CURRENT if (attributes.alive) #endif { #if USE_DEAD_LIST uint deadIndex; InterlockedAdd(deadList[instanceIndex], -1, deadIndex); deadIndex -= 1; deadIndex += DEAD_LIST_OFFSET + instanceIndex * RAW_CAPACITY; uint index = deadList[deadIndex]; #else uint index = particleIndex; #endif ${VFXStoreAttributes} } } }