1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-03-29 19:36:43 +00:00

Restore ranged weapon aiming

This commit is contained in:
scrawl 2015-05-31 18:53:16 +02:00
parent 71bafcb52b
commit ed4863ad7d
8 changed files with 170 additions and 94 deletions

View file

@ -20,7 +20,7 @@ set(GAME_HEADER
source_group(game FILES ${GAME} ${GAME_HEADER}) source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
actors objects renderingmanager animation sky npcanimation vismask actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap bulletdebugdraw globalmap characterpreview camera localmap
# occlusionquery water shadows # occlusionquery water shadows

View file

@ -171,14 +171,16 @@ Resource::ResourceSystem *CreatureWeaponAnimation::getResourceSystem()
return mResourceSystem; return mResourceSystem;
} }
void CreatureWeaponAnimation::addControllers()
{
WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get());
}
osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration) osg::Vec3f CreatureWeaponAnimation::runAnimation(float duration)
{ {
osg::Vec3f ret = Animation::runAnimation(duration); osg::Vec3f ret = Animation::runAnimation(duration);
/* WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]);
if (mSkelBase)
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton());
*/
return ret; return ret;
} }

View file

@ -46,11 +46,13 @@ namespace MWRender
virtual void showWeapon(bool show) { showWeapons(show); } virtual void showWeapon(bool show) { showWeapons(show); }
virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); } virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); }
virtual void addControllers();
virtual osg::Vec3f runAnimation(float duration); virtual osg::Vec3f runAnimation(float duration);
/// A relative factor (0-1) that decides if and how much the skeleton should be pitched /// A relative factor (0-1) that decides if and how much the skeleton should be pitched
/// to indicate the facing orientation of the character. /// to indicate the facing orientation of the character.
//virtual void setPitchFactor(float factor) { mPitchFactor = factor; } virtual void setPitchFactor(float factor) { mPitchFactor = factor; }
private: private:

View file

@ -26,6 +26,7 @@
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "camera.hpp" #include "camera.hpp"
#include "rotatecontroller.hpp"
namespace namespace
{ {
@ -72,64 +73,6 @@ std::string getVampireHead(const std::string& race, bool female)
namespace MWRender namespace MWRender
{ {
/// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller.
/// The rotation is then applied on top of that orientation.
/// @note Must be set on a MatrixTransform.
class RotateController : public osg::NodeCallback
{
public:
RotateController(osg::Node* relativeTo)
: mEnabled(true)
, mRelativeTo(relativeTo)
{
}
void setEnabled(bool enabled)
{
mEnabled = enabled;
}
void setRotate(const osg::Quat& rotate)
{
mRotate = rotate;
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (!mEnabled)
return;
osg::MatrixTransform* transform = static_cast<osg::MatrixTransform*>(node);
osg::Matrix matrix = transform->getMatrix();
osg::Quat worldOrient = getWorldOrientation(node);
osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate();
matrix.setRotate(orient);
transform->setMatrix(matrix);
traverse(node,nv);
}
osg::Quat getWorldOrientation(osg::Node* node)
{
// this could be optimized later, we just need the world orientation, not the full matrix
osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo);
osg::Quat worldOrient;
if (!worldMats.empty())
{
osg::Matrixf worldMat = worldMats[0];
worldOrient = worldMat.getRotate();
}
return worldOrient;
}
protected:
bool mEnabled;
osg::Quat mRotate;
osg::ref_ptr<osg::Node> mRelativeTo;
};
/// Subclass RotateController to add a Z-offset for sneaking in first person mode. /// Subclass RotateController to add a Z-offset for sneaking in first person mode.
/// @note We use inheritance instead of adding another controller, so that we do not have to compute the worldOrient twice. /// @note We use inheritance instead of adding another controller, so that we do not have to compute the worldOrient twice.
/// @note Must be set on a MatrixTransform. /// @note Must be set on a MatrixTransform.
@ -710,17 +653,7 @@ osg::Vec3f NpcAnimation::runAnimation(float timepassed)
mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1))); mHeadController->setRotate(osg::Quat(mHeadPitchRadians, osg::Vec3f(1,0,0)) * osg::Quat(mHeadYawRadians, osg::Vec3f(0,0,1)));
} }
/* WeaponAnimation::configureControllers(mPtr.getRefData().getPosition().rot[0]);
if (mSkelBase)
{
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
if(mViewMode != VM_FirstPerson)
{
// In third person mode we may still need pitch for ranged weapon targeting
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst);
}
}
*/
return ret; return ret;
} }
@ -906,6 +839,8 @@ void NpcAnimation::addControllers()
{ {
mFirstPersonNeckController = NULL; mFirstPersonNeckController = NULL;
mHeadController = NULL; mHeadController = NULL;
WeaponAnimation::deleteControllers();
if (mViewMode == VM_FirstPerson) if (mViewMode == VM_FirstPerson)
{ {
NodeMap::iterator found = mNodeMap.find("bip01 neck"); NodeMap::iterator found = mNodeMap.find("bip01 neck");
@ -927,6 +862,8 @@ void NpcAnimation::addControllers()
node->addUpdateCallback(mHeadController); node->addUpdateCallback(mHeadController);
mActiveControllers.insert(std::make_pair(node, mHeadController)); mActiveControllers.insert(std::make_pair(node, mHeadController));
} }
WeaponAnimation::addControllers(mNodeMap, mActiveControllers, mObjectRoot.get());
} }
} }

