force fields: layermask can be used to mask out particle systems
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user