2006年05月17日

http://earthobservatory.nasa.gov/Newsroom/BlueMarble/BlueMarble_monthlies.html

这次整个地球是一个文件,但是提供了一年中12个月不同的照片,也提供了不同分辨率的图片,分别是8千米/象素,2km/象素,500米/想素。

这样,处理的命令行就变为:osgdem  –whole-globe -t globe.tif –geocentric -l 12 -o globe.ive -a globe.osga

注:下载的图片是jpg格式,直接处理程序会出错,存为tif格式处理就没问题了。

2006年05月12日

三、摄像机控制

(最近更新:2006314)

原文地址:http://www.flmnware.com/


目的:通过本教程,学会用键盘和鼠标实现摄像机的控制。





1、事件处理模型

OpenSceneGraph里,类GUIEventHandler为任何想要处理GUI事件的类提供了一个基本接口。处理事件的方法是:


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

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

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



在这个方法里,有两个参数,第一个是GUI事件的供给者,第二个参数用来handle方法对GUI进行反馈,它可以让GUIEventHandler根据输入事件让GUI进行一些动作。

如果要进行事件处理,可以从GUIEventHandler继承出自己的类,然后覆盖handle方法,在里面进行事件处理。osgProducer::Viewer类维护一个GUIEventHandler队列,事件在这个队列里依次传递,handle的返回值决定这个事件是否继续让后面的GUIEventHandler处理,如果返回true,则停止处理,如果返回false,后面的GUIEventHandler还有机会继续对这个事件进行响应。

如果想向Viewer类加入自己的GUIEventHandler,可以这样,假设我的GUIEventHandlerCMyGUIEventHandler


viewer.getEventHandlerList().push_back(new CmyGUIEventHandler());

viewer.getEventHandlerList().push_back(new CmyGUIEventHandler());

viewer.getEventHandlerList().push_back(new CmyGUIEventHandler());



如果想向节点加入自己的GUIEventHandler,就设置节点的事件回调。


node.setEventCallback(new CmyGUIEventHandler());

node.setEventCallback(new CmyGUIEventHandler());

node.setEventCallback(new CmyGUIEventHandler());



GUIEventHandler可处理的事件类型可以用ea.getEventType()得到,包括以下几种:


事件类型

说明

PUSH

鼠标按键按下

RELEASE

鼠标按键抬起

DOUBLECLICK

鼠标按键双击

DRAG

鼠标按下按键拖动

MOVE

鼠标移动

KEYDOWN

键盘按键按下

KEYUP

键盘按键抬起

FRAME

每帧触发的事件

RESIZE

窗口改变大小

SCROLLUP

鼠标滚轮上滚

SCROLLDOWN

鼠标滚轮下滚

SCROLLLEFT

鼠标滚轮左滚

SCROLLRIGHT

鼠标滚轮右滚


还可以通过ea.getKey()得到键盘按键码,通过ea.getButtonMask()得到鼠标按键码。因为跨平台的关系,OpenSceneGraph自己定义了键盘码,具体可参考GUIEventAdapter头文件。



2、视图矩阵控制模型

OpenSceneGraph的摄像机操作,由osgGA::MatrixManipulator的派生类来完成,可以调用osgProducer::Viewer类的addCameraManipulator方法把自己的摄像机加入进去。默认情况下,Viewer自带了5个摄像机,这些在第一篇里讲过,可用数字键在这些摄像机之间切换,我们自定义的,也依次排在后面。

OpenSceneGraph里,所有的视图矩阵操作都是通过矩阵来完成的,不同摄像机之间的交互也通过矩阵,这样就提供了一个通用的模型,不管你习惯使用gluLookAt方式的,还是习惯操作摄像机位置姿态方式的,都可以很容易嵌入OpenSceneGraph的框架中,因为所有方式的最后结果就是矩阵。

要实现自己的摄像机,关键是实现osgGA::MatrixManipulator类的以下五个纯虚函数:


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

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

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



这个函数在从一个摄像机切换到另一个摄像机时调用,用来把上一个摄像机的视图矩阵传过来,这样就可依此设定自己的初始位置了。

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

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

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



这个方法当在外部直接调用ViewersetViewByMatrix方法时,把设置的矩阵传过来,让摄像机记住新更改的位置。

virtual osg::Matrixd getMatrix() const;

virtual osg::Matrixd getMatrix() const;

virtual osg::Matrixd getMatrix() const;



SetByMatrix方法需要的矩阵就是用这个方法得到的,用来向下一个摄像机传递矩阵。

