diff --git a/examples/PhysicsPlayground/main.cpp b/examples/PhysicsPlayground/main.cpp index 869a9471b..76972cbaa 100644 --- a/examples/PhysicsPlayground/main.cpp +++ b/examples/PhysicsPlayground/main.cpp @@ -60,6 +60,14 @@ int main() Nz::Vector3f target = Nz::Vector3f::Zero(); + std::shared_ptr colliderMat = Nz::Graphics::Instance()->GetDefaultMaterials().basicMaterial->Instantiate(); + colliderMat->SetValueProperty("BaseColor", Nz::Color::Green()); + colliderMat->UpdatePassesStates([](Nz::RenderStates& states) + { + states.primitiveMode = Nz::PrimitiveMode::LineList; + return true; + }); + entt::handle boxEntity = world.CreateEntity(); { std::shared_ptr boxMesh = Nz::GraphicalMesh::Build(Nz::Primitive::Box(Nz::Vector3f(BoxDims), Nz::Vector3ui::Zero(), Nz::Matrix4f::Scale(Nz::Vector3f(-1.f)), Nz::Rectf(0.f, 0.f, 2.f, 2.f))); @@ -123,18 +131,11 @@ int main() auto& boxBody = boxEntity.emplace(physSystem.CreateRigidBody(settings)); #else auto& boxBody = boxEntity.emplace(physSystem.CreateRigidBody(boxCollider)); + boxBody.SetMass(0.f); #endif std::shared_ptr colliderModel; { - std::shared_ptr colliderMat = Nz::Graphics::Instance()->GetDefaultMaterials().basicMaterial->Instantiate(); - colliderMat->SetValueProperty("BaseColor", Nz::Color::Green()); - colliderMat->UpdatePassesStates([](Nz::RenderStates& states) - { - states.primitiveMode = Nz::PrimitiveMode::LineList; - return true; - }); - std::shared_ptr colliderMesh = Nz::Mesh::Build(boxCollider->GenerateDebugMesh()); std::shared_ptr colliderGraphicalMesh = Nz::GraphicalMesh::BuildFromMesh(*colliderMesh); @@ -189,7 +190,6 @@ int main() #else auto& ballPhysics = ballEntity.emplace(physSystem.CreateRigidBody(sphereCollider)); #endif - //ballPhysics.DisableSleeping(); } std::uniform_real_distribution lengthDis(0.2f, 1.5f); @@ -206,7 +206,7 @@ int main() std::uniform_real_distribution yRandom(-BoxDims * 0.5f + height, BoxDims * 0.5f - height); std::uniform_real_distribution zRandom(-BoxDims * 0.5f + depth, BoxDims * 0.5f - depth); - entt::handle ballEntity = world.CreateEntity(); + entt::handle boxEntity = world.CreateEntity(); std::shared_ptr boxMaterial = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate(); boxMaterial->SetValueProperty("BaseColor", Nz::Color::FromHSV(colorDis(rd), 1.f, 1.f)); @@ -214,10 +214,9 @@ int main() std::shared_ptr sphereModel = std::make_shared(boxMesh); sphereModel->SetMaterial(0, std::move(boxMaterial)); - auto& ballGfx = ballEntity.emplace(); - ballGfx.AttachRenderable(std::move(sphereModel)); + boxEntity.emplace(std::move(sphereModel)); - auto& ballNode = ballEntity.emplace(); + auto& ballNode = boxEntity.emplace(); ballNode.SetPosition(xRandom(rd), yRandom(rd), zRandom(rd)); ballNode.SetScale(width, height, depth); @@ -232,12 +231,93 @@ int main() settings.geom = boxCollider; settings.mass = width * height * depth; - ballEntity.emplace(physSystem.CreateRigidBody(settings)); + boxEntity.emplace(physSystem.CreateRigidBody(settings)); #else - ballEntity.emplace(physSystem.CreateRigidBody(boxCollider)); + boxEntity.emplace(physSystem.CreateRigidBody(boxCollider)); #endif } + // Spaceships + { + Nz::MeshParams meshParams; + meshParams.center = true; + meshParams.vertexRotation = Nz::EulerAnglesf(0.f, 90.f, 0.f); + meshParams.vertexScale = Nz::Vector3f(0.002f); + meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV_Tangent); + + std::shared_ptr spaceshipMesh = fs.Load("assets/Spaceship/spaceship.obj", meshParams); + if (!spaceshipMesh) + { + NazaraError("Failed to load model"); + return __LINE__; + } + + const Nz::Boxf& aabb = spaceshipMesh->GetAABB(); + + std::uniform_real_distribution xRandom(-BoxDims * 0.5f + aabb.width, BoxDims * 0.5f - aabb.width); + std::uniform_real_distribution yRandom(-BoxDims * 0.5f + aabb.height, BoxDims * 0.5f - aabb.height); + std::uniform_real_distribution zRandom(-BoxDims * 0.5f + aabb.depth, BoxDims * 0.5f - aabb.depth); + + + std::shared_ptr gfxMesh = Nz::GraphicalMesh::BuildFromMesh(*spaceshipMesh); + + Nz::TextureSamplerInfo samplerInfo; + samplerInfo.anisotropyLevel = 8; + + std::shared_ptr material = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate(); + + Nz::TextureParams texParams; + texParams.loadFormat = Nz::PixelFormat::RGBA8_SRGB; + + material->SetTextureProperty("BaseColorMap", fs.Load("assets/Spaceship/Texture/diffuse.png", texParams)); + + std::shared_ptr model = std::make_shared(std::move(gfxMesh)); + for (std::size_t i = 0; i < model->GetSubMeshCount(); ++i) + model->SetMaterial(i, material); + + Nz::VertexMapper vertexMapper(*spaceshipMesh->GetSubMesh(0)); + Nz::SparsePtr vertices = vertexMapper.GetComponentPtr(Nz::VertexComponent::Position); + +#if USE_JOLT + auto shipCollider = std::make_shared(vertices, vertexMapper.GetVertexCount()); +#else + auto shipCollider = std::make_shared(vertices, vertexMapper.GetVertexCount()); +#endif + + std::shared_ptr colliderModel; + { + std::shared_ptr colliderMesh = Nz::Mesh::Build(shipCollider->GenerateDebugMesh()); + std::shared_ptr colliderGraphicalMesh = Nz::GraphicalMesh::BuildFromMesh(*colliderMesh); + + colliderModel = std::make_shared(colliderGraphicalMesh); + for (std::size_t i = 0; i < colliderModel->GetSubMeshCount(); ++i) + colliderModel->SetMaterial(i, colliderMat); + } + + constexpr std::size_t ShipCount = 1000; + for (std::size_t i = 0; i < ShipCount; ++i) + { + entt::handle shipEntity = world.CreateEntity(); + + shipEntity.emplace(model); + + auto& shipNode = shipEntity.emplace(); + shipNode.SetPosition(xRandom(rd), yRandom(rd), zRandom(rd)); + +#if USE_JOLT + Nz::JoltRigidBody3D::DynamicSettings settings; + settings.geom = shipCollider; + settings.mass = 100.f; + + shipEntity.emplace(physSystem.CreateRigidBody(settings)); +#else + shipEntity.emplace(physSystem.CreateRigidBody(shipCollider)); +#endif + + shipEntity.get().AttachRenderable(colliderModel); + } + } + // Lumière entt::handle lightEntity = world.CreateEntity(); { diff --git a/include/Nazara/JoltPhysics3D/Enums.hpp b/include/Nazara/JoltPhysics3D/Enums.hpp index 884a41e91..996c48c30 100644 --- a/include/Nazara/JoltPhysics3D/Enums.hpp +++ b/include/Nazara/JoltPhysics3D/Enums.hpp @@ -14,6 +14,7 @@ namespace Nz Box, Capsule, Compound, + Convex, Sphere, ScaleDecoration, diff --git a/include/Nazara/JoltPhysics3D/JoltCollider3D.hpp b/include/Nazara/JoltPhysics3D/JoltCollider3D.hpp index 5fc358db8..21b4f0179 100644 --- a/include/Nazara/JoltPhysics3D/JoltCollider3D.hpp +++ b/include/Nazara/JoltPhysics3D/JoltCollider3D.hpp @@ -53,7 +53,7 @@ namespace Nz protected: template const T* GetShapeSettingsAs() const; void ResetShapeSettings(); - template void SetupShapeSettings(std::unique_ptr shapeSettings); + void SetupShapeSettings(std::unique_ptr&& shapeSettings); private: static std::shared_ptr CreateGeomFromPrimitive(const Primitive& primitive); @@ -66,7 +66,7 @@ namespace Nz class NAZARA_JOLTPHYSICS3D_API JoltBoxCollider3D final : public JoltCollider3D { public: - JoltBoxCollider3D(const Vector3f& lengths, float convexRadius = 0.1f); + JoltBoxCollider3D(const Vector3f& lengths, float convexRadius = 0.01f); ~JoltBoxCollider3D() = default; void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; @@ -111,6 +111,17 @@ namespace Nz private: std::vector m_childs; }; + + class NAZARA_JOLTPHYSICS3D_API JoltConvexHullCollider3D final : public JoltCollider3D + { + public: + JoltConvexHullCollider3D(SparsePtr vertices, std::size_t vertexCount, float hullTolerance = 0.001f, float convexRadius = 0.f, float maxErrorConvexRadius = 0.05f); + ~JoltConvexHullCollider3D() = default; + + void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; + + JoltColliderType3D GetType() const override; + }; class NAZARA_JOLTPHYSICS3D_API JoltSphereCollider3D final : public JoltCollider3D { diff --git a/include/Nazara/JoltPhysics3D/JoltCollider3D.inl b/include/Nazara/JoltPhysics3D/JoltCollider3D.inl index cb60a72d6..27d734504 100644 --- a/include/Nazara/JoltPhysics3D/JoltCollider3D.inl +++ b/include/Nazara/JoltPhysics3D/JoltCollider3D.inl @@ -19,15 +19,6 @@ namespace Nz return SafeCast(m_shapeSettings.get()); } - template - void JoltCollider3D::SetupShapeSettings(std::unique_ptr shapeSettings) - { - shapeSettings->SetEmbedded(); // Call SetEmbedded on the template type to prevent compiler to resolve it outside of a file including Jolt - - assert(!m_shapeSettings); - m_shapeSettings = std::move(shapeSettings); - } - inline JoltTranslatedRotatedCollider3D::JoltTranslatedRotatedCollider3D(std::shared_ptr collider, const Vector3f& translation) : JoltTranslatedRotatedCollider3D(std::move(collider), translation, Quaternionf::Identity()) diff --git a/src/Nazara/JoltPhysics3D/JoltCollider3D.cpp b/src/Nazara/JoltPhysics3D/JoltCollider3D.cpp index e1e7ad335..51b519bb7 100644 --- a/src/Nazara/JoltPhysics3D/JoltCollider3D.cpp +++ b/src/Nazara/JoltPhysics3D/JoltCollider3D.cpp @@ -11,9 +11,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -67,7 +69,17 @@ namespace Nz { m_shapeSettings.reset(); } - + + void JoltCollider3D::SetupShapeSettings(std::unique_ptr&& shapeSettings) + { + assert(!m_shapeSettings); + m_shapeSettings = std::move(shapeSettings); + m_shapeSettings->SetEmbedded(); + + if (auto result = m_shapeSettings->Create(); result.HasError()) + throw std::runtime_error(std::string("shape creation failed: ") + result.GetError().c_str()); + } + std::shared_ptr JoltCollider3D::CreateGeomFromPrimitive(const Primitive& primitive) { switch (primitive.type) @@ -272,6 +284,57 @@ namespace Nz return JoltColliderType3D::Compound; } + /******************************** JoltConvexHullCollider3D *********************************/ + + JoltConvexHullCollider3D::JoltConvexHullCollider3D(SparsePtr vertices, std::size_t vertexCount, float hullTolerance, float convexRadius, float maxErrorConvexRadius) + { + std::unique_ptr settings = std::make_unique(); + settings->mHullTolerance = hullTolerance; + settings->mMaxConvexRadius = convexRadius; + settings->mMaxErrorConvexRadius = maxErrorConvexRadius; + + settings->mPoints.resize(vertexCount); + for (std::size_t i = 0; i < vertexCount; ++i) + settings->mPoints[i] = ToJolt(vertices[i]); + + SetupShapeSettings(std::move(settings)); + } + + void JoltConvexHullCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + { + tsl::ordered_map vertexCache; + auto InsertVertex = [&](const Vector3f& position) -> UInt16 + { + auto it = vertexCache.find(position); + if (it != vertexCache.end()) + return it->second; + + UInt16 index = SafeCast(vertices.size()); + + vertices.push_back(position); + vertexCache.emplace(position, index); + + return index; + }; + + const JPH::ConvexHullShapeSettings* settings = GetShapeSettingsAs(); + const JPH::ConvexHullShape* shape = SafeCast(settings->Create().Get().GetPtr()); + + unsigned int pointCount = shape->GetNumPoints(); + for (int i = 1; i < pointCount; ++i) + { + indices.push_back(InsertVertex(offsetMatrix * FromJolt(shape->GetPoint(i - 1)))); + indices.push_back(InsertVertex(offsetMatrix * FromJolt(shape->GetPoint(i)))); + } + indices.push_back(InsertVertex(offsetMatrix* FromJolt(shape->GetPoint(pointCount - 1)))); + indices.push_back(InsertVertex(offsetMatrix* FromJolt(shape->GetPoint(0)))); + } + + JoltColliderType3D JoltConvexHullCollider3D::GetType() const + { + return JoltColliderType3D::Convex; + } + /******************************** JoltSphereCollider3D *********************************/ JoltSphereCollider3D::JoltSphereCollider3D(float radius) @@ -293,6 +356,8 @@ namespace Nz return JoltColliderType3D::Sphere; } + /******************************** JoltTranslatedRotatedCollider3D *********************************/ + JoltTranslatedRotatedCollider3D::JoltTranslatedRotatedCollider3D(std::shared_ptr collider, const Vector3f& translation, const Quaternionf& rotation) : m_collider(std::move(collider)) {