OSG仿真案例(1)

本文档展示了如何使用osgEarth库构建一个3D地球场景,包括加载带有天空的地球模型、创建灯光、雾效、雨雪粒子效果、车灯、速度计、方向显示器等元素。此外,还实现了键盘交互控制汽车行驶、旋转和速度,以及自动和手动驾驶模式的切换。代码中还包含了事件监听回调函数,用于处理键盘输入,更新场景中的元素状态。
摘要由CSDN通过智能技术生成

整体代码的主函数部分如下:

/*********************************************************

main.cpp

*********************************************************/

#include "Include.h"

#include "MyCamera.h"

#include "MyLabelMenu.h"

#include "AutoCars.h"

#include "MyEventCallback.h"

#include "MyRecordCameraPathToFile.h"

const char *titleString = "操作说明";

const char *textString =

{

"a: 向左看            i: 汽车加速\n"

"d: 向右看            j: 汽车左转\n"

"w: 向下看            k: 汽车减速\n"

"s: 向上看            l: 汽车右转\n"

"空格:视角变换        o: 汽车停止\n"

"F1: 显示/隐藏帮助    F3: 全屏/窗口切换\n"

"F2: 打开/关闭车灯    F4:初始化汽车位置\n"

"空格: 第一/第三人称视角"

};

using namespace std;

using namespace osgEarth;

void installMemoryLeakDetector()

{

#if defined(DEBUG) | defined(_DEBUG)

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

//_crtBreakAlloc = 10923;

#endif

}

//创建覆盖整个场景的光源信息

osg::ref_ptr<osg::Node> createLights()

{

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(gSceneLight);

lightS1->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);

osg::ref_ptr<osg::Group> group = new osg::Group;

group->addChild(lightS1);

return group.get();

}

//创建车灯

osg::ref_ptr<osg::Node> createSpotLamp(osg::ref_ptr<osg::Node> car)

{

osg::BoundingSphere bs = car->getBound();

osg::BoundingBox    bb;

bb.expandBy(bs);

float modelSize = bb.radius()*10;

osg::Vec4 pos(bb.center().x(), bb.center().y(), bb.center().z(), 1.0f);

osg::Vec3 direction(bb.center().x() - modelSize, bb.center().y(), -modelSize / 4.0f);

osg::ref_ptr<osg::Light> light1 = new osg::Light;

light1->setLightNum(1);

light1->setDiffuse(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));

light1->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));

light1->setSpecular(osg::Vec4(0.0f, 0.0f, 0.0f, 0.f));

light1->setPosition(pos);

light1->setDirection(direction);

light1->setSpotCutoff(20.0f);

light1->setSpotExponent(10.0f);

osg::ref_ptr<osg::LightSource> lightSource1 = new osg::LightSource;

lightSource1->setLight(light1);

lightSource1->setLocalStateSetModes(osg::StateAttribute::ON);

lightSource1->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON);

osg::ref_ptr<osg::PositionAttitudeTransform> pat1 = new osg::PositionAttitudeTransform;

pat1->addChild(lightSource1.get());

pat1->setName(gLeftSpotLampName);

osg::ref_ptr<osg::Group> group = new osg::Group;

group->addChild(pat1.get());

开启光照

//osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();

//stateset = group->getOrCreateStateSet();

//stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);

//stateset->setMode(GL_LIGHT0, osg::StateAttribute::ON);//允许GL_LIGHT0光照

//stateset->setMode(GL_LIGHT1, osg::StateAttribute::ON);//允许GL_LIGHT1光照

group->getOrCreateStateSet()->setMode(GL_LIGHT1, osg::StateAttribute::ON);

return group.get();

}

/*

驾驶员控制的车辆

功能:对模型model按照位置和姿态(写死的)及缩放变换后返回其node

参数:1、位置坐标。2、缩放比例

*/

osg::ref_ptr<osg::Node> createPlayCar(osg::Vec3 vPos, osg::Vec3 vScale, osg::Node* model)

{

osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;//位姿转换

pat->addChild(model);//将要加载到的节点

pat->setPosition(vPos);//位置坐标

osg::Quat quat(osg::DegreesToRadians(-90.0), osg::Z_AXIS);//位置旋转坐标

pat->setAttitude(quat);

pat->setScale(vScale);//缩放比例

pat->setName("MyPlayCar");//设置名称

return pat.get();//返回位姿转换信息(应该是矩阵)的模型(由于返回类型是node类型)

}

//创建雾效

osg::ref_ptr<osg::Fog> createFog()

{

osg::ref_ptr<osg::Fog> fog = new osg::Fog();

fog->setColor(osg::Vec4(0.5f, 0.5f, 0.5f, 0.0f));

fog->setDensity(0.05f);

fog->setMode(osg::Fog::LINEAR);

fog->setStart(0.0f);

fog->setEnd(400.0f);

return fog.get();

}

//创建驾驶场景

osg::ref_ptr<osg::Node> createScene(osg::Node* model)

{

osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;

pat->addChild(model);

pat->setScale(osg::Vec3(100.0f, 100.0f, 100.0f));

osg::BoundingSphere bs = pat->getBound();

pat->setPosition(osg::Vec3(0 - bs.center().x(), 0 - bs.center().y(), 0 - bs.center().z()));

pat->setName("MyScene");

return pat.get();

}

//创建驾驶场景

osg::ref_ptr<osg::Node> createEarthScene(osg::Node* model)

{

osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;

pat->addChild(model);

pat->setScale(osg::Vec3(1.0f, 1.0f, 1.0f));

osg::BoundingSphere bs = pat->getBound();

pat->setPosition(osg::Vec3(0 - bs.center().x(), 0 - bs.center().y(), 0 - bs.center().z()));

pat->setName("MyScene");

return pat.get();

}

//创建雨、雪效果

osg::ref_ptr<osgParticle::PrecipitationEffect> createPrecipitationEffect()

{

osg::ref_ptr<osgParticle::PrecipitationEffect> precipitationEffect = new osgParticle::PrecipitationEffect;

precipitationEffect->rain(0.0); //雨

precipitationEffect->snow(0.0); //雪

precipitationEffect->setCellSize(osg::Vec3(2.0f, 2.0f, 2.0f));

precipitationEffect->setParticleSize(0.8f);

precipitationEffect->setParticleColor(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));

precipitationEffect->setWind(osg::Vec3(2, 0, 0));

precipitationEffect->setUseFarLineSegments(true);

precipitationEffect->setName(gPrecipitationEffectName);

return precipitationEffect.get();

}

//创建一个图元碎片(给一个四边形贴上纹理)

osg::ref_ptr<osg::Geometry> createSegment(float x, float y, float z, osg::ref_ptr<osg::Image> image, \

bool cullFlag, float alpha)

