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

@ -100,7 +100,6 @@ public:
/// \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.
void cellAdded (MWWorld::CellStore *store);
void waterAdded(MWWorld::CellStore *store);
/// Clear all savegame-specific data (i.e. fog of war textures)
void clear();
@ -121,7 +120,8 @@ public:
/// Updates an object's rotation
void rotateObject (const MWWorld::Ptr& ptr);
void setWaterHeight(const float height);
void setWaterHeight(float height);
void setWaterEnabled(bool enabled);
bool toggleWater();
bool toggleWorld();

@ -278,8 +278,10 @@ namespace MWWorld
if (!ptr.getClass().canWalk(ptr) && !ptr.getClass().canFly(ptr) && !ptr.getClass().canSwim(ptr))
return position;
/* Anything to collide with? */
OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
// Reset per-frame data
physicActor->setWalkingOnWater(false);
/* Anything to collide with? */
if(!physicActor || !physicActor->getCollisionMode())
{
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;
}
if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Water)
physicActor->setWalkingOnWater(true);
newPosition.z = tracer.mEndPos.z + 1.0f;
@ -485,7 +489,7 @@ namespace MWWorld
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
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
@ -494,6 +498,8 @@ namespace MWWorld
PhysicsSystem::~PhysicsSystem()
{
if (mWaterCollisionObject.get())
mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get());
delete mEngine;
}
@ -855,14 +861,8 @@ namespace MWWorld
Ogre::Vector3(iter->first.getRefData().getPosition().pos)))
waterCollision = true;
btStaticPlaneShape planeShape(btVector3(0,0,1), waterlevel);
btCollisionObject object;
object.setCollisionShape(&planeShape);
// TODO: this seems to have a slight performance impact
if (waterCollision)
mEngine->mDynamicsWorld->addCollisionObject(&object,
0xff, OEngine::Physic::CollisionType_Actor);
OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(iter->first.getRefData().getHandle());
physicActor->setCanWaterWalk(waterCollision);
// 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);
@ -871,9 +871,6 @@ namespace MWWorld
world->isFlying(iter->first),
waterlevel, slowFall, mEngine, mCollisions, mStandingCollisions);
if (waterCollision)
mEngine->mDynamicsWorld->removeCollisionObject(&object);
float heightDiff = newpos.z - oldHeight;
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
#define GAME_MWWORLD_PHYSICSSYSTEM_H
#include <memory>
#include <OgreVector3.h>
#include <btBulletCollisionCommon.h>
@ -32,6 +34,10 @@ namespace MWWorld
PhysicsSystem (OEngine::Render::OgreRenderer &_rend);
~PhysicsSystem ();
void enableWater(float height);
void setWaterHeight(float height);
void disableWater();
void addObject (const MWWorld::Ptr& ptr, bool placeable=false);
void addActor (const MWWorld::Ptr& ptr);
@ -108,6 +114,8 @@ namespace MWWorld
private:
void updateWater();
OEngine::Render::OgreRenderer &mRender;
OEngine::Physic::PhysicEngine* mEngine;
std::map<std::string, std::string> handleToMesh;
@ -124,6 +132,12 @@ namespace MWWorld
float mTimeAccum;
float mWaterHeight;
float mWaterEnabled;
std::auto_ptr<btCollisionObject> mWaterCollisionObject;
std::auto_ptr<btCollisionShape> mWaterCollisionShape;
PhysicsSystem (const PhysicsSystem&);
PhysicsSystem& operator= (const PhysicsSystem&);
};

@ -238,6 +238,15 @@ namespace MWWorld
insertCell (*cell, true, loadingListener);
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);
}

@ -1660,6 +1660,7 @@ namespace MWWorld
void World::setWaterHeight(const float height)
{
mPhysics->setWaterHeight(height);
mRendering->setWaterHeight(height);
}
@ -3071,4 +3072,12 @@ namespace MWWorld
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.
virtual void resetActors();
virtual bool isWalkingOnWater (const MWWorld::Ptr& actor);
};
}

@ -74,6 +74,8 @@ namespace Physic
, mExternalCollisionMode(true)
, mForce(0.0f)
, mScale(scale)
, mWalkingOnWater(false)
, mCanWaterWalk(false)
{
if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation))
{
@ -103,8 +105,7 @@ namespace Physic
setPosition(position);
setRotation(rotation);
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
CollisionType_Actor|CollisionType_World|CollisionType_HeightMap|CollisionType_Projectile);
updateCollisionMask();
}
PhysicActor::~PhysicActor()
@ -123,10 +124,22 @@ namespace Physic
void PhysicActor::enableCollisionBody(bool collision)
{
assert(mBody);
if(collision && !mExternalCollisionMode) enableCollisionBody();
if(!collision && mExternalCollisionMode) disableCollisionBody();
mExternalCollisionMode = collision;
if (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
@ -178,18 +191,23 @@ namespace Physic
mOnGround = grounded;
}
void PhysicActor::disableCollisionBody()
bool PhysicActor::isWalkingOnWater() const
{
mEngine->mDynamicsWorld->removeRigidBody(mBody);
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
CollisionType_World|CollisionType_HeightMap);
return mWalkingOnWater;
}
void PhysicActor::enableCollisionBody()
void PhysicActor::setWalkingOnWater(bool walkingOnWater)
{
mEngine->mDynamicsWorld->removeRigidBody(mBody);
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
CollisionType_Actor|CollisionType_World|CollisionType_HeightMap|CollisionType_Projectile);
mWalkingOnWater = walkingOnWater;
}
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_HeightMap = 1<<2, //<collide with heightmap
CollisionType_Raycasting = 1<<3,
CollisionType_Projectile = 1<<4
CollisionType_Projectile = 1<<4,
CollisionType_Water = 1<<5
};
/**
@ -131,9 +132,20 @@ namespace Physic
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:
void disableCollisionBody();
void enableCollisionBody();
/// Removes then re-adds the collision body to the dynamics world
void updateCollisionMask();
bool mCanWaterWalk;
bool mWalkingOnWater;
boost::shared_ptr<btCollisionShape> mShape;

Loading…
Cancel
Save