GPU particle collider support (#529)
This commit is contained in:
Binary file not shown.
@@ -37,6 +37,7 @@ void ColliderWindow::Create(EditorComponent* _editor)
|
||||
shapeCombo.SetPos(XMFLOAT2(x, y));
|
||||
shapeCombo.AddItem("Sphere", (uint64_t)ColliderComponent::Shape::Sphere);
|
||||
shapeCombo.AddItem("Capsule", (uint64_t)ColliderComponent::Shape::Capsule);
|
||||
shapeCombo.AddItem("Plane", (uint64_t)ColliderComponent::Shape::Plane);
|
||||
shapeCombo.OnSelect([=](wi::gui::EventArgs args) {
|
||||
wi::scene::Scene& scene = editor->GetCurrentScene();
|
||||
ColliderComponent* collider = scene.colliders.GetComponent(entity);
|
||||
|
||||
+1
-1
@@ -1001,7 +1001,7 @@ void EditorComponent::Update(float dt)
|
||||
|
||||
optionsWnd.RefreshEntityTree();
|
||||
}
|
||||
else
|
||||
else if(translator.selected.empty())
|
||||
{
|
||||
// Check for interactive grass (hair particle that is child of hovered object:
|
||||
for (size_t i = 0; i < scene.hairs.GetCount(); ++i)
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#define ICON_PAUSE ICON_FA_PAUSE
|
||||
#define ICON_STOP ICON_FA_STOP
|
||||
#define ICON_PEN ICON_FA_PEN
|
||||
#define ICON_FILTER ICON_FA_FILTER
|
||||
|
||||
#define ICON_DARK ICON_FA_MOON
|
||||
#define ICON_BRIGHT ICON_FA_SUN
|
||||
|
||||
@@ -289,7 +289,7 @@ void OptionsWindow::Create(EditorComponent* _editor)
|
||||
|
||||
|
||||
filterCombo.Create("Filter: ");
|
||||
filterCombo.AddItem("All ", (uint64_t)Filter::All);
|
||||
filterCombo.AddItem("All " ICON_FILTER, (uint64_t)Filter::All);
|
||||
filterCombo.AddItem("Transform " ICON_TRANSFORM, (uint64_t)Filter::Transform);
|
||||
filterCombo.AddItem("Material " ICON_MATERIAL, (uint64_t)Filter::Material);
|
||||
filterCombo.AddItem("Mesh " ICON_MESH, (uint64_t)Filter::Mesh);
|
||||
|
||||
@@ -515,6 +515,10 @@ struct ShaderEntity
|
||||
{
|
||||
return GetConeAngleCos();
|
||||
}
|
||||
inline float3 GetColliderTip()
|
||||
{
|
||||
return shadowAtlasMulAdd.xyz;
|
||||
}
|
||||
|
||||
#else
|
||||
// Application-side:
|
||||
@@ -572,6 +576,10 @@ struct ShaderEntity
|
||||
{
|
||||
SetConeAngleCos(value);
|
||||
}
|
||||
inline void SetColliderTip(float3 value)
|
||||
{
|
||||
shadowAtlasMulAdd = float4(value.x, value.y, value.z, 0);
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
};
|
||||
@@ -607,13 +615,21 @@ struct ShaderFrustum
|
||||
#endif // __cplusplus
|
||||
};
|
||||
|
||||
static const uint ENTITY_TYPE_DIRECTIONALLIGHT = 0;
|
||||
static const uint ENTITY_TYPE_POINTLIGHT = 1;
|
||||
static const uint ENTITY_TYPE_SPOTLIGHT = 2;
|
||||
static const uint ENTITY_TYPE_DECAL = 100;
|
||||
static const uint ENTITY_TYPE_ENVMAP = 101;
|
||||
static const uint ENTITY_TYPE_FORCEFIELD_POINT = 200;
|
||||
static const uint ENTITY_TYPE_FORCEFIELD_PLANE = 201;
|
||||
enum SHADER_ENTITY_TYPE
|
||||
{
|
||||
ENTITY_TYPE_DIRECTIONALLIGHT,
|
||||
ENTITY_TYPE_POINTLIGHT,
|
||||
ENTITY_TYPE_SPOTLIGHT,
|
||||
ENTITY_TYPE_DECAL,
|
||||
ENTITY_TYPE_ENVMAP,
|
||||
ENTITY_TYPE_FORCEFIELD_POINT,
|
||||
ENTITY_TYPE_FORCEFIELD_PLANE,
|
||||
ENTITY_TYPE_COLLIDER_SPHERE,
|
||||
ENTITY_TYPE_COLLIDER_CAPSULE,
|
||||
ENTITY_TYPE_COLLIDER_PLANE,
|
||||
|
||||
ENTITY_TYPE_COUNT
|
||||
};
|
||||
|
||||
static const uint ENTITY_FLAG_LIGHT_STATIC = 1 << 0;
|
||||
|
||||
@@ -688,7 +704,7 @@ struct FrameCB
|
||||
uint forcefieldarray_count; // indexing into entity array
|
||||
|
||||
uint envprobearray_offset; // indexing into entity array
|
||||
uint envprobearray_count; // indexing into entity array
|
||||
uint envprobearray_count; // indexing into entity array
|
||||
uint temporalaa_samplerotation;
|
||||
float blue_noise_phase;
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ RWByteAddressBuffer vertexBuffer_COL : register(u9);
|
||||
RWStructuredBuffer<uint> culledIndirectionBuffer : register(u10);
|
||||
RWStructuredBuffer<uint> culledIndirectionBuffer2 : register(u11);
|
||||
|
||||
#define SPH_FLOOR_COLLISION
|
||||
#define SPH_BOX_COLLISION
|
||||
//#define SPH_FLOOR_COLLISION
|
||||
//#define SPH_BOX_COLLISION
|
||||
|
||||
|
||||
[numthreads(THREADCOUNT_SIMULATION, 1, 1)]
|
||||
@@ -40,29 +40,105 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex)
|
||||
Particle particle = particleBuffer[particleIndex];
|
||||
uint v0 = particleIndex * 4;
|
||||
|
||||
const float lifeLerp = 1 - particle.life / particle.maxLife;
|
||||
const float particleSize = lerp(particle.sizeBeginEnd.x, particle.sizeBeginEnd.y, lifeLerp);
|
||||
|
||||
// integrate:
|
||||
particle.force += xParticleGravity;
|
||||
particle.velocity += particle.force * dt;
|
||||
particle.position += particle.velocity * dt;
|
||||
|
||||
// reset force for next frame:
|
||||
particle.force = 0;
|
||||
|
||||
// drag:
|
||||
particle.velocity *= xParticleDrag;
|
||||
|
||||
if (particle.life > 0)
|
||||
{
|
||||
// simulate:
|
||||
// process forces and colliders:
|
||||
for (uint i = 0; i < GetFrame().forcefieldarray_count; ++i)
|
||||
{
|
||||
ShaderEntity forceField = load_entity(GetFrame().forcefieldarray_offset + i);
|
||||
ShaderEntity entity = load_entity(GetFrame().forcefieldarray_offset + i);
|
||||
|
||||
[branch]
|
||||
if (forceField.layerMask & xEmitterLayerMask)
|
||||
if (entity.layerMask & xEmitterLayerMask)
|
||||
{
|
||||
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();
|
||||
}
|
||||
const float range = entity.GetRange();
|
||||
const uint type = entity.GetType();
|
||||
|
||||
particle.force += dir * forceField.GetGravity() * (1 - saturate(dist / forceField.GetRange()));
|
||||
if (type == ENTITY_TYPE_COLLIDER_CAPSULE)
|
||||
{
|
||||
float3 A = entity.position;
|
||||
float3 B = entity.GetColliderTip();
|
||||
float3 N = normalize(A - B);
|
||||
A -= N * range;
|
||||
B += N * range;
|
||||
float3 C = closest_point_on_segment(A, B, particle.position);
|
||||
float3 dir = C - particle.position;
|
||||
float dist = length(dir);
|
||||
dir /= dist;
|
||||
dist = dist - range - particleSize;
|
||||
if (dist < 0)
|
||||
{
|
||||
particle.velocity = reflect(particle.velocity, dir);
|
||||
float3 offset_velocity = dir * dist;
|
||||
particle.position = particle.position + offset_velocity;
|
||||
particle.velocity += offset_velocity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float3 dir = entity.position - particle.position;
|
||||
float dist = length(dir);
|
||||
dir /= dist;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ENTITY_TYPE_FORCEFIELD_POINT:
|
||||
particle.force += dir * entity.GetGravity() * (1 - saturate(dist / range));
|
||||
break;
|
||||
case ENTITY_TYPE_FORCEFIELD_PLANE:
|
||||
particle.force += entity.GetDirection() * entity.GetGravity() * (1 - saturate(dist / range));
|
||||
break;
|
||||
case ENTITY_TYPE_COLLIDER_SPHERE:
|
||||
dist = dist - range - particleSize;
|
||||
if (dist < 0)
|
||||
{
|
||||
particle.velocity = reflect(particle.velocity, dir);
|
||||
float3 offset_velocity = dir * dist;
|
||||
particle.position = particle.position + offset_velocity;
|
||||
particle.velocity += offset_velocity;
|
||||
}
|
||||
break;
|
||||
case ENTITY_TYPE_COLLIDER_PLANE:
|
||||
dir = normalize(entity.GetDirection());
|
||||
dist = plane_point_distance(entity.position, dir, particle.position);
|
||||
if (dist < 0)
|
||||
{
|
||||
dir *= -1;
|
||||
dist = abs(dist);
|
||||
}
|
||||
dist = dist - particleSize;
|
||||
if (dist < 0)
|
||||
{
|
||||
float4x4 planeProjection = load_entitymatrix(entity.GetMatrixIndex());
|
||||
const float3 clipSpacePos = mul(planeProjection, float4(particle.position, 1)).xyz;
|
||||
const float3 uvw = clipspace_to_uv(clipSpacePos.xyz);
|
||||
[branch]
|
||||
if (is_saturated(uvw))
|
||||
{
|
||||
particle.velocity = reflect(particle.velocity, dir);
|
||||
float3 offset_velocity = -dir * dist;
|
||||
particle.position = particle.position + offset_velocity;
|
||||
particle.velocity += offset_velocity;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,9 +158,6 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex)
|
||||
float surfaceLinearDepth = compute_lineardepth(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))
|
||||
{
|
||||
@@ -106,20 +179,6 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex)
|
||||
}
|
||||
#endif // DEPTHCOLLISIONS
|
||||
|
||||
// integrate:
|
||||
particle.force += xParticleGravity;
|
||||
particle.velocity += particle.force * dt;
|
||||
particle.position += particle.velocity * dt;
|
||||
|
||||
// reset force for next frame:
|
||||
particle.force = 0;
|
||||
|
||||
// drag:
|
||||
particle.velocity *= xParticleDrag;
|
||||
|
||||
float lifeLerp = 1 - particle.life / particle.maxLife;
|
||||
float particleSize = lerp(particle.sizeBeginEnd.x, particle.sizeBeginEnd.y, lifeLerp);
|
||||
|
||||
[branch]
|
||||
if (xEmitterOptions & EMITTER_OPTION_BIT_SPH_ENABLED)
|
||||
{
|
||||
|
||||
@@ -1020,6 +1020,13 @@ inline float dither(in float2 pixel)
|
||||
return ditherMask8(pixel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
float plane_point_distance(float3 planeOrigin, float3 planeNormal, float3 P)
|
||||
{
|
||||
return dot(planeNormal, P - planeOrigin);
|
||||
}
|
||||
|
||||
// o : ray origin
|
||||
// d : ray direction
|
||||
// center : sphere center
|
||||
|
||||
@@ -116,30 +116,82 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn
|
||||
|
||||
float3 tip = base + normal * len;
|
||||
|
||||
// Accumulate forces:
|
||||
// Accumulate forces, apply colliders:
|
||||
float3 force = 0;
|
||||
for (uint i = 0; i < GetFrame().forcefieldarray_count; ++i)
|
||||
{
|
||||
ShaderEntity forceField = load_entity(GetFrame().forcefieldarray_offset + i);
|
||||
ShaderEntity entity = load_entity(GetFrame().forcefieldarray_offset + i);
|
||||
|
||||
[branch]
|
||||
if (forceField.layerMask & xHairLayerMask)
|
||||
if (entity.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 - closest_point_on_segment(base, tip, forceField.position));
|
||||
}
|
||||
else // planar force field
|
||||
{
|
||||
dist = dot(forceField.GetDirection(), dir);
|
||||
dir = forceField.GetDirection();
|
||||
}
|
||||
const float range = entity.GetRange();
|
||||
const uint type = entity.GetType();
|
||||
|
||||
force += dir * forceField.GetGravity() * (1 - saturate(dist / forceField.GetRange()));
|
||||
if (type == ENTITY_TYPE_COLLIDER_CAPSULE)
|
||||
{
|
||||
float3 A = entity.position;
|
||||
float3 B = entity.GetColliderTip();
|
||||
float3 N = normalize(A - B);
|
||||
A -= N * range;
|
||||
B += N * range;
|
||||
float3 C = closest_point_on_segment(A, B, tip);
|
||||
float3 dir = C- tip;
|
||||
float dist = length(dir);
|
||||
dir /= dist;
|
||||
dist = dist - range - len;
|
||||
if (dist < 0)
|
||||
{
|
||||
tip = tip - dir * dist;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float3 closest_point = closest_point_on_segment(base, tip, entity.position);
|
||||
float3 dir = entity.position - closest_point;
|
||||
float dist = length(dir);
|
||||
dir /= dist;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ENTITY_TYPE_FORCEFIELD_POINT:
|
||||
force += dir * entity.GetGravity() * (1 - saturate(dist / range));
|
||||
break;
|
||||
case ENTITY_TYPE_FORCEFIELD_PLANE:
|
||||
force += entity.GetDirection() * entity.GetGravity() * (1 - saturate(dist / range));
|
||||
break;
|
||||
case ENTITY_TYPE_COLLIDER_SPHERE:
|
||||
dist = dist - range - len;
|
||||
if (dist < 0)
|
||||
{
|
||||
tip = tip - dir * dist;
|
||||
}
|
||||
break;
|
||||
case ENTITY_TYPE_COLLIDER_PLANE:
|
||||
dir = normalize(entity.GetDirection());
|
||||
dist = plane_point_distance(entity.position, dir, closest_point);
|
||||
if (dist < 0)
|
||||
{
|
||||
dir *= -1;
|
||||
dist = abs(dist);
|
||||
}
|
||||
dist = dist - len;
|
||||
if (dist < 0)
|
||||
{
|
||||
float4x4 planeProjection = load_entitymatrix(entity.GetMatrixIndex());
|
||||
const float3 clipSpacePos = mul(planeProjection, float4(closest_point, 1)).xyz;
|
||||
const float3 uvw = clipspace_to_uv(clipSpacePos.xyz);
|
||||
[branch]
|
||||
if (is_saturated(uvw))
|
||||
{
|
||||
tip = tip + dir * dist;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -404,19 +404,25 @@ namespace wi
|
||||
|
||||
params.cursor = wi::font::Draw(infodisplay_str, params, cmd);
|
||||
|
||||
if (infoDisplay.vram_usage)
|
||||
// VRAM:
|
||||
{
|
||||
GraphicsDevice::MemoryUsage vram = graphicsDevice->GetMemoryUsage();
|
||||
bool warn = false;
|
||||
if (vram.usage > vram.budget)
|
||||
{
|
||||
params.color = wi::Color::Error();
|
||||
warn = true;
|
||||
}
|
||||
else if (float(vram.usage) / float(vram.budget) > 0.9f)
|
||||
{
|
||||
params.color = wi::Color::Warning();
|
||||
warn = true;
|
||||
}
|
||||
if (infoDisplay.vram_usage || warn)
|
||||
{
|
||||
params.cursor = wi::font::Draw("VRAM usage: " + std::to_string(vram.usage / 1024 / 1024) + "MB / " + std::to_string(vram.budget / 1024 / 1024) + "MB\n", params, cmd);
|
||||
params.color = wi::Color::White();
|
||||
}
|
||||
params.cursor = wi::font::Draw("VRAM usage: " + std::to_string(vram.usage / 1024 / 1024) + "MB / " + std::to_string(vram.budget / 1024 / 1024) + "MB\n", params, cmd);
|
||||
params.color = wi::Color::White();
|
||||
}
|
||||
|
||||
// Write warnings below:
|
||||
|
||||
@@ -253,6 +253,11 @@ namespace wi::math
|
||||
XMVECTOR GetClosestPointToLine(const XMVECTOR& A, const XMVECTOR& B, const XMVECTOR& P, bool segmentClamp = false);
|
||||
float GetPointSegmentDistance(const XMVECTOR& point, const XMVECTOR& segmentA, const XMVECTOR& segmentB);
|
||||
|
||||
inline float GetPlanePointDistance(const XMVECTOR& planeOrigin, const XMVECTOR& planeNormal, const XMVECTOR& point)
|
||||
{
|
||||
return XMVectorGetX(XMVector3Dot(planeNormal, point - planeOrigin));
|
||||
}
|
||||
|
||||
float GetAngle(const XMFLOAT2& a, const XMFLOAT2& b);
|
||||
float GetAngle(const XMFLOAT3& a, const XMFLOAT3& b, const XMFLOAT3& axis);
|
||||
void ConstructTriangleEquilateral(float radius, XMFLOAT4& A, XMFLOAT4& B, XMFLOAT4& C);
|
||||
|
||||
@@ -251,8 +251,13 @@ namespace wi::primitive
|
||||
}
|
||||
bool Sphere::intersects(const Sphere& b, float& dist, XMFLOAT3& direction) const
|
||||
{
|
||||
dist = wi::math::Distance(center, b.center);
|
||||
XMStoreFloat3(&direction, (XMLoadFloat3(¢er) - XMLoadFloat3(&b.center)) / dist);
|
||||
XMVECTOR A = XMLoadFloat3(¢er);
|
||||
XMVECTOR B = XMLoadFloat3(&b.center);
|
||||
XMVECTOR DIR = A - B;
|
||||
XMVECTOR DIST = XMVector3Length(DIR);
|
||||
DIR = DIR / DIST;
|
||||
XMStoreFloat3(&direction, DIR);
|
||||
dist = XMVectorGetX(DIST);
|
||||
dist = dist - radius - b.radius;
|
||||
return dist < 0;
|
||||
}
|
||||
@@ -266,8 +271,8 @@ namespace wi::primitive
|
||||
XMVECTOR A = XMLoadFloat3(&b.base);
|
||||
XMVECTOR B = XMLoadFloat3(&b.tip);
|
||||
XMVECTOR N = XMVector3Normalize(A - B);
|
||||
A += N * b.radius;
|
||||
B -= N * b.radius;
|
||||
A -= N * b.radius;
|
||||
B += N * b.radius;
|
||||
XMVECTOR C = XMLoadFloat3(¢er);
|
||||
dist = wi::math::GetPointSegmentDistance(C, A, B);
|
||||
dist = dist - radius - b.radius;
|
||||
@@ -278,8 +283,8 @@ namespace wi::primitive
|
||||
XMVECTOR A = XMLoadFloat3(&b.base);
|
||||
XMVECTOR B = XMLoadFloat3(&b.tip);
|
||||
XMVECTOR N = XMVector3Normalize(A - B);
|
||||
A += N * b.radius;
|
||||
B -= N * b.radius;
|
||||
A -= N * b.radius;
|
||||
B += N * b.radius;
|
||||
XMVECTOR C = XMLoadFloat3(¢er);
|
||||
dist = wi::math::GetPointSegmentDistance(C, A, B);
|
||||
XMStoreFloat3(&direction, (C - wi::math::ClosestPointOnLineSegment(A, B, C)) / dist);
|
||||
|
||||
@@ -3214,7 +3214,7 @@ void UpdatePerFrameData(
|
||||
frameCB.lightarray_offset = frameCB.envprobearray_offset + frameCB.envprobearray_count;
|
||||
frameCB.lightarray_count = (uint)vis.visibleLights.size();
|
||||
frameCB.forcefieldarray_offset = frameCB.lightarray_offset + frameCB.lightarray_count;
|
||||
frameCB.forcefieldarray_count = (uint)vis.scene->forces.GetCount();
|
||||
frameCB.forcefieldarray_count = uint(vis.scene->forces.GetCount() + vis.scene->colliders.GetCount());
|
||||
|
||||
frameCB.envprobe_mipcount = 0;
|
||||
frameCB.envprobe_mipcount_rcp = 1.0f;
|
||||
@@ -3681,6 +3681,57 @@ void UpdateRenderData(
|
||||
entityCounter++;
|
||||
}
|
||||
|
||||
// Write colliders into entity array:
|
||||
for (size_t i = 0; i < vis.scene->colliders.GetCount(); ++i)
|
||||
{
|
||||
if (entityCounter == SHADER_ENTITY_COUNT)
|
||||
{
|
||||
assert(0); // too many entities!
|
||||
entityCounter--;
|
||||
break;
|
||||
}
|
||||
ShaderEntity shaderentity = {};
|
||||
|
||||
const ColliderComponent& collider = vis.scene->colliders[i];
|
||||
|
||||
shaderentity.layerMask = ~0u;
|
||||
|
||||
Entity entity = vis.scene->colliders.GetEntity(i);
|
||||
const LayerComponent* layer = vis.scene->layers.GetComponent(entity);
|
||||
if (layer != nullptr)
|
||||
{
|
||||
shaderentity.layerMask = layer->layerMask;
|
||||
}
|
||||
|
||||
switch (collider.shape)
|
||||
{
|
||||
case ColliderComponent::Shape::Sphere:
|
||||
shaderentity.SetType(ENTITY_TYPE_COLLIDER_SPHERE);
|
||||
shaderentity.position = collider.sphere.center;
|
||||
shaderentity.SetRange(collider.sphere.radius);
|
||||
break;
|
||||
case ColliderComponent::Shape::Capsule:
|
||||
shaderentity.SetType(ENTITY_TYPE_COLLIDER_CAPSULE);
|
||||
shaderentity.position = collider.capsule.base;
|
||||
shaderentity.SetColliderTip(collider.capsule.tip);
|
||||
shaderentity.SetRange(collider.capsule.radius);
|
||||
break;
|
||||
case ColliderComponent::Shape::Plane:
|
||||
shaderentity.SetType(ENTITY_TYPE_COLLIDER_PLANE);
|
||||
shaderentity.position = collider.planeOrigin;
|
||||
shaderentity.SetDirection(collider.planeNormal);
|
||||
shaderentity.SetIndices(matrixCounter, ~0u);
|
||||
std::memcpy(&matrixArray[matrixCounter++], &collider.planeProjection, sizeof(collider.planeProjection));
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
std::memcpy(entityArray + entityCounter, &shaderentity, sizeof(ShaderEntity));
|
||||
entityCounter++;
|
||||
}
|
||||
|
||||
// Write force fields into entity array:
|
||||
for (size_t i = 0; i < vis.scene->forces.GetCount(); ++i)
|
||||
{
|
||||
@@ -5103,7 +5154,36 @@ void DrawDebugWorld(
|
||||
DrawSphere(collider.sphere, XMFLOAT4(1, 0, 1, 1));
|
||||
break;
|
||||
case ColliderComponent::Shape::Capsule:
|
||||
DrawCapsule(collider.capsule, XMFLOAT4(1, 1, 0, 1));
|
||||
DrawCapsule(collider.capsule, XMFLOAT4(1, 0, 1, 1));
|
||||
break;
|
||||
case ColliderComponent::Shape::Plane:
|
||||
{
|
||||
RenderableLine line;
|
||||
line.color_start = XMFLOAT4(1, 0, 1, 1);
|
||||
line.color_end = XMFLOAT4(1, 0, 1, 1);
|
||||
XMMATRIX planeMatrix = XMMatrixInverse(nullptr, XMLoadFloat4x4(&collider.planeProjection));
|
||||
XMVECTOR P0 = XMVector3Transform(XMVectorSet(-1, 0, -1, 1), planeMatrix);
|
||||
XMVECTOR P1 = XMVector3Transform(XMVectorSet(1, 0, -1, 1), planeMatrix);
|
||||
XMVECTOR P2 = XMVector3Transform(XMVectorSet(1, 0, 1, 1), planeMatrix);
|
||||
XMVECTOR P3 = XMVector3Transform(XMVectorSet(-1, 0, 1, 1), planeMatrix);
|
||||
XMStoreFloat3(&line.start, P0);
|
||||
XMStoreFloat3(&line.end, P1);
|
||||
DrawLine(line);
|
||||
XMStoreFloat3(&line.start, P1);
|
||||
XMStoreFloat3(&line.end, P2);
|
||||
DrawLine(line);
|
||||
XMStoreFloat3(&line.start, P2);
|
||||
XMStoreFloat3(&line.end, P3);
|
||||
DrawLine(line);
|
||||
XMStoreFloat3(&line.start, P3);
|
||||
XMStoreFloat3(&line.end, P0);
|
||||
DrawLine(line);
|
||||
XMVECTOR O = XMLoadFloat3(&collider.planeOrigin);
|
||||
XMVECTOR N = XMLoadFloat3(&collider.planeNormal);
|
||||
XMStoreFloat3(&line.start, O);
|
||||
XMStoreFloat3(&line.end, O + N);
|
||||
DrawLine(line);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3196,6 +3196,20 @@ namespace wi::scene
|
||||
tail -= N * collider.capsule.radius;
|
||||
XMStoreFloat3(&collider.capsule.base, offset);
|
||||
XMStoreFloat3(&collider.capsule.tip, tail);
|
||||
|
||||
if (collider.shape == ColliderComponent::Shape::Plane)
|
||||
{
|
||||
collider.planeOrigin = collider.sphere.center;
|
||||
XMVECTOR N = XMVectorSet(0, 1, 0, 0);
|
||||
N = XMVector3Normalize(XMVector3TransformNormal(N, W));
|
||||
XMStoreFloat3(&collider.planeNormal, N);
|
||||
|
||||
XMMATRIX PLANE = XMMatrixScaling(collider.radius, 1, collider.radius);
|
||||
PLANE = PLANE * XMMatrixTranslationFromVector(XMLoadFloat3(&collider.offset));
|
||||
PLANE = PLANE * W;
|
||||
PLANE = XMMatrixInverse(nullptr, PLANE);
|
||||
XMStoreFloat4x4(&collider.planeProjection, PLANE);
|
||||
}
|
||||
}
|
||||
}
|
||||
void Scene::RunSpringUpdateSystem(wi::jobsystem::context& ctx)
|
||||
@@ -3347,6 +3361,31 @@ namespace wi::scene
|
||||
case ColliderComponent::Shape::Capsule:
|
||||
tail_sphere.intersects(collider.capsule, dist, direction);
|
||||
break;
|
||||
case ColliderComponent::Shape::Plane:
|
||||
dist = wi::math::GetPlanePointDistance(XMLoadFloat3(&collider.planeOrigin), XMLoadFloat3(&collider.planeNormal), tail_next);
|
||||
direction = collider.planeNormal;
|
||||
if (dist < 0)
|
||||
{
|
||||
direction.x *= -1;
|
||||
direction.y *= -1;
|
||||
direction.z *= -1;
|
||||
dist = std::abs(dist);
|
||||
}
|
||||
dist = dist - tail_sphere.radius;
|
||||
if (dist < 0)
|
||||
{
|
||||
XMMATRIX planeProjection = XMLoadFloat4x4(&collider.planeProjection);
|
||||
XMVECTOR clipSpacePos = XMVector3Transform(tail_next, planeProjection);
|
||||
XMVECTOR uvw = clipSpacePos * XMVectorSet(0.5f, -0.5f, 0.5f, 1) + XMVectorSet(0.5f, 0.5f, 0.5f, 0);
|
||||
XMVECTOR uvw_sat = XMVectorSaturate(uvw);
|
||||
if (std::abs(XMVectorGetX(uvw) - XMVectorGetX(uvw_sat)) > std::numeric_limits<float>::epsilon())
|
||||
dist = 1; // force no collision
|
||||
else if (std::abs(XMVectorGetY(uvw) - XMVectorGetY(uvw_sat)) > std::numeric_limits<float>::epsilon())
|
||||
dist = 1; // force no collision
|
||||
else if (std::abs(XMVectorGetZ(uvw) - XMVectorGetZ(uvw_sat)) > std::numeric_limits<float>::epsilon())
|
||||
dist = 1; // force no collision
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (dist < 0)
|
||||
|
||||
@@ -1327,6 +1327,7 @@ namespace wi::scene
|
||||
{
|
||||
Sphere,
|
||||
Capsule,
|
||||
Plane,
|
||||
};
|
||||
Shape shape;
|
||||
|
||||
@@ -1337,6 +1338,9 @@ namespace wi::scene
|
||||
// Non-serialized attributes:
|
||||
wi::primitive::Sphere sphere;
|
||||
wi::primitive::Capsule capsule;
|
||||
XMFLOAT3 planeOrigin = {};
|
||||
XMFLOAT3 planeNormal = {};
|
||||
XMFLOAT4X4 planeProjection = wi::math::IDENTITY_MATRIX;
|
||||
|
||||
void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace wi::version
|
||||
// minor features, major updates, breaking compatibility changes
|
||||
const int minor = 71;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 24;
|
||||
const int revision = 25;
|
||||
|
||||
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user