{

osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;

//定义四个点

osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;

v->push_back(osg::Vec3(0.0f, y, z)); //逆时针

v->push_back(osg::Vec3(0.0f, 0.0f, z));

v->push_back(osg::Vec3(x, 0.0f, z));

v->push_back(osg::Vec3(x, y, z));

geom->setVertexArray(v.get());

//定义法线

osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;

osg::Vec3f upVec(0.0f, 0.0f, 1.0f);

n->push_back(upVec);

geom->setNormalArray(n.get());

geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

//设置纹理坐标

osg::ref_ptr<osg::Vec2Array> geomTexcoords = new osg::Vec2Array(4);

(*geomTexcoords)[0].set(0.0f, 1.0f);

(*geomTexcoords)[1].set(0.0f, 0.0f);

(*geomTexcoords)[2].set(1.0f, 0.0f);

(*geomTexcoords)[3].set(1.0f, 1.0f);

geom->setTexCoordArray(0, geomTexcoords.get());

osg::Vec4Array* colors = new osg::Vec4Array;

colors->push_back(osg::Vec4(0.5f, 0.5f, 0.5f, alpha));

geom->setColorArray(colors);

geom->setColorBinding(osg::Geometry::BIND_OVERALL);

//设置顶点关联方式

geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

osg::StateSet* geomState = geom->getOrCreateStateSet();

geomState->setAttributeAndModes(new osg::BlendFunc, osg::StateAttribute::ON);

if (cullFlag) //背面剔除

{

osg::ref_ptr<osg::CullFace> cullface = new osg::CullFace(osg::CullFace::BACK);

geomState->setAttribute(cullface.get());

geomState->setMode(GL_CULL_FACE, osg::StateAttribute::ON);

}

if (image) //如果要添加纹理

{

osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;

tex->setImage(image.get());

geomState->setTextureAttributeAndModes(0, tex.get(), osg::StateAttribute::ON);

}

return geom.get();

}

//创建速度显示节点

osg::ref_ptr<osg::Node> createSpeedNode()

{

osg::ref_ptr<osgText::Text> text = new osgText::Text();

text->setFont("fonts/simhei.ttf");

text->setCharacterSize(4.0f);

text->setColor(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));

text->setAlignment(osgText::Text::CENTER_CENTER);

text->setAxisAlignment(osgText::Text::XY_PLANE);

text->setText("0.0 Km/h");

osg::ref_ptr<osg::Geode> geode = new osg::Geode();

geode->addDrawable(text.get()); //绘制速度文本

geode->setName(gSpeedTextName); //给该速度节点设置名字

geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);  //关闭光照

osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;

pat->addChild(geode.get());

pat->setPosition(osg::Vec3(-1.0f, 8.724f, 15.60f)); //设置文本的初始化位置(即相对于汽车的位置)

pat->setScale(osg::Vec3(0.07f, 0.07f, 0.07f));

pat->setAttitude(osg::Quat(osg::DegreesToRadians(90.0f), osg::X_AXIS)); //旋转

osg::ref_ptr<osg::PositionAttitudeTransform> pat1 = new osg::PositionAttitudeTransform;

pat1->addChild(pat.get());    //在程序的运行过程中,每帧都会更新该节点的位置信息

pat1->setName(gSpeedNodeName); //速度节点的最终位置等于他所有父节点的位置矩阵相乘

return pat1.get();

}

//创建方向指示器

osg::ref_ptr<osg::Node> createCompassNode()

{

//

osg::ref_ptr<osg::Image> compass = osgDB::readImageFile("compass.bmp");

osg::ref_ptr<osg::Geometry> compassGeom = createSegment(1.0f, 1.0f, 0.0f, compass, true, 1.0f);

osg::ref_ptr<osg::Geode> compassGeode = new osg::Geode;

compassGeode->addDrawable(compassGeom.get());

osg::ref_ptr<osg::PositionAttitudeTransform> compassPat = new osg::PositionAttitudeTransform;

compassPat->addChild(compassGeode.get());

compassPat->setPivotPoint(osg::Vec3(0.5f, 0.5f, 0.0f));

compassPat->setPosition(osg::Vec3(0.5f, 0.5f, 0.0f));

compassPat->setName(gCompassName); //在程序的运行过程中,会根据汽车的旋转状态更新此方向盘的旋转状态

  //指针

osg::ref_ptr<osg::Image> point = osgDB::readImageFile("pointer.bmp");

osg::ref_ptr<osg::Geometry> pointGeom = createSegment(0.8f, 0.1f, 0.001f, point, true, 1.0);

osg::ref_ptr<osg::Geode> pointGeode = new osg::Geode;

pointGeode->addDrawable(pointGeom.get());

osg::ref_ptr<osg::PositionAttitudeTransform> pointPat = new osg::PositionAttitudeTransform;

pointPat->addChild(pointGeode.get());

pointPat->setAttitude(osg::Quat(osg::DegreesToRadians(-90.0f), osg::Z_AXIS));

pointPat->setScale(osg::Vec3(0.4f, 0.5f, 0.5f));

pointPat->setPosition(osg::Vec3(0.5f, 0.83f, 0.0f));

osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;

pat->addChild(compassPat.get());

pat->addChild(pointPat.get());

pat->setPosition(osg::Vec3(-1.8, 6.455, 15.2));

pat->setAttitude(osg::Quat(osg::DegreesToRadians(90.0), osg::X_AXIS));

osg::ref_ptr<osg::PositionAttitudeTransform> pat1 = new osg::PositionAttitudeTransform;

pat1->setName(gCompassNodeName); //每帧都会根据汽车当前的位置更新pat1的位置

pat1->addChild(pat.get());

pat1->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

pat1->getOrCreateStateSet()->setMode(GL_LIGHT0, osg::StateAttribute::OFF);

pat1->getOrCreateStateSet()->setMode(GL_LIGHT1, osg::StateAttribute::OFF);

return pat1.get();

}

//创建自动行驶的汽车

osg::ref_ptr<osg::Node> createAutoCar(float rotatef, osg::Vec3 start, osg::Vec3 end, osg::Vec3 speed,

osg::Vec3 scale, char axis, osg::Node *model)

{

osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;

pat->addChild(model);

pat->setScale(scale);

pat->setAttitude(osg::Quat(osg::DegreesToRadians(rotatef), osg::Z_AXIS));

pat->setPosition(start);

pat->addUpdateCallback(new CAutoCar(start, end, speed, axis, rotatef));

return pat.get();

}

//给屏幕添加多辆自动驾驶的汽车

osg::ref_ptr<osg::Node> createAutoCars()

{

osg::ref_ptr<osg::Group> group = new osg::Group;

osg::ref_ptr<osg::Node> publicCar = osgDB::readNodeFile("publicCar.ive"); //公交车

osg::ref_ptr<osg::Node> playCar = osgDB::readNodeFile("playerCar.ive"); //小轿车

group->addChild(createAutoCar(180.0f, osg::Vec3(-2000.0f, 20.0f, 0.0f), osg::Vec3(2000.0f, 20.0f, 0.0f),

osg::Vec3(3.0f, 0.0f, 0.0f), osg::Vec3(4.5f, 4.5f, 4.5f), 'x', publicCar.get()).get());

group->addChild(createAutoCar(90.0f, osg::Vec3(-50.0f, -450.0f, 0.0f), osg::Vec3(-50.0f, 2000.0f, 0.0f),

osg::Vec3(0.0f, 4.0f, 0.0f), osg::Vec3(4.5f, 4.5f, 4.5f), 'y', publicCar.get()).get());

//可以在此添加更多的汽车

return group.get();

}