virtual osg::Matrixd getInverseMatrix() const;

virtual osg::Matrixd getInverseMatrix() const;

virtual osg::Matrixd getInverseMatrix() const;



这个是最重要的方法,这个方法每帧会被调用,它返回当前的视图矩阵。

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

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

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



在这个方法里进行时间的处理,改变自己的状态,进而在 getInverseMatrix 被调用时,改变场景内摄像机的位置姿态。


3、类第一人称射击游戏的摄像机

这个摄像机最早在OpenGVS里实现,在OpenGVS里,摄像机的操作是把它想象成场景中一个有位置姿态的物体。这个摄像机的功能包括adws控制左右前后行走,用HomeEnd控制上下移动,鼠标控制转向,并用空格控制是否使用鼠标的转向功能,用=-控制移动步长。

摄像机的位置用位置和姿态来表示,键盘鼠标控制位置姿态的改变,值得注意的是将位置姿态转化为视图矩阵,看方法 getInverseMatrix()


osg::Matrixd

FPSCamera::getInverseMatrix() const

{

osg::Matrixd mat;

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

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

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

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

}

osg::Matrixd

FPSCamera::getInverseMatrix() const

{

osg::Matrixd mat;

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

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

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

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

}

osg::Matrixd

FPSCamera::getInverseMatrix() const

{

osg::Matrixd mat;

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

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

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

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

}



其中_vPosition是位置,_vRotation是姿态,代码中,先得到旋转矩阵,可以用矩阵类的 makeRotate 方法,参数是旋转角度和旋转轴,然后用矩阵类的translate方法得到平移矩阵,用旋转矩阵左乘平移矩阵,就得到摄像机的旋转变换矩阵,但是视图矩阵是变换矩阵的反矩阵,所以最后要用矩阵类的 inverse方法的到反矩阵。



总结:OpenSceneGraph提供的事件处理非常直接好用,而视图变换这种基于矩阵的设计,一般化了视图矩阵的操作,可以用各种方法实现摄像机的控制,很容易把以前的程序移植过来。



作者:flmn

网站:http://www.flmnware.com

作者:flmn

网站:http://www.flmnware.com

作者:flmn

网站:http://www.flmnware.com


二、节点的更新回调和位置姿态控制

(最近更新:2006314)

原文地址:http://www.flmnware.com/


目的:通过本教程,学会将自定义节点添加入场景图,并控制节点在每一帧的运动。





1、添加自定义节点

OpenSceneGraph提供的节点类(Node及其子类)实现了通用的场景图结构,但是不可能提供每一个用户需要的类,比如我要做一个飞行模拟程序,OpenSceneGraph不会给我提供一个Aircraft类。所以要实现自己的应用程序逻辑,就要自定义自己的类,这个类以OpenSceneGraph提供的类为基类,并能添加到场景图中,实现自己的特定功能。

一个飞机的运动,最简单情况是我们要考虑飞机的位置和姿态,而要想在OpenSceneGraph里控制一个模型的位置、旋转或缩放,需要在这个节点上面添加一个Transform的子类,这要用到矩阵运算,矩阵运算非常复杂,对于控制位置姿态这个经常用到的功能,OpenSceneGraph提供了类PositionAttitudeTransform,通过它可以方便控制位置姿态而不用理会复杂的矩阵运算。

飞机需要导入一个模型,在场景图中,我们就把这个模型加为这个类实例的儿子,这样,这个类可以这样定义,飞机类CCessna


class CCessna :

public osg::PositionAttitudeTransform

{

public:

CCessna(void);

~CCessna(void);

private:

osg::ref_ptr<osg::Node> _Model;

};

class CCessna :

public osg::PositionAttitudeTransform

{

public:

CCessna(void);

~CCessna(void);

private:

osg::ref_ptr<osg::Node> _Model;

};

class CCessna :

public osg::PositionAttitudeTransform

{

public:

CCessna(void);

~CCessna(void);

private:

osg::ref_ptr<osg::Node> _Model;

};

class CCessna :

public osg::PositionAttitudeTransform

{

public:

CCessna(void);

~CCessna(void);

private:

osg::ref_ptr<osg::Node> _Model;

};



成员变量_Model是保存模型的指针。

这样,在构造函数里,将_Model加为儿子:


CCessna::CCessna(void)

{

_Model = osgDB::readNodeFile("cessna.osg");

this->addChild(_Model.get());

}

CCessna::CCessna(void)

{

_Model = osgDB::readNodeFile("cessna.osg");

this->addChild(_Model.get());

}

