diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index 9c4c0c5b3..4e3813ee0 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -676,10 +676,9 @@ void EditorComponent::Load() physicsEnabledCheckBox->SetPos(XMFLOAT2(screenW - 25, 50)); physicsEnabledCheckBox->SetTooltip("Toggle Physics Engine On/Off"); physicsEnabledCheckBox->OnClick([&](wiEventArgs args) { - Scene& scene = wiRenderer::GetScene(); - scene.SetPhysicsEnabled(args.bValue); + wiPhysicsEngine::SetEnabled(args.bValue); }); - physicsEnabledCheckBox->SetCheck(wiRenderer::GetScene().IsPhysicsEnabled()); + physicsEnabledCheckBox->SetCheck(wiPhysicsEngine::IsEnabled()); GetGUI().AddWidget(physicsEnabledCheckBox); cinemaModeCheckBox = new wiCheckBox("Cinema Mode: "); diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index 59f1b7ef7..b5d71c885 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -71,7 +71,7 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) }); meshWindow->AddWidget(softbodyCheckBox); - massSlider = new wiSlider(0, 5000, 0, 100000, "Mass: "); + massSlider = new wiSlider(0, 10, 0, 100000, "Mass: "); massSlider->SetTooltip("Set the mass amount for the physics engine."); massSlider->SetSize(XMFLOAT2(100, 30)); massSlider->SetPos(XMFLOAT2(x, y += step)); @@ -84,7 +84,7 @@ MeshWindow::MeshWindow(wiGUI* gui) : GUI(gui) }); meshWindow->AddWidget(massSlider); - frictionSlider = new wiSlider(0, 5000, 0, 100000, "Friction: "); + frictionSlider = new wiSlider(0, 2, 0, 100000, "Friction: "); frictionSlider->SetTooltip("Set the friction amount for the physics engine."); frictionSlider->SetSize(XMFLOAT2(100, 30)); frictionSlider->SetPos(XMFLOAT2(x, y += step)); diff --git a/WickedEngine/wiPhysicsEngine.h b/WickedEngine/wiPhysicsEngine.h index 77f67c37e..041941beb 100644 --- a/WickedEngine/wiPhysicsEngine.h +++ b/WickedEngine/wiPhysicsEngine.h @@ -7,6 +7,9 @@ namespace wiPhysicsEngine void Initialize(); void CleanUp(); + bool IsEnabled(); + void SetEnabled(bool value); + void RunPhysicsUpdateSystem( const wiSceneSystem::WeatherComponent& weather, wiECS::ComponentManager& transforms, diff --git a/WickedEngine/wiPhysicsEngine_Bullet.cpp b/WickedEngine/wiPhysicsEngine_Bullet.cpp index ca50281c3..97c6cec89 100644 --- a/WickedEngine/wiPhysicsEngine_Bullet.cpp +++ b/WickedEngine/wiPhysicsEngine_Bullet.cpp @@ -21,6 +21,8 @@ using namespace wiSceneSystem; namespace wiPhysicsEngine { + bool ENABLED = true; + btVector3 gravity(0, -10, 0); int softbodyIterationCount = 5; btCollisionConfiguration* collisionConfiguration = nullptr; @@ -33,9 +35,6 @@ namespace wiPhysicsEngine btSoftBodySolverOutput* softBodySolverOutput = nullptr; - unordered_map lookup; - - void Initialize() { // collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration. @@ -79,36 +78,31 @@ namespace wiPhysicsEngine delete collisionConfiguration; } + bool IsEnabled() { return ENABLED; } + void SetEnabled(bool value) { ENABLED = value; } - void Remove(Entity entity) + void Remove(int id) { - auto it = lookup.find(entity); - if (it != lookup.end()) + btCollisionObject* collisionobject = dynamicsWorld->getCollisionObjectArray()[id]; + + btRigidBody* rigidbody = btRigidBody::upcast(collisionobject); + if (rigidbody != nullptr) { - int id = it->second; - lookup.erase(it); - - btCollisionObject* collisionobject = dynamicsWorld->getCollisionObjectArray()[id]; - - btRigidBody* rigidbody = btRigidBody::upcast(collisionobject); - if (rigidbody != nullptr) - { - dynamicsWorld->removeRigidBody(rigidbody); - } - else - { - btSoftBody* softbody = btSoftBody::upcast(collisionobject); - - if (softbody != nullptr) - { - ((btSoftRigidDynamicsWorld*)dynamicsWorld)->removeSoftBody(softbody); - } - } - - dynamicsWorld->removeCollisionObject(collisionobject); + dynamicsWorld->removeRigidBody(rigidbody); } + else + { + btSoftBody* softbody = btSoftBody::upcast(collisionobject); + + if (softbody != nullptr) + { + ((btSoftRigidDynamicsWorld*)dynamicsWorld)->removeSoftBody(softbody); + } + } + + dynamicsWorld->removeCollisionObject(collisionobject); } - int AddRigidBody(Entity entity, wiSceneSystem::RigidBodyPhysicsComponent& physicscomponent, const wiSceneSystem::MeshComponent& mesh, const wiSceneSystem::TransformComponent& transform) + void AddRigidBody(Entity entity, wiSceneSystem::RigidBodyPhysicsComponent& physicscomponent, const wiSceneSystem::MeshComponent& mesh, const wiSceneSystem::TransformComponent& transform) { btVector3 S(transform.scale_local.x, transform.scale_local.y, transform.scale_local.z); @@ -204,12 +198,14 @@ namespace wiPhysicsEngine btDefaultMotionState* myMotionState = new btDefaultMotionState(shapeTransform); btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, shape, localInertia); - rbInfo.m_friction = physicscomponent.friction; - rbInfo.m_restitution = physicscomponent.restitution; - rbInfo.m_linearDamping = physicscomponent.damping; - rbInfo.m_angularDamping = physicscomponent.damping; + //rbInfo.m_friction = physicscomponent.friction; + //rbInfo.m_restitution = physicscomponent.restitution; + //rbInfo.m_linearDamping = physicscomponent.damping; + //rbInfo.m_angularDamping = physicscomponent.damping; btRigidBody* body = new btRigidBody(rbInfo); + body->setUserIndex(*(int*)&entity); + if (physicscomponent.IsKinematic()) { body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); @@ -219,40 +215,45 @@ namespace wiPhysicsEngine body->setActivationState(DISABLE_DEACTIVATION); } - int id = dynamicsWorld->getCollisionObjectArray().size(); - lookup[entity] = id; dynamicsWorld->addRigidBody(body); - return id; + physicscomponent.physicsobject = body; } - - return -1; } - int AddSoftBody(Entity entity, wiSceneSystem::SoftBodyPhysicsComponent& physicscomponent, const wiSceneSystem::MeshComponent& mesh, const wiSceneSystem::TransformComponent& transform) + void AddSoftBody(Entity entity, wiSceneSystem::SoftBodyPhysicsComponent& physicscomponent, const wiSceneSystem::MeshComponent& mesh, const wiSceneSystem::TransformComponent& transform) { btVector3 S = btVector3(transform.scale_local.x, transform.scale_local.y, transform.scale_local.z); btQuaternion R = btQuaternion(transform.rotation_local.x, transform.rotation_local.y, transform.rotation_local.z, transform.rotation_local.z); btVector3 T = btVector3(transform.translation_local.x, transform.translation_local.y, transform.translation_local.z); + if (physicscomponent.physicsvertices.empty()) + { + physicscomponent.CreateFromMesh(mesh); + } + const int vCount = (int)physicscomponent.physicsvertices.size(); btScalar* btVerts = new btScalar[vCount * 3]; - for (int i = 0; i < vCount * 3; i += 3) { - const int vindex = i / 3; - btVerts[i] = btScalar(physicscomponent.physicsvertices[vindex].x); - btVerts[i + 1] = btScalar(physicscomponent.physicsvertices[vindex].y); - btVerts[i + 2] = btScalar(physicscomponent.physicsvertices[vindex].z); + for (int i = 0; i < vCount; ++i) + { + btVerts[i * 3 + 0] = btScalar(physicscomponent.physicsvertices[i].x); + btVerts[i * 3 + 1] = btScalar(physicscomponent.physicsvertices[i].y); + btVerts[i * 3 + 2] = btScalar(physicscomponent.physicsvertices[i].z); } - const int iCount = (int)physicscomponent.physicsindices.size(); + + const int iCount = (int)mesh.indices.size(); const int tCount = iCount / 3; int* btInd = new int[iCount]; - for (int i = 0; i < iCount; ++i) { - btInd[i] = physicscomponent.physicsindices[i]; + for (int i = 0; i < iCount; ++i) + { + uint32_t ind = mesh.indices[i]; + uint32_t mappedIndex = physicscomponent.graphicsToPhysicsVertexMapping[ind]; + btInd[i] = (int)mappedIndex; } btSoftBody* softBody = btSoftBodyHelpers::CreateFromTriMesh( ((btSoftRigidDynamicsWorld*)dynamicsWorld)->getWorldInfo() - , &btVerts[0] - , &btInd[0] + , btVerts + , btInd , tCount , false ); @@ -263,6 +264,8 @@ namespace wiPhysicsEngine if (softBody) { + softBody->setUserIndex(*(int*)&entity); + btSoftBody::Material* pm = softBody->appendMaterial(); pm->m_kLST = 0.5; pm->m_kVST = 0.5; @@ -271,12 +274,12 @@ namespace wiPhysicsEngine softBody->generateBendingConstraints(2, pm); softBody->randomizeConstraints(); - btTransform shapeTransform; - shapeTransform.setIdentity(); - shapeTransform.setOrigin(T); - shapeTransform.setRotation(R); - softBody->scale(S); - softBody->transform(shapeTransform); + //btTransform shapeTransform; + //shapeTransform.setIdentity(); + //shapeTransform.setOrigin(T); + //shapeTransform.setRotation(R); + //softBody->scale(S); + //softBody->transform(shapeTransform); softBody->m_cfg.piterations = softbodyIterationCount; @@ -328,6 +331,11 @@ namespace wiPhysicsEngine // } //} + for (size_t i = 0; i < physicscomponent.physicsvertices.size(); ++i) + { + softBody->setMass((int)i, physicscomponent.mass); + } + softBody->getCollisionShape()->setMargin(btScalar(0.2)); //softBody->setWindVelocity(wind); @@ -336,13 +344,9 @@ namespace wiPhysicsEngine softBody->setActivationState(DISABLE_DEACTIVATION); - int id = dynamicsWorld->getCollisionObjectArray().size(); - lookup[entity] = id; ((btSoftRigidDynamicsWorld*)dynamicsWorld)->addSoftBody(softBody); - return id; + physicscomponent.physicsobject = softBody; } - - return -1; } void RunPhysicsUpdateSystem( @@ -355,41 +359,68 @@ namespace wiPhysicsEngine float dt ) { + if (!IsEnabled()) + { + return; + } + wiProfiler::GetInstance().BeginRange("Physics", wiProfiler::DOMAIN_CPU); btVector3 wind = btVector3(weather.windDirection.x, weather.windDirection.y, weather.windDirection.z); - - // Rigid bodies - Objects: + // Try to register rigidbodies to Objects: for (size_t i = 0; i < rigidbodies.GetCount(); ++i) { - Entity entity = rigidbodies.GetEntity(i); - RigidBodyPhysicsComponent& rigidbody = rigidbodies[i]; - TransformComponent& transform = *transforms.GetComponent(entity); - int id = -1; + RigidBodyPhysicsComponent& physicscomponent = rigidbodies[i]; - auto it = lookup.find(entity); - if (it == lookup.end()) + if (physicscomponent.physicsobject == nullptr) { + Entity entity = rigidbodies.GetEntity(i); + TransformComponent& transform = *transforms.GetComponent(entity); const ObjectComponent& object = *objects.GetComponent(entity); const MeshComponent& mesh = *meshes.GetComponent(object.meshID); - id = AddRigidBody(entity, rigidbody, mesh, transform); + AddRigidBody(entity, physicscomponent, mesh, transform); } - else + } + + // Try to register softbodies to Meshes: + for (size_t i = 0; i < softbodies.GetCount(); ++i) + { + Entity entity = softbodies.GetEntity(i); + SoftBodyPhysicsComponent& physicscomponent = softbodies[i]; + MeshComponent& mesh = *meshes.GetComponent(entity); + mesh.SetDynamic(true); + + if (physicscomponent.physicsobject == nullptr) { - id = it->second; + TransformComponent transform; + AddSoftBody(entity, physicscomponent, mesh, transform); } - assert(id >= 0 && id <= dynamicsWorld->getCollisionObjectArray().size()); + } - btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[id]; - btRigidBody* body = btRigidBody::upcast(obj); + // Update all physics components and remove from simulation if components no longer exist: + for (int i = 0; i < dynamicsWorld->getCollisionObjectArray().size(); ++i) + { + btCollisionObject* collisionobject = dynamicsWorld->getCollisionObjectArray()[i]; + int userIndex = collisionobject->getUserIndex(); + Entity entity = *(Entity*)&userIndex; - if (body != nullptr) + btRigidBody* rigidbody = btRigidBody::upcast(collisionobject); + if (rigidbody != nullptr) { - btMotionState* motionState = body->getMotionState(); + RigidBodyPhysicsComponent* physicscomponent = rigidbodies.GetComponent(entity); + if (physicscomponent == nullptr) + { + Remove(i); + break; + } + + TransformComponent& transform = *transforms.GetComponent(entity); + + btMotionState* motionState = rigidbody->getMotionState(); btTransform physicsTransform; - if (rigidbody.IsKinematic()) + if (physicscomponent->IsKinematic()) { btVector3 T(transform.translation_local.x, transform.translation_local.y, transform.translation_local.z); btQuaternion R(transform.rotation_local.x, transform.rotation_local.y, transform.rotation_local.z, transform.rotation_local.w); @@ -408,59 +439,52 @@ namespace wiPhysicsEngine transform.SetDirty(); } } - - - } - - // Soft bodies - Meshes: - for (size_t i = 0; i < softbodies.GetCount(); ++i) - { - Entity entity = softbodies.GetEntity(i); - SoftBodyPhysicsComponent& softbody = softbodies[i]; - MeshComponent& mesh = *meshes.GetComponent(entity); - mesh.SetDynamic(true); - int id = -1; - - auto it = lookup.find(entity); - if (it == lookup.end()) - { - TransformComponent transform; - id = AddSoftBody(entity, softbody, mesh, transform); - } else { - id = it->second; - } - assert(id >= 0 && id <= dynamicsWorld->getCollisionObjectArray().size()); + btSoftBody* softbody = btSoftBody::upcast(collisionobject); - btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[id]; - btSoftBody* body = btSoftBody::upcast(obj); - if (body != nullptr) - { - body->setWindVelocity(wind); - } + if (softbody != nullptr) + { + SoftBodyPhysicsComponent* physicscomponent = softbodies.GetComponent(entity); + if (physicscomponent == nullptr) + { + Remove(i); + break; + } - } + softbody->setWindVelocity(wind); - // Tidy: - for (auto it : lookup) - { - Entity entity = it.first; - bool exists = rigidbodies.Contains(entity); - if (!exists) - { - exists = softbodies.Contains(entity); - } + MeshComponent& mesh = *meshes.GetComponent(entity); - if (!exists) - { - Remove(entity); - break; + btVector3 aabb_min; + btVector3 aabb_max; + softbody->getAabb(aabb_min, aabb_max); + mesh.aabb = AABB(XMFLOAT3(aabb_min.x(), aabb_min.y(), aabb_min.z()), XMFLOAT3(aabb_max.x(), aabb_max.y(), aabb_max.z())); + + btSoftBody::tNodeArray& nodes(softbody->m_nodes); + for (size_t ind = 0; ind < mesh.vertex_positions.size(); ++ind) + { + uint32_t physicsInd = physicscomponent->graphicsToPhysicsVertexMapping[ind]; + btSoftBody::Node& node = softbody->m_nodes[physicsInd]; + + XMFLOAT3& position = mesh.vertex_positions[ind]; + position.x = node.m_x.getX(); + position.y = node.m_x.getY(); + position.z = node.m_x.getZ(); + + if (!mesh.vertex_normals.empty()) + { + XMFLOAT3& normal = mesh.vertex_normals[ind]; + normal.x = -node.m_n.getX(); + normal.y = -node.m_n.getY(); + normal.z = -node.m_n.getZ(); + } + } + } } } - // Scale dt, otherwise simulation is just too slow (todo: review) - dynamicsWorld->stepSimulation(dt * 60, 10); + dynamicsWorld->stepSimulation(dt, 10); wiProfiler::GetInstance().EndRange(); // Physics } diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 725a7b8af..30063df17 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -3919,6 +3919,35 @@ void UpdateRenderData(GRAPHICSTHREAD threadID) device->EventEnd(threadID); wiProfiler::GetInstance().EndRange(threadID); // skinning + // Update soft body vertex buffers: + for (size_t i = 0; i < scene.softbodies.GetCount(); ++i) + { + Entity entity = scene.softbodies.GetEntity(i); + MeshComponent& mesh = *scene.meshes.GetComponent(entity); + + const size_t vb_size = sizeof(MeshComponent::Vertex_POS) * mesh.vertex_positions.size(); + MeshComponent::Vertex_POS* vb = (MeshComponent::Vertex_POS*)frameAllocators[threadID].allocate(vb_size); + + if (mesh.vertex_normals.empty()) + { + for (size_t ind = 0; ind < mesh.vertex_positions.size(); ++ind) + { + vb[ind].FromFULL(mesh.vertex_positions[ind], XMFLOAT3(0, 0, 0), 0); // subsetindex?? + } + } + else + { + for (size_t ind = 0; ind < mesh.vertex_positions.size(); ++ind) + { + vb[ind].FromFULL(mesh.vertex_positions[ind], mesh.vertex_normals[ind], 0); // subsetindex?? + } + } + + device->UpdateBuffer(mesh.vertexBuffer_POS.get(), vb, threadID, (UINT)vb_size); + + frameAllocators[threadID].free(vb_size); + } + // GPU Particle systems simulation/sorting/culling: for (size_t i = 0; i < scene.emitters.GetCount(); ++i) { diff --git a/WickedEngine/wiSceneSystem.cpp b/WickedEngine/wiSceneSystem.cpp index b594545bb..ab7158eac 100644 --- a/WickedEngine/wiSceneSystem.cpp +++ b/WickedEngine/wiSceneSystem.cpp @@ -5,6 +5,9 @@ #include "wiPhysicsEngine.h" #include "wiArchive.h" +#include +#include + using namespace wiECS; using namespace wiGraphicsTypes; @@ -336,7 +339,7 @@ namespace wiSceneSystem } GPUBufferDesc bd; - bd.Usage = USAGE_IMMUTABLE; + bd.Usage = USAGE_DEFAULT; bd.CPUAccessFlags = 0; bd.BindFlags = BIND_VERTEX_BUFFER | BIND_SHADER_RESOURCE; bd.MiscFlags = RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; @@ -743,6 +746,32 @@ namespace wiSceneSystem CreateRenderData(); } + + void SoftBodyPhysicsComponent::CreateFromMesh(const MeshComponent& mesh) + { + // Create a mapping that maps unique vertex positions to all vertex indices that share that. Unique vertex positions will make up the physics mesh: + std::unordered_map uniquePositions; + graphicsToPhysicsVertexMapping.resize(mesh.vertex_positions.size()); + + for (size_t i = 0; i < mesh.vertex_positions.size(); ++i) + { + const XMFLOAT3& position = mesh.vertex_positions[i]; + + size_t hashes[] = { + std::hash{}(position.x), + std::hash{}(position.y), + std::hash{}(position.z), + }; + size_t vertexHash = (((hashes[0] ^ (hashes[1] << 1) >> 1) ^ (hashes[2] << 1)) >> 1); + + if (uniquePositions.count(vertexHash) == 0) + { + uniquePositions[vertexHash] = i; + physicsvertices.push_back(position); + } + graphicsToPhysicsVertexMapping[i] = (uint32_t)uniquePositions[vertexHash]; + } + } void CameraComponent::CreatePerspective(float newWidth, float newHeight, float newNear, float newFar, float newFOV) { @@ -835,10 +864,7 @@ namespace wiSceneSystem RunAnimationUpdateSystem(animations, transforms, dt); - if (IsPhysicsEnabled()) - { - wiPhysicsEngine::RunPhysicsUpdateSystem(weather, transforms, meshes, objects, rigidbodies, softbodies, dt); - } + wiPhysicsEngine::RunPhysicsUpdateSystem(weather, transforms, meshes, objects, rigidbodies, softbodies, dt); RunTransformUpdateSystem(transforms); diff --git a/WickedEngine/wiSceneSystem.h b/WickedEngine/wiSceneSystem.h index f93933ba8..d17023b7a 100644 --- a/WickedEngine/wiSceneSystem.h +++ b/WickedEngine/wiSceneSystem.h @@ -472,6 +472,9 @@ namespace wiSceneSystem float restitution = 1.0f; float damping = 1.0f; + // Non-serialized attributes: + void* physicsobject = nullptr; + inline void SetDisableDeactivation(bool value) { if (value) { _flags |= DISABLE_DEACTIVATION; } else { _flags &= ~DISABLE_DEACTIVATION; } } inline void SetKinematic(bool value) { if (value) { _flags |= KINEMATIC; } else { _flags &= ~KINEMATIC; } } @@ -493,7 +496,13 @@ namespace wiSceneSystem float mass = 1.0f; float friction = 1.0f; std::vector physicsvertices; - std::vector physicsindices; + std::vector graphicsToPhysicsVertexMapping; + + // Non-serialized attributes: + void* physicsobject = nullptr; + + // Create physics represenation of graphics mesh + void CreateFromMesh(const MeshComponent& mesh); void Serialize(wiArchive& archive, uint32_t seed = 0); }; @@ -894,17 +903,6 @@ namespace wiSceneSystem XMFLOAT4 waterPlane = XMFLOAT4(0, 1, 0, 0); WeatherComponent weather; - enum FLAGS - { - EMPTY = 0, - PHYSICS_ENABLED = 1 << 0, - }; - uint32_t _flags = PHYSICS_ENABLED; - - inline void SetPhysicsEnabled(bool value) { if (value) { _flags |= PHYSICS_ENABLED; } else { _flags &= ~PHYSICS_ENABLED; } } - - inline bool IsPhysicsEnabled() const { return _flags & PHYSICS_ENABLED; } - // Update all components by a given timestep (in seconds): void Update(float dt); // Remove everything from the scene that it owns: diff --git a/WickedEngine/wiSceneSystem_Serializers.cpp b/WickedEngine/wiSceneSystem_Serializers.cpp index 16045be96..4cfeb68ec 100644 --- a/WickedEngine/wiSceneSystem_Serializers.cpp +++ b/WickedEngine/wiSceneSystem_Serializers.cpp @@ -268,7 +268,7 @@ namespace wiSceneSystem archive >> mass; archive >> friction; archive >> physicsvertices; - archive >> physicsindices; + archive >> graphicsToPhysicsVertexMapping; } else { @@ -276,7 +276,7 @@ namespace wiSceneSystem archive << mass; archive << friction; archive << physicsvertices; - archive << physicsindices; + archive << graphicsToPhysicsVertexMapping; } } void ArmatureComponent::Serialize(wiArchive& archive, uint32_t seed) diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index fea4d1683..1ab12e32a 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 21; // minor bug fixes, alterations, refactors, updates - const int revision = 11; + const int revision = 12; long GetVersion()