More efficient water walking

deque
scrawl 10 years ago
parent 04614651fa
commit 064f1964ba

@ -541,6 +541,8 @@ namespace MWBase
/// Resets all actors in the current active cells to their original location within that cell. /// Resets all actors in the current active cells to their original location within that cell.
virtual void resetActors() = 0; virtual void resetActors() = 0;
virtual bool isWalkingOnWater (const MWWorld::Ptr& actor) = 0;
}; };
} }

@ -250,7 +250,6 @@ void RenderingManager::cellAdded (MWWorld::CellStore *store)
mObjects->buildStaticGeometry (*store); mObjects->buildStaticGeometry (*store);
sh::Factory::getInstance().unloadUnreferencedMaterials(); sh::Factory::getInstance().unloadUnreferencedMaterials();
mDebugging->cellAdded(store); mDebugging->cellAdded(store);
waterAdded(store);
} }
void RenderingManager::addObject (const MWWorld::Ptr& ptr){ void RenderingManager::addObject (const MWWorld::Ptr& ptr){
@ -421,18 +420,12 @@ void RenderingManager::postRenderTargetUpdate(const RenderTargetEvent &evt)
mOcclusionQuery->setActive(false); mOcclusionQuery->setActive(false);
} }
void RenderingManager::waterAdded (MWWorld::CellStore *store) void RenderingManager::setWaterEnabled(bool enable)
{ {
if (store->getCell()->mData.mFlags & ESM::Cell::HasWater) mWater->setActive(enable);
{
mWater->changeCell (store->getCell());
mWater->setActive(true);
}
else
removeWater();
} }
void RenderingManager::setWaterHeight(const float height) void RenderingManager::setWaterHeight(float height)
{ {
mWater->setHeight(height); mWater->setHeight(height);
} }

@ -100,7 +100,6 @@ public:
/// \todo this function should be removed later. Instead the rendering subsystems should track /// \todo this function should be removed later. Instead the rendering subsystems should track
/// when rebatching is needed and update automatically at the end of each frame. /// when rebatching is needed and update automatically at the end of each frame.
void cellAdded (MWWorld::CellStore *store); void cellAdded (MWWorld::CellStore *store);
void waterAdded(MWWorld::CellStore *store);
/// Clear all savegame-specific data (i.e. fog of war textures) /// Clear all savegame-specific data (i.e. fog of war textures)
void clear(); void clear();
@ -121,7 +120,8 @@ public:
/// Updates an object's rotation /// Updates an object's rotation
void rotateObject (const MWWorld::Ptr& ptr); void rotateObject (const MWWorld::Ptr& ptr);
void setWaterHeight(const float height); void setWaterHeight(float height);
void setWaterEnabled(bool enabled);
bool toggleWater(); bool toggleWater();
bool toggleWorld(); bool toggleWorld();