CCessna::CCessna(void)

{

_Model = osgDB::readNodeFile("cessna.osg");

this->addChild(_Model.get());

}

CCessna::CCessna(void)

{

_Model = osgDB::readNodeFile("cessna.osg");

this->addChild(_Model.get());

}



继续使用第一个教程的源码,将这一句:


osg::Node* node = osgDB::readNodeFile("cessna.osg");

viewer.setSceneData(node);

osg::Node* node = osgDB::readNodeFile("cessna.osg");

viewer.setSceneData(node);

osg::Node* node = osgDB::readNodeFile("cessna.osg");

viewer.setSceneData(node);

osg::Node* node = osgDB::readNodeFile("cessna.osg");

viewer.setSceneData(node);



改为:


CCessna* cessna = new Ccessna();

viewer.setSceneData(cessna);

CCessna* cessna = new Ccessna();

viewer.setSceneData(cessna);

CCessna* cessna = new Ccessna();

viewer.setSceneData(cessna);

CCessna* cessna = new Ccessna();

viewer.setSceneData(cessna);



就能看到效果了。


2、给节点添加更新回调并控制节点运动

为了控制飞机的运动,我们应该在每一帧根据速度等条件计算飞机的位置,并更新飞机节点,但是我们的更新代码应该加在哪里呢?

在程序的主循环里,可以看到这句:


viewer.update();

viewer.update();

viewer.update();

viewer.update();



在这个方法里,OpenSceneGraph会遍历场景图,调用每个节点的更新回调,我们只要把自己代码放在更新回调里,就能保证每帧代码得到运行,也就能实现我们要求的功能了。

OpenSceneGraph中,每个回调都是类NodeCallback的子类,我们只需要继承它,就能实现功能了。为了保证飞机更新的时候能得到需要的足够信息,又不让飞机的内部实现暴露于外,我们让更新回调只进行一个转手的操作,而实际的更新函数放在CCessna类里。

更新回调代码如下:


class CCessnaUpdateCallback :

public osg::NodeCallback

{

virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)

{

CCessna* cessna = dynamic_cast<CCessna*>(node);

if(cessna != NULL)

{

cessna->update();

}

}

};

class CCessnaUpdateCallback :

public osg::NodeCallback

{

virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)

{

CCessna* cessna = dynamic_cast<CCessna*>(node);

if(cessna != NULL)

{

cessna->update();

}

}

};

class CCessnaUpdateCallback :

public osg::NodeCallback

{

virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)

{

CCessna* cessna = dynamic_cast<CCessna*>(node);

if(cessna != NULL)

{

cessna->update();

}

}

};

class CCessnaUpdateCallback :

public osg::NodeCallback

{

virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)

{

CCessna* cessna = dynamic_cast<CCessna*>(node);

if(cessna != NULL)

{

cessna->update();

}

}

};



这个类覆盖了基类对操作符()的重载,所以说它实际上是一个函数对象,因为这个重载是通用的,在函数里我们要先动态转换成 CCessna 类的指针,然后调用她的更新成员函数。

为了让这个回调起作用,不要忘了在 CCessna 类的构造函数里设置更新回调:


this->setUpdateCallback(new CCessnaUpdateCallback());

this->setUpdateCallback(new CCessnaUpdateCallback());

this->setUpdateCallback(new CCessnaUpdateCallback());

this->setUpdateCallback(new CCessnaUpdateCallback());



下面设计让飞机绕圈飞行,同时让飞机横滚,代码都是写计算操作,需要注意的是PositionAttitudeTransform类提供的设置姿态的方法不是使用通常习惯的HPR为参数,而是一个四元数,关于四元数数学请参考相关书籍,但是HPR向四元数的转换还是很直接的,这就是我们的setRotation方法:


void

CCessna::setRotation(osg::Vec3& rot)

{

osg::Quat q(rot.x(), osg::Vec3(1.0f, 0.0f, 0.0f),

rot.y(), osg::Vec3(0.0f, 1.0f, 0.0f),

rot.z(), osg::Vec3(0.0f, 0.0f, 1.0f));

this->setAttitude(q);

}

void

CCessna::setRotation(osg::Vec3& rot)

{

osg::Quat q(rot.x(), osg::Vec3(1.0f, 0.0f, 0.0f),

rot.y(), osg::Vec3(0.0f, 1.0f, 0.0f),

rot.z(), osg::Vec3(0.0f, 0.0f, 1.0f));

this->setAttitude(q);

}

