From 19d88ab1e0fd8f31aa6085faba8de74d4f2919b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Sat, 24 Feb 2024 08:25:55 +0100 Subject: [PATCH] updates --- .../ScriptingAPI-Documentation.md | 2 +- Editor/IconDefinitions.h | 1 + Editor/OptionsWindow.cpp | 4 +- Editor/VoxelGridWindow.cpp | 84 +++++++++++++------ Editor/VoxelGridWindow.h | 7 +- WickedEngine/wiScene.cpp | 82 ++++++++++++++---- WickedEngine/wiScene.h | 9 +- WickedEngine/wiScene_BindLua.cpp | 11 ++- WickedEngine/wiVersion.cpp | 2 +- features.txt | 1 + 10 files changed, 146 insertions(+), 57 deletions(-) diff --git a/Content/Documentation/ScriptingAPI-Documentation.md b/Content/Documentation/ScriptingAPI-Documentation.md index ad1c73f605..65942becc8 100644 --- a/Content/Documentation/ScriptingAPI-Documentation.md +++ b/Content/Documentation/ScriptingAPI-Documentation.md @@ -780,7 +780,7 @@ The scene holds components. Entity handles can be used to retrieve associated co - RetargetAnimation(Entity dst, src, bool bake_data) : Entity entity -- Retargets an animation from a Humanoid to an other Humanoid such that the new animation will play back on the destination humanoid. dst : destination humanoid that the animation will be fit onto src : the animation to copy, it should already target humanoid bones. bake_data : if true, the retargeted data will be baked into a new animation data. If false, it will reuse the source animation data without creating a new one and retargeting will be applied at runtime on every Update. Returns entity ID of the new animation or INVALID_ENTITY if retargeting was not successful -- VoxelizeObject(int objectIndex, VoxelGrid voxelgrid, bool subtract = false) -- voxelizes a single object into the voxel grid. Subtract parameter controls whether the voxels are added (true) or removed (false). This returns immediately after voxelization is finished. +- VoxelizeObject(int objectIndex, VoxelGrid voxelgrid, bool subtract = false, opt int lod = 0) -- voxelizes a single object into the voxel grid. Subtract parameter controls whether the voxels are added (true) or removed (false). Lod argument selects object's level of detail #### NameComponent Holds a string that can more easily identify an entity to humans than an entity ID. diff --git a/Editor/IconDefinitions.h b/Editor/IconDefinitions.h index 0149d4c7a0..f2d26587ba 100644 --- a/Editor/IconDefinitions.h +++ b/Editor/IconDefinitions.h @@ -39,6 +39,7 @@ #define ICON_VOXELGRID ICON_FA_TABLE_CELLS #define ICON_CLEARVOXELS ICON_FA_TRASH_CAN #define ICON_VOXELIZE ICON_FA_WAVE_SQUARE +#define ICON_VOXELBOUNDS ICON_FA_VECTOR_SQUARE #define ICON_SAVE ICON_FA_FLOPPY_DISK #define ICON_OPEN ICON_FA_FOLDER_OPEN diff --git a/Editor/OptionsWindow.cpp b/Editor/OptionsWindow.cpp index fc6f057f87..b0d5c12255 100644 --- a/Editor/OptionsWindow.cpp +++ b/Editor/OptionsWindow.cpp @@ -248,8 +248,8 @@ void OptionsWindow::Create(EditorComponent* _editor) case NEW_VOXELGRID: { pick.entity = CreateEntity(); - scene.voxel_grids.Create(pick.entity).init(32, 32, 32); - scene.transforms.Create(pick.entity); + scene.voxel_grids.Create(pick.entity).init(64, 64, 64); + scene.transforms.Create(pick.entity).Scale(XMFLOAT3(0.25f, 0.25f, 0.25f)); scene.names.Create(pick.entity) = "voxelgrid"; } break; diff --git a/Editor/VoxelGridWindow.cpp b/Editor/VoxelGridWindow.cpp index bf0f50c729..b481906f9a 100644 --- a/Editor/VoxelGridWindow.cpp +++ b/Editor/VoxelGridWindow.cpp @@ -8,7 +8,7 @@ void VoxelGridWindow::Create(EditorComponent* _editor) { editor = _editor; wi::gui::Window::Create(ICON_VOXELGRID " VoxelGrid", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE); - SetSize(XMFLOAT2(520, 300)); + SetSize(XMFLOAT2(520, 400)); closeButton.SetTooltip("Delete VoxelGrid"); OnClose([=](wi::gui::EventArgs args) { @@ -42,7 +42,7 @@ void VoxelGridWindow::Create(EditorComponent* _editor) wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); if (voxelgrid == nullptr) return; - voxelgrid->init(uint32_t(args.iValue), voxelgrid->resolution.y, voxelgrid->resolution.z); + voxelgrid->init(uint32_t(std::max(1, args.iValue)), voxelgrid->resolution.y, voxelgrid->resolution.z); }); AddWidget(&dimXInput); @@ -54,7 +54,7 @@ void VoxelGridWindow::Create(EditorComponent* _editor) wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); if (voxelgrid == nullptr) return; - voxelgrid->init(voxelgrid->resolution.x, uint32_t(args.iValue), voxelgrid->resolution.z); + voxelgrid->init(voxelgrid->resolution.x, uint32_t(std::max(1, args.iValue)), voxelgrid->resolution.z); }); AddWidget(&dimYInput); @@ -66,7 +66,7 @@ void VoxelGridWindow::Create(EditorComponent* _editor) wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); if (voxelgrid == nullptr) return; - voxelgrid->init(voxelgrid->resolution.x, voxelgrid->resolution.y, uint32_t(args.iValue)); + voxelgrid->init(voxelgrid->resolution.x, voxelgrid->resolution.y, uint32_t(std::max(1, args.iValue))); }); AddWidget(&dimZInput); @@ -81,35 +81,68 @@ void VoxelGridWindow::Create(EditorComponent* _editor) }); AddWidget(&clearButton); - generateWholeButton.Create("Generate full grid " ICON_VOXELIZE); - generateWholeButton.SetTooltip("Generate navigation grid including all meshes."); - generateWholeButton.SetSize(XMFLOAT2(100, hei)); - generateWholeButton.OnClick([=](wi::gui::EventArgs args) { + voxelizeObjectsButton.Create("Voxelize objects " ICON_VOXELIZE); + voxelizeObjectsButton.SetTooltip("Generate navigation grid including all meshes."); + voxelizeObjectsButton.SetSize(XMFLOAT2(100, hei)); + voxelizeObjectsButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); if (voxelgrid == nullptr) return; - wi::jobsystem::context ctx; - voxelgrid->cleardata(); - scene.VoxelizeWholeScene(ctx, *voxelgrid); - wi::jobsystem::Wait(ctx); + scene.VoxelizeScene(*voxelgrid, subtractCheckBox.GetCheck(), wi::enums::FILTER_OBJECT_ALL); }); - AddWidget(&generateWholeButton); + AddWidget(&voxelizeObjectsButton); - generateNavigationButton.Create("Generate navigation grid " ICON_VOXELIZE); - generateNavigationButton.SetTooltip("Generate navigation grid including all navmeshes (object tagged as navmesh)."); - generateNavigationButton.SetSize(XMFLOAT2(100, hei)); - generateNavigationButton.OnClick([=](wi::gui::EventArgs args) { + voxelizeNavigationButton.Create("Voxelize navigation " ICON_VOXELIZE); + voxelizeNavigationButton.SetTooltip("Generate navigation grid including all navmeshes (object tagged as navmesh)."); + voxelizeNavigationButton.SetSize(XMFLOAT2(100, hei)); + voxelizeNavigationButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = editor->GetCurrentScene(); wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); if (voxelgrid == nullptr) return; - wi::jobsystem::context ctx; - voxelgrid->cleardata(); - scene.VoxelizeNavigation(ctx, *voxelgrid); - wi::jobsystem::Wait(ctx); + scene.VoxelizeScene(*voxelgrid, subtractCheckBox.GetCheck(), wi::enums::FILTER_NAVIGATION_MESH); + }); + AddWidget(&voxelizeNavigationButton); + + voxelizeCollidersButton.Create("Voxelize CPU colliders " ICON_VOXELIZE); + voxelizeCollidersButton.SetTooltip("Generate navigation grid including all CPU colliders."); + voxelizeCollidersButton.SetSize(XMFLOAT2(100, hei)); + voxelizeCollidersButton.OnClick([=](wi::gui::EventArgs args) { + Scene& scene = editor->GetCurrentScene(); + wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); + if (voxelgrid == nullptr) + return; + scene.VoxelizeScene(*voxelgrid, subtractCheckBox.GetCheck(), wi::enums::FILTER_COLLIDER); }); - AddWidget(&generateNavigationButton); + AddWidget(&voxelizeCollidersButton); + + fitToSceneButton.Create("Fit bounds to scene " ICON_VOXELBOUNDS); + fitToSceneButton.SetTooltip("Fit the bounds of the voxel grid onto the whole scene."); + fitToSceneButton.SetSize(XMFLOAT2(100, hei)); + fitToSceneButton.OnClick([=](wi::gui::EventArgs args) { + Scene& scene = editor->GetCurrentScene(); + if (scene.bounds.getArea() < 0) + return; + wi::VoxelGrid* voxelgrid = scene.voxel_grids.GetComponent(entity); + if (voxelgrid == nullptr) + return; + voxelgrid->from_aabb(scene.bounds); + TransformComponent* transform = scene.transforms.GetComponent(entity); + if (transform != nullptr) + { + // feed back to transform component if it exists: + transform->translation_local = voxelgrid->center; + transform->scale_local = voxelgrid->voxelSize; + transform->SetDirty(); + } + }); + AddWidget(&fitToSceneButton); + + subtractCheckBox.Create("Subtraction mode: "); + subtractCheckBox.SetTooltip("If enabled, voxelization will be subtractive, so it will remove voxels instead of add."); + subtractCheckBox.SetSize(XMFLOAT2(hei, hei)); + AddWidget(&subtractCheckBox); debugAllCheckBox.Create("Debug draw all: "); debugAllCheckBox.SetTooltip("Draw all voxel grids, whether they are selected or not."); @@ -197,7 +230,10 @@ void VoxelGridWindow::ResizeLayout() y += padding; add_fullwidth(clearButton); - add_fullwidth(generateWholeButton); - add_fullwidth(generateNavigationButton); + add_fullwidth(voxelizeObjectsButton); + add_fullwidth(voxelizeCollidersButton); + add_fullwidth(voxelizeNavigationButton); + add_fullwidth(fitToSceneButton); + add_right(subtractCheckBox); add_right(debugAllCheckBox); } diff --git a/Editor/VoxelGridWindow.h b/Editor/VoxelGridWindow.h index bf8cee85eb..ed9ffe30ee 100644 --- a/Editor/VoxelGridWindow.h +++ b/Editor/VoxelGridWindow.h @@ -15,8 +15,11 @@ class VoxelGridWindow : public wi::gui::Window wi::gui::TextInputField dimYInput; wi::gui::TextInputField dimZInput; wi::gui::Button clearButton; - wi::gui::Button generateWholeButton; - wi::gui::Button generateNavigationButton; + wi::gui::Button voxelizeObjectsButton; + wi::gui::Button voxelizeNavigationButton; + wi::gui::Button voxelizeCollidersButton; + wi::gui::Button fitToSceneButton; + wi::gui::CheckBox subtractCheckBox; wi::gui::CheckBox debugAllCheckBox; void ResizeLayout() override; diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 78bbea3abb..936db00150 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -5750,7 +5750,7 @@ namespace wi::scene return result; } - void Scene::VoxelizeObject(size_t objectIndex, wi::VoxelGrid& grid, bool subtract) + void Scene::VoxelizeObject(size_t objectIndex, wi::VoxelGrid& grid, bool subtract, uint32_t lod) { if (objectIndex >= objects.GetCount() || objectIndex >= aabb_objects.size()) return; @@ -5766,7 +5766,7 @@ namespace wi::scene uint32_t first_subset = 0; uint32_t last_subset = 0; - mesh->GetLODSubsetRange(0, first_subset, last_subset); + mesh->GetLODSubsetRange(lod, first_subset, last_subset); for (uint32_t subsetIndex = first_subset; subsetIndex < last_subset; ++subsetIndex) { const MeshComponent::MeshSubset& subset = mesh->subsets[subsetIndex]; @@ -5816,28 +5816,74 @@ namespace wi::scene } } } - void Scene::VoxelizeNavigation(wi::jobsystem::context& ctx, wi::VoxelGrid& voxelgrid) + + void Scene::VoxelizeScene(wi::VoxelGrid& voxelgrid, bool subtract, wi::enums::FILTER filterMask, uint32_t layerMask, uint32_t lod) { - for (size_t i = 0; i < objects.GetCount(); ++i) + wi::jobsystem::context ctx; + if ((filterMask & FILTER_COLLIDER)) { - const ObjectComponent& object = objects[i]; - if ((object.GetFilterMask() & FILTER::FILTER_NAVIGATION_MESH) == 0) - continue; + for (size_t i = 0; i < collider_count_cpu; ++i) + { + const ColliderComponent& collider = colliders_cpu[i]; - wi::jobsystem::Execute(ctx, [this, i, &voxelgrid](wi::jobsystem::JobArgs args) { - VoxelizeObject(i, voxelgrid); - }); + if ((collider.layerMask & layerMask) == 0) + continue; + + switch (collider.shape) + { + default: + case ColliderComponent::Shape::Sphere: + { + Sphere sphere = collider.sphere; + // TODO: fix heap allocating lambda capture! + wi::jobsystem::Execute(ctx, [&voxelgrid, subtract, sphere](wi::jobsystem::JobArgs args) { + voxelgrid.inject_sphere(sphere, subtract); + }); + } + break; + case ColliderComponent::Shape::Capsule: + { + AABB aabb = collider.capsule.getAABB(); + // TODO: fix heap allocating lambda capture! + wi::jobsystem::Execute(ctx, [&voxelgrid, subtract, aabb](wi::jobsystem::JobArgs args) { + voxelgrid.inject_aabb(aabb, subtract); + }); + } + break; + case ColliderComponent::Shape::Plane: + { + XMMATRIX planeMatrix = XMMatrixInverse(nullptr, XMLoadFloat4x4(&collider.plane.projection)); + 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); + // TODO: fix heap allocating lambda capture! + wi::jobsystem::Execute(ctx, [&voxelgrid, subtract, P0, P1, P2, P3](wi::jobsystem::JobArgs args) { + voxelgrid.inject_triangle(P0, P1, P2, subtract); + voxelgrid.inject_triangle(P0, P2, P3, subtract); + }); + } + break; + } + } } - } - void Scene::VoxelizeWholeScene(wi::jobsystem::context& ctx, wi::VoxelGrid& voxelgrid) - { - for (size_t i = 0; i < objects.GetCount(); ++i) + if (filterMask & FILTER_OBJECT_ALL) { - const ObjectComponent& object = objects[i]; - wi::jobsystem::Execute(ctx, [this, i, &voxelgrid](wi::jobsystem::JobArgs args) { - VoxelizeObject(i, voxelgrid); - }); + for (size_t i = 0; i < objects.GetCount(); ++i) + { + const ObjectComponent& object = objects[i]; + if ((filterMask & object.GetFilterMask()) == 0) + continue; + const AABB& aabb = aabb_objects[i]; + if ((layerMask & aabb.layerMask) == 0) + continue; + // TODO: fix heap allocating lambda capture! + wi::jobsystem::Execute(ctx, [this, &voxelgrid, subtract, lod, i](wi::jobsystem::JobArgs args) { + VoxelizeObject(i, voxelgrid, subtract, lod); + }); + } } + wi::jobsystem::Wait(ctx); } XMFLOAT3 Scene::GetPositionOnSurface(wi::ecs::Entity objectEntity, int vertexID0, int vertexID1, int vertexID2, const XMFLOAT2& bary) const diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index bf4e9d155d..a2fee036c2 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -490,13 +490,10 @@ namespace wi::scene // All triangles of the object will be injected into the voxel grid // subtract: if false (default), voxels will be added, if true then voxels will be removed - void VoxelizeObject(size_t objectIndex, wi::VoxelGrid& grid, bool subtract = false); + void VoxelizeObject(size_t objectIndex, wi::VoxelGrid& grid, bool subtract = false, uint32_t lod = 0); - // Voxelize all navigation meshes into a voxel grid - void VoxelizeNavigation(wi::jobsystem::context& ctx, wi::VoxelGrid& voxelgrid); - - // Voxelize all meshes into a voxel grid - void VoxelizeWholeScene(wi::jobsystem::context& ctx, wi::VoxelGrid& voxelgrid); + // Voxelize all meshes that match the filters into a voxel grid + void VoxelizeScene(wi::VoxelGrid& voxelgrid, bool subtract = false, wi::enums::FILTER filterMask = wi::enums::FILTER_ALL, uint32_t layerMask = ~0, uint32_t lod = 0); // Get the current position on the surface of an object, tracked by the triangle barycentrics XMFLOAT3 GetPositionOnSurface(wi::ecs::Entity objectEntity, int vertexID0, int vertexID1, int vertexID2, const XMFLOAT2& bary) const; diff --git a/WickedEngine/wiScene_BindLua.cpp b/WickedEngine/wiScene_BindLua.cpp index 4f53d0cc4f..e0a9501e2f 100644 --- a/WickedEngine/wiScene_BindLua.cpp +++ b/WickedEngine/wiScene_BindLua.cpp @@ -2947,22 +2947,27 @@ int Scene_BindLua::VoxelizeObject(lua_State* L) int argc = wi::lua::SGetArgCount(L); if (argc < 2) { - wi::lua::SError(L, "VoxelizeObject(int objectIndex, VoxelGrid voxelgrid, opt bool subtract = false) not enough arguments!"); + wi::lua::SError(L, "VoxelizeObject(int objectIndex, VoxelGrid voxelgrid, opt bool subtract = false, opt int lod = 0) not enough arguments!"); return 0; } size_t objectIndex = (size_t)wi::lua::SGetInt(L, 1); VoxelGrid_BindLua* voxelgrid = Luna::lightcheck(L, 2); if (voxelgrid == nullptr) { - wi::lua::SError(L, "VoxelizeObject(int objectIndex, VoxelGrid voxelgrid, opt bool subtract = false) second argument is not a VoxelGrid!"); + wi::lua::SError(L, "VoxelizeObject(int objectIndex, VoxelGrid voxelgrid, opt bool subtract = false, opt int lod = 0) second argument is not a VoxelGrid!"); return 0; } bool subtract = false; + uint32_t lod = 0; if (argc > 2) { subtract = wi::lua::SGetBool(L, 3); + if (argc > 3) + { + lod = (uint32_t)wi::lua::SGetInt(L, 4); + } } - scene->VoxelizeObject(objectIndex, voxelgrid->voxelgrid, subtract); + scene->VoxelizeObject(objectIndex, voxelgrid->voxelgrid, subtract, lod); return 0; } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 95ed2231ff..3331c675d3 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -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 = 381; + const int revision = 382; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision); diff --git a/features.txt b/features.txt index a6d98b0e22..190ec9a1c1 100644 --- a/features.txt +++ b/features.txt @@ -87,6 +87,7 @@ Expressions Humanoid rig Animation retargeting Video decoding: H264 +3D voxel path finding GLTF 2.0 - KHR extensions supported: KHR_materials_unlit