Fixed buoyancy
This commit is contained in:
@@ -501,20 +501,6 @@ void EditorApp::setupECS()
|
||||
void EditorApp::createDefaultEntities()
|
||||
{
|
||||
// Start with empty scene - user creates entities as needed
|
||||
|
||||
// Create global WaterPhysics component for buoyancy system
|
||||
flecs::entity waterPhysicsEntity = m_world.entity("WaterPhysics");
|
||||
WaterPhysics waterPhysics;
|
||||
waterPhysics.enabled = true;
|
||||
waterPhysics.waterSurfaceY =
|
||||
1.0f; // Raise water surface to 1.0m above ground
|
||||
waterPhysics.waterDensity = 1000.0f; // kg/m³
|
||||
waterPhysics.gravity = 9.81f; // m/s²
|
||||
waterPhysics.defaultBuoyancy = 1.0f;
|
||||
waterPhysics.defaultLinearDrag = 0.1f;
|
||||
waterPhysics.defaultAngularDrag = 0.05f;
|
||||
waterPhysics.defaultSubmergedThreshold = 0.3f;
|
||||
waterPhysicsEntity.set<WaterPhysics>(waterPhysics);
|
||||
}
|
||||
|
||||
void EditorApp::setupLights()
|
||||
@@ -674,12 +660,7 @@ bool EditorApp::frameRenderingQueued(const Ogre::FrameEvent &evt)
|
||||
m_characterSystem->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
/* --- Main physics step --- */
|
||||
if (m_physicsSystem) {
|
||||
m_physicsSystem->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
/* --- Buoyancy system (after physics) --- */
|
||||
/* --- Buoyancy system (before physics so impulse is integrated) --- */
|
||||
if (m_buoyancySystem) {
|
||||
// Update camera position for water detection area
|
||||
if (m_camera) {
|
||||
@@ -689,6 +670,11 @@ bool EditorApp::frameRenderingQueued(const Ogre::FrameEvent &evt)
|
||||
m_buoyancySystem->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
/* --- Main physics step --- */
|
||||
if (m_physicsSystem) {
|
||||
m_physicsSystem->update(evt.timeSinceLastFrame);
|
||||
}
|
||||
|
||||
/* --- Rendering support systems --- */
|
||||
if (m_lightSystem) {
|
||||
m_lightSystem->update();
|
||||
|
||||
@@ -8,9 +8,9 @@ struct WaterPhysics {
|
||||
float waterSurfaceY = -0.1f;
|
||||
|
||||
// Default buoyancy parameters (used when entity has no BuoyancyInfo)
|
||||
float defaultBuoyancy = 1.0f; // 1.0 = neutral buoyancy
|
||||
float defaultLinearDrag = 0.1f;
|
||||
float defaultAngularDrag = 0.05f;
|
||||
float defaultBuoyancy = 1.5f; // 1.0 = neutral, >1 floats (Jolt convention)
|
||||
float defaultLinearDrag = 0.5f; // Jolt recommends ~0.5
|
||||
float defaultAngularDrag = 0.01f; // Jolt recommends ~0.01
|
||||
float defaultSubmergedThreshold =
|
||||
0.1f; // Minimum submerged fraction to apply buoyancy
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "BuoyancySystem.hpp"
|
||||
#include "../components/EditorMarker.hpp"
|
||||
#include "../components/EntityName.hpp"
|
||||
#include "../components/Character.hpp"
|
||||
#include <OgreLogManager.h>
|
||||
#include <set>
|
||||
@@ -10,20 +8,6 @@ BuoyancySystem::BuoyancySystem(flecs::world &world, JoltPhysicsWrapper *physics)
|
||||
, m_physics(physics)
|
||||
, m_buoyancyInfoQuery(world.query<BuoyancyInfo>())
|
||||
{
|
||||
// Create default WaterPhysics entity if none exists
|
||||
bool hasWaterPhysics = false;
|
||||
world.query<WaterPhysics>().each(
|
||||
[&](flecs::entity, WaterPhysics &) { hasWaterPhysics = true; });
|
||||
|
||||
if (!hasWaterPhysics) {
|
||||
flecs::entity waterEntity = world.entity("WaterPhysics");
|
||||
waterEntity.set<WaterPhysics>({});
|
||||
waterEntity.add<EditorMarkerComponent>();
|
||||
waterEntity.set<EntityNameComponent>(
|
||||
EntityNameComponent("Water Physics"));
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"BuoyancySystem: Created default WaterPhysics entity");
|
||||
}
|
||||
}
|
||||
|
||||
void BuoyancySystem::initialize()
|
||||
@@ -162,7 +146,6 @@ void BuoyancySystem::applyBuoyancyToBody(JPH::BodyID bodyID, float deltaTime,
|
||||
float buoyancy = waterPhysics->defaultBuoyancy;
|
||||
float linearDrag = waterPhysics->defaultLinearDrag;
|
||||
float angularDrag = waterPhysics->defaultAngularDrag;
|
||||
float submergedThreshold = waterPhysics->defaultSubmergedThreshold;
|
||||
|
||||
// Override with per-entity settings if available
|
||||
if (buoyancyInfo) {
|
||||
@@ -172,25 +155,14 @@ void BuoyancySystem::applyBuoyancyToBody(JPH::BodyID bodyID, float deltaTime,
|
||||
buoyancy = buoyancyInfo->buoyancy;
|
||||
linearDrag = buoyancyInfo->linearDrag;
|
||||
angularDrag = buoyancyInfo->angularDrag;
|
||||
submergedThreshold = buoyancyInfo->submergedThreshold;
|
||||
}
|
||||
|
||||
// Check if body is sufficiently submerged
|
||||
if (!isBodySubmerged(bodyID, waterSurfaceY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get body position
|
||||
Ogre::Vector3 bodyPos = m_physics->getPosition(bodyID);
|
||||
|
||||
// Calculate submerged depth (how far below water surface)
|
||||
float submergedDepth = waterSurfaceY - bodyPos.y;
|
||||
if (submergedDepth <= 0.0f) {
|
||||
return; // Not submerged
|
||||
}
|
||||
|
||||
// Simple approximation: use body's bounding sphere radius
|
||||
// In a more advanced implementation, we would calculate actual submerged volume
|
||||
// Let Jolt handle submersion detection internally via ApplyBuoyancyImpulse.
|
||||
// The previous center-point check prevented partial submersion from working,
|
||||
// which caused characters standing in shallow water to receive no buoyancy.
|
||||
Ogre::Vector3 surfacePosition(bodyPos.x, waterSurfaceY, bodyPos.z);
|
||||
Ogre::Vector3 surfaceNormal(0.0f, 1.0f, 0.0f); // Water surface faces up
|
||||
Ogre::Vector3 fluidVelocity(0.0f, 0.0f, 0.0f); // Still water for now
|
||||
|
||||
@@ -231,11 +231,20 @@ void CharacterSystem::update(float deltaTime)
|
||||
JoltPhysics::convert(nodePos));
|
||||
}
|
||||
|
||||
/* Apply velocity via Jolt linear velocity (matches
|
||||
* original game code) */
|
||||
state.character->SetLinearVelocity(
|
||||
JoltPhysics::convert<JPH::Vec3>(
|
||||
cc.linearVelocity));
|
||||
/* Apply velocity via Jolt linear velocity.
|
||||
* Preserve physics-driven Y velocity when no explicit
|
||||
* vertical input is given so gravity/buoyancy/jumps
|
||||
* are not overwritten every frame. */
|
||||
JPH::Vec3 currentVel = state.character->GetLinearVelocity();
|
||||
JPH::Vec3 desiredVel = JoltPhysics::convert<JPH::Vec3>(
|
||||
cc.linearVelocity);
|
||||
JPH::Vec3 finalVel;
|
||||
finalVel.SetX(desiredVel.GetX());
|
||||
finalVel.SetZ(desiredVel.GetZ());
|
||||
finalVel.SetY(desiredVel.GetY() != 0.0f ?
|
||||
desiredVel.GetY() :
|
||||
currentVel.GetY());
|
||||
state.character->SetLinearVelocity(finalVel);
|
||||
if (cc.linearVelocity.squaredLength() > 0.0001f) {
|
||||
std::cout << "CharacterSystem::update: entity="
|
||||
<< e.id()
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "../components/PhysicsCollider.hpp"
|
||||
#include "../components/RigidBody.hpp"
|
||||
#include "../components/BuoyancyInfo.hpp"
|
||||
#include "../components/WaterPhysics.hpp"
|
||||
#include "../components/Light.hpp"
|
||||
#include "../components/Camera.hpp"
|
||||
#include "../components/Lod.hpp"
|
||||
@@ -311,79 +312,6 @@ void EditorUISystem::renderHierarchyWindow()
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Water Physics");
|
||||
ImGui::Separator();
|
||||
|
||||
// Find and edit WaterPhysics component
|
||||
WaterPhysics *waterPhysics = nullptr;
|
||||
m_world.query<WaterPhysics>().each(
|
||||
[&](flecs::entity entity,
|
||||
WaterPhysics &wp) {
|
||||
waterPhysics = ℘
|
||||
});
|
||||
|
||||
if (waterPhysics) {
|
||||
if (ImGui::Checkbox(
|
||||
"Water Physics Enabled",
|
||||
&waterPhysics->enabled)) {
|
||||
}
|
||||
if (ImGui::SliderFloat(
|
||||
"Water Surface Y",
|
||||
&waterPhysics->waterSurfaceY,
|
||||
-10.0f, 10.0f, "%.2f")) {
|
||||
}
|
||||
if (ImGui::SliderFloat(
|
||||
"Water Density (kg/m³)",
|
||||
&waterPhysics->waterDensity,
|
||||
500.0f, 2000.0f, "%.0f")) {
|
||||
}
|
||||
if (ImGui::SliderFloat(
|
||||
"Gravity (m/s²)",
|
||||
&waterPhysics->gravity,
|
||||
0.0f, 20.0f, "%.2f")) {
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text(
|
||||
"Default Buoyancy Parameters");
|
||||
|
||||
if (ImGui::SliderFloat(
|
||||
"Default Buoyancy",
|
||||
&waterPhysics
|
||||
->defaultBuoyancy,
|
||||
0.0f, 5.0f, "%.2f")) {
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled("(?)");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Default buoyancy density multiplier (1.0 = neutral buoyancy)");
|
||||
}
|
||||
|
||||
if (ImGui::SliderFloat(
|
||||
"Default Linear Drag",
|
||||
&waterPhysics
|
||||
->defaultLinearDrag,
|
||||
0.0f, 1.0f, "%.3f")) {
|
||||
}
|
||||
if (ImGui::SliderFloat(
|
||||
"Default Angular Drag",
|
||||
&waterPhysics
|
||||
->defaultAngularDrag,
|
||||
0.0f, 1.0f, "%.3f")) {
|
||||
}
|
||||
if (ImGui::SliderFloat(
|
||||
"Submerged Threshold",
|
||||
&waterPhysics
|
||||
->defaultSubmergedThreshold,
|
||||
0.0f, 1.0f, "%.2f")) {
|
||||
}
|
||||
} else {
|
||||
ImGui::TextDisabled(
|
||||
"No WaterPhysics component found");
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
@@ -683,6 +611,13 @@ void EditorUISystem::renderComponentList(flecs::entity entity)
|
||||
componentCount++;
|
||||
}
|
||||
|
||||
// Render WaterPhysics if present
|
||||
if (entity.has<WaterPhysics>()) {
|
||||
auto &wp = entity.get_mut<WaterPhysics>();
|
||||
m_componentRegistry.render<WaterPhysics>(entity, wp);
|
||||
componentCount++;
|
||||
}
|
||||
|
||||
// Render LOD Settings if present
|
||||
if (entity.has<LodSettingsComponent>()) {
|
||||
auto &lodSettings = entity.get_mut<LodSettingsComponent>();
|
||||
|
||||
@@ -2287,9 +2287,9 @@ void SceneSerializer::deserializeWaterPhysics(flecs::entity entity,
|
||||
water.waterSurfaceY = json.value("waterSurfaceY", -0.1f);
|
||||
water.waterDensity = json.value("waterDensity", 1000.0f);
|
||||
water.gravity = json.value("gravity", 9.81f);
|
||||
water.defaultBuoyancy = json.value("defaultBuoyancy", 1.0f);
|
||||
water.defaultLinearDrag = json.value("defaultLinearDrag", 0.1f);
|
||||
water.defaultAngularDrag = json.value("defaultAngularDrag", 0.05f);
|
||||
water.defaultBuoyancy = json.value("defaultBuoyancy", 1.5f);
|
||||
water.defaultLinearDrag = json.value("defaultLinearDrag", 0.5f);
|
||||
water.defaultAngularDrag = json.value("defaultAngularDrag", 0.01f);
|
||||
water.defaultSubmergedThreshold =
|
||||
json.value("defaultSubmergedThreshold", 0.3f);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user