肖鹏的CSouth漫游器 详解

 肖鹏的CSouth漫游器 详解:

下图是初始的Opengl坐标系,及相机右转,并往前走时的分析:

上图中,当按下右箭头时,相机向右转,此时vRotation[2]由0变为-10,即上图的下半部分绕Z轴旋转了-10度,vRotation[2]=-10,图中角度A=90-10=90+ vRotation[2],此时ES=m_fMoveSpeed,M为S在X 轴上的投影点,SM=ES*Sin(A)= ES*Sin(90+ vRotation[2]),EM=ES*Cos(A)=ES*Cos(90+ vRotation[2]),故当按下相机往前走的键时,实际SE往前走的距离投影到Opengl的X、Y轴上的距离分别为EM、SM(注意视线方向D与Y轴平行),视点的坐标增量为(EM,SM,0)=( ES*Cos(90+ vRotation[2]), ES*Sin(90+ vRotation[2]),0),也即下面代码中的:

ChangePosition(osg::Vec3 (0, m_fMoveSpeed*sinf(osg::PI_2+m_vRotation._v[2]),0));

ChangePosition(osg::Vec3 (m_fMoveSpeed*cosf(osg::PI_2+m_vRotation._v[2]),0,0));

――――――――――――――――

完整源代码(3个文件:“ManipulatorTravel.h”,“TravelManipulator.cpp”,“cjmy.cpp”):

1.  “ManipulatorTravel.h”:

#pragma once

#include <osgViewer/Viewer>

#include <osg/LineSegment>

#include <osg/Point>

#include <osg/Geometry>

#include <osg/Node>

#include <osg/Geode>

#include <osg/Group>

#include <osgGA/MatrixManipulator>

#include <osgUtil/IntersectVisitor>

#include <vector>

class TravelManipulator :public osgGA::MatrixManipulator

{public:   TravelManipulator();

          ~TravelManipulator(void);

          static TravelManipulator* TravelToScene(osg::ref_ptr<osgViewer::Viewer> viewer);

 

private:

    osg::ref_ptr<osgViewer::Viewer> m_pHostViewer;

    float m_fMoveSpeed;

    osg::Vec3 m_vPosition;//相机的坐标

    osg::Vec3 m_vRotation;//分别绕X、Y、Z轴旋转的角度

 

public:

    bool m_bLeftButtonDown  ;

    float m_fpushY;//鼠标在屏幕中的坐标

   float m_fpushX;

 

    virtual void setByMatrix(const osg::Matrixd& matrix);

    virtual void setByInverseMatrix(const osg::Matrixd& matrix);

    virtual osg::Matrixd getMatrix(void) const;

    virtual osg::Matrixd getInverseMatrix(void)const;

 

    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us);

 

    float m_fAngle;

    void ChangePosition(osg::Vec3& delta);

 

 

    bool m_bPeng;

    float getSpeed();

    void setSpeed(float &);

    void SetPosition(osg::Vec3 &position);

    osg::Vec3 GetPosition();

};

――――――――――――

2.  “TravelManipulator.cpp”:

#include "stdafx.h"

#include "ManipulatorTravel.h"

TravelManipulator::TravelManipulator():m_fMoveSpeed(1.0f)

,m_bLeftButtonDown(false)

,m_fpushX(0)

,m_fAngle(2.5)

,m_bPeng(true)

,m_fpushY(0)

{   m_vPosition = osg::Vec3(-22.0f,-274.0f,100.0f);//相机位置

    m_vRotation = osg::Vec3(osg::PI_2,0.0f,0.0f);

//初始将视点坐标系绕X轴旋转90度

}

TravelManipulator::~TravelManipulator()

{}

TravelManipulator * TravelManipulator::TravelToScene(osg::ref_ptr<osgViewer::Viewer> viewer)

{   TravelManipulator* camera = new TravelManipulator;

    viewer->setCameraManipulator(camera);

//viewer中添加的相机操作器为当前TravelManipulator对象  

    camera->m_pHostViewer = viewer;//保存viewer

    return camera;

}