void

CCessna::setRotation(osg::Vec3& rot)

{

osg::Quat q(rot.x(), osg::Vec3(1.0f, 0.0f, 0.0f),

rot.y(), osg::Vec3(0.0f, 1.0f, 0.0f),

rot.z(), osg::Vec3(0.0f, 0.0f, 1.0f));

this->setAttitude(q);

}

void

CCessna::setRotation(osg::Vec3& rot)

{

osg::Quat q(rot.x(), osg::Vec3(1.0f, 0.0f, 0.0f),

rot.y(), osg::Vec3(0.0f, 1.0f, 0.0f),

rot.z(), osg::Vec3(0.0f, 0.0f, 1.0f));

this->setAttitude(q);

}



update方法里,通过设置位置和旋转来控制飞机运动,具体请查看代码。


3、完善程序

由于Viewer类在程序开始会根据模型的包围盒调整视点初始位置,这样能保证程序开始能看到模型,但是因为我们的模型是运动的,运行一点之后飞机会飞出视线,所以我们给飞机提供一个场地,这个场地就是一个正方体,代码如下:


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

osg::Geode* geode = new osg::Geode();

geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, -20.0f), 200.0f, 200.0f, 2.0f)));

root->addChild(geode);

CCessna* cessna = new CCessna();

root->addChild(cessna);

viewer.setSceneData(root);

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

osg::Geode* geode = new osg::Geode();

geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, -20.0f), 200.0f, 200.0f, 2.0f)));

root->addChild(geode);

CCessna* cessna = new CCessna();

root->addChild(cessna);

viewer.setSceneData(root);

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

osg::Geode* geode = new osg::Geode();

geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, -20.0f), 200.0f, 200.0f, 2.0f)));

root->addChild(geode);

CCessna* cessna = new CCessna();

root->addChild(cessna);

viewer.setSceneData(root);

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

osg::Geode* geode = new osg::Geode();

geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, -20.0f), 200.0f, 200.0f, 2.0f)));

root->addChild(geode);

CCessna* cessna = new CCessna();

root->addChild(cessna);

viewer.setSceneData(root);



这里用到了Geode 类和Drawable类的子类ShapeDrawableGeode 是场景图的叶子节点,所有的几何体都包含在 Geode 里,而一个 Geode 里可以有多个Drawable的子类,我们看到的图像真正是Drawable画的,这个后面在讨论。



总结:要想实现自己的功能,加入自己的代码,就要定义自己的节点类,由于OpenSceneGraph使用了组合设计模式,我们自己定义的类在OpenSceneGraph看来和它自己的类是一样的,OpenSceneGraph的这种场景图结构,基本上是业界的一种标准,很多程序都实现了类似的结构。



作者:flmn

网站:http://www.flmnware.com

作者:flmn

网站:http://www.flmnware.com

作者:flmn

网站:http://www.flmnware.com

作者:flmn

网站:http://www.flmnware.com


一、最简单的OpenSceneGraph程序

(最近更新:2006314)

原文地址:http://www.flmnware.com/


目的:通过本教程,学会OpenSceneGraph工程属性的设置,加载并查看三维模型,熟悉Viewer类提供的用户操作。




1、建立和设置工程

启动Microsoft Visual Studio .NET 2003,建立一个Win32控制台项目,在应用程序设置选项卡里,选择空项目,点击完成。为了在工程选项里出现C/C++的选项,先给工程添加一个空的C++源文件。

OpenSceneGraph运行需要多线程DLL的运行时库和RTTI,所以,在建立每个OpenSceneGraph工程后,第一件事就是更改工程设置。

打开项目属性,在C/C++选项卡里,点击代码生成页,更改运行时库,对于Debug版,用多线程调试 DLL (/Mdd),对于Release版,用多线程 DLL (/MD)

设置C/C++选项卡里的语言页的启用运行时类型信息为:是(/GR)

OpenSceneGraph程序需要链接对应的库文件,打开链接器选项卡里的输入页,设置附加依赖项,对于Debug版,是OpenThreadsWin32d.lib Producerd.lib osgd.lib osgDBd.lib osgFXd.lib osgGAd.lib osgParticled.lib osgProducerd.lib osgSimd.lib osgTerraind.lib osgTextd.lib osgUtild.lib,对于Release版,设置这些lib文件不带“d”的版本。

这样,工程属性就设置好了。


2、编辑程序

在刚才建立的空文件里输入如下内容:

#include <osgDB/ReadFile>

