add physX settings through the setting window for editor

This commit is contained in:
2025-12-29 13:44:00 +08:00
parent 9a44dd8d79
commit ce41e348f8
18 changed files with 605 additions and 267 deletions

View File

@ -388,7 +388,7 @@ namespace Prism
}
m_SceneHierarchyPanel->OnImGuiRender();
PhysicsSettingsWindow::OnImGuiRender(&m_ShowPhysicsSettings);
PhysicsSettingsWindow::OnImGuiRender(m_ShowPhysicsSettings);
ImGui::Begin("Materials");

View File

@ -6,6 +6,130 @@ Environment:
Radiance: [1, 1, 1]
Multiplier: 0.515
Entities:
- Entity: 18306113171518048249
TagComponent:
Tag: Box
TransformComponent:
Position: [0, 0, 0]
Rotation: [1, 0, 0, 0]
Scale: [50, 1, 50]
MeshComponent:
AssetPath: assets/meshes/Cube1m.fbx
RigidBodyComponent:
BodyType: 0
Mass: 1
IsKinematic: false
Layer: 1
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
PhysicsMaterialComponent:
StaticFriction: 1
DynamicFriction: 1
Bounciness: 0
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [1, 1, 1]
IsTrigger: false
- Entity: 5178862374589434728
TagComponent:
Tag: Camera
TransformComponent:
Position: [2.808, 2.25, 0]
Rotation: [1, 0, 0, 0]
Scale: [1, 1, 1]
CameraComponent:
Camera: some camera data...
Primary: true
- Entity: 14057422478420564497
TagComponent:
Tag: Sphere
TransformComponent:
Position: [-3.9876995, 1, -1.9669533e-06]
Rotation: [1, 0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetPath: assets/meshes/Sphere1m.fbx
RigidBodyComponent:
BodyType: 1
Mass: 1
IsKinematic: false
Layer: 1
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
PhysicsMaterialComponent:
StaticFriction: 0.1
DynamicFriction: 0.1
Bounciness: 0.1
SphereColliderComponent:
Radius: 0.5
IsTrigger: false
- Entity: 10169503531257462571
TagComponent:
Tag: Box
TransformComponent:
Position: [0, 1.5, 0]
Rotation: [1, 0, 0, 0]
Scale: [2, 2, 2]
MeshComponent:
AssetPath: assets/meshes/Cube1m.fbx
RigidBodyComponent:
BodyType: 1
Mass: 0.5
IsKinematic: false
Layer: 1
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
PhysicsMaterialComponent:
StaticFriction: 1
DynamicFriction: 1
Bounciness: 0
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [1, 1, 1]
IsTrigger: false
- Entity: 11149966982516343187
TagComponent:
Tag: Mesh Collider
TransformComponent:
Position: [-2.6045518, 1, -0.0017139912]
Rotation: [1, 0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetPath: assets/meshes/Sphere1m.fbx
RigidBodyComponent:
BodyType: 1
Mass: 0.1
IsKinematic: false
Layer: 1
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
PhysicsMaterialComponent:
StaticFriction: 1
DynamicFriction: 1
Bounciness: 0.1
MeshColliderComponent:
AssetPath: assets/meshes/Sphere1m.fbx
IsTrigger: false
- Entity: 3247025703490125974
TagComponent:
Tag: Player
@ -52,131 +176,10 @@ Entities:
MeshColliderComponent:
AssetPath: assets/meshes/Capsule.fbx
IsTrigger: false
- Entity: 11149966982516343187
TagComponent:
Tag: Mesh Collider
TransformComponent:
Position: [-2.6045518, 1, -0.0017139912]
Rotation: [1, 0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetPath: assets/meshes/Sphere1m.fbx
RigidBodyComponent:
BodyType: 1
Mass: 0.1
IsKinematic: false
Layer: 1
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
PhysicsMaterialComponent:
StaticFriction: 1
DynamicFriction: 1
Bounciness: 0.1
MeshColliderComponent:
AssetPath: assets/meshes/Sphere1m.fbx
IsTrigger: false
- Entity: 10169503531257462571
TagComponent:
Tag: Box
TransformComponent:
Position: [0, 1.5, 0]
Rotation: [1, 0, 0, 0]
Scale: [2, 2, 2]
MeshComponent:
AssetPath: assets/meshes/Cube1m.fbx
RigidBodyComponent:
BodyType: 1
Mass: 0.5
IsKinematic: false
Layer: 0
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
PhysicsMaterialComponent:
StaticFriction: 1
DynamicFriction: 1
Bounciness: 0
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [1, 1, 1]
IsTrigger: false
- Entity: 14057422478420564497
TagComponent:
Tag: Sphere
TransformComponent:
Position: [-3.9876995, 1, -1.9669533e-06]
Rotation: [1, 0, 0, 0]
Scale: [1, 1, 1]
MeshComponent:
AssetPath: assets/meshes/Sphere1m.fbx
RigidBodyComponent:
BodyType: 1
Mass: 1
IsKinematic: false
Layer: 1
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
PhysicsMaterialComponent:
StaticFriction: 0.1
DynamicFriction: 0.1
Bounciness: 0.1
SphereColliderComponent:
Radius: 0.5
IsTrigger: false
- Entity: 5178862374589434728
TagComponent:
Tag: Camera
TransformComponent:
Position: [2.808, 2.25, 0]
Rotation: [1, 0, 0, 0]
Scale: [1, 1, 1]
CameraComponent:
Camera: some camera data...
Primary: true
- Entity: 18306113171518048249
TagComponent:
Tag: Box
TransformComponent:
Position: [0, 0, 0]
Rotation: [1, 0, 0, 0]
Scale: [50, 1, 50]
MeshComponent:
AssetPath: assets/meshes/Cube1m.fbx
RigidBodyComponent:
BodyType: 0
Mass: 1
IsKinematic: false
Layer: 0
Constraints:
LockPositionX: false
LockPositionY: false
LockPositionZ: false
LockRotationX: false
LockRotationY: false
LockRotationZ: false
PhysicsMaterialComponent:
StaticFriction: 1
DynamicFriction: 1
Bounciness: 0
BoxColliderComponent:
Offset: [0, 0, 0]
Size: [1, 1, 1]
IsTrigger: false
PhysicsLayers:
- Name: Default
CollidesWith:
[]
- Name: Box
- Name: Box
CollidesWith:
- Name: Default

View File

@ -185,6 +185,12 @@ namespace Prism
public class RigidBodyComponent : Component
{
public enum Type
{
Static,
Dynamic
}
public enum ForceMode
{
Force = 0,
@ -192,6 +198,14 @@ namespace Prism
VelocityChange,
Acceleration
}
public Type BodyType
{
get
{
return GetBodyType_Native(Entity.ID);
}
}
public float Mass
{
@ -226,6 +240,17 @@ namespace Prism
SetLinearVelocity_Native(Entity.ID, ref velocity);
}
public Vec3 GetAngularVelocity()
{
GetAngularVelocity_Native(Entity.ID, out Vec3 velocity);
return velocity;
}
public void SetAngularVelocity(Vec3 velocity)
{
SetAngularVelocity_Native(Entity.ID, ref velocity);
}
public void Rotate(Vec3 rotation)
{
Rotate_Native(Entity.ID, ref rotation);
@ -243,6 +268,12 @@ namespace Prism
internal static extern void GetLinearVelocity_Native(ulong entityID, out Vec3 velocity);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void SetLinearVelocity_Native(ulong entityID, ref Vec3 velocity);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void GetAngularVelocity_Native(ulong entityID, out Vec3 velocity);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void SetAngularVelocity_Native(ulong entityID, ref Vec3 velocity);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void Rotate_Native(ulong entityID, ref Vec3 rotation);
@ -252,8 +283,12 @@ namespace Prism
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern float GetMass_Native(ulong entityID);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern float SetMass_Native(ulong entityID, float mass);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern Type GetBodyType_Native(ulong entityID);
}
}

View File

@ -5,6 +5,8 @@
#include "PhysicsSettingsWindow.h"
#include "imgui.h"
#include "imgui_internal.h"
#include "Prism/Physics/Physics3D.h"
#include "Prism/Physics/PhysicsLayer.h"
namespace Prism
@ -12,23 +14,51 @@ namespace Prism
static int32_t s_SelectedLayer = -1;
static char s_NewLayerNameBuffer[50];
void PhysicsSettingsWindow::OnImGuiRender(bool* show)
void PhysicsSettingsWindow::OnImGuiRender(bool& show)
{
if (!(*show))
if (!show)
return;
ImGui::Begin("Physics", show);
ImGui::Begin("Physics", &show);
ImGui::PushID(0);
ImGui::Columns(2);
RenderWorldSettings();
ImGui::EndColumns();
ImGui::PopID();
ImGui::Separator();
ImGui::PushID(1);
ImGui::Columns(2);
RenderLayerList();
ImGui::NextColumn();
RenderSelectedLayer();
ImGui::EndColumns();
ImGui::PopID();
ImGui::End();
}
void PhysicsSettingsWindow::RenderWorldSettings()
{
PhysicsSettings& settings = Physics3D::GetSettings();
Property("Fixed Timestep (Default: 0.006)", settings.FixedTimestep, 0.001f);
Property("Gravity (Default: -9.81)", settings.Gravity.y);
// Broadphase Type
static const char* broadphaseTypeStrings[] = { "Sweep And Prune", "Multi Box Pruning", "Automatic Box Pruning" };
Property("Broadphase Type", broadphaseTypeStrings, 3, reinterpret_cast<int*>(&settings.BroadphaseAlgorithm));
if (settings.BroadphaseAlgorithm != BroadphaseType::AutomaticBoxPrune)
{
Property("World Bounds (Min)", settings.WorldBoundsMin);
Property("World Bounds (Max)", settings.WorldBoundsMax);
Property("Grid Subdivisions", settings.WorldBoundsSubdivisions, 1, 10000);
}
}
void PhysicsSettingsWindow::RenderLayerList()
{
if (ImGui::Button("New Layer"))
@ -104,6 +134,88 @@ namespace Prism
PhysicsLayerManager::SetLayerCollision(s_SelectedLayer, layer.LayerID, shouldCollide);
}
}
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::IsWindowHovered() && !ImGui::IsAnyItemHovered())
{
s_SelectedLayer = -1;
}
}
bool PhysicsSettingsWindow::Property(const char* label, const char** options, const int32_t optionCount, int32_t* selected)
{
const char* current = options[*selected];
ImGui::Text(label);
ImGui::NextColumn();
ImGui::PushItemWidth(-1);
bool changed = false;
const std::string id = "##" + std::string(label);
if (ImGui::BeginCombo(id.c_str(), current))
{
for (int i = 0; i < optionCount; i++)
{
const bool is_selected = (current == options[i]);
if (ImGui::Selectable(options[i], is_selected))
{
current = options[i];
*selected = i;
changed = true;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
ImGui::PopItemWidth();
ImGui::NextColumn();
return changed;
}
bool PhysicsSettingsWindow::Property(const char* label, float& value, const float min, const float max)
{
ImGui::Text(label);
ImGui::NextColumn();
ImGui::PushItemWidth(-1);
const std::string id = "##" + std::string(label);
const bool changed = ImGui::SliderFloat(id.c_str(), &value, min, max);
ImGui::PopItemWidth();
ImGui::NextColumn();
return changed;
}
bool PhysicsSettingsWindow::Property(const char* label, uint32_t& value, const uint32_t min, const uint32_t max)
{
ImGui::Text(label);
ImGui::NextColumn();
ImGui::PushItemWidth(-1);
const std::string id = "##" + std::string(label);
const bool changed = ImGui::DragInt(id.c_str(), (int*)&value, 1.0F, min, max);
ImGui::PopItemWidth();
ImGui::NextColumn();
return changed;
}
bool PhysicsSettingsWindow::Property(const char* label, glm::vec3& value, const float min, const float max)
{
ImGui::Text(label);
ImGui::NextColumn();
ImGui::PushItemWidth(-1);
const std::string id = "##" + std::string(label);
const bool changed = ImGui::DragFloat3(id.c_str(), glm::value_ptr(value), 1.0F, min, max);
ImGui::PopItemWidth();
ImGui::NextColumn();
return changed;
}
}

View File

@ -4,15 +4,25 @@
#ifndef PHYSICSSETTINGSWINDOW_H
#define PHYSICSSETTINGSWINDOW_H
#include "glm/glm.hpp"
namespace Prism
{
class PRISM_API PhysicsSettingsWindow
{
public:
static void OnImGuiRender(bool* show);
static void OnImGuiRender(bool& show);
private:
static void RenderWorldSettings();
static void RenderLayerList();
static void RenderSelectedLayer();
private:
static bool Property(const char* label, const char** options, int32_t optionCount, int32_t* selected);
static bool Property(const char* label, float& value, float min = -1.0f, float max = 1.0f);
static bool Property(const char* label, uint32_t& value, uint32_t min = 0.0F, uint32_t max = 1.0F);
static bool Property(const char* label, glm::vec3& value, float min = 0.0F, float max = 0.0F);
};
}

View File

@ -18,6 +18,17 @@
namespace Prism
{
static physx::PxScene* s_Scene;
static std::vector<Entity> s_SimulatedEntities;
static Entity* s_EntityStorageBuffer;
static uint32_t s_EntityBufferCount;
static int s_EntityStorageBufferPosition;
static float s_SimulationTime = 0.0f;
static PhysicsSettings s_Settings;
static std::tuple<glm::vec3, glm::quat, glm::vec3> GetTransformDecomposition(const glm::mat4& transform)
{
glm::vec3 scale, translation, skew;
@ -28,11 +39,6 @@ namespace Prism
return { translation, orientation, scale };
}
static physx::PxScene* s_Scene;
static std::vector<Entity> s_SimulatedEntities;
static Entity* s_EntityStorageBuffer;
static int s_EntityStorageBufferPosition;
void Physics3D::Init()
{
PhysicsWrappers::Initialize();
@ -44,14 +50,38 @@ namespace Prism
PhysicsWrappers::Shutdown();
}
void Physics3D::CreateScene(const SceneParams& params)
PhysicsSettings& Physics3D::GetSettings()
{
PM_CORE_ASSERT(s_Scene == nullptr, "Scene already has a Physics Scene!");
s_Scene = PhysicsWrappers::CreateScene(params);
return s_Settings;
}
void Physics3D::CreateActor(Entity e, int entityCount)
void Physics3D::CreateScene()
{
PM_CORE_ASSERT(s_Scene == nullptr, "Scene already has a Physics Scene!");
s_Scene = PhysicsWrappers::CreateScene();
if (s_Settings.BroadphaseAlgorithm != BroadphaseType::AutomaticBoxPrune)
{
physx::PxBounds3* regionBounds = nullptr;
const physx::PxBounds3 globalBounds(ToPhysXVector(s_Settings.WorldBoundsMin), ToPhysXVector(s_Settings.WorldBoundsMax));
const uint32_t regionCount = physx::PxBroadPhaseExt::createRegionsFromWorldBounds(regionBounds, globalBounds, s_Settings.WorldBoundsSubdivisions);
if (regionBounds)
{
for (uint32_t i = 0; i < regionCount; i++)
{
physx::PxBroadPhaseRegion region;
region.mBounds = regionBounds[i];
s_Scene->addBroadPhaseRegion(region);
}
}
}
}
void Physics3D::CreateActor(Entity e)
{
PM_CORE_ASSERT(s_Scene);
if (!e.HasComponent<RigidBodyComponent>())
{
PM_CORE_WARN("Trying to create PhysX actor from a non-rigidbody actor!");
@ -66,15 +96,16 @@ namespace Prism
RigidBodyComponent& rigidbody = e.GetComponent<RigidBodyComponent>();
if (s_EntityStorageBuffer == nullptr)
s_EntityStorageBuffer = new Entity[entityCount];
physx::PxRigidActor* actor = PhysicsWrappers::CreateActor(rigidbody, e.Transform());
s_SimulatedEntities.push_back(e);
Entity* entityStorage = &s_EntityStorageBuffer[s_EntityStorageBufferPosition++];
if (rigidbody.BodyType == RigidBodyComponent::Type::Dynamic)
s_SimulatedEntities.push_back(e);
Entity* entityStorage = &s_EntityStorageBuffer[s_EntityStorageBufferPosition];
*entityStorage = e;
actor->userData = (void*)entityStorage;
rigidbody.RuntimeActor = actor;
rigidbody.EntityBufferIndex = s_EntityStorageBufferPosition;
s_EntityStorageBufferPosition++;
const physx::PxMaterial* material = PhysicsWrappers::CreateMaterial(e.GetComponent<PhysicsMaterialComponent>());
@ -117,7 +148,17 @@ namespace Prism
void Physics3D::Simulate(TimeStep ts)
{
s_Scene->simulate(ts);
// TODO: Allow projects to control the fixed step amount
s_SimulationTime += ts.GetMilliseconds();
if (s_SimulationTime < s_Settings.FixedTimestep)
return;
s_SimulationTime -= s_Settings.FixedTimestep;
s_Scene->simulate(s_Settings.FixedTimestep);
s_Scene->fetchResults(true);
for (Entity& e : s_SimulatedEntities)
@ -128,19 +169,14 @@ namespace Prism
const auto& rb = e.GetComponent<RigidBodyComponent>();
const auto actor = static_cast<physx::PxRigidActor*>(rb.RuntimeActor);
if (rb.BodyType == RigidBodyComponent::Type::Dynamic)
{
transform = FromPhysXTransform(actor->getGlobalPose()) * glm::scale(glm::mat4(1.0f), scale);
}
else if (rb.BodyType == RigidBodyComponent::Type::Static)
{
actor->setGlobalPose(ToPhysXTransform(transform));
}
transform = FromPhysXTransform(actor->getGlobalPose()) * glm::scale(glm::mat4(1.0F), scale);
}
}
void Physics3D::DestroyScene()
{
PM_CORE_ASSERT(s_Scene);
delete[] s_EntityStorageBuffer;
s_EntityStorageBuffer = nullptr;
s_EntityStorageBufferPosition = 0;
@ -173,5 +209,36 @@ namespace Prism
PhysicsWrappers::DisconnectPVD();
}
void Physics3D::ExpandEntityBuffer(const uint32_t entityCount)
{
PM_CORE_ASSERT(s_Scene);
if (s_EntityStorageBuffer != nullptr)
{
const auto temp = new Entity[s_EntityBufferCount + entityCount];
memcpy(temp, s_EntityStorageBuffer, s_EntityBufferCount * sizeof(Entity));
for (uint32_t i = 0; i < s_EntityBufferCount; i++)
{
Entity& e = s_EntityStorageBuffer[i];
const auto& rb = e.GetComponent<RigidBodyComponent>();
if (rb.RuntimeActor)
{
auto* actor = static_cast<physx::PxRigidActor*>(rb.RuntimeActor);
actor->userData = &temp[rb.EntityBufferIndex];
}
}
delete[] s_EntityStorageBuffer;
s_EntityStorageBuffer = temp;
s_EntityBufferCount += entityCount;
}
else
{
s_EntityStorageBuffer = new Entity[entityCount];
s_EntityBufferCount = entityCount;
}
}
}

View File

@ -35,19 +35,44 @@ namespace Prism
float Distance;
};
struct SceneParams
enum class BroadphaseType
{
glm::vec3 Gravity = { 0.0F, -9.81F, 0.0F };
SweepAndPrune,
MultiBoxPrune,
AutomaticBoxPrune
};
enum class FrictionType
{
Patch,
OneDirectional,
TwoDirectional
};
struct PhysicsSettings
{
float FixedTimestep = 0.006f;
glm::vec3 Gravity = { 0.0f, -9.81f, 0.0f };
BroadphaseType BroadphaseAlgorithm = BroadphaseType::AutomaticBoxPrune;
glm::vec3 WorldBoundsMin = glm::vec3(0.0f);
glm::vec3 WorldBoundsMax = glm::vec3(1.0f);
uint32_t WorldBoundsSubdivisions = 2;
// FrictionType FrictionModel = FrictionType::Patch;
};
class PRISM_API Physics3D
{
public:
static void Init();
static void Shutdown();
static PhysicsSettings& GetSettings();
static void CreateScene(const SceneParams& params);
static void CreateActor(Entity e, int entityCount);
static void ExpandEntityBuffer(uint32_t entityCount);
static void CreateScene();
static void CreateActor(Entity e);
static void Simulate(TimeStep ts);
@ -58,6 +83,7 @@ namespace Prism
static bool ConnectPVD();
static bool IsPVDConnected();
static void DisconnectPVD();
};
}

View File

@ -59,15 +59,15 @@ namespace Prism
RemoveIfExists<PhysicsLayer>(s_Layers, [&](const PhysicsLayer& layer) { return layer.LayerID == layerId; });
}
void PhysicsLayerManager::SetLayerCollision(uint32_t layerId, uint32_t otherLayer, bool collides)
void PhysicsLayerManager::SetLayerCollision(const uint32_t layerId, const uint32_t otherLayer, const bool shouldCollide)
{
if (ShouldCollide(layerId, otherLayer) && collides)
if (ShouldCollide(layerId, otherLayer) && shouldCollide)
return;
PhysicsLayer& layerInfo = GetLayer(layerId);
PhysicsLayer& otherLayerInfo = GetLayer(otherLayer);
if (collides)
if (shouldCollide)
{
layerInfo.CollidesWith |= otherLayerInfo.BitValue;
otherLayerInfo.CollidesWith |= layerInfo.BitValue;
@ -79,7 +79,7 @@ namespace Prism
}
}
const std::vector<PhysicsLayer>& PhysicsLayerManager::GetLayerCollisions(uint32_t layerId)
std::vector<PhysicsLayer> PhysicsLayerManager::GetLayerCollisions(const uint32_t layerId)
{
const PhysicsLayer& layer = GetLayer(layerId);
@ -160,7 +160,7 @@ namespace Prism
lastId = layer.LayerID;
}
return s_Layers.size();
return static_cast<uint32_t>(s_Layers.size());
}
std::vector<PhysicsLayer> PhysicsLayerManager::s_Layers;