//给场景添加雾效

void addStateSet(osg::ref_ptr<osg::Group> root)

{

osg::StateSet *stateset = root->getOrCreateStateSet();

stateset->setAttributeAndModes(createFog(), osg::StateAttribute::OFF);

stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);

stateset->setMode(GL_LIGHT0, osg::StateAttribute::ON);

stateset->setMode(GL_LIGHT1, osg::StateAttribute::OFF);

osgUtil::Optimizer optimizer;

optimizer.optimize(root.get());

}

void setupProperties(osgText::Text& textObject, osgText::Font *font, float size, const osg::Vec3 &pos)

{

textObject.setFont(font); //设置文本的各种信息

textObject.setCharacterSize(size);

textObject.setPosition(pos);

textObject.setColor(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0));

textObject.setAlignment(osgText::Text::LEFT_TOP); //左上角对齐

textObject.setAxisAlignment(osgText::Text::XZ_PLANE);//在XZ平面上

}

void createContent(osgText::Text &textObject, const char *string)

{

int requiredSize = mbstowcs(NULL, string, 0); //文本字体格式转换,使其支持中文

wchar_t *wtext = new wchar_t[requiredSize + 1];

mbstowcs(wtext, string, requiredSize + 1);

textObject.setText(wtext);

delete wtext;

wtext = NULL;

}

//帮助窗口

osg::ref_ptr<osg::Node> createHelpNode()

{

setlocale(LC_ALL, ".936");

osgText::Font* fontHei = osgText::readFontFile("Fonts/simhei.ttf");

osg::ref_ptr<osgText::Text> title = new osgText::Text;

setupProperties(*title, fontHei, 1.5f, osg::Vec3(0.0f, 0.0f, 0.0f));

createContent(*title, titleString);

osg::ref_ptr<osgText::Text> text = new osgText::Text;

setupProperties(*text, fontHei, 1.0f, osg::Vec3(0.0f, 0.0f, 0.0f));

createContent(*text, textString);

//

osg::ref_ptr<osg::Geode> geode1 = new osg::Geode;

geode1->addDrawable(createSegment(30.0f, 14.0f, 0.0f, NULL, true, 0.4f));

osg::ref_ptr<osg::PositionAttitudeTransform> pat1 = new osg::PositionAttitudeTransform;

pat1->addChild(geode1.get());

pat1->setAttitude(osg::Quat(osg::DegreesToRadians(90.0f), osg::X_AXIS));

pat1->setPosition(osg::Vec3(0.0f, 0.05f, 0.0f));

//

osg::ref_ptr<osg::Geode> geode2 = new osg::Geode;

geode2->addDrawable(title.get());

osg::ref_ptr<osg::PositionAttitudeTransform> pat2 = new osg::PositionAttitudeTransform;

pat2->addChild(geode2.get());

pat2->setPosition(osg::Vec3(12.5f, 0.0f, 12.5f));

//

osg::ref_ptr<osg::Geode> geode3 = new osg::Geode;

geode3->addDrawable(text.get());

osg::ref_ptr<osg::PositionAttitudeTransform> pat3 = new osg::PositionAttitudeTransform;

pat3->addChild(geode3.get());

pat3->setPosition(osg::Vec3(6.0f, 0.0f, 10.0f));

//

osg::ref_ptr<osg::PositionAttitudeTransform> pat4 = new osg::PositionAttitudeTransform;

pat4->addChild(pat1.get());

pat4->addChild(pat2.get());

pat4->addChild(pat3.get());

pat4->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

pat4->getOrCreateStateSet()->setMode(GL_LIGHT0, osg::StateAttribute::OFF);

pat4->getOrCreateStateSet()->setMode(GL_LIGHT1, osg::StateAttribute::OFF);

osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;

pat->addChild(pat4.get());

pat->setName(gHelpNodeName);

return pat.get();

}

//仿照<osgEarthUtil/ExampleResources>中,通过读取命令行的形式读取参数(地球和_sky),实实现获得带有sky的地球

osg::Group* load(osg::ArgumentParser&   args, osgViewer::Viewer*    view)

{

Config  c;

c.add("elevation_smoothing", false);

TerrainOptions  to(c);

MapNodeOptions  defMNO;

defMNO.setTerrainOptions(to);

osg::Node*  node = osgDB::readNodeFile("G:/YCThirdParty/EarthData/demo.earth");

osg::ref_ptr<MapNode>   mapNode = MapNode::get(node);

//  a   root    node    to  hold    everything:

osg::Group* root = new  osg::Group();

root->addChild(node);

if (view)

{

//1

if (!root)

root = mapNode.get();

//  options to  use for the load

osg::ref_ptr<osgDB::Options>    dbOptions = osgEarth::Registry::instance()->cloneOrCreateOptions();

ControlCanvas*  canvas = ControlCanvas::getOrCreate(view);

Container*  mainContainer;

{

mainContainer = new VBox();

mainContainer->setAbsorbEvents(true);

mainContainer->setBackColor(Color(Color::Black, 0.2));

mainContainer->setHorizAlign(Control::ALIGN_RIGHT);

mainContainer->setVertAlign(Control::ALIGN_BOTTOM);

}

canvas->addControl(mainContainer);

const   Config& externals = mapNode->externalConfig();

mapNode->addExtension(Extension::create("sky_simple", ConfigOptions()));//增加天空、大气效果。

    Hook    up  the extensions!增加拖拽条功能。

for (std::vector<osg::ref_ptr<Extension> >::const_iterator eiter = mapNode->getExtensions().begin(); eiter != mapNode->getExtensions().end(); ++eiter)

{

Extension*  e = eiter->get();

//  Check   for a   View    interface:

ExtensionInterface<osg::View>*  viewIF = ExtensionInterface<osg::View>::get(e);

if (viewIF)

viewIF->connect(view);

}

root->addChild(canvas);

//1

}

if (view)

{

//configureView(    view    );

view->addEventHandler(new   osgViewer::StatsHandler());

view->addEventHandler(new   osgViewer::WindowSizeHandler());

view->addEventHandler(new   osgViewer::ThreadingHandler());

view->addEventHandler(new   osgViewer::LODScaleHandler());

view->addEventHandler(new   osgGA::StateSetManipulator(view->getCamera()->getOrCreateStateSet()));

//view->addEventHandler(new osgViewer::RecordCameraPathHandler());

view->addEventHandler(new   osgViewer::ScreenCaptureHandler());

}

return  root;

}

// 世界坐标转经纬度

osg::Vec3d WorldToLonLatAlt(const osg::Vec3d world)

