forked from teamnwah/openmw-tes3coop
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.
|
/// 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…
Reference in a new issue