void TravelManipulator::setByMatrix(const osg::Matrixd& matrix)

{}

void TravelManipulator::setByInverseMatrix(const osg::Matrixd& matrix)

{}

osg::Matrixd TravelManipulator::getMatrix(void) const

{   osg::Matrixd mat;

    mat.makeRotate(m_vRotation._v[0],osg::Vec3(1.0f,0.0f,0.0f),

       m_vRotation._v[1],osg::Vec3(0.0f,1.0f,0.0f),

       m_vRotation._v[2],osg::Vec3(0.0f,0.0f,1.0f));

//先后绕Z、Y、X轴旋转对应的角度

 

    return mat * osg::Matrixd::translate(m_vPosition);

//先平移视点坐标系,再旋转

}

osg::Matrixd TravelManipulator::getInverseMatrix(void) const

{   osg::Matrixd mat;

    mat.makeRotate(m_vRotation._v[0],osg::Vec3(1.0f,0.0f,0.0f),

       m_vRotation._v[1],osg::Vec3(0.0f,1.0f,0.0f),

       m_vRotation._v[2],osg::Vec3(0.0f,0.0f,1.0f));

return osg::Matrixd::inverse(mat * osg::Matrixd::translate(m_vPosition));

//上一函数的逆,也是最终被调用的逆矩阵

}

bool TravelManipulator::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us)

{   float mouseX = ea.getX();

    float mouseY = ea.getY();

    switch(ea.getEventType())

    {case(osgGA::GUIEventAdapter::KEYDOWN):

       {   if(ea.getKey() == 0x20)

           {  us.requestRedraw();

              us.requestContinuousUpdate(false);

              return true;

           }

           if(ea.getKey() == 0xFF50) //相机向上移动

           {  ChangePosition(osg::Vec3(0,0,m_fMoveSpeed));

              return true;

           }

           if(ea.getKey() == 0xFF57)

           {  ChangePosition(osg::Vec3(0,0,-m_fMoveSpeed));

              return true;

           }

           if(ea.getKey() == 0x2B)

           {  m_fMoveSpeed += 1.0f;

              return true;

           }

           if(ea.getKey() == 0x2D)

           {  m_fMoveSpeed -= 1.0f;

              if(m_fMoveSpeed < 1.0f)

              {  m_fMoveSpeed = 1.0f;

              }

              return true;

           }

           if(ea.getKey() == 0xFF52 || ea.getKey() == 0x57 || ea.getKey() == 0x77)//up,则相机往前走

           {   ChangePosition(osg::Vec3 (0, m_fMoveSpeed*sinf(osg::PI_2+m_vRotation._v[2]),0));

 

              ChangePosition(osg::Vec3 (m_fMoveSpeed*cosf(osg::PI_2+m_vRotation._v[2]),0,0));

              return true;

           }

 

           if(ea.getKey() == 0xFF54 || ea.getKey() == 0x53 || ea.getKey() == 0x73)//down

           {              ChangePosition(osg::Vec3(0,-m_fMoveSpeed*sinf(osg::PI_2+m_vRotation._v[2]),0));             ChangePosition(osg::Vec3(-m_fMoveSpeed*cosf(osg::PI_2+m_vRotation._v[2]),0,0));

              return true;

           }

           if(ea.getKey() == 0x41 || ea.getKey() == 0x61)

           {

              ChangePosition(osg::Vec3 (0,m_fMoveSpeed*cosf(osg::PI_2+m_vRotation._v[2]),0));

              ChangePosition(osg::Vec3 (-m_fMoveSpeed*sinf(osg::PI_2+m_vRotation._v[2]),0,0));

              return true;

           }

           if(ea.getKey() ==  0x44||ea.getKey() == 0x64)

           {   ChangePosition(osg::Vec3 (0,-m_fMoveSpeed*cosf(osg::PI_2+m_vRotation._v[2]),0));

              ChangePosition(osg::Vec3 (m_fMoveSpeed*sinf(osg::PI_2+m_vRotation._v[2]),0,0));

              return true;

           }

           if(ea.getKey() == 0xFF53)//按下右箭头,则相机向右转

           {   m_vRotation._v[2]-=osg::DegreesToRadians(m_fAngle);

//绕Z轴旋转的角度减小,如由0变为-10

           }

           if(ea.getKey() == 0xFF51)

           {   m_vRotation._v[2] += osg::DegreesToRadians(m_fAngle);

           }

           if(ea.getKey() == 0x46 || ea.getKey() == 0x66)//F

           {   m_fAngle -= 0.2;

              return true;

           }

           if(ea.getKey() == 0x47 || ea.getKey() == 0x67)//G

           {   m_fAngle += 0.2;

              return true;

           }

 

           return false;

           }

           case(osgGA::GUIEventAdapter::PUSH):

              if(ea.getButton() == 1)

              {   m_fpushX = mouseX;

                  m_fpushY = mouseY;

                  m_bLeftButtonDown = true;

              }            

              return false;

 

              case(osgGA::GUIEventAdapter::DRAG):

                  if(m_bLeftButtonDown)

                  {//水平旋转相机,跟按下左、右箭头来旋转相机一样

                     m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle * (mouseX-m_fpushX));

                     m_vRotation._v[0] += osg::DegreesToRadians(1.1*(mouseY-m_fpushY));

//俯、仰角度(即抬头、低头,绕X 轴旋转):初始为90度,表示在OSG坐标下垂直平面向里看;完全低头为0,完全仰头为180度(即弧度3.14);且不能往后看。

                     if(m_vRotation._v[0] >= 3.14)

                     {   m_vRotation._v[0] = 3.14;

                     }

                     if(m_vRotation._v[0] <= 0)

                     {   m_vRotation._v[0] = 0;

                     }

                  }

                  return false;

              case(osgGA::GUIEventAdapter::RELEASE):

                  if(ea.getButton() ==1)

                  {   m_bLeftButtonDown = false;

                  }

                  return false;

              default:

                  return false;

              }

}