@ -278,8 +278,10 @@ namespace MWWorld
if (!ptr.getClass().canWalk(ptr) && !ptr.getClass().canFly(ptr) && !ptr.getClass().canSwim(ptr)) if (!ptr.getClass().canWalk(ptr) && !ptr.getClass().canFly(ptr) && !ptr.getClass().canSwim(ptr))
return position; return position;
/* Anything to collide with? */
OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
// Reset per-frame data
physicActor->setWalkingOnWater(false);
/* Anything to collide with? */
if(!physicActor || !physicActor->getCollisionMode()) if(!physicActor || !physicActor->getCollisionMode())
{ {
return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
@ -457,6 +459,8 @@ namespace MWWorld
{ {
standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName; standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName;
} }
if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Water)
physicActor->setWalkingOnWater(true);
newPosition.z = tracer.mEndPos.z + 1.0f; newPosition.z = tracer.mEndPos.z + 1.0f;
@ -485,7 +489,7 @@ namespace MWWorld
PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) :
mRender(_rend), mEngine(0), mTimeAccum(0.0f) mRender(_rend), mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0)
{ {
// Create physics. shapeLoader is deleted by the physic engine // Create physics. shapeLoader is deleted by the physic engine
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
@ -494,6 +498,8 @@ namespace MWWorld
PhysicsSystem::~PhysicsSystem() PhysicsSystem::~PhysicsSystem()
{ {
if (mWaterCollisionObject.get())
mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get());
delete mEngine; delete mEngine;
} }
@ -855,14 +861,8 @@ namespace MWWorld
Ogre::Vector3(iter->first.getRefData().getPosition().pos))) Ogre::Vector3(iter->first.getRefData().getPosition().pos)))
waterCollision = true; waterCollision = true;
btStaticPlaneShape planeShape(btVector3(0,0,1), waterlevel); OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(iter->first.getRefData().getHandle());
btCollisionObject object; physicActor->setCanWaterWalk(waterCollision);
object.setCollisionShape(&planeShape);
// TODO: this seems to have a slight performance impact
if (waterCollision)
mEngine->mDynamicsWorld->addCollisionObject(&object,
0xff, OEngine::Physic::CollisionType_Actor);
// 100 points of slowfall reduce gravity by 90% (this is just a guess) // 100 points of slowfall reduce gravity by 90% (this is just a guess)
float slowFall = 1-std::min(std::max(0.f, (effects.get(ESM::MagicEffect::SlowFall).getMagnitude() / 100.f) * 0.9f), 0.9f); float slowFall = 1-std::min(std::max(0.f, (effects.get(ESM::MagicEffect::SlowFall).getMagnitude() / 100.f) * 0.9f), 0.9f);
@ -871,9 +871,6 @@ namespace MWWorld
world->isFlying(iter->first), world->isFlying(iter->first),
waterlevel, slowFall, mEngine, mCollisions, mStandingCollisions); waterlevel, slowFall, mEngine, mCollisions, mStandingCollisions);
if (waterCollision)
mEngine->mDynamicsWorld->removeCollisionObject(&object);
float heightDiff = newpos.z - oldHeight; float heightDiff = newpos.z - oldHeight;
if (heightDiff < 0) if (heightDiff < 0)
@ -949,4 +946,48 @@ namespace MWWorld
} }
} }
void PhysicsSystem::disableWater()
{
if (mWaterEnabled)
{
mWaterEnabled = false;
updateWater();
}
}
void PhysicsSystem::enableWater(float height)
{
if (!mWaterEnabled || mWaterHeight != height)
{
mWaterEnabled = true;
mWaterHeight = height;
updateWater();
}
}
void PhysicsSystem::setWaterHeight(float height)
{
if (mWaterHeight != height)
{
mWaterHeight = height;
updateWater();
}
}
void PhysicsSystem::updateWater()
{
if (mWaterCollisionObject.get())
{
mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get());
}
if (!mWaterEnabled)
return;
mWaterCollisionObject.reset(new btCollisionObject());
mWaterCollisionShape.reset(new btStaticPlaneShape(btVector3(0,0,1), mWaterHeight));
mWaterCollisionObject->setCollisionShape(mWaterCollisionShape.get());
mEngine->mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), OEngine::Physic::CollisionType_Water,
OEngine::Physic::CollisionType_Actor);
}
} }

@ -1,6 +1,8 @@
#ifndef GAME_MWWORLD_PHYSICSSYSTEM_H #ifndef GAME_MWWORLD_PHYSICSSYSTEM_H
#define GAME_MWWORLD_PHYSICSSYSTEM_H #define GAME_MWWORLD_PHYSICSSYSTEM_H
#include <memory>
#include <OgreVector3.h> #include <OgreVector3.h>
#include <btBulletCollisionCommon.h> #include <btBulletCollisionCommon.h>
@ -32,6 +34,10 @@ namespace MWWorld
PhysicsSystem (OEngine::Render::OgreRenderer &_rend); PhysicsSystem (OEngine::Render::OgreRenderer &_rend);
~PhysicsSystem (); ~PhysicsSystem ();
void enableWater(float height);
void setWaterHeight(float height);
void disableWater();
void addObject (const MWWorld::Ptr& ptr, bool placeable=false); void addObject (const MWWorld::Ptr& ptr, bool placeable=false);
void addActor (const MWWorld::Ptr& ptr); void addActor (const MWWorld::Ptr& ptr);
@ -108,6 +114,8 @@ namespace MWWorld
private: private:
void updateWater();
OEngine::Render::OgreRenderer &mRender; OEngine::Render::OgreRenderer &mRender;
OEngine::Physic::PhysicEngine* mEngine; OEngine::Physic::PhysicEngine* mEngine;
std::map<std::string, std::string> handleToMesh; std::map<std::string, std::string> handleToMesh;
@ -124,6 +132,12 @@ namespace MWWorld
float mTimeAccum; float mTimeAccum;
float mWaterHeight;
float mWaterEnabled;
std::auto_ptr<btCollisionObject> mWaterCollisionObject;
std::auto_ptr<btCollisionShape> mWaterCollisionShape;
PhysicsSystem (const PhysicsSystem&); PhysicsSystem (const PhysicsSystem&);
PhysicsSystem& operator= (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&);
}; };

@ -238,6 +238,15 @@ namespace MWWorld
insertCell (*cell, true, loadingListener); insertCell (*cell, true, loadingListener);
mRendering.cellAdded (cell); mRendering.cellAdded (cell);
bool waterEnabled = cell->getCell()->hasWater();
mRendering.setWaterEnabled(waterEnabled);
if (waterEnabled)
{
mPhysics->enableWater(cell->getWaterLevel());
mRendering.setWaterHeight(cell->getWaterLevel());
}
else
mPhysics->disableWater();
mRendering.configureAmbient(*cell); mRendering.configureAmbient(*cell);
} }

