Fixed water body presence physics

This commit is contained in:
2025-09-03 22:16:53 +03:00
parent aca04ff621
commit 1c56387c35
6 changed files with 249 additions and 18 deletions

View File

@@ -620,6 +620,8 @@ public:
void updateWorld(float delta)
{
mDynWorld->getBtWorld()->stepSimulation(delta, 4);
mDbgDraw->update();
ECS::update(delta);
}
void updateWater(float delta)

View File

@@ -3,6 +3,7 @@
#include <OgreBullet.h>
#include "GameData.h"
#include "CharacterModule.h"
#include "WaterModule.h"
#include "Components.h"
namespace ECS
{
@@ -191,7 +192,19 @@ CharacterModule::CharacterModule(flecs::world &ecs)
bool is_on_floor = false;
bool penetration = false;
Ogre::Vector3 gravity(0, -9.8, 0);
body.gvelocity += gravity * delta;
if (e.has<InWater>()) {
float full_subm = 2.0f;
float current_subm = -Ogre::Math::Clamp(
pos.y, -full_subm, 0.0f);
float b = 9.0 * current_subm / full_subm;
body.gvelocity +=
(gravity + Ogre::Vector3(0, b, 0)) *
delta;
body.gvelocity.y = Ogre::Math::Clamp(
body.gvelocity.y, -1.0f, 1.0f);
std::cout << "InWater!!!!!!!\n";
} else
body.gvelocity += gravity * delta;
velocity += body.gvelocity;
Ogre::Vector3 rotMotion = velocity * delta;
btVector3 currentPosition =
@@ -293,9 +306,8 @@ CharacterModule::CharacterModule(flecs::world &ecs)
inertia);
}
body.mGhostObject->setCollisionFlags(
btCollisionObject::CF_KINEMATIC_OBJECT |
btCollisionObject::
CF_NO_CONTACT_RESPONSE);
btCollisionObject::CF_KINEMATIC_OBJECT /*|
btCollisionObject::CF_NO_CONTACT_RESPONSE */);
body.mGhostObject->setActivationState(
DISABLE_DEACTIVATION);
eng.mWorld->attachCollisionObject(
@@ -459,6 +471,48 @@ CharacterModule::CharacterModule(flecs::world &ecs)
body.checkGround = false;
}
});
ecs.system<const WaterBody, const CharacterBase, CharacterBody>(
"CharacterWater1")
.kind(flecs::OnUpdate)
.with<Character>()
.without<InWater>()
.each([](flecs::entity e, const WaterBody &waterb,
const CharacterBase &ch, CharacterBody &body) {
if (waterb.mInWater.find(body.mGhostObject) !=
waterb.mInWater.end() &&
ch.mBodyNode->_getDerivedPosition().y < -0.05f) {
e.add<InWater>();
std::cout << "Big Splash\n";
}
#if 0
if (waterb.mInWater.find(body.mGhostObject) ==
waterb.mInWater.end())
e.add<InWater>();
std::cout << waterb.mInWater.size() << " InWater\n";
#endif
});
ecs.system<const WaterBody, const CharacterBase, CharacterBody>(
"CharacterWater2")
.kind(flecs::OnUpdate)
.with<Character>()
.with<InWater>()
.each([](flecs::entity e, const WaterBody &waterb,
const CharacterBase &ch, CharacterBody &body) {
if (waterb.mInWater.find(body.mGhostObject) ==
waterb.mInWater.end() &&
ch.mBodyNode->_getDerivedPosition().y > 0.05f)
e.remove<InWater>();
});
ecs.system<const EngineData, CharacterBase, CharacterBody>(
"DisplayPlayerPos")
.kind(flecs::OnUpdate)
.with<Character>()
.with<Player>()
.each([](const EngineData &eng, CharacterBase &ch,
CharacterBody &body) {
std::cout << "player: " << ch.mBodyNode->getPosition()
<< "\n";
});
}
void CharacterModule::setAnimation(AnimationControl &anim)

View File

@@ -46,5 +46,6 @@ struct Camera {
Ogre::SceneNode *mCameraGoal;
Ogre::Real mPivotPitch;
};
struct InWater {};
}
#endif

View File