#include <osgProducer/Viewer>

int

main(int, char**)

{

osgProducer::Viewer viewer;

viewer.setUpViewer();

osg::Node* node = osgDB::readNodeFile("cessna.osg");

viewer.setSceneData(node);

viewer.realize();

while (!viewer.done())

{

viewer.sync();

viewer.update();

viewer.frame();

}

viewer.sync();

return 0;

}

#include <osgDB/ReadFile>

#include <osgProducer/Viewer>

int

main(int, char**)

{

osgProducer::Viewer viewer;

viewer.setUpViewer();

osg::Node* node = osgDB::readNodeFile("cessna.osg");

viewer.setSceneData(node);

viewer.realize();

while (!viewer.done())

{

viewer.sync();

viewer.update();

viewer.frame();

}

viewer.sync();

return 0;

}



编译运行后,就能看到一个飞机的模型。


NOTE如果看不到模型,检查OSG1.0是否正确安装,即OSG_FILE_PATH是否设置正确。


这个程序的核心是,osgProducer命名空间的Viewer类实例,这个类负责管理窗口的创建,控制投影矩阵,控制OpenGL的渲染,实现程序的主循环。它还具有控制场景渲染状态,查看帧速,抓图等功能。OsgDB命名空间的readNodeFile函数负责从文件里读入三维模型及其纹理等数据,它返回读入的节点,可以加到场景图中。主循环分三步,同步,更新和绘制,当用户按下ESC键时,osgProducer::Viewer::done()返回true,主循环结束。


3、程序的操作


鼠标:

摄像机操作器

Trackball

Flight

Drive

Terrain

左键

旋转视图

加速

加速

旋转视图

中键

平移视图

停止

停止

平移视图

右键

缩放

减速/倒退

减速/倒退

缩放




键盘:

Escape

退出程序

Space

重置摄像机位置

1

选择“轨迹球(Trackball)”摄像机操作器

2

选择“飞行(Flight)”摄像机操作器

3

选择“驾驶(Drive)”摄像机操作器

4

选择“地形(Terrain)”摄像机操作器

5

选择“不明飞行物(UFO)”摄像机操作器

b

开关背面剔除

f

全屏/窗口切换

h

显示帮助

H

在摄像机控制器是 UFO ,重置到起始位置

l

开关灯光

o

将当前场景的场景图保存到文件"saved_model.osg"

O

抓图,保存为文件"saved_image*.rgb"

s

显示帧速等信息

t

开关纹理

v

开关垂直同步

w

切换多边形、线、点显示模式

z

开始记录摄像机路径

Z

如果正在记录摄像机路径,保存路径到文件"saved_animation.path",然后开始播放这个路径文件



总结:OpenSceneGraphViewer类本身提供了很多功能,所以,只需要简单的几句代码,就能有一个不错的程序,这些功能如果用OpenGL实现,需要很多的时间。当不再为这些基础功能操心的时候,我们就能把精力放在我们要实现的功能上面。



作者:flmn

网站:http://www.flmnware.com

作者:flmn

网站:http://www.flmnware.com


http://www.flmnware.com/osg/tutorial/

我网站的教程,现在已经有3篇了。

计划如下:

 一、最简单的OpenSceneGraph程序

学会OpenSceneGraph工程属性的设置,加载并查看三维模型,熟悉Viewer类提供的用户操作。


二、节点的更新回调和位置姿态控制

学会将自定义节点添加入场景图,并控制节点在每一帧的运动。


三、摄像机控制

学会用键盘和鼠标实现摄像机的控制。


四、点选[HTML][PDF]


五、文字osgText[HTML][PDF]


六、渲染状态操作[HTML][PDF]


七、绘制几何体[HTML][PDF]


八、嵌入OpenGL语句[HTML][PDF]


九、使用GLSL[HTML][PDF]


十、粒子系统[HTML][PDF]


十一、地形模块osgTerrain[HTML][PDF]


十二、3ds Max插件OSGExp[HTML][PDF]

2005年12月23日

作者:flmn 出自:http://www.flmnware.com/

一、谁适合学习OpenSceneGraph

 

 

 

如果你的公司要搞视景仿真,并且不想多花钱,使用OpenSceneGraph,她是开源的,免费的。

 

 

 

如果你是学生,对计算机图形学有着强烈的兴趣,请你使用。如果你是学生,毕设题目是视景仿真,毕业后不会再搞相关方向,请你使用更简单的视景软件,如Vega,他开发更快速,也能找到*免费*版,而且Multigen公司也不会指着你的论文大叫:交钱。

 

 

 