View File

@ -23,8 +23,8 @@ namespace Prism
static uint32_t AddLayer(const std::string& name, bool setCollisions = true);
static void RemoveLayer(uint32_t layerId);
static void SetLayerCollision(uint32_t layerId, uint32_t otherLayer, bool collides);
static const std::vector<PhysicsLayer>& GetLayerCollisions(uint32_t layerId);
static void SetLayerCollision(uint32_t layerId, uint32_t otherLayer, bool shouldCollide);
static std::vector<PhysicsLayer> GetLayerCollisions(uint32_t layerId);
static const std::vector<PhysicsLayer>& GetLayers() { return s_Layers; }
@ -35,14 +35,16 @@ namespace Prism
static bool ShouldCollide(uint32_t layer1, uint32_t layer2);
static bool IsLayerValid(uint32_t layerId);
static void ClearLayers();
private:
static void ClearLayers();
static uint32_t GetNextLayerID();
private:
static std::vector<PhysicsLayer> s_Layers;
static PhysicsLayer s_NullLayer;
private:
friend class SceneSerializer;
};
}

View File

@ -85,76 +85,5 @@ namespace Prism
return physx::PxFilterFlag::eSUPPRESS;
}
void ContactListener::onConstraintBreak(physx::PxConstraintInfo* constraints, physx::PxU32 count)
{
PX_UNUSED(constraints);
PX_UNUSED(count);
}
void ContactListener::onWake(physx::PxActor** actors, physx::PxU32 count)
{
for (uint32_t i = 0; i < count; i++)
{
physx::PxActor& actor = *actors[i];
Entity& entity = *(Entity*)actor.userData;
PM_CORE_INFO("PhysX Actor waking up: ID: {0}, Name: {1}", static_cast<uint64_t>(entity.GetUUID()), entity.GetComponent<TagComponent>().Tag);
}
}
void ContactListener::onSleep(physx::PxActor** actors, physx::PxU32 count)
{
for (uint32_t i = 0; i < count; i++)
{
physx::PxActor& actor = *actors[i];
Entity& entity = *(Entity*)actor.userData;
PM_CORE_INFO("PhysX Actor going to sleep: ID: {0}, Name: {1}", static_cast<uint64_t>(entity.GetUUID()), entity.GetComponent<TagComponent>().Tag);
}
}
void ContactListener::onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, physx::PxU32 nbPairs)
{
const Entity& a = *static_cast<Entity*>(pairHeader.actors[0]->userData);
const Entity& b = *static_cast<Entity*>(pairHeader.actors[1]->userData);
if (pairs->flags == physx::PxContactPairFlag::eACTOR_PAIR_HAS_FIRST_TOUCH)
{
if (ScriptEngine::IsEntityModuleValid(a)) ScriptEngine::OnCollisionBegin(a);
if (ScriptEngine::IsEntityModuleValid(b)) ScriptEngine::OnCollisionBegin(b);
}
else if (pairs->flags == physx::PxContactPairFlag::eACTOR_PAIR_LOST_TOUCH)
{
if (ScriptEngine::IsEntityModuleValid(a)) ScriptEngine::OnCollisionEnd(a);
if (ScriptEngine::IsEntityModuleValid(b)) ScriptEngine::OnCollisionEnd(b);
}
}
void ContactListener::onTrigger(physx::PxTriggerPair* pairs, physx::PxU32 count)
{
const Entity& a = *static_cast<Entity*>(pairs->triggerActor->userData);
const Entity& b = *static_cast<Entity*>(pairs->otherActor->userData);
if (pairs->status == physx::PxPairFlag::eNOTIFY_TOUCH_FOUND)
{
if (ScriptEngine::IsEntityModuleValid(a)) ScriptEngine::OnTriggerBegin(a);
if (ScriptEngine::IsEntityModuleValid(b)) ScriptEngine::OnTriggerBegin(b);
}
else if (pairs->status == physx::PxPairFlag::eNOTIFY_TOUCH_LOST)
{
if (ScriptEngine::IsEntityModuleValid(a)) ScriptEngine::OnTriggerEnd(a);
if (ScriptEngine::IsEntityModuleValid(b)) ScriptEngine::OnTriggerEnd(b);
}
PX_UNUSED(count);
}
void ContactListener::onAdvance(const physx::PxRigidBody* const* bodyBuffer, const physx::PxTransform* poseBuffer, const physx::PxU32 count)
{
PX_UNUSED(bodyBuffer);
PX_UNUSED(poseBuffer);
PX_UNUSED(count);
}
}