@@ -15,6 +15,7 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
ecs.component<GameData>().add(flecs::Singleton);
ecs.component<Input>().add(flecs::Singleton);
ecs.component<Camera>().add(flecs::Singleton);
ecs.component<InWater>();
ecs.set<EngineData>({ scnMgr, world, 0.0f });
ecs.set<Camera>({ cameraNode, camera, false });
ecs.add<GameData>();
@@ -24,8 +25,8 @@ void setup(Ogre::SceneManager *scnMgr, Ogre::Bullet::DynamicsWorld *world,
.each([](EngineData &eng) {
eng.delta = ECS::get().delta_time();
});
ecs.import <CharacterModule>();
ecs.import <WaterModule>();
ecs.import <CharacterModule>();
}
void update(float delta)
{

View File

@@ -1,3 +1,4 @@
#include <iostream>
#include <Ogre.h>
#include <OgreColourValue.h>
#include <OgreShaderSubRenderState.h>
@@ -164,12 +165,23 @@ WaterModule::WaterModule(flecs::world &ecs)
texture_unit->setTextureFiltering(
Ogre::FT_MIP, Ogre::FO_LINEAR);
#if 0
bool success =
Ogre::RTShader::ShaderGenerator::getSingletonPtr()
->createShaderBasedTechnique(
*mat,
Ogre::MSN_DEFAULT,
Ogre::MSN_SHADERGEN);
OgreAssert(
success,
"createShaderBasedTechnique");
Ogre::RTShader::RenderState *renderState =
Ogre::RTShader::ShaderGenerator::
getSingletonPtr()
->createOrRetrieveRenderState(
Ogre::MSN_SHADERGEN)
.first;
->getRenderState(
Ogre::MSN_SHADERGEN,
*mat,
0);
Ogre::RTShader::SubRenderState *perPixelLightModel =
Ogre::RTShader::ShaderGenerator::getSingletonPtr()
->createSubRenderState(
@@ -283,26 +295,183 @@ WaterModule::WaterModule(flecs::world &ecs)
ecs.system<const EngineData, const WaterSurface, WaterBody>(
"UpdateWaterBody")
.kind(flecs::OnUpdate)
.each([](const EngineData &eng, const WaterSurface &water,
WaterBody &body) {
.each([this](const EngineData &eng, const WaterSurface &water,
WaterBody &body) {
int i;
if (!body.mWaterBody) {
body.mWaterBody = new btGhostObject;
btBoxShape *boxShape = new btBoxShape(
btVector3(1000, 1000, 1000));
btCompoundShape *shape = new btCompoundShape;
shape->addChildShape(
btTransform(btQuaternion(),
btVector3(0, -1000, 0)),
boxShape);
btBoxShape *boxShape1 = new btBoxShape(
btVector3(1000, 20, 1000));
btBoxShape *boxShape2 = new btBoxShape(
btVector3(1000, 100, 1000));
btBoxShape *boxShape3 = new btBoxShape(
btVector3(1000, 1000, 1000));
btTransform boxShapeXform1(btQuaternion(),
btVector3(0, -20.2f,
0));
btTransform boxShapeXform2(btQuaternion(),
btVector3(0, -120.2f,
0));
btTransform boxShapeXform3(
btQuaternion(),
btVector3(0, -1120.2f, 0));
shape->addChildShape(boxShapeXform1, boxShape1);
shape->addChildShape(boxShapeXform2, boxShape2);
shape->addChildShape(boxShapeXform3, boxShape3);
body.mWaterBody = new btPairCachingGhostObject;
body.mWaterBody->setCollisionShape(shape);
body.mWaterBody->setCollisionFlags(
body.mWaterBody->getCollisionFlags() |
btCollisionObject::CF_NO_CONTACT_RESPONSE |
btCollisionObject::CF_STATIC_OBJECT);
body.mWaterBody->setActivationState(
DISABLE_DEACTIVATION);
body.mWaterBody->getWorldTransform().setOrigin(
btVector3(0, 0, 0));
eng.mWorld->attachCollisionObject(
body.mWaterBody, water.mWaterEnt, 16,
0x7fffffff & ~2);
}
Ogre::Vector3 waterPos =
water.mWaterNode->_getDerivedPosition();
Ogre::Vector3 waterBodyPos = Ogre::Bullet::convert(
body.mWaterBody->getWorldTransform()
.getOrigin());
waterPos.y = 0;
waterBodyPos.y = 0;
Ogre::Vector3 d = waterPos - waterBodyPos;
d.y = 0;
std::cout << "aabb: "
<< Ogre::Bullet::convert(body.mShapeAabbMin)
<< " "
<< Ogre::Bullet::convert(body.mShapeAabbMax)
<< "\n";
// Ogre::Vector3 waterPosition = mCameraPos;
// mWaterNode->setPosition(waterPosition);
if (d.squaredLength() > 10.0f * 10.0f)
body.mWaterBody->getWorldTransform().setOrigin(
Ogre::Bullet::convert(waterBodyPos +
d));
std::cout
<< "node: " << water.mWaterNode->getPosition()
<< " body: "
<< Ogre::Bullet::convert(
body.mWaterBody->getWorldTransform()
.getOrigin())
<< "\n";
btCompoundShape *mshape =
static_cast<btCompoundShape *>(
body.mWaterBody->getCollisionShape());
body.mShapeAabbMin =
body.mWaterBody->getWorldTransform()
.getOrigin() +
btVector3(-1000, -1000, -1000);
body.mShapeAabbMax =
body.mWaterBody->getWorldTransform()
.getOrigin() +
btVector3(1000, -0.2, 1000);
#if 0
mshape->getChildShape(0)->getAabb(
body.mWaterBody->getWorldTransform() *
mshape->getChildTransform(0),
body.mShapeAabbMin, body.mShapeAabbMax);
#endif
btDispatcher *dispatch =
eng.mWorld->getBtWorld()->getDispatcher();
eng.mWorld->getBtWorld()->getBroadphase()->setAabb(
body.mWaterBody->getBroadphaseHandle(),
body.mShapeAabbMin, body.mShapeAabbMax,
eng.mWorld->getBtWorld()->getDispatcher());
dispatch->dispatchAllCollisionPairs(
body.mWaterBody->getOverlappingPairCache(),
eng.mWorld->getBtWorld()->getDispatchInfo(),
dispatch);
btBroadphasePairArray &collisionPairs =
body.mWaterBody->getOverlappingPairCache()
->getOverlappingPairArray();
std::set<btCollisionObject *> currentOverlaps;
std::set<btCollisionObject *>::iterator it;
const int numObjects = collisionPairs.size();
for (int i = 0; i < numObjects; i++) {
body.mManifoldArray.resize(0);
const btBroadphasePair &collisionPair =
collisionPairs[i];
if (collisionPair.m_algorithm)
collisionPair.m_algorithm
->getAllContactManifolds(
body.mManifoldArray);
for (int j = 0; j < body.mManifoldArray.size();
j++) {
btPersistentManifold *manifold =
body.mManifoldArray[j];
if (manifold->getNumContacts() == 0)
continue;
const btCollisionObject *obj =
(manifold->getBody0() ==
body.mWaterBody) ?
manifold->getBody1() :
manifold->getBody0();
btCollisionObject *nobj =
const_cast<btCollisionObject *>(
obj);
if (obj->getCollisionFlags() &
btCollisionObject::CF_STATIC_OBJECT)
continue;
bool ok = false;
Ogre::Vector3 contactPosA, contactPosB;
float minDist = 0.0f;
for (int p = 0;
p < manifold->getNumContacts();
p++) {
const btManifoldPoint &pt =
manifold->getContactPoint(
p);
float dist = pt.getDistance();
if (dist < minDist) {
minDist = dist;
std::cout
<< " distance: "
<< dist << "\n";
contactPosA = Ogre::Bullet::convert(
pt.getPositionWorldOnA());
contactPosB = Ogre::Bullet::convert(
pt.getPositionWorldOnB());
std::cout
<< "positionA: "
<< contactPosA
<< "\n";
std::cout
<< "positionB: "
<< contactPosA
<< "\n";
ok = true;
}
}
if (ok) {
currentOverlaps.insert(nobj);
if (body.mInWater.find(nobj) ==
body.mInWater.end()) {
/* new body */
body.mInWater.insert(
nobj);
/* calculate proj surface */
body.mSurface[nobj] =
100.0f;
}
}
}
}
for (it = body.mInWater.begin();
it != body.mInWater.end();) {
btCollisionObject *obj = *it;
if (currentOverlaps.find(obj) ==
currentOverlaps.end()) {
/* remove body */
it = body.mInWater.erase(it);
body.mSurface.erase(obj);
} else
it++;
}
});
}
void WaterSurface::RenderTextureListener::preRenderTargetUpdate(

View File

@@ -25,7 +25,11 @@ struct WaterSurface {
Ogre::Viewport *mViewports[2];
};
struct WaterBody {
btGhostObject *mWaterBody;
btPairCachingGhostObject *mWaterBody;
std::set<btCollisionObject *> mInWater;
std::unordered_map<btCollisionObject *, float> mSurface;
btManifoldArray mManifoldArray;
btVector3 mShapeAabbMin, mShapeAabbMax;
};
struct WaterModule {
WaterModule(flecs::world &ecs);