Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
205 lines (162 sloc) 5.96 KB
#include "globals.hlsli"
#include "ShaderInterop_EmittedParticle.h"
#include "reconstructPositionHF.hlsli"
#include "depthConvertHF.hlsli"
RWSTRUCTUREDBUFFER(particleBuffer, Particle, 0);
RWSTRUCTUREDBUFFER(aliveBuffer_CURRENT, uint, 1);
RWSTRUCTUREDBUFFER(aliveBuffer_NEW, uint, 2);
RWSTRUCTUREDBUFFER(deadBuffer, uint, 3);
RWRAWBUFFER(counterBuffer, 4);
RWSTRUCTUREDBUFFER(distanceBuffer, float, 6);
#define NUM_LDS_FORCEFIELDS 32
struct LDS_ForceField
{
uint type;
float3 position;
float gravity;
float range_inverse;
float3 normal;
};
groupshared LDS_ForceField forceFields[NUM_LDS_FORCEFIELDS];
#define SPH_FLOOR_COLLISION
#define SPH_BOX_COLLISION
[numthreads(THREADCOUNT_SIMULATION, 1, 1)]
void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex)
{
//uint aliveCount = counterBuffer[0].aliveCount;
uint aliveCount = counterBuffer.Load(PARTICLECOUNTER_OFFSET_ALIVECOUNT);
// Load the forcefields into LDS:
uint numForceFields = min(g_xFrame_ForceFieldArrayCount, NUM_LDS_FORCEFIELDS);
if (Gid < numForceFields)
{
uint forceFieldID = g_xFrame_ForceFieldArrayOffset + Gid;
ShaderEntityType forceField = EntityArray[forceFieldID];
forceFields[Gid].type = (uint)forceField.GetType();
forceFields[Gid].position = forceField.positionWS;
forceFields[Gid].gravity = forceField.energy;
forceFields[Gid].range_inverse = forceField.range;
forceFields[Gid].normal = forceField.directionWS;
}
GroupMemoryBarrierWithGroupSync();
if (DTid.x < aliveCount)
{
// simulation can be either fixed or variable timestep:
const float dt = xEmitterFixedTimestep >= 0 ? xEmitterFixedTimestep : g_xFrame_DeltaTime;
uint particleIndex = aliveBuffer_CURRENT[DTid.x];
Particle particle = particleBuffer[particleIndex];
if (particle.life > 0)
{
// simulate:
for (uint i = 0; i < numForceFields; ++i)
{
LDS_ForceField forceField = forceFields[i];
float3 dir = forceField.position - particle.position;
float dist;
if (forceField.type == ENTITY_TYPE_FORCEFIELD_POINT) // point-based force field
{
dist = length(dir);
}
else // planar force field
{
dist = dot(forceField.normal, dir);
dir = forceField.normal;
}
particle.force += dir * forceField.gravity * (1 - saturate(dist * forceField.range_inverse));
}
#ifdef DEPTHCOLLISIONS
// NOTE: We are using the textures from previous frame, so reproject against those! (PrevVP)
float4 pos2D = mul(float4(particle.position, 1), g_xFrame_MainCamera_PrevVP);
pos2D.xyz /= pos2D.w;
if (pos2D.x > -1 && pos2D.x < 1 && pos2D.y > -1 && pos2D.y < 1)
{
float2 uv = pos2D.xy * float2(0.5f, -0.5f) + 0.5f;
uint2 pixel = uv * g_xFrame_InternalResolution;
float depth0 = texture_depth[pixel + uint2(0, 0)];
float surfaceLinearDepth = getLinearDepth(depth0);
float surfaceThickness = 1.5f;
float lifeLerp = 1 - particle.life / particle.maxLife;
float particleSize = lerp(particle.sizeBeginEnd.x, particle.sizeBeginEnd.y, lifeLerp);
// check if particle is colliding with the depth buffer, but not completely behind it:
if ((pos2D.w + particleSize > surfaceLinearDepth) && (pos2D.w - particleSize < surfaceLinearDepth + surfaceThickness))
{
// Calculate surface normal and bounce off the particle:
float depth1 = texture_depth[pixel + uint2(1, 0)];
float depth2 = texture_depth[pixel + uint2(0, 1)];
float3 p0 = getPositionEx(uv, depth0, g_xFrame_MainCamera_PrevInvVP);
float3 p1 = getPositionEx(uv, depth1, g_xFrame_MainCamera_PrevInvVP);
float3 p2 = getPositionEx(uv, depth2, g_xFrame_MainCamera_PrevInvVP);
float3 surfaceNormal = normalize(cross(p2 - p0, p1 - p0));
const float restitution = 0.98f;
particle.velocity = reflect(particle.velocity, surfaceNormal) * restitution;
}
}
#endif // DEPTHCOLLISIONS
// integrate:
particle.velocity += particle.force * dt;
particle.position += particle.velocity * dt;
// reset force for next frame:
particle.force = 0;
if (xSPH_ENABLED)
{
// drag:
particle.velocity *= 0.98f;
// debug collisions:
float elastic = 0.6;
float lifeLerp = 1 - particle.life / particle.maxLife;
float particleSize = lerp(particle.sizeBeginEnd.x, particle.sizeBeginEnd.y, lifeLerp);
#ifdef SPH_FLOOR_COLLISION
// floor collision:
if (particle.position.y - particleSize < 0)
{
particle.position.y = particleSize;
particle.velocity.y *= -elastic;
}
#endif // FLOOR_COLLISION
#ifdef SPH_BOX_COLLISION
// box collision:
float3 extent = float3(40, 0, 22);
if (particle.position.x + particleSize > extent.x)
{
particle.position.x = extent.x - particleSize;
particle.velocity.x *= -elastic;
}
if (particle.position.x - particleSize < -extent.x)
{
particle.position.x = -extent.x + particleSize;
particle.velocity.x *= -elastic;
}
if (particle.position.z + particleSize > extent.z)
{
particle.position.z = extent.z - particleSize;
particle.velocity.z *= -elastic;
}
if (particle.position.z - particleSize < -extent.z)
{
particle.position.z = -extent.z + particleSize;
particle.velocity.z *= -elastic;
}
#endif // BOX_COLLISION
}
particle.life -= dt;
// write back simulated particle:
particleBuffer[particleIndex] = particle;
// add to new alive list:
uint newAliveIndex;
counterBuffer.InterlockedAdd(PARTICLECOUNTER_OFFSET_ALIVECOUNT_AFTERSIMULATION, 1, newAliveIndex);
aliveBuffer_NEW[newAliveIndex] = particleIndex;
#ifdef SORTING
// store squared distance to main camera:
float3 eyeVector = particle.position - g_xFrame_MainCamera_CamPos;
float distSQ = dot(eyeVector, eyeVector);
distanceBuffer[particleIndex] = -distSQ; // this can be negated to modify sorting order here instead of rewriting sorting shaders...
#endif // SORTING
}
else
{
// kill:
uint deadIndex;
counterBuffer.InterlockedAdd(PARTICLECOUNTER_OFFSET_DEADCOUNT, 1, deadIndex);
deadBuffer[deadIndex] = particleIndex;
}
}
}
You can’t perform that action at this time.