WIP on materials

This commit is contained in:
Lynix 2017-12-10 22:17:41 +01:00
parent f1b84bfc9e
commit afa874de26
10 changed files with 151 additions and 3 deletions

View File

@ -52,6 +52,8 @@ namespace Ndk
void SetLinearVelocity(const Nz::Vector3f& velocity); void SetLinearVelocity(const Nz::Vector3f& velocity);
void SetMass(float mass); void SetMass(float mass);
void SetMassCenter(const Nz::Vector3f& center); void SetMassCenter(const Nz::Vector3f& center);
void SetMaterial(const Nz::String& materialName);
void SetMaterial(int materialIndex);
void SetPosition(const Nz::Vector3f& position); void SetPosition(const Nz::Vector3f& position);
void SetRotation(const Nz::Quaternionf& rotation); void SetRotation(const Nz::Quaternionf& rotation);

View File

@ -365,7 +365,6 @@ namespace Ndk
* *
* \remark Produces a NazaraAssert if the physics object is invalid * \remark Produces a NazaraAssert if the physics object is invalid
*/ */
inline void PhysicsComponent3D::SetMassCenter(const Nz::Vector3f& center) inline void PhysicsComponent3D::SetMassCenter(const Nz::Vector3f& center)
{ {
NazaraAssert(m_object, "Invalid physics object"); NazaraAssert(m_object, "Invalid physics object");
@ -373,6 +372,34 @@ namespace Ndk
m_object->SetMassCenter(center); 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 * \brief Sets the position of the physics object
* *

View File

@ -18,7 +18,6 @@ namespace Ndk
{ {
public: public:
PhysicsSystem3D(); PhysicsSystem3D();
PhysicsSystem3D(const PhysicsSystem3D& system);
~PhysicsSystem3D() = default; ~PhysicsSystem3D() = default;
Nz::PhysWorld3D& GetWorld(); Nz::PhysWorld3D& GetWorld();

View File

@ -59,6 +59,7 @@ namespace Ndk
m_staticBody = std::make_unique<Nz::RigidBody3D>(&physWorld, m_geom); m_staticBody = std::make_unique<Nz::RigidBody3D>(&physWorld, m_geom);
m_staticBody->EnableAutoSleep(false); m_staticBody->EnableAutoSleep(false);
m_staticBody->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
} }
/*! /*!

View File

@ -42,6 +42,7 @@ namespace Ndk
m_object = std::make_unique<Nz::RigidBody3D>(&world, geom, matrix); m_object = std::make_unique<Nz::RigidBody3D>(&world, geom, matrix);
m_object->SetMass(1.f); m_object->SetMass(1.f);
m_object->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
} }
/*! /*!

View File

@ -134,7 +134,7 @@ namespace Ndk
Nz::Vector3f textBox = m_textSprite->GetBoundingVolume().obb.localBox.GetLengths(); Nz::Vector3f textBox = m_textSprite->GetBoundingVolume().obb.localBox.GetLengths();
m_textEntity->GetComponent<NodeComponent>().SetPosition(origin.x + checkboxSize.x + (m_adaptativeMargin ? checkboxSize.x / 2.f : m_textMargin), m_textEntity->GetComponent<NodeComponent>().SetPosition(origin.x + checkboxSize.x + (m_adaptativeMargin ? checkboxSize.x / 2.f : m_textMargin),
origin.y + checkboxSize.y / 2.f - textBox.y / 2.f); origin.y + checkboxSize.y / 2.f - textBox.y / 2.f);
} }
void CheckboxWidget::OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) void CheckboxWidget::OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button)

View File

@ -8,35 +8,56 @@
#define NAZARA_PHYSWORLD_HPP #define NAZARA_PHYSWORLD_HPP
#include <Nazara/Prerequesites.hpp> #include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/String.hpp>
#include <Nazara/Math/Vector3.hpp> #include <Nazara/Math/Vector3.hpp>
#include <Nazara/Physics3D/Config.hpp> #include <Nazara/Physics3D/Config.hpp>
#include <unordered_map>
class NewtonJoint;
class NewtonWorld; class NewtonWorld;
namespace Nz namespace Nz
{ {
class RigidBody3D;
class NAZARA_PHYSICS3D_API PhysWorld3D class NAZARA_PHYSICS3D_API PhysWorld3D
{ {
public: public:
using CollisionCallback = std::function<bool(const RigidBody3D& firstBody, const RigidBody3D& secondBody)>;
PhysWorld3D(); PhysWorld3D();
PhysWorld3D(const PhysWorld3D&) = delete; PhysWorld3D(const PhysWorld3D&) = delete;
PhysWorld3D(PhysWorld3D&&) = delete; ///TODO PhysWorld3D(PhysWorld3D&&) = delete; ///TODO
~PhysWorld3D(); ~PhysWorld3D();
int CreateMaterial(Nz::String name = Nz::String());
Vector3f GetGravity() const; Vector3f GetGravity() const;
NewtonWorld* GetHandle() const; NewtonWorld* GetHandle() const;
int GetMaterial(const Nz::String& name);
float GetStepSize() const; float GetStepSize() const;
void SetGravity(const Vector3f& gravity); void SetGravity(const Vector3f& gravity);
void SetSolverModel(unsigned int model); void SetSolverModel(unsigned int model);
void SetStepSize(float stepSize); void SetStepSize(float stepSize);
void SetMaterialCollisionCallback(int firstMaterial, int secondMaterial, CollisionCallback callback);
void Step(float timestep); void Step(float timestep);
PhysWorld3D& operator=(const PhysWorld3D&) = delete; PhysWorld3D& operator=(const PhysWorld3D&) = delete;
PhysWorld3D& operator=(PhysWorld3D&&) = delete; ///TODO PhysWorld3D& operator=(PhysWorld3D&&) = delete; ///TODO
private: private:
struct Callback
{
CollisionCallback collisionCallback;
};
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;
Vector3f m_gravity; Vector3f m_gravity;
NewtonWorld* m_world; NewtonWorld* m_world;
float m_stepSize; float m_stepSize;

View File

@ -47,9 +47,11 @@ namespace Nz
Vector3f GetLinearVelocity() const; Vector3f GetLinearVelocity() const;
float GetMass() const; float GetMass() const;
Vector3f GetMassCenter(CoordSys coordSys = CoordSys_Local) const; Vector3f GetMassCenter(CoordSys coordSys = CoordSys_Local) const;
int GetMaterial() const;
const Matrix4f& GetMatrix() const; const Matrix4f& GetMatrix() const;
Vector3f GetPosition() const; Vector3f GetPosition() const;
Quaternionf GetRotation() const; Quaternionf GetRotation() const;
void* GetUserdata() const;
PhysWorld3D* GetWorld() const; PhysWorld3D* GetWorld() const;
bool IsAutoSleepEnabled() const; bool IsAutoSleepEnabled() const;
@ -65,8 +67,11 @@ namespace Nz
void SetLinearVelocity(const Vector3f& velocity); void SetLinearVelocity(const Vector3f& velocity);
void SetMass(float mass); void SetMass(float mass);
void SetMassCenter(const Vector3f& center); void SetMassCenter(const Vector3f& center);
void SetMaterial(const Nz::String& materialName);
void SetMaterial(int materialIndex);
void SetPosition(const Vector3f& position); void SetPosition(const Vector3f& position);
void SetRotation(const Quaternionf& rotation); void SetRotation(const Quaternionf& rotation);
void SetUserdata(void* ud);
RigidBody3D& operator=(const RigidBody3D& object); RigidBody3D& operator=(const RigidBody3D& object);
RigidBody3D& operator=(RigidBody3D&& object); RigidBody3D& operator=(RigidBody3D&& object);
@ -82,6 +87,7 @@ namespace Nz
Vector3f m_torqueAccumulator; Vector3f m_torqueAccumulator;
NewtonBody* m_body; NewtonBody* m_body;
PhysWorld3D* m_world; PhysWorld3D* m_world;
void* m_userdata;
float m_gravityFactor; float m_gravityFactor;
float m_mass; float m_mass;
}; };

View File

@ -3,7 +3,9 @@
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Physics3D/PhysWorld3D.hpp> #include <Nazara/Physics3D/PhysWorld3D.hpp>
#include <Nazara/Core/MemoryHelper.hpp>
#include <Newton/Newton.h> #include <Newton/Newton.h>
#include <cassert>
#include <Nazara/Physics3D/Debug.hpp> #include <Nazara/Physics3D/Debug.hpp>
namespace Nz namespace Nz
@ -15,6 +17,8 @@ namespace Nz
{ {
m_world = NewtonCreate(); m_world = NewtonCreate();
NewtonWorldSetUserData(m_world, this); NewtonWorldSetUserData(m_world, this);
m_materialIds.emplace("default", NewtonMaterialGetDefaultGroupID(m_world));
} }
PhysWorld3D::~PhysWorld3D() PhysWorld3D::~PhysWorld3D()
@ -22,6 +26,16 @@ namespace Nz
NewtonDestroy(m_world); 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;
}
Vector3f PhysWorld3D::GetGravity() const Vector3f PhysWorld3D::GetGravity() const
{ {
return m_gravity; return m_gravity;
@ -32,6 +46,14 @@ namespace Nz
return m_world; 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;
}
float PhysWorld3D::GetStepSize() const float PhysWorld3D::GetStepSize() const
{ {
return m_stepSize; return m_stepSize;
@ -52,6 +74,22 @@ namespace Nz
m_stepSize = stepSize; m_stepSize = stepSize;
} }
void PhysWorld3D::SetMaterialCollisionCallback(int firstMaterial, int secondMaterial, CollisionCallback callback)
{
static_assert(sizeof(Nz::UInt64) >= 2 * sizeof(int), "Oops");
auto callbackPtr = std::make_unique<Callback>();
callbackPtr->collisionCallback = std::move(callback);
NewtonMaterialSetCollisionCallback(m_world, firstMaterial, secondMaterial, callbackPtr.get(), nullptr, ProcessContact);
Nz::UInt64 firstMaterialId(firstMaterial);
Nz::UInt64 secondMaterialId(secondMaterial);
Nz::UInt64 callbackIndex = firstMaterialId << 32 | secondMaterialId;
m_callbacks[callbackIndex] = std::move(callbackPtr);
}
void PhysWorld3D::Step(float timestep) void PhysWorld3D::Step(float timestep)
{ {
m_timestepAccumulator += timestep; m_timestepAccumulator += timestep;
@ -62,4 +100,32 @@ namespace Nz
m_timestepAccumulator -= m_stepSize; m_timestepAccumulator -= m_stepSize;
} }
} }
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);
if (!callbackData->collisionCallback(*bodyA, *bodyB))
NewtonContactJointRemoveContact(contactJoint, contact);
}
}
} }

View File

@ -213,6 +213,11 @@ namespace Nz
return center; return center;
} }
int RigidBody3D::GetMaterial() const
{
return NewtonBodyGetMaterialGroupID(m_body);
}
const Matrix4f& RigidBody3D::GetMatrix() const const Matrix4f& RigidBody3D::GetMatrix() const
{ {
return m_matrix; return m_matrix;
@ -228,6 +233,11 @@ namespace Nz
return m_matrix.GetRotation(); return m_matrix.GetRotation();
} }
void* RigidBody3D::GetUserdata() const
{
return m_userdata;
}
PhysWorld3D* RigidBody3D::GetWorld() const PhysWorld3D* RigidBody3D::GetWorld() const
{ {
return m_world; return m_world;
@ -322,6 +332,16 @@ namespace Nz
NewtonBodySetCentreOfMass(m_body, center); 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) void RigidBody3D::SetPosition(const Vector3f& position)
{ {
m_matrix.SetTranslation(position); m_matrix.SetTranslation(position);
@ -336,6 +356,11 @@ namespace Nz
UpdateBody(); UpdateBody();
} }
void RigidBody3D::SetUserdata(void* ud)
{
m_userdata = ud;
}
RigidBody3D& RigidBody3D::operator=(const RigidBody3D& object) RigidBody3D& RigidBody3D::operator=(const RigidBody3D& object)
{ {
RigidBody3D physObj(object); RigidBody3D physObj(object);