void TravelManipulator::ChangePosition(osg::Vec3& delta)

{   if(m_bPeng)

    {   osg::Vec3 newPosl = m_vPosition + delta;

       osgUtil::IntersectVisitor ivXY;

       osg::ref_ptr<osg::LineSegment> lineXY = new osg::LineSegment(newPosl, m_vPosition);

       osg::ref_ptr<osg::LineSegment> lineZ = new osg::LineSegment(newPosl+osg::Vec3(0.0f,0.0f,

           10.0f),newPosl-osg::Vec3(0.0f,0.0f,-10.0f));

       ivXY.addLineSegment(lineZ.get());

       ivXY.addLineSegment(lineXY.get());

       m_pHostViewer->getSceneData()->accept(ivXY);

       if(!ivXY.hits())

       {   m_vPosition += delta;

       }

    }

    else

    {   m_vPosition += delta;//如无碰撞,则直接到新位置

    }

}

void TravelManipulator::setSpeed(float &sp)

{   m_fMoveSpeed = sp;

}

float TravelManipulator::getSpeed()

{   return m_fMoveSpeed;

}

void TravelManipulator::SetPosition(osg::Vec3 &position)

{   m_vPosition = position;

}

osg::Vec3 TravelManipulator::GetPosition()

{   return m_vPosition;

}

――――――――――――

3.  “cjmy.cpp”:

#include"stdafx.h"

#include<osgViewer/Viewer>

#include<osg/Node>

#include<osg/Geode>

#include<osg/Group>

#include<osgDB/ReadFile>

#include<osgDB/WriteFile>

#include<osgUtil/Optimizer>

#include "ManipulatorTravel.h"

int _tmain(int argc, _TCHAR* argv[])

{   osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();

    TravelManipulator::TravelToScene(viewer.get());

//在Viewer中添加相机操作器

    osg::ref_ptr<osg::Group> root = new osg::Group();

    osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("lz.osg");

    root->addChild(node.get());

    osgUtil::Optimizer optimizer;

    optimizer.optimize(root.get());

    viewer->setSceneData(root.get());

    viewer->realize();

    viewer->run();

    return 0;

}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值