View File

@ -28,16 +28,6 @@ namespace Prism
physx::PxFilterFlags PrismFilterShader(physx::PxFilterObjectAttributes attributes0, physx::PxFilterData filterData0, physx::PxFilterObjectAttributes attributes1,
physx::PxFilterData filterData1, physx::PxPairFlags& pairFlags, const void* constantBlock, physx::PxU32 constantBlockSize);
class ContactListener final : public physx::PxSimulationEventCallback
{
public:
virtual void onConstraintBreak(physx::PxConstraintInfo* constraints, physx::PxU32 count) override;
virtual void onWake(physx::PxActor** actors, physx::PxU32 count) override;
virtual void onSleep(physx::PxActor** actors, physx::PxU32 count) override;
virtual void onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, physx::PxU32 nbPairs) override;
virtual void onTrigger(physx::PxTriggerPair* pairs, physx::PxU32 count) override;
virtual void onAdvance(const physx::PxRigidBody* const* bodyBuffer, const physx::PxTransform* poseBuffer, physx::PxU32 count) override;
};
}

View File

@ -10,6 +10,7 @@
#include <glm/gtx/rotate_vector.hpp>
#include "PhysicsLayer.h"
#include "Prism/Script/ScriptEngine.h"
#define PHYSX_DEBUGGER
namespace Prism
@ -68,12 +69,99 @@ namespace Prism
}
}
void ContactListener::onConstraintBreak(physx::PxConstraintInfo* constraints, physx::PxU32 count)
{
PX_UNUSED(constraints);
PX_UNUSED(count);
}
physx::PxScene* PhysicsWrappers::CreateScene(const SceneParams& sceneParams)
void ContactListener::onWake(physx::PxActor** actors, physx::PxU32 count)
{
for (uint32_t i = 0; i < count; i++)
{
physx::PxActor& actor = *actors[i];
Entity& entity = *(Entity*)actor.userData;
PM_CORE_INFO("PhysX Actor waking up: ID: {0}, Name: {1}", static_cast<uint64_t>(entity.GetUUID()), entity.GetComponent<TagComponent>().Tag);
}
}
void ContactListener::onSleep(physx::PxActor** actors, physx::PxU32 count)
{
for (uint32_t i = 0; i < count; i++)
{
physx::PxActor& actor = *actors[i];
Entity& entity = *(Entity*)actor.userData;
PM_CORE_INFO("PhysX Actor going to sleep: ID: {0}, Name: {1}", static_cast<uint64_t>(entity.GetUUID()), entity.GetComponent<TagComponent>().Tag);
}
}
void ContactListener::onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, physx::PxU32 nbPairs)
{
const Entity& a = *static_cast<Entity*>(pairHeader.actors[0]->userData);
const Entity& b = *static_cast<Entity*>(pairHeader.actors[1]->userData);
if (pairs->flags == physx::PxContactPairFlag::eACTOR_PAIR_HAS_FIRST_TOUCH)
{
if (ScriptEngine::IsEntityModuleValid(a)) ScriptEngine::OnCollisionBegin(a);
if (ScriptEngine::IsEntityModuleValid(b)) ScriptEngine::OnCollisionBegin(b);
}
else if (pairs->flags == physx::PxContactPairFlag::eACTOR_PAIR_LOST_TOUCH)
{
if (ScriptEngine::IsEntityModuleValid(a)) ScriptEngine::OnCollisionEnd(a);
if (ScriptEngine::IsEntityModuleValid(b)) ScriptEngine::OnCollisionEnd(b);
}
}
void ContactListener::onTrigger(physx::PxTriggerPair* pairs, physx::PxU32 count)
{
const Entity& a = *static_cast<Entity*>(pairs->triggerActor->userData);
const Entity& b = *static_cast<Entity*>(pairs->otherActor->userData);
if (pairs->status == physx::PxPairFlag::eNOTIFY_TOUCH_FOUND)
{
if (ScriptEngine::IsEntityModuleValid(a)) ScriptEngine::OnTriggerBegin(a);
if (ScriptEngine::IsEntityModuleValid(b)) ScriptEngine::OnTriggerBegin(b);
}
else if (pairs->status == physx::PxPairFlag::eNOTIFY_TOUCH_LOST)
{
if (ScriptEngine::IsEntityModuleValid(a)) ScriptEngine::OnTriggerEnd(a);
if (ScriptEngine::IsEntityModuleValid(b)) ScriptEngine::OnTriggerEnd(b);
}
PX_UNUSED(count);
}
void ContactListener::onAdvance(const physx::PxRigidBody* const* bodyBuffer, const physx::PxTransform* poseBuffer, const physx::PxU32 count)
{
PX_UNUSED(bodyBuffer);
PX_UNUSED(poseBuffer);
PX_UNUSED(count);
}
static physx::PxBroadPhaseType::Enum PrismToPhysXBroadphaseType(const BroadphaseType type)
{
switch (type)
{
case Prism::BroadphaseType::SweepAndPrune: return physx::PxBroadPhaseType::eSAP;
case Prism::BroadphaseType::MultiBoxPrune: return physx::PxBroadPhaseType::eMBP;
case Prism::BroadphaseType::AutomaticBoxPrune: return physx::PxBroadPhaseType::eABP;
}
return physx::PxBroadPhaseType::eABP;
}
physx::PxScene* PhysicsWrappers::CreateScene()
{
physx::PxSceneDesc sceneDesc(s_Physics->getTolerancesScale());
sceneDesc.gravity = ToPhysXVector(sceneParams.Gravity);
const PhysicsSettings& settings = Physics3D::GetSettings();
sceneDesc.gravity = ToPhysXVector(settings.Gravity);
sceneDesc.broadPhaseType = PrismToPhysXBroadphaseType(settings.BroadphaseAlgorithm);
sceneDesc.cpuDispatcher = physx::PxDefaultCpuDispatcherCreate(1);
sceneDesc.filterShader = PrismFilterShader;
sceneDesc.simulationEventCallback = &s_ContactListener;
@ -378,8 +466,11 @@ namespace Prism
PM_CORE_ASSERT(s_Foundation, "PxCreateFoundation Failed!");
#ifdef PHYSX_DEBUGGER
s_VisualDebugger = PxCreatePvd(*s_Foundation);
ConnectPVD();
if (s_Foundation)
{
s_VisualDebugger = PxCreatePvd(*s_Foundation);
ConnectPVD();
}
#endif
s_Physics = PxCreatePhysics(PX_PHYSICS_VERSION, *s_Foundation, physx::PxTolerancesScale(), true, s_VisualDebugger);

View File

@ -15,16 +15,28 @@ namespace Prism
struct RaycastHit;
struct SceneParams;
class PhysicsErrorCallback final : public physx::PxErrorCallback
{
public:
void reportError(physx::PxErrorCode::Enum code, const char* message, const char* file, int line) override;
};
class ContactListener final : public physx::PxSimulationEventCallback
{
public:
virtual void onConstraintBreak(physx::PxConstraintInfo* constraints, physx::PxU32 count) override;
virtual void onWake(physx::PxActor** actors, physx::PxU32 count) override;
virtual void onSleep(physx::PxActor** actors, physx::PxU32 count) override;
virtual void onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, physx::PxU32 nbPairs) override;
virtual void onTrigger(physx::PxTriggerPair* pairs, physx::PxU32 count) override;
virtual void onAdvance(const physx::PxRigidBody* const* bodyBuffer, const physx::PxTransform* poseBuffer, physx::PxU32 count) override;
};
class PhysicsWrappers
{
public:
static physx::PxScene* CreateScene(const SceneParams& sceneParams);
static physx::PxScene* CreateScene();
static physx::PxRigidActor* CreateActor(const RigidBodyComponent& rigidbody, const glm::mat4& transform);
static void SetCollisionFilters(const physx::PxRigidActor& actor, uint32_t physicsLayer);

View File

@ -166,6 +166,7 @@ namespace Prism
bool LockRotationZ = false;
void* RuntimeActor = nullptr;
int32_t EntityBufferIndex = -1;
RigidBodyComponent() = default;
RigidBodyComponent(const RigidBodyComponent& other) = default;

View File

@ -138,9 +138,7 @@ namespace Prism
if (!isEditorScene)
{
SceneParams sceneDesc;
sceneDesc.Gravity = glm::vec3(0.0F, -9.81F, 0.0F);
Physics3D::CreateScene(sceneDesc);
Physics3D::CreateScene();
}
Init();
@ -478,10 +476,11 @@ namespace Prism
{
auto view = m_Registry.view<RigidBodyComponent>();
Physics3D::ExpandEntityBuffer(static_cast<uint32_t>(view.size()));
for (auto entity : view)
{
Entity e = { entity, this };
Physics3D::CreateActor(e, (int)view.size());
Physics3D::CreateActor(e);
}
}

View File

@ -102,10 +102,16 @@ namespace Prism
mono_add_internal_call("Prism.Texture2D::Destructor_Native", (const void*)Prism::Script::Prism_Texture2D_Destructor);
mono_add_internal_call("Prism.Texture2D::SetData_Native", (const void*)Prism::Script::Prism_Texture2D_SetData);
// Physics3D
// RigidBodyComponent
mono_add_internal_call("Prism.RigidBodyComponent::GetBodyType_Native", (const void*)Prism::Script::Prism_RigidBodyComponent_GetBodyType);
mono_add_internal_call("Prism.RigidBodyComponent::AddForce_Native", (const void*)Prism::Script::Prism_RigidBodyComponent_AddForce);
mono_add_internal_call("Prism.RigidBodyComponent::AddTorque_Native", (const void*)Prism::Script::Prism_RigidBodyComponent_AddTorque);
mono_add_internal_call("Prism.RigidBodyComponent::GetLinearVelocity_Native", (const void*)Prism::Script::Prism_RigidBodyComponent_GetLinearVelocity);
mono_add_internal_call("Prism.RigidBodyComponent::SetLinearVelocity_Native", (const void*)Prism::Script::Prism_RigidBodyComponent_SetLinearVelocity);
mono_add_internal_call("Prism.RigidBodyComponent::GetAngularVelocity_Native", (const void*)Prism::Script::Prism_RigidBodyComponent_GetAngularVelocity);
mono_add_internal_call("Prism.RigidBodyComponent::SetAngularVelocity_Native", (const void*)Prism::Script::Prism_RigidBodyComponent_SetAngularVelocity);
mono_add_internal_call("Prism.RigidBodyComponent::Rotate_Native", (const void*)Prism::Script::Prism_RigidBodyComponent_Rotate);
mono_add_internal_call("Prism.RigidBodyComponent::GetLayer_Native", (const void*)Prism::Script::Prism_RigidBodyComponent_GetLayer);
mono_add_internal_call("Prism.RigidBodyComponent::GetMass_Native", (const void*)Prism::Script::Prism_RigidBodyComponent_GetMass);

View File

@ -100,14 +100,14 @@ namespace Prism { namespace Script {
}
// Helper function for the Overlap functions below
static void AddCollidersToArray(MonoArray* array, const std::array<physx::PxOverlapHit, OVERLAP_MAX_COLLIDERS>& hits, const uint32_t count)
static void AddCollidersToArray(MonoArray* array, const std::array<physx::PxOverlapHit, OVERLAP_MAX_COLLIDERS>& hits, const uint32_t count, uint32_t arrayLength)
{
uint32_t arrayIndex = 0;
for (uint32_t i = 0; i < count; i++)
{
Entity& entity = *static_cast<Entity*>(hits[i].actor->userData);
if (entity.HasComponent<BoxColliderComponent>())
if (entity.HasComponent<BoxColliderComponent>() && arrayIndex < arrayLength)
{
auto& boxCollider = entity.GetComponent<BoxColliderComponent>();
@ -123,7 +123,7 @@ namespace Prism { namespace Script {
mono_array_set(array, MonoObject*, arrayIndex++, obj);
}
if (entity.HasComponent<SphereColliderComponent>())
if (entity.HasComponent<SphereColliderComponent>() && arrayIndex < arrayLength)
{
auto& sphereCollider = entity.GetComponent<SphereColliderComponent>();
@ -138,7 +138,7 @@ namespace Prism { namespace Script {
mono_array_set(array, MonoObject*, arrayIndex++, obj);
}
if (entity.HasComponent<CapsuleColliderComponent>())
if (entity.HasComponent<CapsuleColliderComponent>() && arrayIndex < arrayLength)
{
auto& capsuleCollider = entity.GetComponent<CapsuleColliderComponent>();
@ -154,7 +154,7 @@ namespace Prism { namespace Script {
mono_array_set(array, MonoObject*, arrayIndex++, obj);
}
if (entity.HasComponent<MeshColliderComponent>())
if (entity.HasComponent<MeshColliderComponent>() && arrayIndex < arrayLength)
{
auto& meshCollider = entity.GetComponent<MeshColliderComponent>();
@ -184,7 +184,7 @@ namespace Prism { namespace Script {
if (PhysicsWrappers::OverlapBox(*origin, *halfSize, s_OverlapBuffer, &count))
{
outColliders = mono_array_new(mono_domain_get(), ScriptEngine::GetCoreClass("Prism.Collider"), count);
AddCollidersToArray(outColliders, s_OverlapBuffer, count);
AddCollidersToArray(outColliders, s_OverlapBuffer, count, count);
}
return outColliders;
@ -199,7 +199,7 @@ namespace Prism { namespace Script {
if (PhysicsWrappers::OverlapCapsule(*origin, radius, halfHeight, s_OverlapBuffer, &count))
{
outColliders = mono_array_new(mono_domain_get(), ScriptEngine::GetCoreClass("Prism.Collider"), count);
AddCollidersToArray(outColliders, s_OverlapBuffer, count);
AddCollidersToArray(outColliders, s_OverlapBuffer, count, count);
}
return outColliders;
@ -214,7 +214,7 @@ namespace Prism { namespace Script {
if (PhysicsWrappers::OverlapSphere(*origin, radius, s_OverlapBuffer, &count))
{
outColliders = mono_array_new(mono_domain_get(), ScriptEngine::GetCoreClass("Prism.Collider"), count);
AddCollidersToArray(outColliders, s_OverlapBuffer, count);
AddCollidersToArray(outColliders, s_OverlapBuffer, count, count);
}
return outColliders;
@ -232,7 +232,7 @@ namespace Prism { namespace Script {
if (count > arrayLength)
count = static_cast<uint32_t>(arrayLength);
AddCollidersToArray(outColliders, s_OverlapBuffer, count);
AddCollidersToArray(outColliders, s_OverlapBuffer, count, static_cast<uint32_t>(arrayLength));
}
return static_cast<int32_t>(count);
@ -250,7 +250,7 @@ namespace Prism { namespace Script {
if (count > arrayLength)
count = static_cast<uint32_t>(arrayLength);
AddCollidersToArray(outColliders, s_OverlapBuffer, count);
AddCollidersToArray(outColliders, s_OverlapBuffer, count, static_cast<uint32_t>(arrayLength));
}
return static_cast<int32_t>(count);
@ -268,7 +268,7 @@ namespace Prism { namespace Script {
if (count > arrayLength)
count = static_cast<uint32_t>(arrayLength);
AddCollidersToArray(outColliders, s_OverlapBuffer, count);
AddCollidersToArray(outColliders, s_OverlapBuffer, count, static_cast<uint32_t>(arrayLength));
}
return static_cast<int32_t>(count);
@ -456,6 +456,19 @@ namespace Prism { namespace Script {
b2Body_SetLinearVelocity(component.RuntimeBodyID, {velocity->x, velocity->y});
}
RigidBodyComponent::Type Prism_RigidBodyComponent_GetBodyType(const uint64_t entityID)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
PM_CORE_ASSERT(scene, "No active scene!");
const auto& entityMap = scene->GetEntityMap();
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
Entity entity = entityMap.at(entityID);
PM_CORE_ASSERT(entity.HasComponent<RigidBodyComponent>());
const auto& component = entity.GetComponent<RigidBodyComponent>();
return component.BodyType;
}
void Prism_RigidBodyComponent_AddForce(const uint64_t entityID, glm::vec3* force, ForceMode forceMode)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
@ -554,6 +567,45 @@ namespace Prism { namespace Script {
dynamicActor->setLinearVelocity({ velocity->x, velocity->y, velocity->z });
}
void Prism_RigidBodyComponent_GetAngularVelocity(uint64_t entityID, glm::vec3* outVelocity)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
PM_CORE_ASSERT(scene, "No active scene!");
const auto& entityMap = scene->GetEntityMap();
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
Entity entity = entityMap.at(entityID);
PM_CORE_ASSERT(entity.HasComponent<RigidBodyComponent>());
const auto& component = entity.GetComponent<RigidBodyComponent>();
const auto actor = static_cast<physx::PxRigidActor*>(component.RuntimeActor);
const auto* dynamicActor = actor->is<physx::PxRigidDynamic>();
PM_CORE_ASSERT(dynamicActor);
PM_CORE_ASSERT(outVelocity);
physx::PxVec3 velocity = dynamicActor->getAngularVelocity();
*outVelocity = { velocity.x, velocity.y, velocity.z };
}
void Prism_RigidBodyComponent_SetAngularVelocity(uint64_t entityID, glm::vec3* velocity)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();
PM_CORE_ASSERT(scene, "No active scene!");
const auto& entityMap = scene->GetEntityMap();
PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!");
Entity entity = entityMap.at(entityID);
PM_CORE_ASSERT(entity.HasComponent<RigidBodyComponent>());
const auto& component = entity.GetComponent<RigidBodyComponent>();
auto* actor = static_cast<physx::PxRigidActor*>(component.RuntimeActor);
auto* dynamicActor = actor->is<physx::PxRigidDynamic>();
PM_CORE_ASSERT(dynamicActor);
PM_CORE_ASSERT(velocity);
dynamicActor->setAngularVelocity({ velocity->x, velocity->y, velocity->z });
}
void Prism_RigidBodyComponent_Rotate(uint64_t entityID, glm::vec3* rotation)
{
Ref<Scene> scene = ScriptEngine::GetCurrentSceneContext();

View File

@ -55,10 +55,13 @@ namespace Prism { namespace Script {
void Prism_RigidBody2DComponent_SetLinearVelocity(uint64_t entityID, const glm::vec2* velocity);
// 3D Physic
RigidBodyComponent::Type Prism_RigidBodyComponent_GetBodyType(uint64_t entityID);
void Prism_RigidBodyComponent_AddForce(uint64_t entityID, glm::vec3* force, ForceMode forceMode);
void Prism_RigidBodyComponent_AddTorque(uint64_t entityID, glm::vec3* torque, ForceMode forceMode);
void Prism_RigidBodyComponent_GetLinearVelocity(uint64_t entityID, glm::vec3* outVelocity);
void Prism_RigidBodyComponent_SetLinearVelocity(uint64_t entityID, glm::vec3* velocity);
void Prism_RigidBodyComponent_GetAngularVelocity(uint64_t entityID, glm::vec3* outVelocity);
void Prism_RigidBodyComponent_SetAngularVelocity(uint64_t entityID, glm::vec3* velocity);
void Prism_RigidBodyComponent_Rotate(uint64_t entityID, glm::vec3* rotation);
uint32_t Prism_RigidBodyComponent_GetLayer(uint64_t entityID);
float Prism_RigidBodyComponent_GetMass(uint64_t entityID);