1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 18:19:55 +00:00

Apply third person camera distance to the camera node instead of only the camera itself (Fixes #1705)

This commit is contained in:
scrawl 2014-10-01 18:55:35 +02:00
parent f9b6cc468d
commit 85f5754bb6
6 changed files with 86 additions and 41 deletions

View file

@ -19,6 +19,7 @@ namespace MWRender
Camera::Camera (Ogre::Camera *camera)
: mCamera(camera),
mCameraNode(NULL),
mCameraPosNode(NULL),
mAnimation(NULL),
mFirstPersonView(true),
mPreviewMode(false),
@ -66,12 +67,16 @@ namespace MWRender
}
Ogre::Quaternion xr(Ogre::Radian(getPitch() + Ogre::Math::HALF_PI), Ogre::Vector3::UNIT_X);
if (!mVanity.enabled && !mPreviewMode) {
mCamera->getParentNode()->setOrientation(xr);
} else {
Ogre::Quaternion orient = xr;
if (mVanity.enabled || mPreviewMode) {
Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::UNIT_Z);
mCamera->getParentNode()->setOrientation(zr * xr);
orient = zr * xr;
}
if (isFirstPerson())
mCamera->getParentNode()->setOrientation(orient);
else
mCameraNode->setOrientation(orient);
}
const std::string &Camera::getHandle() const
@ -79,20 +84,40 @@ namespace MWRender
return mTrackingPtr.getRefData().getHandle();
}
void Camera::attachTo(const MWWorld::Ptr &ptr)
Ogre::SceneNode* Camera::attachTo(const MWWorld::Ptr &ptr)
{
mTrackingPtr = ptr;
Ogre::SceneNode *node = mTrackingPtr.getRefData().getBaseNode()->createChildSceneNode(Ogre::Vector3(0.0f, 0.0f, mHeight));
node->setInheritScale(false);
Ogre::SceneNode *posNode = node->createChildSceneNode();
posNode->setInheritScale(false);
if(mCameraNode)
{
node->setOrientation(mCameraNode->getOrientation());
node->setPosition(mCameraNode->getPosition());
node->setScale(mCameraNode->getScale());
posNode->setPosition(mCameraPosNode->getPosition());
mCameraNode->getCreator()->destroySceneNode(mCameraNode);
mCameraNode->getCreator()->destroySceneNode(mCameraPosNode);
}
mCameraNode = node;
if(!mCamera->isAttached())
mCameraNode->attachObject(mCamera);
mCameraPosNode = posNode;
if (!isFirstPerson())
{
mCamera->detachFromParent();
mCameraPosNode->attachObject(mCamera);
}
return mCameraPosNode;
}
void Camera::setPosition(const Ogre::Vector3& position)
{
mCameraPosNode->setPosition(position);
}
void Camera::setPosition(float x, float y, float z)
{
setPosition(Ogre::Vector3(x,y,z));
}
void Camera::updateListener()
@ -155,9 +180,9 @@ namespace MWRender
processViewChange();
if (mFirstPersonView) {
mCamera->setPosition(0.f, 0.f, 0.f);
setPosition(0.f, 0.f, 0.f);
} else {
mCamera->setPosition(0.f, 0.f, mCameraDistance);
setPosition(0.f, 0.f, mCameraDistance);
}
}
@ -191,14 +216,14 @@ namespace MWRender
Ogre::Vector3 rot(0.f, 0.f, 0.f);
if (mVanity.enabled) {
rot.x = Ogre::Degree(-30.f).valueRadians();
mMainCam.offset = mCamera->getPosition().z;
mMainCam.offset = mCameraPosNode->getPosition().z;
} else {
rot.x = getPitch();
offset = mMainCam.offset;
}
rot.z = getYaw();
mCamera->setPosition(0.f, 0.f, offset);
setPosition(0.f, 0.f, offset);
rotateCamera(rot, false);
return true;
@ -215,7 +240,7 @@ namespace MWRender
mPreviewMode = enable;
processViewChange();
float offset = mCamera->getPosition().z;
float offset = mCameraPosNode->getPosition().z;
if (mPreviewMode) {
mMainCam.offset = offset;
offset = mPreviewCam.offset;
@ -224,7 +249,7 @@ namespace MWRender
offset = mMainCam.offset;
}
mCamera->setPosition(0.f, 0.f, offset);
setPosition(0.f, 0.f, offset);
}
void Camera::setSneakOffset(float offset)
@ -283,7 +308,7 @@ namespace MWRender
float Camera::getCameraDistance() const
{
return mCamera->getPosition().z;
return mCameraPosNode->getPosition().z;
}
void Camera::setCameraDistance(float dist, bool adjust, bool override)
@ -295,7 +320,7 @@ namespace MWRender
Ogre::Vector3 v(0.f, 0.f, dist);
if (adjust) {
v += mCamera->getPosition();
v += mCameraPosNode->getPosition();
}
if (v.z >= mFurthest) {
v.z = mFurthest;
@ -305,7 +330,7 @@ namespace MWRender
v.z = mNearest;
mIsNearest = true;
}
mCamera->setPosition(v);
setPosition(v);
if (override) {
if (mVanity.enabled || mPreviewMode) {
@ -322,9 +347,9 @@ namespace MWRender
{
if (mDistanceAdjusted) {
if (mVanity.enabled || mPreviewMode) {
mCamera->setPosition(0, 0, mPreviewCam.offset);
setPosition(0, 0, mPreviewCam.offset);
} else if (!mFirstPersonView) {
mCamera->setPosition(0, 0, mCameraDistance);
setPosition(0, 0, mCameraDistance);
}
}
mDistanceAdjusted = false;
@ -355,10 +380,10 @@ namespace MWRender
Ogre::TagPoint *tag = mAnimation->attachObjectToBone("Head", mCamera);
tag->setInheritOrientation(false);
}
else
else
{
mAnimation->setViewMode(NpcAnimation::VM_Normal);
mCameraNode->attachObject(mCamera);
mCameraPosNode->attachObject(mCamera);
}
rotateCamera(Ogre::Vector3(getPitch(), 0.f, getYaw()), false);
}
@ -368,8 +393,7 @@ namespace MWRender
mCamera->getParentSceneNode()->needUpdate(true);
camera = mCamera->getRealPosition();
focal = Ogre::Vector3((mCamera->getParentNode()->_getFullTransform() *
Ogre::Vector4(0.0f, 0.0f, 0.0f, 1.0f)).ptr());
focal = mCameraNode->_getDerivedPosition();
}
void Camera::togglePlayerLooking(bool enable)

