Merge branch 'physics3d-material'
This commit is contained in:
commit
1ca4839def
|
|
@ -54,6 +54,8 @@ namespace Ndk
|
|||
void SetLinearVelocity(const Nz::Vector3f& velocity);
|
||||
void SetMass(float mass);
|
||||
void SetMassCenter(const Nz::Vector3f& center);
|
||||
void SetMaterial(const Nz::String& materialName);
|
||||
void SetMaterial(int materialIndex);
|
||||
void SetPosition(const Nz::Vector3f& position);
|
||||
void SetRotation(const Nz::Quaternionf& rotation);
|
||||
|
||||
|
|
|
|||
|
|
@ -396,7 +396,6 @@ namespace Ndk
|
|||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent3D::SetMassCenter(const Nz::Vector3f& center)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
|
@ -404,6 +403,34 @@ namespace Ndk
|
|||
m_object->SetMassCenter(center);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the material of the object, affecting how object does respond to collisions
|
||||
*
|
||||
* \param materialName Name of the material, previously registered to physics world
|
||||
*
|
||||
* \remark materialName must exists in PhysWorld before this call
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetMaterial(const Nz::String& materialName)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetMaterial(materialName);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the material of the object, affecting how object does respond to collisions
|
||||
*
|
||||
* \param materialIndex Id of the material, previously retrieved from a physics world
|
||||
*
|
||||
* \remark materialIndex must come from a call to in PhysWorld::CreateMaterial
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetMaterial(int materialIndex)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetMaterial(materialIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the position of the physics object
|
||||
*
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ namespace Ndk
|
|||
{
|
||||
public:
|
||||
PhysicsSystem3D();
|
||||
PhysicsSystem3D(const PhysicsSystem3D& system);
|
||||
~PhysicsSystem3D() = default;
|
||||
|
||||
Nz::PhysWorld3D& GetWorld();
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ namespace Ndk
|
|||
|
||||
m_staticBody = std::make_unique<Nz::RigidBody3D>(&physWorld, m_geom);
|
||||
m_staticBody->EnableAutoSleep(false);
|
||||
m_staticBody->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ namespace Ndk
|
|||
matrix.MakeIdentity();
|
||||
|
||||
m_object = std::make_unique<Nz::RigidBody3D>(&world, geom, matrix);
|
||||
m_object->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
|
||||
|
||||
if (m_pendingStates.valid)
|
||||
ApplyPhysicsState(*m_object);
|
||||
|
|
|
|||
|
|
@ -8,23 +8,40 @@
|
|||
#define NAZARA_PHYSWORLD_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <Nazara/Math/Box.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <Nazara/Physics3D/Config.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
class NewtonBody;
|
||||
class NewtonJoint;
|
||||
class NewtonMaterial;
|
||||
class NewtonWorld;
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class RigidBody3D;
|
||||
|
||||
class NAZARA_PHYSICS3D_API PhysWorld3D
|
||||
{
|
||||
public:
|
||||
using BodyIterator = std::function<bool(const RigidBody3D& body)>;
|
||||
using AABBOverlapCallback = std::function<bool(const RigidBody3D& firstBody, const RigidBody3D& secondBody)>;
|
||||
using CollisionCallback = std::function<bool(const RigidBody3D& firstBody, const RigidBody3D& secondBody)>;
|
||||
|
||||
PhysWorld3D();
|
||||
PhysWorld3D(const PhysWorld3D&) = delete;
|
||||
PhysWorld3D(PhysWorld3D&&) = delete; ///TODO
|
||||
~PhysWorld3D();
|
||||
|
||||
int CreateMaterial(Nz::String name = Nz::String());
|
||||
|
||||
void ForEachBodyInAABB(const Nz::Boxf& box, BodyIterator iterator);
|
||||
|
||||
Vector3f GetGravity() const;
|
||||
NewtonWorld* GetHandle() const;
|
||||
int GetMaterial(const Nz::String& name);
|
||||
std::size_t GetMaxStepCount() const;
|
||||
float GetStepSize() const;
|
||||
|
||||
|
|
@ -33,12 +50,30 @@ namespace Nz
|
|||
void SetSolverModel(unsigned int model);
|
||||
void SetStepSize(float stepSize);
|
||||
|
||||
void SetMaterialCollisionCallback(int firstMaterial, int secondMaterial, AABBOverlapCallback aabbOverlapCallback, CollisionCallback collisionCallback);
|
||||
void SetMaterialDefaultCollidable(int firstMaterial, int secondMaterial, bool collidable);
|
||||
void SetMaterialDefaultElasticity(int firstMaterial, int secondMaterial, float elasticCoef);
|
||||
void SetMaterialDefaultFriction(int firstMaterial, int secondMaterial, float staticFriction, float kineticFriction);
|
||||
void SetMaterialDefaultSoftness(int firstMaterial, int secondMaterial, float softness);
|
||||
void SetMaterialSurfaceThickness(int firstMaterial, int secondMaterial, float thickness);
|
||||
|
||||
void Step(float timestep);
|
||||
|
||||
PhysWorld3D& operator=(const PhysWorld3D&) = delete;
|
||||
PhysWorld3D& operator=(PhysWorld3D&&) = delete; ///TODO
|
||||
|
||||
private:
|
||||
struct Callback
|
||||
{
|
||||
AABBOverlapCallback aabbOverlapCallback;
|
||||
CollisionCallback collisionCallback;
|
||||
};
|
||||
|
||||
static int OnAABBOverlap(const NewtonMaterial* const material, const NewtonBody* const body0, const NewtonBody* const body1, int threadIndex);
|
||||
static void ProcessContact(const NewtonJoint* const contact, float timestep, int threadIndex);
|
||||
|
||||
std::unordered_map<Nz::UInt64, std::unique_ptr<Callback>> m_callbacks;
|
||||
std::unordered_map<Nz::String, int> m_materialIds;
|
||||
std::size_t m_maxStepCount;
|
||||
Vector3f m_gravity;
|
||||
NewtonWorld* m_world;
|
||||
|
|
|
|||
|
|
@ -47,9 +47,11 @@ namespace Nz
|
|||
Vector3f GetLinearVelocity() const;
|
||||
float GetMass() const;
|
||||
Vector3f GetMassCenter(CoordSys coordSys = CoordSys_Local) const;
|
||||
int GetMaterial() const;
|
||||
const Matrix4f& GetMatrix() const;
|
||||
Vector3f GetPosition() const;
|
||||
Quaternionf GetRotation() const;
|
||||
void* GetUserdata() const;
|
||||
PhysWorld3D* GetWorld() const;
|
||||
|
||||
bool IsAutoSleepEnabled() const;
|
||||
|
|
@ -65,8 +67,11 @@ namespace Nz
|
|||
void SetLinearVelocity(const Vector3f& velocity);
|
||||
void SetMass(float mass);
|
||||
void SetMassCenter(const Vector3f& center);
|
||||
void SetMaterial(const Nz::String& materialName);
|
||||
void SetMaterial(int materialIndex);
|
||||
void SetPosition(const Vector3f& position);
|
||||
void SetRotation(const Quaternionf& rotation);
|
||||
void SetUserdata(void* ud);
|
||||
|
||||
RigidBody3D& operator=(const RigidBody3D& object);
|
||||
RigidBody3D& operator=(RigidBody3D&& object);
|
||||
|
|
@ -82,6 +87,7 @@ namespace Nz
|
|||
Vector3f m_torqueAccumulator;
|
||||
NewtonBody* m_body;
|
||||
PhysWorld3D* m_world;
|
||||
void* m_userdata;
|
||||
float m_gravityFactor;
|
||||
float m_mass;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Physics3D/PhysWorld3D.hpp>
|
||||
#include <Nazara/Core/MemoryHelper.hpp>
|
||||
#include <Newton/Newton.h>
|
||||
#include <cassert>
|
||||
#include <Nazara/Physics3D/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
|
|
@ -16,6 +18,8 @@ namespace Nz
|
|||
{
|
||||
m_world = NewtonCreate();
|
||||
NewtonWorldSetUserData(m_world, this);
|
||||
|
||||
m_materialIds.emplace("default", NewtonMaterialGetDefaultGroupID(m_world));
|
||||
}
|
||||
|
||||
PhysWorld3D::~PhysWorld3D()
|
||||
|
|
@ -23,6 +27,28 @@ namespace Nz
|
|||
NewtonDestroy(m_world);
|
||||
}
|
||||
|
||||
int PhysWorld3D::CreateMaterial(Nz::String name)
|
||||
{
|
||||
NazaraAssert(m_materialIds.find(name) == m_materialIds.end(), "Material \"" + name + "\" already exists");
|
||||
|
||||
int materialId = NewtonMaterialCreateGroupID(m_world);
|
||||
m_materialIds.emplace(std::move(name), materialId);
|
||||
|
||||
return materialId;
|
||||
}
|
||||
|
||||
void PhysWorld3D::ForEachBodyInAABB(const Nz::Boxf& box, BodyIterator iterator)
|
||||
{
|
||||
auto NewtonCallback = [](const NewtonBody* const body, void* const userdata) -> int
|
||||
{
|
||||
BodyIterator& iterator = *static_cast<BodyIterator*>(userdata);
|
||||
RigidBody3D* nzBody = static_cast<RigidBody3D*>(NewtonBodyGetUserData(body));
|
||||
return iterator(*nzBody);
|
||||
};
|
||||
|
||||
NewtonWorldForEachBodyInAABBDo(m_world, box.GetMinimum(), box.GetMaximum(), NewtonCallback, &iterator);
|
||||
}
|
||||
|
||||
Vector3f PhysWorld3D::GetGravity() const
|
||||
{
|
||||
return m_gravity;
|
||||
|
|
@ -33,6 +59,14 @@ namespace Nz
|
|||
return m_world;
|
||||
}
|
||||
|
||||
int PhysWorld3D::GetMaterial(const Nz::String& name)
|
||||
{
|
||||
auto it = m_materialIds.find(name);
|
||||
NazaraAssert(it != m_materialIds.end(), "Material \"" + name + "\" does not exists");
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::size_t PhysWorld3D::GetMaxStepCount() const
|
||||
{
|
||||
return m_maxStepCount;
|
||||
|
|
@ -63,6 +97,48 @@ namespace Nz
|
|||
m_stepSize = stepSize;
|
||||
}
|
||||
|
||||
void PhysWorld3D::SetMaterialCollisionCallback(int firstMaterial, int secondMaterial, AABBOverlapCallback aabbOverlapCallback, CollisionCallback collisionCallback)
|
||||
{
|
||||
static_assert(sizeof(Nz::UInt64) >= 2 * sizeof(int), "Oops");
|
||||
|
||||
auto callbackPtr = std::make_unique<Callback>();
|
||||
callbackPtr->aabbOverlapCallback = std::move(aabbOverlapCallback);
|
||||
callbackPtr->collisionCallback = std::move(collisionCallback);
|
||||
|
||||
NewtonMaterialSetCollisionCallback(m_world, firstMaterial, secondMaterial, callbackPtr.get(), (callbackPtr->aabbOverlapCallback) ? OnAABBOverlap : nullptr, (callbackPtr->collisionCallback) ? ProcessContact : nullptr);
|
||||
|
||||
Nz::UInt64 firstMaterialId(firstMaterial);
|
||||
Nz::UInt64 secondMaterialId(secondMaterial);
|
||||
|
||||
Nz::UInt64 callbackIndex = firstMaterialId << 32 | secondMaterialId;
|
||||
m_callbacks[callbackIndex] = std::move(callbackPtr);
|
||||
}
|
||||
|
||||
void PhysWorld3D::SetMaterialDefaultCollidable(int firstMaterial, int secondMaterial, bool collidable)
|
||||
{
|
||||
NewtonMaterialSetDefaultCollidable(m_world, firstMaterial, secondMaterial, collidable);
|
||||
}
|
||||
|
||||
void PhysWorld3D::SetMaterialDefaultElasticity(int firstMaterial, int secondMaterial, float elasticCoef)
|
||||
{
|
||||
NewtonMaterialSetDefaultElasticity(m_world, firstMaterial, secondMaterial, elasticCoef);
|
||||
}
|
||||
|
||||
void PhysWorld3D::SetMaterialDefaultFriction(int firstMaterial, int secondMaterial, float staticFriction, float kineticFriction)
|
||||
{
|
||||
NewtonMaterialSetDefaultFriction(m_world, firstMaterial, secondMaterial, staticFriction, kineticFriction);
|
||||
}
|
||||
|
||||
void PhysWorld3D::SetMaterialDefaultSoftness(int firstMaterial, int secondMaterial, float softness)
|
||||
{
|
||||
NewtonMaterialSetDefaultSoftness(m_world, firstMaterial, secondMaterial, softness);
|
||||
}
|
||||
|
||||
void PhysWorld3D::SetMaterialSurfaceThickness(int firstMaterial, int secondMaterial, float thickness)
|
||||
{
|
||||
NewtonMaterialSetSurfaceThickness(m_world, firstMaterial, secondMaterial, thickness);
|
||||
}
|
||||
|
||||
void PhysWorld3D::Step(float timestep)
|
||||
{
|
||||
m_timestepAccumulator += timestep;
|
||||
|
|
@ -75,4 +151,46 @@ namespace Nz
|
|||
stepCount++;
|
||||
}
|
||||
}
|
||||
|
||||
int PhysWorld3D::OnAABBOverlap(const NewtonMaterial* const material, const NewtonBody* const body0, const NewtonBody* const body1, int threadIndex)
|
||||
{
|
||||
Nz::RigidBody3D* bodyA = static_cast<Nz::RigidBody3D*>(NewtonBodyGetUserData(body0));
|
||||
Nz::RigidBody3D* bodyB = static_cast<Nz::RigidBody3D*>(NewtonBodyGetUserData(body1));
|
||||
assert(bodyA && bodyB);
|
||||
|
||||
Callback* callbackData = static_cast<Callback*>(NewtonMaterialGetMaterialPairUserData(material));
|
||||
assert(callbackData);
|
||||
assert(callbackData->aabbOverlapCallback);
|
||||
|
||||
return callbackData->aabbOverlapCallback(*bodyA, *bodyB);
|
||||
}
|
||||
|
||||
void PhysWorld3D::ProcessContact(const NewtonJoint* const contactJoint, float timestep, int threadIndex)
|
||||
{
|
||||
Nz::RigidBody3D* bodyA = static_cast<Nz::RigidBody3D*>(NewtonBodyGetUserData(NewtonJointGetBody0(contactJoint)));
|
||||
Nz::RigidBody3D* bodyB = static_cast<Nz::RigidBody3D*>(NewtonBodyGetUserData(NewtonJointGetBody1(contactJoint)));
|
||||
assert(bodyA && bodyB);
|
||||
|
||||
using ContactJoint = void*;
|
||||
|
||||
// Query all joints first, to prevent removing a joint from the list while iterating on it
|
||||
Nz::StackArray<ContactJoint> contacts = NazaraStackAllocationNoInit(ContactJoint, NewtonContactJointGetContactCount(contactJoint));
|
||||
std::size_t contactIndex = 0;
|
||||
for (ContactJoint contact = NewtonContactJointGetFirstContact(contactJoint); contact; contact = NewtonContactJointGetNextContact(contactJoint, contact))
|
||||
{
|
||||
assert(contactIndex < contacts.size());
|
||||
contacts[contactIndex++] = contact;
|
||||
}
|
||||
|
||||
for (ContactJoint contact : contacts)
|
||||
{
|
||||
NewtonMaterial* material = NewtonContactGetMaterial(contact);
|
||||
Callback* callbackData = static_cast<Callback*>(NewtonMaterialGetMaterialPairUserData(material));
|
||||
assert(callbackData);
|
||||
assert(callbackData->collisionCallback);
|
||||
|
||||
if (!callbackData->collisionCallback(*bodyA, *bodyB))
|
||||
NewtonContactJointRemoveContact(contactJoint, contact);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,6 +216,11 @@ namespace Nz
|
|||
return center;
|
||||
}
|
||||
|
||||
int RigidBody3D::GetMaterial() const
|
||||
{
|
||||
return NewtonBodyGetMaterialGroupID(m_body);
|
||||
}
|
||||
|
||||
const Matrix4f& RigidBody3D::GetMatrix() const
|
||||
{
|
||||
return m_matrix;
|
||||
|
|
@ -231,6 +236,11 @@ namespace Nz
|
|||
return m_matrix.GetRotation();
|
||||
}
|
||||
|
||||
void* RigidBody3D::GetUserdata() const
|
||||
{
|
||||
return m_userdata;
|
||||
}
|
||||
|
||||
PhysWorld3D* RigidBody3D::GetWorld() const
|
||||
{
|
||||
return m_world;
|
||||
|
|
@ -335,6 +345,16 @@ namespace Nz
|
|||
NewtonBodySetCentreOfMass(m_body, center);
|
||||
}
|
||||
|
||||
void RigidBody3D::SetMaterial(const Nz::String& materialName)
|
||||
{
|
||||
SetMaterial(m_world->GetMaterial(materialName));
|
||||
}
|
||||
|
||||
void RigidBody3D::SetMaterial(int materialIndex)
|
||||
{
|
||||
NewtonBodySetMaterialGroupID(m_body, materialIndex);
|
||||
}
|
||||
|
||||
void RigidBody3D::SetPosition(const Vector3f& position)
|
||||
{
|
||||
m_matrix.SetTranslation(position);
|
||||
|
|
@ -349,6 +369,11 @@ namespace Nz
|
|||
UpdateBody();
|
||||
}
|
||||
|
||||
void RigidBody3D::SetUserdata(void* ud)
|
||||
{
|
||||
m_userdata = ud;
|
||||
}
|
||||
|
||||
RigidBody3D& RigidBody3D::operator=(const RigidBody3D& object)
|
||||
{
|
||||
RigidBody3D physObj(object);
|
||||
|
|
|
|||
Loading…
Reference in New Issue