{

osg::EllipsoidModel* em = new osg::EllipsoidModel();

osg::Vec3d lonLatAlt;

em->convertXYZToLatLongHeight(world.x(), world.y(), world.z(),

lonLatAlt.y(), lonLatAlt.x(), lonLatAlt.z());

lonLatAlt.x() = osg::RadiansToDegrees(lonLatAlt.x());

lonLatAlt.y() = osg::RadiansToDegrees(lonLatAlt.y());

return lonLatAlt;

}

//经纬度转世界坐标系

osg::Vec3d LonLatAltToWorld(const osg::Vec3d lonLatAlt)

{

osg::Vec3d world;

osg::EllipsoidModel* em = new osg::EllipsoidModel();

//Lat纬度Long经度

em->convertLatLongHeightToXYZ(osg::DegreesToRadians(lonLatAlt.y()),

osg::DegreesToRadians(lonLatAlt.x()), lonLatAlt.z(), world.x(), world.y(), world.z());

return world;

}

//int main_driver(int argc, char **argv)

//模拟自动驾驶,通过参数切换是自动驾驶还是手动驾驶,实际中,手动驾驶有问题。地球的位置不对。

int main_driver()

{

installMemoryLeakDetector();

setlocale(LC_ALL, "chs");

cout << "请稍等,正在加载程序运行资源...";

osgViewer::Viewer viewer;

osgWidget::WindowManager* wm = new osgWidget::WindowManager(&viewer, WINDOW_WIDTH, WINDOW_HEIGHT, MASK_3D);

osgWidget::Window *menu = new osgWidget::Box("menu", osgWidget::Box::HORIZONTAL);

menu->addWidget(new CMyLabelMenu("菜单")); //添加菜单按钮

menu->getBackground()->setColor(1.0f, 1.0f, 1.0f, 1.0f);

menu->setPosition(15.0f, 15.0f, 0.0f);

wm->addChild(menu);

改为地球的model

//模拟命令行内容

int argc = 2;

char* argv[] = { "11" ,"G:/YCThirdParty/EarthData/demo.earth","--sky" };

osg::ArgumentParser args1(&argc, argv);//通过命令行的方式加载带有sky的earth(源于oe的源代码)

ref_ptr <Node> MyScene = load(args1, &viewer);//加载地球

if (!MyScene)

{

osg::notify(osg::NOTICE) << "No  MyScene " << std::endl;

return 1;

}

改为地球的model

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

//root->addChild(createEarthScene(MyScene).get());  //整个地球节点(包含sky),此处在加载时,做了加载中转转换(未完全弄懂)

root->addChild( (MyScene) );  //整个地球节点(包含sky)

osg::ref_ptr<osg::Node> car = osgDB::readNodeFile("MyCar.ive");

if (!car)

{

osg::notify(osg::NOTICE) << "No  Car " << std::endl;

return 1;

}

/设置相机的初始地球位置↓

root->addChild(createPrecipitationEffect().get());  //添加粒子效果,如“雪天、雾天”(初始化的一些操作,一下几个操作类似)

addStateSet(root);

root->addChild(createHelpNode().get());      // 添加帮助窗口

root->addChild(createLights().get());        // 添加全局光照

root->addChild(createSpotLamp(car).get());  // 添加车灯

root->addChild(createSpeedNode().get());    // 添加速度计

root->addChild(createCompassNode().get());  // 添加方向显示器

//root->setEventCallback(new CMyEventCallback(false)); //设置事件监听回调函数true/false(是否为自动驾驶)

root->setEventCallback(new CMyEventCallback(false)); // 测试不适应operator()

viewer.setRunMaxFrameRate(125);//设置帧率

osg::Vec3d cameraPosition = LonLatAltToWorld(Vec3d(116, 40, 0));//将经纬度转换成世界坐标系centerLat = 46.0;centerLon = 46.0;

osg::Vec3d CARPosition = LonLatAltToWorld(Vec3d(116, 40, 0 ));

root->addChild(createPlayCar(CARPosition, osg::Vec3(0.1, 0.1, 0.1), car.get()));  //汽车加载,并设置好加载的位置、尺寸缩放、姿态等信息

osg::ref_ptr<CMyCamera> camera = new CMyCamera();

camera->setPosition(cameraPosition);  //设置摄像机的初始位置

//camera->setHomeViewpoint(Viewpoint("Home",

//  -71.0763, 42.34425, 0,  // longitude, latitude, altitude

//  24.261, -21.6, 3450.0), // heading, pitch, range

//  5.0);                    // duration

viewer.setCameraManipulator(camera);//相机操作器(其继承与类CameraManipulator)

viewer.addEventHandler(new CMyViewerHandler); //重写原始的操作器,内容什么都没有写,目的是用以屏蔽原来的键盘鼠标操作

/设置相机的初始地球位置↑

return osgWidget::createExample(viewer, wm, root);

}

/*

#if 0//是否添加处理earth以外的其他物体

#endif

///由经纬度获得高程

osgEarth::ElevationQuery *query;

ref_ptr<MapNode> mapNode1 = osgEarth::MapNode::findMapNode(MyScene);

if (!mapNode1){

OE_NOTICE << "Could not find MapNode " << std::endl;

return -1;

}

query = new osgEarth::ElevationQuery(mapNode1->getMap());

double query_resolution = 0.00000001;

double out_hamsl = 0.0;

double out_resolution = 0.0;

query->getElevation(GeoPoint(mapNode1->getMapSRS(), 116, 40, 0.0, osgEarth::AltitudeMode::ALTMODE_ABSOLUTE),out_hamsl,query_resolution,&out_resolution);

///由经纬度获得高程

*/

核心代码(1)加载带有天空(sky)的地球
//仿照<osgEarthUtil/ExampleResources>中,通过读取命令行的形式读取参数(地球和_sky),实实现获得带有sky的地球

osg::Group* load(osg::ArgumentParser&       args, osgViewer::Viewer*    view)
{
    Config  c;
    c.add("elevation_smoothing", false);
    TerrainOptions  to(c);
    MapNodeOptions  defMNO;
    defMNO.setTerrainOptions(to);

    osg::Node*  node = osgDB::readNodeFile("G:/YCThirdParty/EarthData/demo.earth");

    osg::ref_ptr<MapNode>   mapNode = MapNode::get(node);
    //  a   root    node    to  hold    everything:
    osg::Group* root = new  osg::Group();
    root->addChild(node);

    if (view)
    {
        //1
        if (!root)
            root = mapNode.get();
        //  options to  use for the load
        osg::ref_ptr<osgDB::Options>    dbOptions = osgEarth::Registry::instance()->cloneOrCreateOptions();
        ControlCanvas*  canvas = ControlCanvas::getOrCreate(view);

        Container*  mainContainer;

        {
            mainContainer = new VBox();
            mainContainer->setAbsorbEvents(true);
            mainContainer->setBackColor(Color(Color::Black, 0.2));
            mainContainer->setHorizAlign(Control::ALIGN_RIGHT);
            mainContainer->setVertAlign(Control::ALIGN_BOTTOM);
        }
        canvas->addControl(mainContainer);
        const   Config& externals = mapNode->externalConfig();

        mapNode->addExtension(Extension::create("sky_simple", ConfigOptions()));//增加天空、大气效果。
                                                                                    Hook    up  the extensions!增加拖拽条功能。
        for (std::vector<osg::ref_ptr<Extension> >::const_iterator eiter = mapNode->getExtensions().begin(); eiter != mapNode->getExtensions().end(); ++eiter)
        {
            Extension*  e = eiter->get();
            //  Check   for a   View    interface:
            ExtensionInterface<osg::View>*  viewIF = ExtensionInterface<osg::View>::get(e);
            if (viewIF)
                viewIF->connect(view);
        }
        root->addChild(canvas);
        //1
    }

    if (view)
    {
        //configureView(    view    );
        view->addEventHandler(new   osgViewer::StatsHandler());
        view->addEventHandler(new   osgViewer::WindowSizeHandler());
        view->addEventHandler(new   osgViewer::ThreadingHandler());
        view->addEventHandler(new   osgViewer::LODScaleHandler());
        view->addEventHandler(new   osgGA::StateSetManipulator(view->getCamera()->getOrCreateStateSet()));
        //view->addEventHandler(new osgViewer::RecordCameraPathHandler());
        view->addEventHandler(new   osgViewer::ScreenCaptureHandler());
    }

    return  root;
}