View file

@ -0,0 +1,57 @@
#include "rotatecontroller.hpp"
#include <osg/MatrixTransform>
namespace MWRender
{
RotateController::RotateController(osg::Node *relativeTo)
: mEnabled(true)
, mRelativeTo(relativeTo)
{
}
void RotateController::setEnabled(bool enabled)
{
mEnabled = enabled;
}
void RotateController::setRotate(const osg::Quat &rotate)
{
mRotate = rotate;
}
void RotateController::operator()(osg::Node *node, osg::NodeVisitor *nv)
{
if (!mEnabled)
{
traverse(node, nv);
return;
}
osg::MatrixTransform* transform = static_cast<osg::MatrixTransform*>(node);
osg::Matrix matrix = transform->getMatrix();
osg::Quat worldOrient = getWorldOrientation(node);
osg::Quat orient = worldOrient * mRotate * worldOrient.inverse() * matrix.getRotate();
matrix.setRotate(orient);
transform->setMatrix(matrix);
traverse(node,nv);
}
osg::Quat RotateController::getWorldOrientation(osg::Node *node)
{
// this could be optimized later, we just need the world orientation, not the full matrix
osg::MatrixList worldMats = node->getWorldMatrices(mRelativeTo);
osg::Quat worldOrient;
if (!worldMats.empty())
{
osg::Matrixf worldMat = worldMats[0];
worldOrient = worldMat.getRotate();
}
return worldOrient;
}
}

View file

@ -0,0 +1,36 @@
#ifndef OPENMW_MWRENDER_ROTATECONTROLLER_H
#define OPENMW_MWRENDER_ROTATECONTROLLER_H
#include <osg/NodeCallback>
#include <osg/Quat>
namespace MWRender
{
/// Applies a rotation in \a relativeTo's space.
/// @note Assumes that the node being rotated has its "original" orientation set every frame by a different controller.
/// The rotation is then applied on top of that orientation.
/// @note Must be set on a MatrixTransform.
class RotateController : public osg::NodeCallback
{
public:
RotateController(osg::Node* relativeTo);
void setEnabled(bool enabled);
void setRotate(const osg::Quat& rotate);
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
protected:
osg::Quat getWorldOrientation(osg::Node* node);
bool mEnabled;
osg::Quat mRotate;
osg::ref_ptr<osg::Node> mRelativeTo;
};
}
#endif

View file

