forked from mirror/openmw-tes3mp
More efficient water walking
This commit is contained in:
parent
04614651fa
commit
064f1964ba
10 changed files with 142 additions and 42 deletions
|
@ -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();
|
||||
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…
Reference in a new issue