核心代码(2) MyEventCallback类,实现键盘的交互,并在交互中,实时刷新,

1)MyEventCallback.cpp的内容

#include "MyEventCallback.h"

extern bool gSnow;   //定义在MyLabelMenu.cpp文件
extern bool gFog;
extern bool gHelp;
extern bool gRain;
extern bool gNight;
extern bool gFullScreen;
extern bool gMousePush;


CMyEventCallback::CMyEventCallback(bool auto_Drive)//通过在新建类的时候,传入不同的值,实现自动操作和手动操作(专业的应该是:使用外部按键来切换)
{
    m_speed = 0.0f;//速度的初始值
    m_rotatef = 0.0f;
    m_fogFlag = false;
    m_theThreeView = false;
    m_DisplayHelp = false;
    m_flag_Auto_Drive = !auto_Drive;
}

CMyEventCallback::~CMyEventCallback()
{

}

//初始化类中成员变量
void CMyEventCallback::init(osg::Node* node, osg::NodeVisitor* nv)
{
    //得到整个场景的根节点
    m_rootNode = 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_camera = dynamic_cast<CMyCamera*>(viewer->getCameraManipulator());

    //得到窗口信息
    vector<osgViewer::GraphicsWindow*> vgw;
    viewer->getWindows(vgw);
    m_gw = vgw[0];

    //得到屏幕分辨率
    osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface();
    wsi->getScreenResolution(*(m_gw->getTraits()), m_screenWidth, m_screenHeight);

    //初始化窗口模式时 窗口的位置和宽、高
    m_screenWindowWidth = m_screenWidth*0.75;
    m_screenWindowHeight = m_screenHeight*0.75;
    m_screenX = (m_screenWidth - m_screenWindowWidth) / 2;
    m_screenY = (m_screenHeight - m_screenWindowHeight) / 2;

    //设置屏幕窗口大小
    m_gw->setWindowRectangle(m_screenX, m_screenY, m_screenWindowWidth, m_screenWindowHeight);

    //节点访问器
    CMyNodeVisitor nodeVisitor;

    //查找并获取汽车节点
    nodeVisitor.setNameToFind("MyPlayCar");
    m_rootNode->accept(nodeVisitor);
    m_playCar = dynamic_cast<osg::PositionAttitudeTransform*>(nodeVisitor.getFindNode());

    //查找并获取雨、雪节点
    nodeVisitor.setNameToFind(gPrecipitationEffectName);
    m_rootNode->accept(nodeVisitor);
    m_precipitationEffect = dynamic_cast<osgParticle::PrecipitationEffect*>(nodeVisitor.getFindNode());

    //查找并获取全局光源节点
    nodeVisitor.setNameToFind(gSceneLight);
    m_rootNode->accept(nodeVisitor);
    m_sceneLight = dynamic_cast<osg::LightSource*>(nodeVisitor.getFindNode())->getLight();

    //查找并获取汽车车灯
    nodeVisitor.setNameToFind(gLeftSpotLampName);
    m_rootNode->accept(nodeVisitor);
    m_SpotLamp = dynamic_cast<osg::PositionAttitudeTransform*>(nodeVisitor.getFindNode());

    //查找并获取方向显示器节点
    nodeVisitor.setNameToFind(gCompassName);
    m_rootNode->accept(nodeVisitor);
    m_compass = dynamic_cast<osg::PositionAttitudeTransform*>(nodeVisitor.getFindNode());

    //查找并获取方向图 节点
    nodeVisitor.setNameToFind(gCompassNodeName);
    m_rootNode->accept(nodeVisitor);
    m_compassNode = dynamic_cast<osg::PositionAttitudeTransform*>(nodeVisitor.getFindNode());

    //查找并获取驾驶速度文本节点
    nodeVisitor.setNameToFind(gSpeedTextName);
    m_rootNode->accept(nodeVisitor);
    m_speedText = dynamic_cast<osgText::Text*>(dynamic_cast<osg::Geode*>(nodeVisitor.getFindNode())->getDrawable(0));

    //查找并获取显示驾驶速度的位置节点
    nodeVisitor.setNameToFind(gSpeedNodeName);
    m_rootNode->accept(nodeVisitor);
    m_speedNode = dynamic_cast<osg::PositionAttitudeTransform*>(nodeVisitor.getFindNode());

    //查找并获取驾驶地图节点
    nodeVisitor.setNameToFind("MyScene");
    m_rootNode->accept(nodeVisitor);
    m_map = dynamic_cast<osg::PositionAttitudeTransform*>(nodeVisitor.getFindNode());

    //查找并获取显示帮助信息的节点
    nodeVisitor.setNameToFind(gHelpNodeName);
    m_rootNode->accept(nodeVisitor);
    m_helpNode = dynamic_cast<osg::PositionAttitudeTransform*>(nodeVisitor.getFindNode());

    //得到雾效状态
    m_fog = dynamic_cast<osg::Fog*>(m_rootNode->getOrCreateStateSet()->getAttribute(osg::StateAttribute::FOG));

}

