From e22ce3e79b706a92a4ada1dc15ac17ed61395a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Sat, 24 Feb 2024 14:30:18 +0100 Subject: [PATCH] capsule voxelization --- .../ScriptingAPI-Documentation.md | 1 + Content/scripts/pathfinding.lua | 1 + WickedEngine/wiScene.cpp | 6 +- WickedEngine/wiVoxelGrid.cpp | 70 +++++++++++++++++++ WickedEngine/wiVoxelGrid.h | 1 + WickedEngine/wiVoxelGrid_BindLua.cpp | 23 ++++++ WickedEngine/wiVoxelGrid_BindLua.h | 1 + 7 files changed, 100 insertions(+), 3 deletions(-) diff --git a/Content/Documentation/ScriptingAPI-Documentation.md b/Content/Documentation/ScriptingAPI-Documentation.md index 2ac8b0eaf9..aac306dff1 100644 --- a/Content/Documentation/ScriptingAPI-Documentation.md +++ b/Content/Documentation/ScriptingAPI-Documentation.md @@ -1745,6 +1745,7 @@ Tracks a physics pick drag operation. Use it with `phyiscs.PickDrag()` function. - InjectTriangle(Vector a,b,c, opt bool subtract = false) -- voxelizes triangle, and either adds it to the voxels (default), or removes voxels - InjectAABB(AABB aabb, opt bool subtract = false) -- voxelizes axis aligned bounding box, and either adds it to the voxels (default), or removes voxels - InjectSphere(Sphere sphere, opt bool subtract = false) -- voxelizes sphere, and either adds it to the voxels (default), or removes voxels +- InjectCapsule(Capsule capsule, opt bool subtract = false) -- voxelizes capsule, and either adds it to the voxels (default), or removes voxels - WorldToCoord(Vector pos) : int x,y,z -- converts a position in world space to voxel coordinate - CoordToWorld(int x,y,z) : Vector -- converts voxel coordinate to world space position - CheckVoxel(Vector pos) : bool -- returns false if voxel is empty, true if it's valid diff --git a/Content/scripts/pathfinding.lua b/Content/scripts/pathfinding.lua index 9fc33f19e7..40fb21e7e4 100644 --- a/Content/scripts/pathfinding.lua +++ b/Content/scripts/pathfinding.lua @@ -14,6 +14,7 @@ voxelgrid.InjectAABB(AABB(Vector(4, 0, 0.8), Vector(8, voxelsize.GetY() * 2, 5)) voxelgrid.InjectAABB(AABB(Vector(4, 0, 3), Vector(8, voxelsize.GetY() * 3.5, 7))) voxelgrid.InjectAABB(AABB(Vector(4, 0, 6), Vector(8, voxelsize.GetY() * 4.5, 7))) voxelgrid.InjectSphere(Sphere(Vector(-4.8,1.6,-2.5), 1.6)) +voxelgrid.InjectCapsule(Capsule(Vector(4.8,-0.6,-2.5), Vector(2, 1, 1), 0.4)) -- If teapot model can be loaded, then load it and voxelize it too: local scene = Scene() diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index fa98fb149a..f59c797d3d 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -5843,10 +5843,10 @@ namespace wi::scene break; case ColliderComponent::Shape::Capsule: { - AABB aabb = collider.capsule.getAABB(); + Capsule capsule = collider.capsule; // TODO: fix heap allocating lambda capture! - wi::jobsystem::Execute(ctx, [&voxelgrid, subtract, aabb](wi::jobsystem::JobArgs args) { - voxelgrid.inject_aabb(aabb, subtract); + wi::jobsystem::Execute(ctx, [&voxelgrid, subtract, capsule](wi::jobsystem::JobArgs args) { + voxelgrid.inject_capsule(capsule, subtract); }); } break; diff --git a/WickedEngine/wiVoxelGrid.cpp b/WickedEngine/wiVoxelGrid.cpp index 63ba1be563..9fc4ad735c 100644 --- a/WickedEngine/wiVoxelGrid.cpp +++ b/WickedEngine/wiVoxelGrid.cpp @@ -236,6 +236,76 @@ namespace wi } } } + void VoxelGrid::inject_capsule(const wi::primitive::Capsule& capsule, bool subtract) + { + const XMVECTOR CENTER = XMLoadFloat3(¢er); + const XMVECTOR RESOLUTION = XMLoadUInt3(&resolution); + const XMVECTOR RESOLUTION_RCP = XMLoadFloat3(&resolution_rcp); + const XMVECTOR VOXELSIZE_RCP = XMLoadFloat3(&voxelSize_rcp); + + AABB aabb = capsule.getAABB(); + + XMVECTOR _MIN = XMLoadFloat3(&aabb._min); + XMVECTOR _MAX = XMLoadFloat3(&aabb._max); + + // world -> uvw space: + _MIN = world_to_uvw(_MIN, CENTER, RESOLUTION_RCP, VOXELSIZE_RCP); + _MAX = world_to_uvw(_MAX, CENTER, RESOLUTION_RCP, VOXELSIZE_RCP); + + // pixel space: + _MIN *= RESOLUTION; + _MAX *= RESOLUTION; + + // After changing spaces, need to minmax again: + XMVECTOR MIN = XMVectorMin(_MIN, _MAX); + XMVECTOR MAX = XMVectorMax(_MIN, _MAX); + + MIN = XMVectorFloor(MIN); + MAX = XMVectorCeiling(MAX + XMVectorSet(0.5f, 0.5f, 0.5f, 0)); + + MIN = XMVectorMax(MIN, XMVectorZero()); + MAX = XMVectorMin(MAX, RESOLUTION); + + XMUINT3 mini, maxi; + XMStoreUInt3(&mini, MIN); + XMStoreUInt3(&maxi, MAX); + + volatile long long* data = (volatile long long*)voxels.data(); + for (uint32_t x = mini.x; x < maxi.x; ++x) + { + for (uint32_t y = mini.y; y < maxi.y; ++y) + { + for (uint32_t z = mini.z; z < maxi.z; ++z) + { + wi::primitive::AABB voxel_aabb; + XMUINT3 voxel_center_coord = XMUINT3(x, y, z); + XMFLOAT3 voxel_center_world = coord_to_world(voxel_center_coord); + voxel_aabb.createFromHalfWidth(voxel_center_world, voxelSize); + for (int c = 0; c < 8; ++c) + { + // This capsule-box test can fail if capsule doesn't contain any of the corners, + // but it intersects with the cube. But for now this simple method is used. + if (capsule.intersects(voxel_aabb.corner(c))) + { + const uint3 coord = uint3(x / 4u, y / 4u, z / 4u); + const uint3 sub_coord = uint3(x % 4u, y % 4u, z % 4u); + const uint32_t idx = flatten3D(coord, resolution_div4); + const uint32_t bit = flatten3D(sub_coord, uint3(4, 4, 4)); + const uint64_t mask = 1ull << bit; + if (subtract) + { + AtomicAnd(data + idx, ~mask); + } + else + { + AtomicOr(data + idx, mask); + } + } + } + } + } + } + } XMUINT3 VoxelGrid::world_to_coord(const XMFLOAT3& worldpos) const { diff --git a/WickedEngine/wiVoxelGrid.h b/WickedEngine/wiVoxelGrid.h index a4e51d8dbe..3884ab076b 100644 --- a/WickedEngine/wiVoxelGrid.h +++ b/WickedEngine/wiVoxelGrid.h @@ -34,6 +34,7 @@ namespace wi void inject_triangle(XMVECTOR A, XMVECTOR B, XMVECTOR C, bool subtract = false); void inject_aabb(const wi::primitive::AABB& aabb, bool subtract = false); void inject_sphere(const wi::primitive::Sphere& sphere, bool subtract = false); + void inject_capsule(const wi::primitive::Capsule& capsule, bool subtract = false); XMUINT3 world_to_coord(const XMFLOAT3& worldpos) const; XMFLOAT3 coord_to_world(const XMUINT3& coord) const; bool check_voxel(XMUINT3 coord) const; diff --git a/WickedEngine/wiVoxelGrid_BindLua.cpp b/WickedEngine/wiVoxelGrid_BindLua.cpp index 70cc98b051..0c4c4f6ef8 100644 --- a/WickedEngine/wiVoxelGrid_BindLua.cpp +++ b/WickedEngine/wiVoxelGrid_BindLua.cpp @@ -11,6 +11,7 @@ namespace wi::lua lunamethod(VoxelGrid_BindLua, InjectTriangle), lunamethod(VoxelGrid_BindLua, InjectAABB), lunamethod(VoxelGrid_BindLua, InjectSphere), + lunamethod(VoxelGrid_BindLua, InjectCapsule), lunamethod(VoxelGrid_BindLua, WorldToCoord), lunamethod(VoxelGrid_BindLua, CoordToWorld), lunamethod(VoxelGrid_BindLua, CheckVoxel), @@ -156,6 +157,28 @@ namespace wi::lua voxelgrid->inject_sphere(sphere->sphere, subtract); return 0; } + int VoxelGrid_BindLua::InjectCapsule(lua_State* L) + { + int argc = wi::lua::SGetArgCount(L); + if (argc < 1) + { + wi::lua::SError(L, "VoxelGrid::InjectCapsule(Capsule capsule, opt bool subtract = false) not enough arguments!"); + return 0; + } + primitive::Capsule_BindLua* capsule = Luna::lightcheck(L, 1); + if (capsule == nullptr) + { + wi::lua::SError(L, "VoxelGrid::InjectCapsule(Capsule capsule, opt bool subtract = false) first argument is not a Vector!"); + return 0; + } + bool subtract = false; + if (argc > 1) + { + subtract = wi::lua::SGetBool(L, 2); + } + voxelgrid->inject_capsule(capsule->capsule, subtract); + return 0; + } int VoxelGrid_BindLua::WorldToCoord(lua_State* L) { int argc = wi::lua::SGetArgCount(L); diff --git a/WickedEngine/wiVoxelGrid_BindLua.h b/WickedEngine/wiVoxelGrid_BindLua.h index ba1aaf63a3..129bbc96ac 100644 --- a/WickedEngine/wiVoxelGrid_BindLua.h +++ b/WickedEngine/wiVoxelGrid_BindLua.h @@ -28,6 +28,7 @@ namespace wi::lua int InjectTriangle(lua_State* L); int InjectAABB(lua_State* L); int InjectSphere(lua_State* L); + int InjectCapsule(lua_State* L); int WorldToCoord(lua_State* L); int CoordToWorld(lua_State* L); int CheckVoxel(lua_State* L);