@ -1660,6 +1660,7 @@ namespace MWWorld
void World::setWaterHeight(const float height) void World::setWaterHeight(const float height)
{ {
mPhysics->setWaterHeight(height);
mRendering->setWaterHeight(height); mRendering->setWaterHeight(height);
} }
@ -3071,4 +3072,12 @@ namespace MWWorld
cellstore->forEach(functor); cellstore->forEach(functor);
} }
} }
bool World::isWalkingOnWater(const Ptr &actor)
{
OEngine::Physic::PhysicActor* physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle());
if (physicActor && physicActor->isWalkingOnWater())
return true;
return false;
}
} }

@ -615,6 +615,8 @@ namespace MWWorld
/// Resets all actors in the current active cells to their original location within that cell. /// Resets all actors in the current active cells to their original location within that cell.
virtual void resetActors(); virtual void resetActors();
virtual bool isWalkingOnWater (const MWWorld::Ptr& actor);
}; };
} }

@ -74,6 +74,8 @@ namespace Physic
, mExternalCollisionMode(true) , mExternalCollisionMode(true)
, mForce(0.0f) , mForce(0.0f)
, mScale(scale) , mScale(scale)
, mWalkingOnWater(false)
, mCanWaterWalk(false)
{ {
if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation)) if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation))
{ {
@ -103,8 +105,7 @@ namespace Physic
setPosition(position); setPosition(position);
setRotation(rotation); setRotation(rotation);
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor, updateCollisionMask();
CollisionType_Actor|CollisionType_World|CollisionType_HeightMap|CollisionType_Projectile);
} }
PhysicActor::~PhysicActor() PhysicActor::~PhysicActor()
@ -123,10 +124,22 @@ namespace Physic
void PhysicActor::enableCollisionBody(bool collision) void PhysicActor::enableCollisionBody(bool collision)
{ {
assert(mBody); if (mExternalCollisionMode != collision)
if(collision && !mExternalCollisionMode) enableCollisionBody(); {
if(!collision && mExternalCollisionMode) disableCollisionBody(); mExternalCollisionMode = collision;
mExternalCollisionMode = collision; updateCollisionMask();
}
}
void PhysicActor::updateCollisionMask()
{
mEngine->mDynamicsWorld->removeRigidBody(mBody);
int collisionMask = CollisionType_World | CollisionType_HeightMap;
if (mExternalCollisionMode)
collisionMask |= CollisionType_Actor | CollisionType_Projectile;
if (mCanWaterWalk)
collisionMask |= CollisionType_Water;
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor, collisionMask);
} }
const Ogre::Vector3& PhysicActor::getPosition() const const Ogre::Vector3& PhysicActor::getPosition() const
@ -178,18 +191,23 @@ namespace Physic
mOnGround = grounded; mOnGround = grounded;
} }
void PhysicActor::disableCollisionBody() bool PhysicActor::isWalkingOnWater() const
{ {
mEngine->mDynamicsWorld->removeRigidBody(mBody); return mWalkingOnWater;
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
CollisionType_World|CollisionType_HeightMap);
} }
void PhysicActor::enableCollisionBody() void PhysicActor::setWalkingOnWater(bool walkingOnWater)
{ {
mEngine->mDynamicsWorld->removeRigidBody(mBody); mWalkingOnWater = walkingOnWater;
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor, }
CollisionType_Actor|CollisionType_World|CollisionType_HeightMap|CollisionType_Projectile);
void PhysicActor::setCanWaterWalk(bool waterWalk)
{
if (waterWalk != mCanWaterWalk)
{
mCanWaterWalk = waterWalk;
updateCollisionMask();
}
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

@ -47,7 +47,8 @@ namespace Physic
CollisionType_Actor = 1<<1, //<Collide sith actors CollisionType_Actor = 1<<1, //<Collide sith actors
CollisionType_HeightMap = 1<<2, //<collide with heightmap CollisionType_HeightMap = 1<<2, //<collide with heightmap
CollisionType_Raycasting = 1<<3, CollisionType_Raycasting = 1<<3,
CollisionType_Projectile = 1<<4 CollisionType_Projectile = 1<<4,
CollisionType_Water = 1<<5
}; };
/** /**
@ -131,9 +132,20 @@ namespace Physic
return mBody; return mBody;
} }
/// Sets whether this actor should be able to collide with the water surface
void setCanWaterWalk(bool waterWalk);
/// Sets whether this actor has been walking on the water surface in the last frame
void setWalkingOnWater(bool walkingOnWater);
bool isWalkingOnWater() const;
private: private:
void disableCollisionBody(); /// Removes then re-adds the collision body to the dynamics world
void enableCollisionBody(); void updateCollisionMask();
bool mCanWaterWalk;
bool mWalkingOnWater;
boost::shared_ptr<btCollisionShape> mShape; boost::shared_ptr<btCollisionShape> mShape;

Loading…
Cancel
Save