/
void CMyEventCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
    static bool isInit = false;
    if (!isInit)                 //在程序最开始运行的时候初始化类中成员变量(虽然每帧都会判断是否初始化,但是一旦初始化过,但并不执行)
    {
        init(node, nv);
        isInit = true;
    }

    if (nv->getVisitorType() == osg::NodeVisitor::EVENT_VISITOR)//判断访问器类型
    {
        osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(nv);
        if (!ev)
        {
            return;
        }
        else
        {
            osgGA::GUIActionAdapter* aa = ev->getActionAdapter();  //得到执行动作
            osgGA::EventQueue::Events& events = ev->getEvents();
            osgGA::EventQueue::Events::iterator itr;
            for (itr = events.begin();itr != events.end();++itr)
            {
                osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter();
                if (!event)
                {
                    return;
                }
                else
                {
                    if (m_flag_Auto_Drive)//手动驾驶模式
                    {
                        handle(*(event), *aa);
                    }   
                    else//自动驾驶模式
                    {
                        m_speed += 0.2f;//让速度动态变起来
                                        //保证其他东西也一起动起来
                        osg::Quat quat = osg::Quat(m_rotatef - osg::PI_2, osg::Z_AXIS);
                        m_playCar->setAttitude(quat);
                        m_SpotLamp->setAttitude(quat);

                        m_speedNode->setAttitude(osg::Quat(m_rotatef, osg::Z_AXIS));
                        m_compass->setAttitude(osg::Quat(m_rotatef, osg::Z_AXIS));
                        m_compassNode->setAttitude(osg::Quat(m_rotatef, osg::Z_AXIS));

                        m_camera->setRotatefZ(m_rotatef);

                        //设置汽车风向与行驶方向相等
                        m_precipitationEffect->setWind(osg::Vec3d(-m_speed*sin(m_rotatef), m_speed*cos(m_rotatef), 0.0));

                        //如果汽车的速度发生了变化,更新速度显示器的内容
                        float speed = ((int)(m_speed * 3600 * 30 / 1000)) / 20;
                        char text[12];
                        sprintf_s(text, "%.1f", speed);

                        string label(text);
                        label += " Km/h";
                        m_speedText->setText(label);

                        //设置粒子风向与汽车行驶方向相等
                        m_precipitationEffect->setWind(osg::Vec3d(-m_speed*sin(m_rotatef), m_speed*cos(m_rotatef), 0.0));
                    }
                }
            }
        }
    }
    updateScene(); //每帧都需要更新场景数据
 }

//处理每一个事件
bool CMyEventCallback::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
    switch (ea.getEventType())
    {
    case osgGA::GUIEventAdapter::KEYDOWN:
    {
        m_key = ea.getKey();//判断按键值(实际中是不断判断---即在operator中执行)

    //  bool controlKey = processFog() || processPrecipitationEffect() || processSceneLight() || processSpotLamp() || processMap();//需要改回2020年9月21日15:11:59
        bool controlKey = processMap();
        if (controlKey)
        {
            break;
        }
        else if (processPlayCar())
        {
            break;
        }
        else
        {
            break;
        }

        m_key = -10000;
    }
    break;

    default:
        break;
    }

    return true;
}

//更新场景数据
void CMyEventCallback::updateScene()
{
    processMenu();

    //更新汽车位置
    m_position = m_playCar->getPosition();
    changePosition(osg::Vec3d(-m_speed*sin(m_rotatef), m_speed*cos(m_rotatef), 0.0));//做碰撞检测
    m_playCar->setPosition(m_position);

    //更新车灯位置
    m_SpotLamp->setPosition(m_position);

    //更新摄像机位置
    if (m_theThreeView) //判断是否处于第三人称视角(为真是是第三人称)
    {
        m_cameraPos = m_position + osg::Vec3f(0, -100, 35)*osg::Matrixd(osg::Quat(m_rotatef, osg::Z_AXIS));
    }
    else
    {
        m_cameraPos = m_position + osg::Vec3f(-5, -2.2, 19)*osg::Matrixd(osg::Quat(m_rotatef, osg::Z_AXIS));
    }
    m_camera->setPosition(m_cameraPos);

    //更新速度显示器位置
    m_speedNode->setPosition(m_position);

    //更新方向显示器位置
    m_compassNode->setPosition(m_position);

    //更新帮助节点的位置
    if (m_DisplayHelp)
    {
        osg::Quat quat(m_camera->getRotatefX() - osg::PI_2, osg::Vec3(1.0f, 0.0f, 0.0f),m_camera->getRotatefY(), osg::Vec3(0.0f, 1.0f, 0.0f),m_camera->getRotatefZ(), osg::Vec3(0.0f, 0.0f, 1.0f));
        m_helpNode->setAttitude(quat);
        m_helpNode->setPosition(m_cameraPos + osg::Vec3(-15.0f, 40.0f, -7.0f)*osg::Matrixd(quat));
    }
    else
    {
        m_helpNode->setPosition(osg::Vec3(0.0f, 0.0f, -1000.0f)); //此时把该节点的位置设置到视线外
    }

}

//碰撞检测,判断汽车是否能够移动
void CMyEventCallback::changePosition(osg::Vec3d delta)
{
    if (m_speed > -0.05f && m_speed < 0.05f)
        return;

    if (m_speed < 0.0f)  //倒车时的碰撞检测没有实现
    {
        m_position += delta;
        return;
    }

    osg::BoundingSphere bs = m_playCar->getBound();
    float radius = bs.radius() / 10;//此处包围盒的半径并不会随着pat节点的放大、缩小而变化,是固定的
    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;    //上面的直线段的起点

                          //    if (m_speed > 0.0f)
                          //    {
    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());
    //}
    //else  //倒车时候的碰撞检测,被注释了
    //{
    //  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> midIntersector = new osgUtil::LineSegmentIntersector
    (midStart, midStart + delta);
    osg::ref_ptr<osgUtil::LineSegmentIntersector> downIntersector = new osgUtil::LineSegmentIntersector
    (downStart, downStart + delta);
    osg::ref_ptr<osgUtil::LineSegmentIntersector> upIntersector = new osgUtil::LineSegmentIntersector
    (upStart, upStart + delta);

    osgUtil::IntersectionVisitor mindIntersectVisitor(midIntersector.get());
    osgUtil::IntersectionVisitor downIntersectVisitor(downIntersector.get());
    osgUtil::IntersectionVisitor upIntersectVisitor(upIntersector.get());

    m_rootNode->accept(mindIntersectVisitor);
    m_rootNode->accept(downIntersectVisitor);
    m_rootNode->accept(upIntersectVisitor);

    if (midIntersector->containsIntersections()||downIntersector->containsIntersections()||upIntersector->containsIntersections())
    {
        //只要有任何一条线段发生了碰撞,即判定汽车与场景碰撞,此时汽车无法前行
    }
    else
    {
        m_position += delta;
    }

}

//处理雾效
bool CMyEventCallback::processFog()
{
    switch (m_key)
    {
    case '1':
        m_fog->setColor(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); //雾的颜色设置为纯白色
        return true;

    case '2':
        m_fog->setColor(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); //雾的颜色设置为纯黑色
        return true;

    case '3':
        m_fog->setColor(osg::Vec4(0.5f, 0.5f, 0.5f, 1.0f)); //雾的颜色设置为灰色
        return true;

    case '9':
        if (m_fogFlag = !m_fogFlag)  //开启/关闭雾效
        {
            m_rootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF);
        }
        else
        {
            m_rootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::ON);
        }
        return true;
    default:
        return false;
    }

    return false;
}