View file

@ -27,6 +27,7 @@ namespace MWRender
Ogre::Camera *mCamera;
Ogre::SceneNode *mCameraNode;
Ogre::SceneNode *mCameraPosNode;
NpcAnimation *mAnimation;
@ -52,6 +53,9 @@ namespace MWRender
/// Updates sound manager listener data
void updateListener();
void setPosition(const Ogre::Vector3& position);
void setPosition(float x, float y, float z);
public:
Camera(Ogre::Camera *camera);
~Camera();
@ -72,7 +76,7 @@ namespace MWRender
const std::string &getHandle() const;
/// Attach camera to object
void attachTo(const MWWorld::Ptr &);
Ogre::SceneNode* attachTo(const MWWorld::Ptr &);
/// @param Force view mode switch, even if currently not allowed by the animation.
void toggleViewMode(bool force=false);

View file

@ -312,7 +312,7 @@ void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr)
if(mPlayerAnimation)
mPlayerAnimation->updatePtr(ptr);
if(mCamera->getHandle() == ptr.getRefData().getHandle())
mCamera->attachTo(ptr);
attachCameraTo(ptr);
}
void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr)
@ -327,7 +327,7 @@ void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr)
anim->rebuild();
if(mCamera->getHandle() == ptr.getRefData().getHandle())
{
mCamera->attachTo(ptr);
attachCameraTo(ptr);
mCamera->setAnimation(anim);
}
}
@ -869,7 +869,13 @@ void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned i
void RenderingManager::setupPlayer(const MWWorld::Ptr &ptr)
{
ptr.getRefData().setBaseNode(mRendering.getScene()->getSceneNode("player"));
mCamera->attachTo(ptr);
attachCameraTo(ptr);
}
void RenderingManager::attachCameraTo(const MWWorld::Ptr &ptr)
{
Ogre::SceneNode* cameraNode = mCamera->attachTo(ptr);
mSkyManager->attachToNode(cameraNode);
}
void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr)

