force fields: layermask can be used to mask out particle systems

This commit is contained in:
Turanszki Janos
2021-03-27 00:36:26 +01:00
parent ece110e03f
commit e6870dc542
11 changed files with 62 additions and 96 deletions
@@ -62,7 +62,7 @@ CBUFFER(EmittedParticleCB, CBSLOT_OTHER_EMITTEDPARTICLE)
float2 xEmitterTexMul;
float xEmitterFrameRate;
float padding_xEmitter;
uint xEmitterLayerMask;
float xSPH_h; // smoothing radius
float xSPH_h_rcp; // 1.0f / smoothing radius
@@ -44,9 +44,8 @@ CBUFFER(HairParticleCB, CBSLOT_OTHER_HAIRPARTICLE)
uint xHairFrameStart;
float2 xHairTexMul;
float xHairAspect;
float3 padding_xHair;
uint xHairLayerMask;
};
#endif // WI_SHADERINTEROP_HAIRPARTICLE_H
@@ -8,17 +8,6 @@ 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_rcp;
float3 normal;
};
groupshared LDS_ForceField forceFields[NUM_LDS_FORCEFIELDS];
#define SPH_FLOOR_COLLISION
#define SPH_BOX_COLLISION
@@ -29,22 +18,6 @@ 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;
ShaderEntity forceField = EntityArray[forceFieldID];
forceFields[Gid].type = (uint)forceField.GetType();
forceFields[Gid].position = forceField.position;
forceFields[Gid].gravity = forceField.GetEnergy();
forceFields[Gid].range_rcp = forceField.GetRange(); // it is actually uploaded from CPU as 1.0f / range
forceFields[Gid].normal = forceField.GetDirection();
}
GroupMemoryBarrierWithGroupSync();
if (DTid.x < aliveCount)
{
// simulation can be either fixed or variable timestep:
@@ -56,24 +29,27 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex)
if (particle.life > 0)
{
// simulate:
for (uint i = 0; i < numForceFields; ++i)
for (uint i = 0; i < g_xFrame_ForceFieldArrayCount; ++i)
{
LDS_ForceField forceField = forceFields[i];
ShaderEntity forceField = EntityArray[g_xFrame_ForceFieldArrayOffset + i];
float3 dir = forceField.position - particle.position;
float dist;
if (forceField.type == ENTITY_TYPE_FORCEFIELD_POINT) // point-based force field
[branch]
if (forceField.layerMask & xEmitterLayerMask)
{
dist = length(dir);
}
else // planar force field
{
dist = dot(forceField.normal, dir);
dir = forceField.normal;
}
float3 dir = forceField.position - particle.position;
float dist;
if (forceField.GetType() == ENTITY_TYPE_FORCEFIELD_POINT) // point-based force field
{
dist = length(dir);
}
else // planar force field
{
dist = dot(forceField.GetDirection(), dir);
dir = forceField.GetDirection();
}
particle.force += dir * forceField.gravity * (1 - saturate(dist * forceField.range_rcp));
particle.force += dir * forceField.GetEnergy() * (1 - saturate(dist * forceField.GetRange())); // GetRange() is actually uploaded as 1.0 / range
}
}
@@ -10,35 +10,9 @@ TYPEDBUFFER(meshIndexBuffer, uint, TEXSLOT_ONDEMAND0);
RAWBUFFER(meshVertexBuffer_POS, TEXSLOT_ONDEMAND1);
TYPEDBUFFER(meshVertexBuffer_length, float, TEXSLOT_ONDEMAND2);
#define NUM_LDS_FORCEFIELDS 32
struct LDS_ForceField
{
uint type;
float3 position;
float gravity;
float range_rcp;
float3 normal;
};
groupshared LDS_ForceField forceFields[NUM_LDS_FORCEFIELDS];
[numthreads(THREADCOUNT_SIMULATEHAIR, 1, 1)]
void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIndex : SV_GroupIndex)
{
// Load the forcefields into LDS:
uint numForceFields = min(g_xFrame_ForceFieldArrayCount, NUM_LDS_FORCEFIELDS);
if (groupIndex < numForceFields)
{
uint forceFieldID = g_xFrame_ForceFieldArrayOffset + groupIndex;
ShaderEntity forceField = EntityArray[forceFieldID];
forceFields[groupIndex].type = (uint)forceField.GetType();
forceFields[groupIndex].position = forceField.position;
forceFields[groupIndex].gravity = forceField.GetEnergy();
forceFields[groupIndex].range_rcp = forceField.GetRange(); // it is actually uploaded from CPU as 1.0f / range
forceFields[groupIndex].normal = forceField.GetDirection();
}
GroupMemoryBarrierWithGroupSync();
if (DTid.x >= xHairParticleCount)
return;
@@ -130,25 +104,29 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn
// Accumulate forces:
float3 force = 0;
for (uint i = 0; i < numForceFields; ++i)
for (uint i = 0; i < g_xFrame_ForceFieldArrayCount; ++i)
{
LDS_ForceField forceField = forceFields[i];
ShaderEntity forceField = EntityArray[g_xFrame_ForceFieldArrayOffset + i];
//float3 dir = forceField.position - PointOnLineSegmentNearestPoint(base, tip, forceField.position);
float3 dir = forceField.position - tip;
float dist;
if (forceField.type == ENTITY_TYPE_FORCEFIELD_POINT) // point-based force field
{
//dist = length(dir);
dist = length(forceField.position - ClosestPointOnSegment(base, tip, forceField.position));
}
else // planar force field
{
dist = dot(forceField.normal, dir);
dir = forceField.normal;
}
[branch]
if (forceField.layerMask & xHairLayerMask)
{
//float3 dir = forceField.position - PointOnLineSegmentNearestPoint(base, tip, forceField.position);
float3 dir = forceField.position - tip;
float dist;
if (forceField.GetType() == ENTITY_TYPE_FORCEFIELD_POINT) // point-based force field
{
//dist = length(dir);
dist = length(forceField.position - ClosestPointOnSegment(base, tip, forceField.position));
}
else // planar force field
{
dist = dot(forceField.GetDirection(), dir);
dir = forceField.GetDirection();
}
force += dir * forceField.gravity * (1 - saturate(dist * forceField.range_rcp));
force += dir * forceField.GetEnergy() * (1 - saturate(dist * forceField.GetRange())); // GetRange() is actually uploaded as 1.0 / range
}
}
// Pull back to rest position:
+1
View File
@@ -276,6 +276,7 @@ void wiEmittedParticle::UpdateGPU(const TransformComponent& transform, const Mat
cb.xParticleDrag = drag;
XMStoreFloat3(&cb.xParticleVelocity, XMVector3TransformNormal(XMLoadFloat3(&velocity), XMLoadFloat4x4(&transform.world)));
cb.xParticleRandomColorFactor = random_color;
cb.xEmitterLayerMask = layerMask;
cb.xEmitterOptions = 0;
if (IsSPHEnabled())
+1
View File
@@ -117,6 +117,7 @@ public:
// Non-serialized attributes:
XMFLOAT3 center;
uint32_t statisticsReadBackIndex = 0;
uint32_t layerMask = ~0u;
inline bool IsDebug() const { return _flags & FLAG_DEBUG; }
inline bool IsPaused() const { return _flags & FLAG_PAUSED; }
+1
View File
@@ -189,6 +189,7 @@ void wiHairParticle::UpdateGPU(const MeshComponent& mesh, const MaterialComponen
hcb.xHairFrameStart = frameStart;
hcb.xHairTexMul = float2(1.0f / (float)hcb.xHairFramesXY.x, 1.0f / (float)hcb.xHairFramesXY.y);
hcb.xHairAspect = (float)std::max(1u, desc.Width) / (float)std::max(1u, desc.Height);
hcb.xHairLayerMask = layerMask;
device->UpdateBuffer(&cb, &hcb, cmd);
// Simulate:
+1
View File
@@ -60,6 +60,7 @@ public:
XMFLOAT4X4 worldPrev;
AABB aabb;
std::vector<uint32_t> indices; // it is dependent on vertex_lengths and contains triangles with non-zero lengths
uint32_t layerMask = ~0u;
void Serialize(wiArchive& archive, wiECS::EntitySerializer& seri);
+4 -8
View File
@@ -3559,9 +3559,8 @@ void UpdateVisibility(Visibility& vis)
// Cull emitters:
for (size_t i = 0; i < vis.scene->emitters.GetCount(); ++i)
{
Entity entity = vis.scene->emitters.GetEntity(i);
const LayerComponent* layer = vis.scene->layers.GetComponent(entity);
if (layer != nullptr && !(layer->GetLayerMask() & vis.layerMask))
const wiEmittedParticle& emitter = vis.scene->emitters[i];
if (!(emitter.layerMask & vis.layerMask))
{
continue;
}
@@ -3576,14 +3575,11 @@ void UpdateVisibility(Visibility& vis)
// Cull hairs:
for (size_t i = 0; i < vis.scene->hairs.GetCount(); ++i)
{
Entity entity = vis.scene->hairs.GetEntity(i);
const LayerComponent* layer = vis.scene->layers.GetComponent(entity);
if (layer != nullptr && !(layer->GetLayerMask() & vis.layerMask))
const wiHairParticle& hair = vis.scene->hairs[i];
if (!(hair.layerMask & vis.layerMask))
{
continue;
}
const wiHairParticle& hair = vis.scene->hairs[i];
if (hair.meshID == INVALID_ENTITY || !vis.frustum.CheckBoxFast(hair.aabb))
{
continue;
+14 -1
View File
@@ -3152,6 +3152,13 @@ namespace wiScene
wiEmittedParticle& emitter = emitters[args.jobIndex];
Entity entity = emitters.GetEntity(args.jobIndex);
const LayerComponent* layer = layers.GetComponent(entity);
if (layer != nullptr)
{
emitter.layerMask = layer->GetLayerMask();
}
const TransformComponent& transform = *transforms.GetComponent(entity);
emitter.UpdateCPU(transform, dt);
});
@@ -3159,10 +3166,16 @@ namespace wiScene
wiJobSystem::Dispatch(ctx, (uint32_t)hairs.GetCount(), small_subtask_groupsize, [&](wiJobArgs args) {
wiHairParticle& hair = hairs[args.jobIndex];
Entity entity = hairs.GetEntity(args.jobIndex);
const LayerComponent* layer = layers.GetComponent(entity);
if (layer != nullptr)
{
hair.layerMask = layer->GetLayerMask();
}
if (hair.meshID != INVALID_ENTITY)
{
Entity entity = hairs.GetEntity(args.jobIndex);
const MeshComponent* mesh = meshes.GetComponent(hair.meshID);
if (mesh != nullptr)
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wiVersion
// minor features, major updates, breaking compatibility changes
const int minor = 55;
// minor bug fixes, alterations, refactors, updates
const int revision = 3;
const int revision = 4;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);