//处理整个驾驶地图
bool CMyEventCallback::processMap()
{
    static bool isFullScreen = false;

    switch (m_key)
    {
    case osgGA::GUIEventAdapter::KEY_F1:
        if (m_DisplayHelp = !m_DisplayHelp)
        {
            gHelp = true;
            m_theThreeView = true;  // 当需要显示帮助时,驾驶视角将处于第三人称角度
        }
        else
        {
            gHelp = false;
        }
        return true;

    case osgGA::GUIEventAdapter::KEY_F3:   //全屏/窗口 模式切换
        if (isFullScreen = !isFullScreen)
        {
            m_gw->setWindowDecoration(false); //隐藏标题栏
            m_gw->setWindowRectangle(0, 0, m_screenWidth, m_screenHeight);
        }
        else
        {
            m_gw->setWindowDecoration(true);  //显示标题栏
            m_gw->setWindowRectangle(m_screenX, m_screenY, m_screenWindowWidth, m_screenWindowHeight);
        }
        return true;

    case osgGA::GUIEventAdapter::KEY_F4:
        m_playCar->setPosition(osg::Vec3(-60.0, -800.0, 0.0)); //汽车的位置重置到原点
        return true;

    default:
        return false;
    }

    return false;
}

//控制汽车移动
bool CMyEventCallback::processPlayCar()
{
    bool changeSpeed = false;
    bool changeRotatef = false;

    unsigned int curtime = GetTickCount();

    switch (m_key)
    {
    case 'I':
        changeSpeed = true;
        m_speed += 0.2f;
        break;
    case 'K':
        changeSpeed = true;
        m_speed -= 0.2f;
        break;
    case 'J':
        changeRotatef = true;
        m_rotatef += 0.02f;
        break;
    case 'L':
        changeRotatef = true;
        m_rotatef -= 0.02f;
        break;
    case 'O':
        changeSpeed = true;
        m_speed = 0.0f;
        break;
    case osgGA::GUIEventAdapter::KEY_Space:
        if (!(m_theThreeView = !m_theThreeView))
        {
            m_DisplayHelp = false;
        }
        break;

    default:
        break;
    }

    //如果汽车的旋转角度发生了变化,更新汽车、车灯、速度显示器、方向显示器、摄像机的旋转角度//保证其他东西也一起动起来
    if (changeRotatef)
    {
        osg::Quat quat = osg::Quat(m_rotatef - osg::PI_2, osg::Z_AXIS);
        m_playCar->setAttitude(quat);
        m_SpotLamp->setAttitude(quat);

        m_speedNode->setAttitude(osg::Quat(m_rotatef, osg::Z_AXIS));
        m_compass->setAttitude(osg::Quat(m_rotatef, osg::Z_AXIS));
        m_compassNode->setAttitude(osg::Quat(m_rotatef, osg::Z_AXIS));

        m_camera->setRotatefZ(m_rotatef);

        //设置汽车风向与行驶方向相等
        m_precipitationEffect->setWind(osg::Vec3d(-m_speed*sin(m_rotatef), m_speed*cos(m_rotatef), 0.0));
    }

    //如果汽车的速度发生了变化,更新速度显示器的内容
    if (changeSpeed)
    {
        float speed = ((int)(m_speed * 3600 * 30 / 1000)) / 20;
        char text[12];
        sprintf_s(text, "%.1f", speed);

        string label(text);
        label += " Km/h";

        m_speedText->setText(label);

        //设置粒子风向与汽车行驶方向相等
        m_precipitationEffect->setWind(osg::Vec3d(-m_speed*sin(m_rotatef), m_speed*cos(m_rotatef), 0.0));
    }
    return false;
}

//控制雨雪效果
bool CMyEventCallback::processPrecipitationEffect()
{
    switch (m_key)
    {
    case '3':
        m_precipitationEffect->rain(0.0f);
        return true;

    case '4':
        m_precipitationEffect->snow(0.001f);
        m_precipitationEffect->rain(0.5f);
        return true;

    case '5':
        m_precipitationEffect->snow(0.0f);
        return true;

    case '6':
        m_precipitationEffect->rain(0.001f);
        m_precipitationEffect->snow(0.5f);
        m_precipitationEffect->setCellSize(osg::Vec3(2.0f, 2.0f, 2.0f));
        return true;

    default:
        return false;
    }

    return false;
}

//控制车灯
bool CMyEventCallback::processSpotLamp()
{
    static bool isOpen = true;

    switch (m_key)
    {
    case osgGA::GUIEventAdapter::KEY_F2:
        if (isOpen = !isOpen) //车灯是否开启/关闭
        {
            m_rootNode->getOrCreateStateSet()->setMode(GL_LIGHT1, osg::StateAttribute::OFF);
        }
        else
        {
            m_rootNode->getOrCreateStateSet()->setMode(GL_LIGHT1, osg::StateAttribute::ON);
        }
        return true;

    default:
        return false;
    }
    return false;
}

