OSG建立场景时,一般包含以下步骤:
1,建立模型根节点以及场景类;
2,加入模型;
3,加入模型场景;
4,建立摄像操作,加入场景类;
5,建立模型控制类,加入模型根节点;
6,运行场景。
如下的主函数包含所有的步骤:
其中MyOSGCamera
为摄像机控制类;CMyNodeCallback
为模型控制类;CMyHelpHandler
为帮助显示类
MyOSGCamera控制摄像机的移动方向;
CMyNodeCallback控制模型的前后左右移动;
CMyHelpHandler按 H 键弹出帮助提示。
相关功能比较简单,感兴趣可以看看。
#include "Include.h"
#include "MyOSGCamera.h"
#include "MyNodeCallback.h"
#include "MyHelpHandler.h"
int main(int* argc,char **argv)
{
osg::ref_ptr<osgViewer::Viewer> myviewer = new osgViewer::Viewer;
//加载模型
osg::ref_ptr<osg::Group> myroot = new osg::Group;
myroot->setName("root");
osg::ref_ptr<osg::Node> mycarNode = osgDB::readNodeFile("myCar.ive");
osg::ref_ptr<osg::Node> mySceneNode = osgDB::readNodeFile("MyScene.ive");
myroot->addChild(osgDB::readNodeFile("SkyBox.ive"));
//控制位置Car
osg::Vec3 vp1 = osg::Vec3(-60.0, -800.0, 0.0);
osg::Vec3 vp2 = osg::Vec3(0.1, 0.1, 0.1);
osg::ref_ptr<osg::PositionAttitudeTransform> chposCar = new osg::PositionAttitudeTransform;
chposCar->addChild(mycarNode);
chposCar->setPosition(vp1);
osg::Quat quat(osg::DegreesToRadians(-90.0), osg::Z_AXIS);
chposCar->setAttitude(quat);
chposCar->setScale(vp2);
//设置名字,用于遍历
chposCar->setName(gMyCarStr);
myroot->addChild(chposCar);
//控制位置场景
osg::ref_ptr<osg::PositionAttitudeTransform> chposScene = new osg::PositionAttitudeTransform;
chposScene->addChild(mySceneNode);
chposScene->setScale(osg::Vec3f(100.0, 100.0, 100.0));
osg::BoundingSphere bs = chposScene->getBound();
chposScene->setPosition(osg::Vec3(0-bs.center().x(), 0-bs.center().y(), 0-bs.center().z()));
chposScene->setName(gMySceneStr);
myroot->addChild(chposScene);
//光源
osg::ref_ptr<osg::Light> myLight1 = new osg::Light;
myLight1->setLightNum(0);
myLight1->setPosition(osg::Vec4(0.0f, 0.0f, 4800.0f, 1.0f));
myLight1->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
myLight1->setDiffuse(osg::Vec4(0.25f, 0.25f, 0.25f, 0.25f));
myLight1->setSpecular(osg::Vec4(0.0f, 0.0f, 0.0f, 0.25f));
myLight1->setConstantAttenuation(1.0f); //设置恒衰减指数
myLight1->setLinearAttenuation(0.0f); //设置线性衰减指数
myLight1->setQuadraticAttenuation(0.0f); //设置二次方衰减指数
myLight1->setDirection(osg::Vec3(0.0, 0.0, -2000.0f));
osg::ref_ptr<osg::LightSource> lightS1 = new osg::LightSource;
lightS1->setLight(myLight1);
lightS1->setName(gMyLightStr);
lightS1->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);
myroot->addChild(lightS1);
//加入粒子系统
osg::ref_ptr<osgParticle::PrecipitationEffect> myParticle = new osgParticle::PrecipitationEffect;
myParticle->rain(0.15);
myParticle->snow(0.22);
osg::ref_ptr<osg::Fog> myFog = new osg::Fog;
myFog->setColor(osg::Vec4(0.5, 0.5, 0.5, 0.0));
myFog->setDensity(0.05);
myFog->setMode(osg::Fog::EXP);
myFog->setStart(0.0);
myFog->setEnd(300.0);
myParticle->setFog(myFog);
myroot->addChild(myParticle);
//模型控制
myroot->setEventCallback(new CMyNodeCallback);
//设置摄像机
osg::ref_ptr<MyOSGCamera> pmyCamera = new MyOSGCamera();
//设置摄像机的初始位置
pmyCamera->setPosition(osg::Vec3f(-2.9797, 7.17492, 30));
myviewer->setCameraManipulator(pmyCamera);
//将模型放入场景
myviewer->setSceneData(myroot.get());
//添加帮助
myviewer->addEventHandler(new osgViewer::HelpHandler);
myviewer->addEventHandler(new CMyHelpHandler);
//运行
myviewer->realize();
myviewer->run();
return 0;
}
#include “Include.h”
#pragma once
#include <osg/Node>
#include <osg/Group>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osg/CullFace>
#include <osg/Polytope>
#include <osg/BlendFunc>
#include <osg/AlphaFunc>
#include <osg/Matrixd>
#include <osg/Matrix>
#include <osg/MatrixTransform>
#include <osg/AutoTransform>
#include <osg/PositionAttitudeTransform>
#include <osg/Material>
#include <osg/TexGen>
#include <osg/Light>
#include <osg/LightSource>
#include <osg/BoundingSphere>
#include <osg/BoundingBox>
#include <osg/Fog>
#include <osg/StateAttribute>
#include <osg/Point>
#include <osg/LineSegment>
#include <osg/TextureCubeMap>
#include <osg/TexGen>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/GraphicsWindow>
#include <osgGA/CameraManipulator>
#include <osgGA/StateSetManipulator>
#include <osgDB/ReadFile>
#include <osgDB/Registry>
#include <osgText/Text>
#include <osgWidget/WindowManager>
#include <osgWidget/Box>
#include <osgWidget/Table>
#include <osgWidget/Label>
#include <osgParticle/PrecipitationEffect>
#include <osgUtil/SmoothingVisitor>
#include <osgUtil/Optimizer>
#include <osgUtil/IntersectionVisitor>
#include <osgUtil/PolytopeIntersector>
#include <string>
#include <memory>
#include <windows.h>
#include <deque>
#include <locale.h>
using namespace std;
const unsigned int WINDOW_WIDTH = 1300;
const unsigned int WINDOW_HEIGHT = 650;
const unsigned int MASK_2D = 0xF0000000;
const unsigned int MASK_3D = 0x0F000000;
static const std::string gMyCarStr = "mycar";
static const std::string gMySceneStr = "mysecen";
static const std::string gMyLightStr = "myLight";
#ifdef _DEBUG
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgTextd.lib")
#pragma comment(lib, "osgWidgetd.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "osgShadowd.lib")
#pragma comment(lib, "osgAnimationd.lib")
#pragma comment(lib, "osgParticled.lib")
#else
#pragma comment(lib, "osg.lib")
#pragma comment(lib, "osgDB.lib")
#pragma comment(lib, "osgViewer.lib")
#pragma comment(lib, "OpenThreads.lib")
#pragma comment(lib, "osgGA.lib")
#pragma comment(lib, "osgUtil.lib")
#pragma comment(lib, "osgText.lib")
#pragma comment(lib, "osgWidget.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "osgShadow.lib")
#pragma comment(lib, "osgAnimation.lib")
#pragma comment(lib, "osgParticle.lib")
#endif;
MyOSGCamera控制摄像机的移动方向类
#pragma once
#include "Include.h"
class MyOSGCamera :
public osgGA::CameraManipulator
{
public:
MyOSGCamera(void);
~MyOSGCamera(void);
public:
osg::Vec3f m_vPosition; //位置
osg::Vec3f m_vRotation; //旋转角度
float m_fCarRotateZ; //汽车转弯带动的摄像机旋转
float m_fMyRotateZ; //玩家控制摄像机绕Z轴旋转的角度
float m_fMoveSpeed; //移动速度
float m_fAngle; //屏幕角度
public:
void setPosition(osg::Vec3f);
void setRotatefZ(float rotatefZ);
void resetRotateZ();
public:
virtual void setByMatrix(const osg::Matrixd& matrix);
virtual void setByInverseMatrix(const osg::Matrixd& matrix);
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);//主要事件控制器
virtual osg::Matrixd getMatrix(void) const;
virtual osg::Matrixd getInverseMatrix(void) const; //得到逆矩阵
};
/**************************cpp****************************************/
#include "MyOSGCamera.h"
MyOSGCamera::MyOSGCamera(void)
{
m_vPosition = osg::Vec3f(0.0, 0.0f, 5.0f);
m_vRotation = osg::Vec3f(osg::PI_2-0.165f, 0.0f, 0.0f);
m_fAngle = 2.5f; //左右旋转角度
m_fCarRotateZ = 0.0f;
m_fMyRotateZ = 0.0f;
}
MyOSGCamera::~MyOSGCamera(void)
{
}
void MyOSGCamera::setByMatrix(const osg::Matrixd& matrix)
{
}
void MyOSGCamera::setByInverseMatrix(const osg::Matrixd& matrix)
{
}
bool MyOSGCamera::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us)
{
switch(ea.getEventType())
{
case osgGA::GUIEventAdapter::KEYDOWN:
{
if (ea.getKey() == 'a') //左转
{
m_fMyRotateZ += osg::DegreesToRadians(m_fAngle);
resetRotateZ();
}
if (ea.getKey() == 'd') //右转
{
m_fMyRotateZ -= osg::DegreesToRadians(m_fAngle);
resetRotateZ();
}
if (ea.getKey() == 'w') //抬头看
{
m_vRotation._v[0] += 0.015f;
return true;
}
if (ea.getKey() == 's') //低头看
{
m_vRotation._v[0] -= 0.015f;
return true;
}
}
default:
break;
}
return true;
}
osg::Matrixd MyOSGCamera::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));
return mat * osg::Matrixd::translate(m_vPosition);
}
osg::Matrixd MyOSGCamera::getInverseMatrix(void) const
{
return osg::Matrixd::inverse(getMatrix()); //先得到当前的视图矩阵,然后返回其逆矩阵
}
void MyOSGCamera::setPosition(osg::Vec3f pos)
{
m_vPosition = pos;
}
void MyOSGCamera::setRotatefZ(float rotatefZ)
{
m_fCarRotateZ = rotatefZ;
resetRotateZ();
}
void MyOSGCamera::resetRotateZ()
{
m_vRotation._v[2] = m_fMyRotateZ + m_fCarRotateZ;
}
CMyNodeCallback控制模型类,其中CMyNodeVisitor
为自定义节点访问器。
#pragma once
#include "Include.h"
#include "MyOSGCamera.h"
#include "MyNodeVisitor.h"
class CMyNodeCallback :
public osg::NodeCallback
{
public:
CMyNodeCallback(void);
virtual ~CMyNodeCallback(void);
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
public:
void InitNode(osg::Node* node, osg::NodeVisitor* nv); //初始化类中成员变量
//碰撞检测
void CollisionDetection(osg::Vec3d nextpos);
private:
//场景的根节点
osg::ref_ptr<osg::Group> m_rootGroup;
//场景中的摄像机
MyOSGCamera *m_myCamera;
//整个场景的全局光源
osg::Light *m_myLight;
//用于控制汽车的节点
osg::PositionAttitudeTransform *m_myCarNode;
//整个地图
osg::PositionAttitudeTransform *m_mySceneNode;
//汽车位置
osg::Vec3 m_myCarPos;
//摄像机位置
osg::Vec3 m_myCameraPos;
//汽车的行驶速度 以及 汽车绕整个场景Z轴的旋转角度
float m_speed;
float m_rotatef;
};
/*****************************cpp*****************************/
#include "MyNodeCallback.h"
CMyNodeCallback::CMyNodeCallback(void)
{
m_speed = 0.0f;
m_rotatef = 0.0f;
}
CMyNodeCallback::~CMyNodeCallback(void)
{
}
void CMyNodeCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
//std::cout<<"+++++++++++CMyNodeCallback++++++++++++++++"<<std::endl;
static bool isInit = false;
if (!isInit) //在程序最开始运行的时候初始化类中成员变量
{
InitNode(node, nv);
isInit = true;
}
if (osg::NodeVisitor::EVENT_VISITOR == nv->getVisitorType()) //判断访问器类型
{
//创建事件访问器并初始化
osg::ref_ptr<osgGA::EventVisitor> ev = dynamic_cast<osgGA::EventVisitor*>(nv);
if (ev)
{
osgGA::GUIActionAdapter* aa = ev->getActionAdapter(); //得到执行动作
osgGA::EventQueue::Events& events = ev->getEvents(); //得到事件队列
//遍历整个事件队列并处理每一个事件
for (osgGA::EventQueue::Events::iterator itr = events.begin(); itr != events.end(); ++itr)
{
handle(*(*itr), *(aa));
}
}
}
//更新场景
m_myCarPos = m_myCarNode->getPosition();
CollisionDetection(osg::Vec3d(-m_speed*sin(m_rotatef), m_speed*cos(m_rotatef), 0.0));
//m_myCarPos += osg::Vec3d(-m_speed*sin(m_rotatef), m_speed*cos(m_rotatef), 0.0);
//m_myCarPos += osg::Vec3d(-0.5*sin(0.0), 0.5*cos(0.0), 0.0);
m_myCarNode->setPosition(m_myCarPos);
m_myCameraPos = m_myCarPos + osg::Vec3f(0, -100, 35)*osg::Matrixd(osg::Quat(m_rotatef,osg::Z_AXIS));
m_myCamera->setPosition(m_myCameraPos);
}
bool CMyNodeCallback::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
switch(ea.getEventType())
{
case osgGA::GUIEventAdapter::KEYDOWN:
{
if (ea.getKey() == 'i')
{
m_speed += 0.2f;
}
if (ea.getKey() == 'k')
{
m_speed -= 0.2f;
}
if (ea.getKey() == 'j')
{
m_rotatef += 0.02f;
osg::Quat quat = osg::Quat(m_rotatef - osg::PI_2, osg::Z_AXIS);
m_myCarNode->setAttitude(quat);
m_myCamera->setRotatefZ(m_rotatef);
}
if (ea.getKey() == 'l')
{
m_rotatef -= 0.02f;
osg::Quat quat = osg::Quat(m_rotatef - osg::PI_2, osg::Z_AXIS);
m_myCarNode->setAttitude(quat);
m_myCamera->setRotatefZ(m_rotatef);
}
if (ea.getKey() == 'o')
{
m_speed = 0.00f;
//m_rotatef = 0.0f;
}
break;
}
default:
break;
}
return true;
}
void CMyNodeCallback::InitNode(osg::Node* node, osg::NodeVisitor* nv)
{
m_rootGroup = dynamic_cast<osg::Group*>(node);
osg::ref_ptr<osgGA::EventVisitor> ev = dynamic_cast<osgGA::EventVisitor*>(nv);
osgViewer::Viewer *viewer = dynamic_cast<osgViewer::Viewer*>(ev->getActionAdapter());
m_myCamera = dynamic_cast<MyOSGCamera*>(viewer->getCameraManipulator());
//遍历节点
CMyNodeVisitor myNodevisitor;
myNodevisitor.SetFindNodeName(gMyCarStr);
m_rootGroup->accept(myNodevisitor);
m_myCarNode = dynamic_cast<osg::PositionAttitudeTransform*>(myNodevisitor.GetFindNode());
myNodevisitor.SetFindNodeName(gMySceneStr);
m_rootGroup->accept(myNodevisitor);
m_mySceneNode = dynamic_cast<osg::PositionAttitudeTransform*>(myNodevisitor.GetFindNode());
myNodevisitor.SetFindNodeName(gMyLightStr);
m_rootGroup->accept(myNodevisitor);
m_myLight = dynamic_cast<osg::LightSource*>(myNodevisitor.GetFindNode())->getLight();
}
void CMyNodeCallback::CollisionDetection(osg::Vec3d nextpos)
{
if (m_speed < 0.0f)
{
m_myCarPos += nextpos;
return ;
}
//获取包围盒
osg::BoundingSphere bs = m_myCarNode->getBound();
float radius = bs.radius()/10;
float downRotatef = m_rotatef + osg::PI_4/3;
float upRotatef = m_rotatef - osg::PI_4/3;
osg::Vec3 midStart; //中间的直线段的起点
osg::Vec3 downStart; //下面的直线段的起点
osg::Vec3 upStart; //上面的直线段的起点
midStart = osg::Vec3(bs.center().x()-radius*sin(m_rotatef),
bs.center().y()+radius*cos(m_rotatef), bs.center().z());
downStart = osg::Vec3(bs.center().x()-radius*sin(downRotatef),
bs.center().y()+radius*cos(downRotatef), bs.center().z());
upStart = osg::Vec3(bs.center().x()-radius*sin(upRotatef),
bs.center().y()+radius*cos(upRotatef), bs.center().z());
osg::ref_ptr<osgUtil::LineSegmentIntersector> midIntor = new osgUtil::LineSegmentIntersector(midStart, midStart+nextpos);
osg::ref_ptr<osgUtil::LineSegmentIntersector> downIntor = new osgUtil::LineSegmentIntersector(downStart, downStart+nextpos);
osg::ref_ptr<osgUtil::LineSegmentIntersector> upIntor = new osgUtil::LineSegmentIntersector(upStart, upStart+nextpos);
osgUtil::IntersectionVisitor midInterVis(midIntor.get());
osgUtil::IntersectionVisitor downInterVis(downIntor.get());
osgUtil::IntersectionVisitor upInterVis(upIntor.get());
m_rootGroup->accept(midInterVis);
m_rootGroup->accept(downInterVis);
m_rootGroup->accept(upInterVis);
if (midIntor->containsIntersections() || downIntor->containsIntersections() || upIntor->containsIntersections())
{
}
else
{
m_myCarPos += nextpos;
}
}
CMyNodeVisitor 节点访问器类
#pragma once
#include "Include.h"
/************************************************************************/
/* 节点遍历器 */
/************************************************************************/
class CMyNodeVisitor :
public osg::NodeVisitor
{
public:
CMyNodeVisitor(void);
~CMyNodeVisitor(void);
private:
std::string m_strfindName;
osg::ref_ptr<osg::Node> m_myFindNode;
public:
osg::Node *GetFindNode();
void SetFindNodeName(const std::string &strname);
virtual void apply(osg::Node& node);
};
/*************************************cpp***********************************/
#include "MyNodeVisitor.h"
CMyNodeVisitor::CMyNodeVisitor(void):osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
m_strfindName.clear();
}
CMyNodeVisitor::~CMyNodeVisitor(void)
{
}
osg::Node* CMyNodeVisitor::GetFindNode()
{
return m_myFindNode;
}
void CMyNodeVisitor::SetFindNodeName(const std::string &strname)
{
m_strfindName = strname;
}
void CMyNodeVisitor::apply(osg::Node& node)
{
if (node.getName() == m_strfindName)
{
m_myFindNode = &node;
}
traverse(node);
}
CMyHelpHandler提示帮助类
#pragma once
#include "Include.h"
class CMyHelpHandler :
public osgGA::GUIEventHandler
{
public:
CMyHelpHandler(void);
~CMyHelpHandler(void);
virtual void getUsage(osg::ApplicationUsage&) const;
};
/*************************************cpp***********************************/
#include "MyHelpHandler.h"
CMyHelpHandler::CMyHelpHandler(void)
{
}
CMyHelpHandler::~CMyHelpHandler(void)
{
}
void CMyHelpHandler::getUsage(osg::ApplicationUsage& usage) const
{
usage.addKeyboardMouseBinding("W","Camera up\n");
usage.addKeyboardMouseBinding("S","Camera down\n");
usage.addKeyboardMouseBinding("A","Camera left\n");
usage.addKeyboardMouseBinding("D","Camera right\n");
usage.addKeyboardMouseBinding("i","Car up\n");
usage.addKeyboardMouseBinding("k","Car down\n");
usage.addKeyboardMouseBinding("j","Car left\n");
usage.addKeyboardMouseBinding("l","Car right\n");
}
运行效果图