View file

@ -221,6 +221,8 @@ private:
void setAmbientMode();
void applyFog(bool underwater);
void attachCameraTo(const MWWorld::Ptr& ptr);
void setMenuTransparency(float val);
bool mSunEnabled;

View file

@ -382,9 +382,7 @@ void SkyManager::clearRain()
for (std::map<Ogre::SceneNode*, NifOgre::ObjectScenePtr>::iterator it = mRainModels.begin(); it != mRainModels.end();)
{
it->second.setNull();
Ogre::SceneNode* parent = it->first->getParentSceneNode();
mSceneMgr->destroySceneNode(it->first);
mSceneMgr->destroySceneNode(parent);
mRainModels.erase(it++);
}
}
@ -402,9 +400,7 @@ void SkyManager::updateRain(float dt)
if (pos.z < -minHeight)
{
it->second.setNull();
Ogre::SceneNode* parent = it->first->getParentSceneNode();
mSceneMgr->destroySceneNode(it->first);
mSceneMgr->destroySceneNode(parent);
mRainModels.erase(it++);
}
else
@ -420,17 +416,20 @@ void SkyManager::updateRain(float dt)
{
mRainTimer = 0;
// TODO: handle rain settings from Morrowind.ini
const float rangeRandom = 100;
float xOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2);
float yOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2);
Ogre::SceneNode* sceneNode = mCamera->getParentSceneNode()->createChildSceneNode();
sceneNode->setInheritOrientation(false);
// Create a separate node to control the offset, since a node with setInheritOrientation(false) will still
// consider the orientation of the parent node for its position, just not for its orientation
float startHeight = 700;
Ogre::SceneNode* offsetNode = sceneNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight));
Ogre::SceneNode* offsetNode = mParticleNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight));
// Spawn a new rain object for each instance.
// TODO: this is inefficient. We could try to use an Ogre::ParticleSystem instead, but then we would need to make assumptions
// about the rain meshes being Quads and their dimensions.
// Or we could clone meshes into one vertex buffer manually.
NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(offsetNode, mRainEffect);
for (unsigned int i=0; i<objects->mEntities.size(); ++i)
{
@ -562,12 +561,6 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
}
else
{
if (!mParticleNode)
{
mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode();
mParticleNode->setInheritOrientation(false);
}
mParticle = NifOgre::Loader::createObjects(mParticleNode, mCurrentParticleEffect);
for(size_t i = 0; i < mParticle->mParticles.size(); ++i)
{
@ -783,3 +776,16 @@ void SkyManager::setGlareEnabled (bool enabled)
return;
mSunGlare->setVisible (mSunEnabled && enabled);
}
void SkyManager::attachToNode(SceneNode *sceneNode)
{
if (!mParticleNode)
{
mParticleNode = sceneNode->createChildSceneNode();
mParticleNode->setInheritOrientation(false);
}
else
{
sceneNode->addChild(mParticleNode);
}
}

View file

@ -116,6 +116,9 @@ namespace MWRender
SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera);
~SkyManager();
/// Attach weather particle effects to this scene node (should be the Camera's parent node)
void attachToNode(Ogre::SceneNode* sceneNode);
void update(float duration);
void enable();