bool CMyEventCallback::processSceneLight()
{
    static bool isNight = false;

    switch (m_key)
    {
    case '7':
        if (isNight = !isNight) //控制场景为白天/黑夜
        {
            m_sceneLight->setAmbient(osg::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
            m_sceneLight->setDiffuse(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
            m_sceneLight->setSpecular(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
        }
        else
        {
            m_sceneLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
            m_sceneLight->setDiffuse(osg::Vec4(0.25f, 0.25f, 0.25f, 1.0f));
            m_sceneLight->setSpecular(osg::Vec4(0.1f, 0.1f, 0.1f, 1.0f));
        }
        return true;

    default:
        return false;
    }

    return false;
}

void CMyEventCallback::processMenu()
{
    if (!gMousePush)
        return;
    gMousePush = false;

    if (gSnow && gRain)  //雪
    {
        m_precipitationEffect->snow(0.5f);
        m_precipitationEffect->rain(0.5f);
    }
    else if (gSnow && !gRain)
    {
        m_precipitationEffect->rain(0.001f);
        m_precipitationEffect->snow(0.5f);
    }
    else if (!gSnow && gRain)
    {
        m_precipitationEffect->snow(0.001f);
        m_precipitationEffect->rain(0.5f);
    }
    else
    {
        m_precipitationEffect->rain(0.0f);
        m_precipitationEffect->snow(0.0f);
    }

    if (gFog) //雾
    {
        m_rootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::ON);
    }
    else
    {
        m_rootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF);
    }

    if (gNight) //夜晚
    {
        m_sceneLight->setAmbient(osg::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
        m_sceneLight->setDiffuse(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
        m_sceneLight->setSpecular(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
    }
    else
    {
        m_sceneLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
        m_sceneLight->setDiffuse(osg::Vec4(0.25f, 0.25f, 0.25f, 1.0f));
    }

    if (gHelp)  //帮助
    {
        m_DisplayHelp = true;
        m_theThreeView = true;
    }
    else
    {
        m_DisplayHelp = false;
    }

    if (gFullScreen) //是否全屏
    {
        m_gw->setWindowDecoration(false);
        m_gw->setWindowRectangle(0, 0, m_screenWidth, m_screenHeight);
    }
    else
    {
        m_gw->setWindowDecoration(true);
        m_gw->setWindowRectangle(m_screenX, m_screenY, m_screenWindowWidth, m_screenWindowHeight);
    }
}

2)MyEventCallback.h的内容

#pragma once
#include "Include.h"
#include "NodeVisitor.h"
#include "MyCamera.h"


class CMyEventCallback : /*public osg::NodeCallback:*/ public osgGA::GUIEventHandler
{
public:
    CMyEventCallback(bool auto_Drive);
    ~CMyEventCallback();

    void init(osg::Node* node, osg::NodeVisitor* nv);    //初始化类中成员变量

    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);

    void updateScene();                //更新场景数据

    bool processFog();                 //控制雾效
    bool processPlayCar();             //控制汽车行驶
    bool processPrecipitationEffect(); //控制雨雪效果
    bool processSceneLight();          //控制全局光源的各项参数
    bool processSpotLamp();            //控制车灯参数
    bool processMap();                 //控制地图  

    void processMenu();                //处理鼠标点击菜单

    void changePosition(osg::Vec3d delta); //碰撞检测,判断汽车是否能够前进

    bool m_flag_Auto_Drive;                 //控制是否为自动驾驶(即自动运行,键盘操作无效)

private:

    //场景的根节点
    osg::Group          *m_rootNode;

    //当前的键盘按键的键值
    int                  m_key;

    //用于控制整个窗口
    osgViewer::GraphicsWindow *m_gw;

    //全屏的大小
    unsigned int        m_screenWidth;
    unsigned int        m_screenHeight;

    //非全屏时,程序窗口的起始位置和宽、高
    unsigned int        m_screenX;
    unsigned int        m_screenY;
    unsigned int        m_screenWindowWidth;
    unsigned int        m_screenWindowHeight;

    //场景中的摄像机
    CMyCamera           *m_camera;

    //雾效开启/关闭标志 以及 雾效状态
    bool                 m_fogFlag;
    osg::Fog            *m_fog;

    //雨雪节点
    osgParticle::PrecipitationEffect *m_precipitationEffect;

    //整个场景的全局光源
    osg::Light          *m_sceneLight;

    //显示汽车行驶方向的 方向显示器节点
    osg::PositionAttitudeTransform  *m_compass;
    osg::PositionAttitudeTransform  *m_compassNode;

    //显示汽车行驶速度的 文本节点
    osgText::Text                   *m_speedText;
    osg::PositionAttitudeTransform  *m_speedNode;

    //车灯
    osg::PositionAttitudeTransform  *m_SpotLamp;

    //整个驾驶地图
    osg::PositionAttitudeTransform  *m_map;

    //当前汽车在场景的位置 以及 摄像机的位置
    osg::Vec3                        m_position;
    osg::Vec3                        m_cameraPos;

    //汽车的行驶速度 以及 汽车绕整个场景Z轴的旋转角度
    float                            m_speed;
    float                            m_rotatef;

    //是否处于第三人称视角驾驶汽车
    bool                             m_theThreeView;

    //用于控制汽车行驶的节点
    osg::PositionAttitudeTransform  *m_playCar;

    //用于显示帮助菜单
    osg::PositionAttitudeTransform  *m_helpNode;
    bool                             m_DisplayHelp;

    //用来记录按下转弯键时的时间
    deque<unsigned int>              m_rotatefTime;

};


class CMyViewerHandler : public osgGA::GUIEventHandler
{
public:
    CMyViewerHandler() {};
    ~CMyViewerHandler() {};


    //重载此函数,目的是为了覆盖OSG本身自带的某些键盘交互键
    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
        return true;
    };

private:
};

(3)相机控制类:CMyCamera
1)CMyCamera.h的部分内容

#pragma once

#include "Include.h"

class CMyCamera : public osgGA::CameraManipulator,public EarthManipulator
{
public:
    CMyCamera(void);
    ~CMyCamera(void);
    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);//主要事件控制器
};

2)CMyCamera.h的部分内容

//****************************************************************** 
//function description: 事件控制器
//
bool CMyCamera::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
{
    if (ea.getEventType() == osgGA::GUIEventAdapter::FRAME)
    {
        osg::Timer_t time = osg::Timer::instance()->tick();
        double delta = osg::Timer::instance()->delta_s(_lastFrameTime, time);
        _lastFrameTime = time;
        if ( _delta >= _interval)
        {
            if(0)   /*do something Here......*/
            {    
                    coutforFrame++;
                    cout << "preFrame:   " << coutforFrame << endl;
                    //m_vRotation._v[0] += 0.015f;//单帧中做姿态转换
                    m_vPosition.x() = m_vPosition.x() + 20;//单帧中做位置变换
                    m_vPosition.y() = m_vPosition.y() + 20;
                    m_vPosition.z() = m_vPosition.z() + 20;
            }
            _delta = 0.0f;
        }
        else
        {
            _delta += delta;
        }
        return true;
    }

    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;
            }
        }
    }
    return false;
}

(4)CMyViewerHandler类:保证自身的键鼠操作不被执行,而是按照自行设置的键鼠操作,避免冲突

class CMyViewerHandler : public osgGA::GUIEventHandler
{
public:
    CMyViewerHandler() {};
    ~CMyViewerHandler() {};


    //重载此函数,目的是为了覆盖OSG本身自带的某些键盘交互键
    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
        return true;
    };

private:
};
在C++中使用OGRE (Object-Oriented Graphics Rendering Engine) 实现红外仿真,而不是OSG,因为OGRE是一款更强大的三维图形引擎。以下是创建红外仿真的一些步骤: 1. **导入库和资源**:首先,你需要在工程中引入Ogre的相关头文件,并加载红外纹理或者图像资源。例如: ```cpp #include "OgreSceneManager.h" #include "OgreTextureManager.h" Ogre::String infraredTexName = "path/to/infrared_texture.png"; Ogre::TextureManager& tm = Ogre::Root::getSingleton().getTextureManager(); Ogre::TexturePtr infraredTex = tm.load(m_resourceGroup, infraredTexName); ``` 2. **创建材质**:定义一个自定义材质,可能使用`Ogre::Technique`来控制红外效果: ```cpp Ogre:: Technique* tech = new Ogre::Technique; tech->setName("Infrared"); tech->setLightingEnabled(false); // 禁用光照,以便专注于颜色 Ogre::Pass* pass = new Ogre::Pass; pass->setSceneBlending(Ogre::SBT_TRANSPARENT_Z_WRITE); // 可能透明混合 pass->setTextureUnitState(0, *infraredTex, Ogre::TU_RENDERTARGET | Ogre::TU_SRGB_WRITE); tech->addPass(pass); ``` 3. **创建实体和材质应用**:在场景中创建一个实体并为其设置上述红外材质: ```cpp Ogre::MeshPtr mesh = ...; // 加载或创建一个几何体 Ogre::Entity* entity = sceneMgr->createEntity(mesh->getName(), mesh); entity->setMaterialName("Infrared"); // 应用红外技术 sceneMgr->getRootSceneNode()->attachObject(entity); ``` 4. **实时反馈**:如果红外数据实时变化,可以通过更新纹理内容或创建程序性纹理来反映这种变化。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rexinx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值