@ -1,5 +1,7 @@
#include "weaponanimation.hpp" #include "weaponanimation.hpp"
#include <osg/MatrixTransform>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
@ -15,6 +17,7 @@
#include "../mwmechanics/combat.hpp" #include "../mwmechanics/combat.hpp"
#include "animation.hpp" #include "animation.hpp"
#include "rotatecontroller.hpp"
namespace MWRender namespace MWRender
{ {
@ -46,6 +49,11 @@ WeaponAnimation::WeaponAnimation()
{ {
} }
WeaponAnimation::~WeaponAnimation()
{
}
void WeaponAnimation::attachArrow(MWWorld::Ptr actor) void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
{ {
MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor); MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
@ -149,28 +157,49 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor)
} }
} }
/* void WeaponAnimation::addControllers(const std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >& nodes,
void WeaponAnimation::pitchSkeleton(float xrot, Ogre::SkeletonInstance* skel) std::multimap<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback> > &map, osg::Node* objectRoot)
{ {
if (mPitchFactor == 0) for (int i=0; i<2; ++i)
{
mSpineControllers[i] = NULL;
std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >::const_iterator found = nodes.find(i == 0 ? "bip01 spine1" : "bip01 spine2");
if (found != nodes.end())
{
osg::Node* node = found->second;
mSpineControllers[i] = new RotateController(objectRoot);
node->addUpdateCallback(mSpineControllers[i]);
map.insert(std::make_pair(node, mSpineControllers[i]));
}
}
}
void WeaponAnimation::deleteControllers()
{
for (int i=0; i<2; ++i)
mSpineControllers[i] = NULL;
}
void WeaponAnimation::configureControllers(float characterPitchRadians)
{
if (!mSpineControllers[0])
return; return;
float pitch = xrot * mPitchFactor; if (mPitchFactor == 0.f || characterPitchRadians == 0.f)
Ogre::Node *node; {
for (int i=0; i<2; ++i)
mSpineControllers[i]->setEnabled(false);
return;
}
// In spherearcher.nif, we have spine, not Spine. Not sure if all bone names should be case insensitive? float pitch = characterPitchRadians * mPitchFactor;
if (skel->hasBone("Bip01 spine2")) osg::Quat rotate (pitch/2, osg::Vec3f(-1,0,0));
node = skel->getBone("Bip01 spine2"); for (int i=0; i<2; ++i)
else {
node = skel->getBone("Bip01 Spine2"); mSpineControllers[i]->setRotate(rotate);
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD); mSpineControllers[i]->setEnabled(true);
}
if (skel->hasBone("Bip01 spine1")) // in spherearcher.nif
node = skel->getBone("Bip01 spine1");
else
node = skel->getBone("Bip01 Spine1");
node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
} }
*/
} }

View file

@ -9,6 +9,8 @@
namespace MWRender namespace MWRender
{ {
class RotateController;
class WeaponAnimationTime : public SceneUtil::ControllerSource class WeaponAnimationTime : public SceneUtil::ControllerSource
{ {
private: private:
@ -28,7 +30,7 @@ namespace MWRender
{ {
public: public:
WeaponAnimation(); WeaponAnimation();
virtual ~WeaponAnimation() {} virtual ~WeaponAnimation();
/// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op.
void attachArrow(MWWorld::Ptr actor); void attachArrow(MWWorld::Ptr actor);
@ -36,9 +38,20 @@ namespace MWRender
/// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op. /// @note If no weapon (or an invalid weapon) is equipped, this function is a no-op.
void releaseArrow(MWWorld::Ptr actor); void releaseArrow(MWWorld::Ptr actor);
/// Add WeaponAnimation-related controllers to \a nodes and store the added controllers in \a map.
void addControllers(const std::map<std::string, osg::ref_ptr<osg::MatrixTransform> >& nodes,
std::multimap<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::NodeCallback> >& map, osg::Node* objectRoot);
void deleteControllers();
/// Configure controllers, should be called every animation frame.
void configureControllers(float characterPitchRadians);
protected: protected:
PartHolderPtr mAmmunition; PartHolderPtr mAmmunition;
osg::ref_ptr<RotateController> mSpineControllers[2];
virtual osg::Group* getArrowBone() = 0; virtual osg::Group* getArrowBone() = 0;
virtual osg::Node* getWeaponNode() = 0; virtual osg::Node* getWeaponNode() = 0;
virtual Resource::ResourceSystem* getResourceSystem() = 0; virtual Resource::ResourceSystem* getResourceSystem() = 0;