二、需要时刻记住的几个观点:

OpenSceneGraph是从Unix操作系统移植过来的,所以有些操作只在Unix上有效。

OpenSceneGraph是一个纯粹的Scene Graph,没有其他不相关的功能。

 

 

 

三、什么是最有效的学习方式:

信息来源

信息总来源:官方站点http://www.openscenegraph.org或者http://www.openscenegraph.net

中文信息来源:

中国虚拟现实开发者网络:http://vrdn.net/

中国VR技术社区:http://www.vrforum.cn/

FLMNWaRehttp://www.flmnware.com/

 

 

 

看仅有的几个教程

http://www.openscenegraph.net/osgwiki/pmwiki.php/Tutorials/Tutorials

 

 

 

看例子

osgviewer开始,以后遇到什么问题看对应例子。

 

 

 

看邮件列表

先用自己的邮件订阅吧,这样每天可以收到一个简报,随时了解最新进展和最新问题。

或者查看邮件列表归档,地址:http://www.openscenegraph.net/archiver/osg-users/

 

 

 

看源码

在实在无计可施的情况下,可以去看源码,因为OpenSceneGraph的一切都在源码里,而且对所有人开放。

 

 

 

四、帮助更多人

可以把自己的心得,作品发到网上,避免后来人和你犯同样的错误。

 

 

 

2005年12月19日

原文网址:http://www.flmnware.com

安装OSG1.0后,我把以前写的几个程序重新编译了一下,都很顺利,不像0.9.8-2升级到0.9.9有几个基本接口有大的变化,这次我用到的几个类接口都没有变化。

运行的时候也很顺利,不过,有一个程序的HUD文字不见了,但是另一个程序使用同样HUD技术,即Projection下面一个MatrixTransform,再下面是Geode,确没有问题,查看之下,出问题的Projection设的是:
projection->setMatrix(Matrix::ortho2D(-1, 1, -1, 1));
而没出问题的代码是:
projection->setMatrix(Matrix::ortho2D(0, 1024, 0, 768));
我把后面的代码改成:
projection->setMatrix(Matrix::ortho2D(-512, 512, -384, 384));
也不会出问题。
最后我还是用了下面方式避免了这个错误:
projection->setMatrix(Matrix::ortho2D(0, 1024, 0, 768));
在OSG1.0中,添加了一个新类CameraNode,官方说,以后的HUD最好用CameraNode,使用起来简单一点吧。

有些程序要给别人,所以还需要用0.9.9编译,可以这样让0.9.9和1.0共存:
将0.9.9和1.0都装上,安装时最好改变一下开始菜单名字避免两个混在一起。
装完后,在path系统变量中,让1.0的bin在0.9.9的bin前面,在OSG_FILE_PATH环境变量中,也是把1.0的data放在0.9.9的data前面,中间用分号“;”分隔。
在VC7.1的include和lib设置中,都把1.0的放在0.9.9前面。
这样,编译程序是,如果用1.0,这样设置就可以了,编译、运行都没问题,如果想用0.9.9,则把1.0的安装目录改个名字就可以了。

2005年12月13日


下载地址:
http://www.flmnware.com/

说明:

本安装包只支持Microsoft Visual Studio .NET 2003,即VC++7.1!

为了进行开发,需将安装目录的include和lib目录添加入VC.net集成开发环境的对应项。

安装包包含OpenThreads、Producer和OpenSceneGraph的运行时动态链接库,开发用头文件和库文件,例子程序,版本分别为:
OpenThreads 1.4.2
Producer 1.0.1
OpenSceneGraph 1.0

还包括需要的第三方库,版本分别为:
FreeType 2.1.10
GDAL 1.3.1
Jpeg 6b
LibPng 1.2.8
LibUnGif 4.1.4
Tiff 3.7.4
Zlib 1.2.3

包含OpenSceneGraph-Data,版本为1.0。

包含OpenThreads、Producer和OpenSceneGraph的chm格式文档。

包含OpenThreads、Producer和OpenSceneGraph的源代码。

安装程序修改了系统的"PATH"环境变量,将安装目录的bin目录添加进去。

安装程序添加了环境变量"OSG_FILE_PATH",设定为安装目录的data目录。

2005年11月07日

接着上篇文章继续说

http://www.vrforum.cn/viewthread.php?tid=10769

2005年11月04日

晓康写的,可以到下面地址下载:

http://www.vrdn.net/viewthread.php?fpage=1&tid=831