some docs
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
# Buoyancy System Analysis
|
||||
|
||||
## Problem: Characters are not affected by buoyancy
|
||||
|
||||
After analyzing the code in `src/features/editScene`, I've identified several potential issues:
|
||||
|
||||
## 1. Character Gravity Factor Issue
|
||||
|
||||
**Root Cause**: Characters have gravity factor set to 0.0f by default.
|
||||
|
||||
In `CharacterSystem.cpp` line 163:
|
||||
```cpp
|
||||
m_physics->setGravityFactor(ch->GetBodyID(), 0.0f);
|
||||
```
|
||||
|
||||
This means characters won't sink into water naturally. The `BuoyancySystem` tries to handle this by setting gravity factor to 1.0f when characters are in water (line 127 in `BuoyancySystem.cpp`), but there may be timing or detection issues.
|
||||
|
||||
## 2. Broadphase Query Area Settings
|
||||
|
||||
The `broadphaseQuery` function in `physics.cpp` uses these settings:
|
||||
|
||||
```cpp
|
||||
JPH::AABox water_box(-JPH::Vec3(1000, 1000, 1000),
|
||||
JPH::Vec3(1000, 0.1f, 1000));
|
||||
water_box.Translate(JPH::Vec3(surface_point));
|
||||
```
|
||||
|
||||
Where `surface_point = position + Ogre::Vector3(0, -0.1f, 0)` (position is the water surface Y level).
|
||||
|
||||
**Dimensions**:
|
||||
- X: -1000 to 1000 (2000 units wide, centered at surface_point.x)
|
||||
- Y: -1000 to 0.1f (1000.1 units tall, but centered 0.1 units BELOW water surface)
|
||||
- Z: -1000 to 1000 (2000 units deep, centered at surface_point.z)
|
||||
|
||||
**Issue**: The water box extends 1000 units BELOW the surface point, but only 0.1 units ABOVE it. Since `surface_point` is 0.1 units below the actual water surface, the box effectively covers:
|
||||
- From 1000.1 units below water surface
|
||||
- To 0.0 units at water surface (not above it)
|
||||
|
||||
This means bodies need to be at or below the water surface to be detected.
|
||||
|
||||
## 3. Character Detection in Broadphase
|
||||
|
||||
Characters are `JPH::Character` objects, not regular dynamic bodies. The broadphase query filters for:
|
||||
- `BroadPhaseLayers::MOVING` layer
|
||||
- `Layers::MOVING` object layer
|
||||
|
||||
Characters should be in these layers, but there may be issues with how character bodies are registered in the broadphase.
|
||||
|
||||
## 4. Debugging Approach
|
||||
|
||||
### 4.1 Enable Debug Logging
|
||||
|
||||
Modify `BuoyancySystem.cpp` to add debug logging:
|
||||
|
||||
```cpp
|
||||
// In update() method, after broadphaseQuery call:
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"BuoyancySystem: Found " + Ogre::StringConverter::toString(m_bodiesInWater.size()) +
|
||||
" bodies in water");
|
||||
|
||||
// In the loop applying buoyancy:
|
||||
for (JPH::BodyID bodyID : m_bodiesInWater) {
|
||||
Ogre::SceneNode *node = m_physics->getSceneNodeFromBodyID(bodyID);
|
||||
if (node) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Body " + Ogre::StringConverter::toString(bodyID.GetIndex()) +
|
||||
" at position: " + Ogre::StringConverter::toString(m_physics->getPosition(bodyID)));
|
||||
}
|
||||
|
||||
// Check if it's a character
|
||||
if (m_physics->bodyIsCharacter(bodyID)) {
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Body " + Ogre::StringConverter::toString(bodyID.GetIndex()) + " is a character");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Visual Debugging - Draw Water Box
|
||||
|
||||
Add debug rendering to visualize the water detection area:
|
||||
|
||||
```cpp
|
||||
// In BuoyancySystem::update(), after broadphaseQuery:
|
||||
void drawDebugWaterBox(const Ogre::Vector3& waterSurfacePos) {
|
||||
// Create a manual object to visualize the water box
|
||||
static Ogre::ManualObject* waterBoxDebug = nullptr;
|
||||
if (!waterBoxDebug) {
|
||||
waterBoxDebug = m_sceneManager->createManualObject("WaterBoxDebug");
|
||||
Ogre::SceneNode* debugNode = m_sceneManager->getRootSceneNode()->createChildSceneNode();
|
||||
debugNode->attachObject(waterBoxDebug);
|
||||
}
|
||||
|
||||
waterBoxDebug->clear();
|
||||
waterBoxDebug->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_LINE_LIST);
|
||||
|
||||
// Water box dimensions (matching broadphaseQuery)
|
||||
float halfSize = 1000.0f;
|
||||
float top = waterSurfacePos.y - 0.1f + 0.1f; // surface_point.y + 0.1f
|
||||
float bottom = waterSurfacePos.y - 0.1f - 1000.0f; // surface_point.y - 1000.0f
|
||||
|
||||
// Draw box edges
|
||||
Ogre::Vector3 corners[8] = {
|
||||
{waterSurfacePos.x - halfSize, bottom, waterSurfacePos.z - halfSize},
|
||||
{waterSurfacePos.x + halfSize, bottom, waterSurfacePos.z - halfSize},
|
||||
{waterSurfacePos.x + halfSize, bottom, waterSurfacePos.z + halfSize},
|
||||
{waterSurfacePos.x - halfSize, bottom, waterSurfacePos.z + halfSize},
|
||||
{waterSurfacePos.x - halfSize, top, waterSurfacePos.z - halfSize},
|
||||
{waterSurfacePos.x + halfSize, top, waterSurfacePos.z - halfSize},
|
||||
{waterSurfacePos.x + halfSize, top, waterSurfacePos.z + halfSize},
|
||||
{waterSurfacePos.x - halfSize, top, waterSurfacePos.z + halfSize}
|
||||
};
|
||||
|
||||
// Bottom square
|
||||
for (int i = 0; i < 4; i++) {
|
||||
waterBoxDebug->position(corners[i]);
|
||||
waterBoxDebug->position(corners[(i+1)%4]);
|
||||
}
|
||||
|
||||
// Top square
|
||||
for (int i = 4; i < 8; i++) {
|
||||
waterBoxDebug->position(corners[i]);
|
||||
waterBoxDebug->position(corners[4 + (i-3)%4]);
|
||||
}
|
||||
|
||||
// Vertical edges
|
||||
for (int i = 0; i < 4; i++) {
|
||||
waterBoxDebug->position(corners[i]);
|
||||
waterBoxDebug->position(corners[i+4]);
|
||||
}
|
||||
|
||||
waterBoxDebug->end();
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 Check Character Position Relative to Water
|
||||
|
||||
Add a debug function to check character positions:
|
||||
|
||||
```cpp
|
||||
void debugCharacterPositions() {
|
||||
m_world.query<CharacterComponent, TransformComponent>().each(
|
||||
[&](flecs::entity entity, CharacterComponent &cc, TransformComponent &transform) {
|
||||
if (transform.node) {
|
||||
Ogre::Vector3 worldPos = transform.node->_getDerivedPosition();
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Character entity " + Ogre::StringConverter::toString(entity.id()) +
|
||||
" at Y: " + Ogre::StringConverter::toString(worldPos.y));
|
||||
|
||||
// Check if character has physics body
|
||||
auto it = m_states.find(entity.id());
|
||||
if (it != m_states.end() && it->second.character) {
|
||||
JPH::BodyID bodyID = it->second.character->GetBodyID();
|
||||
Ogre::Vector3 bodyPos = m_physics->getPosition(bodyID);
|
||||
Ogre::LogManager::getSingleton().logMessage(
|
||||
"Character body at Y: " + Ogre::StringConverter::toString(bodyPos.y) +
|
||||
", gravity factor: " + Ogre::StringConverter::toString(m_physics->getGravityFactor(bodyID)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Recommended Fixes
|
||||
|
||||
### 5.1 Adjust Water Box Parameters
|
||||
|
||||
The current water box may be too shallow (only 0.1 units at the top). Consider adjusting:
|
||||
|
||||
```cpp
|
||||
// In broadphaseQuery function:
|
||||
JPH::AABox water_box(-JPH::Vec3(1000, 1.0f, 1000), // Increased from 0.1f to 1.0f
|
||||
JPH::Vec3(1000, 1000, 1000)); // Symmetrical above/below
|
||||
```
|
||||
|
||||
This creates a 2-unit tall detection area centered on the surface point.
|
||||
|
||||
### 5.2 Fix Character Gravity Handling
|
||||
|
||||
Modify `BuoyancySystem::update()` to better handle character gravity:
|
||||
|
||||
```cpp
|
||||
// Current issue: characters with gravity factor 0 won't sink into water
|
||||
// Even if buoyancy is applied, they need gravity to sink first
|
||||
|
||||
// Potential fix: Always give characters some minimal gravity when near water
|
||||
// or modify CharacterSystem to not set gravity factor to 0
|
||||
```
|
||||
|
||||
### 5.3 Verify Character Body Registration
|
||||
|
||||
Ensure character bodies are properly registered in the physics system and included in broadphase queries. Check that:
|
||||
1. Characters are added to the physics system (`ch->AddToPhysicsSystem()`)
|
||||
2. They are in the `MOVING` broadphase layer
|
||||
3. Their body IDs are valid for queries
|
||||
|
||||
## 6. Testing Procedure
|
||||
|
||||
1. **Enable debug logging** as shown above
|
||||
2. **Place a character in water** (Y position below water surface)
|
||||
3. **Check console output** for:
|
||||
- Number of bodies detected in water
|
||||
- Character body positions
|
||||
- Gravity factor changes
|
||||
4. **Use visual debug** to see water box
|
||||
5. **Adjust water surface Y** in WaterPhysics component to ensure it's above character position
|
||||
|
||||
## 7. Water Physics Settings
|
||||
|
||||
Default `WaterPhysics` component has:
|
||||
- `waterSurfaceY = -0.1f` (slightly below origin)
|
||||
- `defaultBuoyancy = 1.0f` (neutral buoyancy)
|
||||
- `enabled = true`
|
||||
|
||||
Make sure:
|
||||
1. WaterPhysics entity exists (BuoyancySystem creates one if missing)
|
||||
2. `waterSurfaceY` is above character positions for testing
|
||||
3. Water physics is enabled (`enabled = true`)
|
||||
Reference in New Issue
Block a user