JoltPhysics3D: Add JoltConvexHullCollider3D

This commit is contained in:
SirLynix 2023-04-06 18:57:00 +02:00 committed by Jérôme Leclercq
parent 60ed70d3fd
commit 1415dcbf1a
5 changed files with 175 additions and 27 deletions

View File

@ -60,6 +60,14 @@ int main()
Nz::Vector3f target = Nz::Vector3f::Zero(); Nz::Vector3f target = Nz::Vector3f::Zero();
std::shared_ptr<Nz::MaterialInstance> 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(); entt::handle boxEntity = world.CreateEntity();
{ {
std::shared_ptr<Nz::GraphicalMesh> 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))); std::shared_ptr<Nz::GraphicalMesh> 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<Nz::JoltRigidBody3DComponent>(physSystem.CreateRigidBody(settings)); auto& boxBody = boxEntity.emplace<Nz::JoltRigidBody3DComponent>(physSystem.CreateRigidBody(settings));
#else #else
auto& boxBody = boxEntity.emplace<Nz::BulletRigidBody3DComponent>(physSystem.CreateRigidBody(boxCollider)); auto& boxBody = boxEntity.emplace<Nz::BulletRigidBody3DComponent>(physSystem.CreateRigidBody(boxCollider));
boxBody.SetMass(0.f);
#endif #endif
std::shared_ptr<Nz::Model> colliderModel; std::shared_ptr<Nz::Model> colliderModel;
{ {
std::shared_ptr<Nz::MaterialInstance> 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<Nz::Mesh> colliderMesh = Nz::Mesh::Build(boxCollider->GenerateDebugMesh()); std::shared_ptr<Nz::Mesh> colliderMesh = Nz::Mesh::Build(boxCollider->GenerateDebugMesh());
std::shared_ptr<Nz::GraphicalMesh> colliderGraphicalMesh = Nz::GraphicalMesh::BuildFromMesh(*colliderMesh); std::shared_ptr<Nz::GraphicalMesh> colliderGraphicalMesh = Nz::GraphicalMesh::BuildFromMesh(*colliderMesh);
@ -189,7 +190,6 @@ int main()
#else #else
auto& ballPhysics = ballEntity.emplace<Nz::BulletRigidBody3DComponent>(physSystem.CreateRigidBody(sphereCollider)); auto& ballPhysics = ballEntity.emplace<Nz::BulletRigidBody3DComponent>(physSystem.CreateRigidBody(sphereCollider));
#endif #endif
//ballPhysics.DisableSleeping();
} }
std::uniform_real_distribution<float> lengthDis(0.2f, 1.5f); std::uniform_real_distribution<float> lengthDis(0.2f, 1.5f);
@ -206,7 +206,7 @@ int main()
std::uniform_real_distribution<float> yRandom(-BoxDims * 0.5f + height, BoxDims * 0.5f - height); std::uniform_real_distribution<float> yRandom(-BoxDims * 0.5f + height, BoxDims * 0.5f - height);
std::uniform_real_distribution<float> zRandom(-BoxDims * 0.5f + depth, BoxDims * 0.5f - depth); std::uniform_real_distribution<float> zRandom(-BoxDims * 0.5f + depth, BoxDims * 0.5f - depth);
entt::handle ballEntity = world.CreateEntity(); entt::handle boxEntity = world.CreateEntity();
std::shared_ptr<Nz::MaterialInstance> boxMaterial = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate(); std::shared_ptr<Nz::MaterialInstance> boxMaterial = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate();
boxMaterial->SetValueProperty("BaseColor", Nz::Color::FromHSV(colorDis(rd), 1.f, 1.f)); boxMaterial->SetValueProperty("BaseColor", Nz::Color::FromHSV(colorDis(rd), 1.f, 1.f));
@ -214,10 +214,9 @@ int main()
std::shared_ptr<Nz::Model> sphereModel = std::make_shared<Nz::Model>(boxMesh); std::shared_ptr<Nz::Model> sphereModel = std::make_shared<Nz::Model>(boxMesh);
sphereModel->SetMaterial(0, std::move(boxMaterial)); sphereModel->SetMaterial(0, std::move(boxMaterial));
auto& ballGfx = ballEntity.emplace<Nz::GraphicsComponent>(); boxEntity.emplace<Nz::GraphicsComponent>(std::move(sphereModel));
ballGfx.AttachRenderable(std::move(sphereModel));
auto& ballNode = ballEntity.emplace<Nz::NodeComponent>(); auto& ballNode = boxEntity.emplace<Nz::NodeComponent>();
ballNode.SetPosition(xRandom(rd), yRandom(rd), zRandom(rd)); ballNode.SetPosition(xRandom(rd), yRandom(rd), zRandom(rd));
ballNode.SetScale(width, height, depth); ballNode.SetScale(width, height, depth);
@ -232,12 +231,93 @@ int main()
settings.geom = boxCollider; settings.geom = boxCollider;
settings.mass = width * height * depth; settings.mass = width * height * depth;
ballEntity.emplace<Nz::JoltRigidBody3DComponent>(physSystem.CreateRigidBody(settings)); boxEntity.emplace<Nz::JoltRigidBody3DComponent>(physSystem.CreateRigidBody(settings));
#else #else
ballEntity.emplace<Nz::BulletRigidBody3DComponent>(physSystem.CreateRigidBody(boxCollider)); boxEntity.emplace<Nz::BulletRigidBody3DComponent>(physSystem.CreateRigidBody(boxCollider));
#endif #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<Nz::Mesh> spaceshipMesh = fs.Load<Nz::Mesh>("assets/Spaceship/spaceship.obj", meshParams);
if (!spaceshipMesh)
{
NazaraError("Failed to load model");
return __LINE__;
}
const Nz::Boxf& aabb = spaceshipMesh->GetAABB();
std::uniform_real_distribution<float> xRandom(-BoxDims * 0.5f + aabb.width, BoxDims * 0.5f - aabb.width);
std::uniform_real_distribution<float> yRandom(-BoxDims * 0.5f + aabb.height, BoxDims * 0.5f - aabb.height);
std::uniform_real_distribution<float> zRandom(-BoxDims * 0.5f + aabb.depth, BoxDims * 0.5f - aabb.depth);
std::shared_ptr<Nz::GraphicalMesh> gfxMesh = Nz::GraphicalMesh::BuildFromMesh(*spaceshipMesh);
Nz::TextureSamplerInfo samplerInfo;
samplerInfo.anisotropyLevel = 8;
std::shared_ptr<Nz::MaterialInstance> material = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate();
Nz::TextureParams texParams;
texParams.loadFormat = Nz::PixelFormat::RGBA8_SRGB;
material->SetTextureProperty("BaseColorMap", fs.Load<Nz::Texture>("assets/Spaceship/Texture/diffuse.png", texParams));
std::shared_ptr<Nz::Model> model = std::make_shared<Nz::Model>(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<Nz::Vector3f> vertices = vertexMapper.GetComponentPtr<Nz::Vector3f>(Nz::VertexComponent::Position);
#if USE_JOLT
auto shipCollider = std::make_shared<Nz::JoltConvexHullCollider3D>(vertices, vertexMapper.GetVertexCount());
#else
auto shipCollider = std::make_shared<Nz::BulletConvexCollider3D>(vertices, vertexMapper.GetVertexCount());
#endif
std::shared_ptr<Nz::Model> colliderModel;
{
std::shared_ptr<Nz::Mesh> colliderMesh = Nz::Mesh::Build(shipCollider->GenerateDebugMesh());
std::shared_ptr<Nz::GraphicalMesh> colliderGraphicalMesh = Nz::GraphicalMesh::BuildFromMesh(*colliderMesh);
colliderModel = std::make_shared<Nz::Model>(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<Nz::GraphicsComponent>(model);
auto& shipNode = shipEntity.emplace<Nz::NodeComponent>();
shipNode.SetPosition(xRandom(rd), yRandom(rd), zRandom(rd));
#if USE_JOLT
Nz::JoltRigidBody3D::DynamicSettings settings;
settings.geom = shipCollider;
settings.mass = 100.f;
shipEntity.emplace<Nz::JoltRigidBody3DComponent>(physSystem.CreateRigidBody(settings));
#else
shipEntity.emplace<Nz::BulletRigidBody3DComponent>(physSystem.CreateRigidBody(shipCollider));
#endif
shipEntity.get<Nz::GraphicsComponent>().AttachRenderable(colliderModel);
}
}
// Lumière // Lumière
entt::handle lightEntity = world.CreateEntity(); entt::handle lightEntity = world.CreateEntity();
{ {

View File

@ -14,6 +14,7 @@ namespace Nz
Box, Box,
Capsule, Capsule,
Compound, Compound,
Convex,
Sphere, Sphere,
ScaleDecoration, ScaleDecoration,

View File

@ -53,7 +53,7 @@ namespace Nz
protected: protected:
template<typename T> const T* GetShapeSettingsAs() const; template<typename T> const T* GetShapeSettingsAs() const;
void ResetShapeSettings(); void ResetShapeSettings();
template<typename T> void SetupShapeSettings(std::unique_ptr<T> shapeSettings); void SetupShapeSettings(std::unique_ptr<JPH::ShapeSettings>&& shapeSettings);
private: private:
static std::shared_ptr<JoltCollider3D> CreateGeomFromPrimitive(const Primitive& primitive); static std::shared_ptr<JoltCollider3D> CreateGeomFromPrimitive(const Primitive& primitive);
@ -66,7 +66,7 @@ namespace Nz
class NAZARA_JOLTPHYSICS3D_API JoltBoxCollider3D final : public JoltCollider3D class NAZARA_JOLTPHYSICS3D_API JoltBoxCollider3D final : public JoltCollider3D
{ {
public: public:
JoltBoxCollider3D(const Vector3f& lengths, float convexRadius = 0.1f); JoltBoxCollider3D(const Vector3f& lengths, float convexRadius = 0.01f);
~JoltBoxCollider3D() = default; ~JoltBoxCollider3D() = default;
void BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const override; void BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const override;
@ -111,6 +111,17 @@ namespace Nz
private: private:
std::vector<ChildCollider> m_childs; std::vector<ChildCollider> m_childs;
}; };
class NAZARA_JOLTPHYSICS3D_API JoltConvexHullCollider3D final : public JoltCollider3D
{
public:
JoltConvexHullCollider3D(SparsePtr<const Vector3f> vertices, std::size_t vertexCount, float hullTolerance = 0.001f, float convexRadius = 0.f, float maxErrorConvexRadius = 0.05f);
~JoltConvexHullCollider3D() = default;
void BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const override;
JoltColliderType3D GetType() const override;
};
class NAZARA_JOLTPHYSICS3D_API JoltSphereCollider3D final : public JoltCollider3D class NAZARA_JOLTPHYSICS3D_API JoltSphereCollider3D final : public JoltCollider3D
{ {

View File

@ -19,15 +19,6 @@ namespace Nz
return SafeCast<T*>(m_shapeSettings.get()); return SafeCast<T*>(m_shapeSettings.get());
} }
template<typename T>
void JoltCollider3D::SetupShapeSettings(std::unique_ptr<T> 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<JoltCollider3D> collider, const Vector3f& translation) : inline JoltTranslatedRotatedCollider3D::JoltTranslatedRotatedCollider3D(std::shared_ptr<JoltCollider3D> collider, const Vector3f& translation) :
JoltTranslatedRotatedCollider3D(std::move(collider), translation, Quaternionf::Identity()) JoltTranslatedRotatedCollider3D(std::move(collider), translation, Quaternionf::Identity())

View File

@ -11,9 +11,11 @@
#include <Nazara/Utility/StaticMesh.hpp> #include <Nazara/Utility/StaticMesh.hpp>
#include <Nazara/Utility/VertexBuffer.hpp> #include <Nazara/Utility/VertexBuffer.hpp>
#include <NazaraUtils/MemoryHelper.hpp> #include <NazaraUtils/MemoryHelper.hpp>
#include <tsl/ordered_map.h>
#include <Jolt/Core/Core.h> #include <Jolt/Core/Core.h>
#include <Jolt/Physics/Collision/Shape/BoxShape.h> #include <Jolt/Physics/Collision/Shape/BoxShape.h>
#include <Jolt/Physics/Collision/Shape/CapsuleShape.h> #include <Jolt/Physics/Collision/Shape/CapsuleShape.h>
#include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
#include <Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h> #include <Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h>
#include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h> #include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
#include <Jolt/Physics/Collision/Shape/SphereShape.h> #include <Jolt/Physics/Collision/Shape/SphereShape.h>
@ -67,7 +69,17 @@ namespace Nz
{ {
m_shapeSettings.reset(); m_shapeSettings.reset();
} }
void JoltCollider3D::SetupShapeSettings(std::unique_ptr<JPH::ShapeSettings>&& 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> JoltCollider3D::CreateGeomFromPrimitive(const Primitive& primitive) std::shared_ptr<JoltCollider3D> JoltCollider3D::CreateGeomFromPrimitive(const Primitive& primitive)
{ {
switch (primitive.type) switch (primitive.type)
@ -272,6 +284,57 @@ namespace Nz
return JoltColliderType3D::Compound; return JoltColliderType3D::Compound;
} }
/******************************** JoltConvexHullCollider3D *********************************/
JoltConvexHullCollider3D::JoltConvexHullCollider3D(SparsePtr<const Vector3f> vertices, std::size_t vertexCount, float hullTolerance, float convexRadius, float maxErrorConvexRadius)
{
std::unique_ptr<JPH::ConvexHullShapeSettings> settings = std::make_unique<JPH::ConvexHullShapeSettings>();
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<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const
{
tsl::ordered_map<Vector3f, UInt16> vertexCache;
auto InsertVertex = [&](const Vector3f& position) -> UInt16
{
auto it = vertexCache.find(position);
if (it != vertexCache.end())
return it->second;
UInt16 index = SafeCast<UInt16>(vertices.size());
vertices.push_back(position);
vertexCache.emplace(position, index);
return index;
};
const JPH::ConvexHullShapeSettings* settings = GetShapeSettingsAs<JPH::ConvexHullShapeSettings>();
const JPH::ConvexHullShape* shape = SafeCast<const JPH::ConvexHullShape*>(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::JoltSphereCollider3D(float radius) JoltSphereCollider3D::JoltSphereCollider3D(float radius)
@ -293,6 +356,8 @@ namespace Nz
return JoltColliderType3D::Sphere; return JoltColliderType3D::Sphere;
} }
/******************************** JoltTranslatedRotatedCollider3D *********************************/
JoltTranslatedRotatedCollider3D::JoltTranslatedRotatedCollider3D(std::shared_ptr<JoltCollider3D> collider, const Vector3f& translation, const Quaternionf& rotation) : JoltTranslatedRotatedCollider3D::JoltTranslatedRotatedCollider3D(std::shared_ptr<JoltCollider3D> collider, const Vector3f& translation, const Quaternionf& rotation) :
m_collider(std::move(collider)) m_collider(std::move(collider))
{ {