点击鼠标实现对模型的移动,旋转功能,需要用到漫游器。在实现的过程中的需要用到osgGA模块的知识,
重写osgGA下的该函数virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);
可以实现对模型的操作。
1、模型的移动:
static Matrixd translate (const Vec3f &dv)
2、模型的缩放
static Matrixd scale (const Vec3f &sv)
3、模型的旋转
static Matrixd rotate (const Vec3f &from, const Vec3f &to)
4、可以直接用MatrixTransform操作矩阵,来控制模型的平移、缩放和旋转
osg::ref_ptr mt = new osg::MatrixTransform;
osg::ref_ptr cow= osgDB::readNodeFile("cow.osg");
mt->addChild(cow);
//先向x轴移动30, 绕x轴旋转90度, 再缩放到原来的0.2倍
mt->setMatrix(osg::Matrix::translate(osg::Vec3(30, 0, 0)) *
osg::Matrix::rotate(90, osg::Vec3d(1, 0, 0)) *
osg::Matrix::scale(osg::Vec3(0.2, 0.2, 0.2)) );
如何实现?
可以通过按W、A、S 、D去实现模型的移动,可以按鼠标左键进行物体位置的拖移,按鼠标右键拖移可以实现物体的旋转。
在实现的过程有一个屏幕坐标向世界坐标转换的过程。以下部分代码的函数和变量并未有用到。
#include "stdafx.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class TravelManipulator :public osgGA::CameraManipulator
{
public:
TravelManipulator();
~TravelManipulator();
public:
//设置当前视口
virtual void setByMatrix(const osg::Matrixd&matrix);
//设置当前视口
virtual void setByInverseMatrix(const osg::Matrixd&matrix);
//得到当前矩阵
virtual osg::Matrixd getMatrix() const;
//得到当前矩阵
virtual osg::Matrixd getInverseMatrix() const;
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);
osg::Vec3 screen2World(float x, float y);
private:
//视点
osg::Vec3 mPosition;
//朝向
osg::Vec3 mRotation;
osg::ref_ptr view;
bool lbuttonDown;
bool m_rButtonDown;
float m_leftX;
float m_leftY;
float m_leftZ;
float m_rightX;
float m_rightY;
float m_rightZ;
};
TravelManipulator::TravelManipulator()
{
mPosition = osg::Vec3(0, 0, 50);
mRotation = osg::Vec3(0, 0, 0);
m_rButtonDown = false;
lbuttonDown = false;
m_leftX = 0;
m_leftY = 0;
m_rightX = 0;
m_rightY = 0;
}
TravelManipulator::~TravelManipulator()
{
}
void TravelManipulator::setByMatrix(const osg::Matrixd&matrix)
{
}
void TravelManipulator::setByInverseMatrix(const osg::Matrixd&matrix)
{
}
osg::Matrixd TravelManipulator::getMatrix() const
{
osg::Matrixd mat;
mat.makeTranslate(mPosition);
return mat*osg::Matrixd::rotate(mRotation[0], osg::X_AXIS, mRotation[1], osg::Y_AXIS, mRotation[2], osg::Z_AXIS);
}
osg::Matrixd TravelManipulator::getInverseMatrix() const
{
osg::Matrixd mat;
mat.makeTranslate(mPosition);
return osg::Matrixd::inverse(mat*osg::Matrixd::rotate(mRotation[0], osg::X_AXIS, mRotation[1], osg::Y_AXIS, mRotation[2], osg::Z_AXIS));
}
bool TravelManipulator::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us)
{
view = dynamic_cast(&us);
if (!view)return false;
switch (ea.getEventType()) {
case osgGA::GUIEventAdapter::KEYDOWN:
if (ea.getKey() == 'w') {
mPosition[2] += 2;
}
else if (ea.getKey() == 's') {
mPosition[2] -= 2;
}
else if (ea.getKey() == 'a') {
mPosition[0] -= 2;
}
else if (ea.getKey() == 'd') {
mPosition[0] += 2;
}
break;
case osgGA::GUIEventAdapter::PUSH:
{
if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
osg::Vec3 vec1 = screen2World(ea.getX(), ea.getY());
/*m_leftX = ea.getX();
m_leftY = ea.getY();*/
m_leftZ = vec1.z();
m_leftX = vec1.x();
m_leftY = vec1.y();
lbuttonDown = true;
}
if (ea.getButton()==osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
{
m_rightX = ea.getX();
m_rightY = ea.getY();
m_rButtonDown = true;
}
return false;
}
case osgGA::GUIEventAdapter::DRAG:
{
if (lbuttonDown)
{
osg::Vec3 vec1 = screen2World(ea.getX(), ea.getY());
float ix = vec1.x() - m_leftX;
float iy = vec1.y() - m_leftY;
float iz = vec1.z() - m_leftZ;
mPosition[2] += 0.1*iz;
mPosition[1] -= 0.1*iy;
mPosition[0] -= 0.1*ix;
}
if (m_rButtonDown)
{
float ix = ea.getX() - m_rightX;
float iy = ea.getY() - m_rightY;
mRotation[2] += osg::DegreesToRadians(0.1*ix);
mRotation[0] -= osg::DegreesToRadians(0.1*iy);
}
return false;
}
case osgGA::GUIEventAdapter::RELEASE:
{
if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
lbuttonDown = false;
}
if (ea.getButton() == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
{
m_rButtonDown = false;
}
}
default:
break;
}
return false;
}
osg::Vec3 TravelManipulator::screen2World(float x, float y)
{
osg::Vec3 vec3;
osg::ref_ptr camera = view->getCamera();
osg::Vec3 vScreen(x, y, 0);
osg::Matrix mVPW = camera->getViewMatrix() * camera->getProjectionMatrix() * camera->getViewport()->computeWindowMatrix();
osg::Matrix invertVPW;
invertVPW.invert(mVPW);
vec3 = vScreen * invertVPW;
return vec3;
}
int main(int argc, char** argv)
{
osg::ref_ptr viewer = new osgViewer::Viewer();
viewer->addEventHandler(new osgViewer::WindowSizeHandler);
viewer->addEventHandler(new osgViewer::StatsHandler);
osg::ref_ptr root = new osg::Group;
root->addChild(osgDB::readNodeFile("cow.osg"));
viewer->setSceneData(root);
viewer->setCameraManipulator(new TravelManipulator());
viewer->realize();
viewer->run();
return 0;
}
注意:mat 放置前后位置不同,会出现不同的现象
mat*osg::Matrixd::rotate(mRotation[0], osg::X_AXIS, mRotation[1], osg::Y_AXIS, mRotation[2], osg::Z_AXIS);