osg示例解析之osgLight(1)

来源:互联网 发布:数组中删除指定元素 编辑:程序博客网 时间:2024/05/18 15:57

1. 简介

osgLight示例演示了osg如何使用光照。

2. 描述

首先看一下osgLight的运行效果图,如下图所示: 
osgLight

3. 创建立方体

3.1 绘制一个面

首先是创建场景中的立方体,在创建中需要创建立方体的每一个面,实现在函数 createWall中,createWall的函数原型如下

osg::Geometry* createWall(const osg::Vec3& v1,const osg::Vec3& v2,const osg::Vec3& v3,osg::StateSet* stateset)
  • 1
  • 1

调用它的代码如下所示:

    // create front side.    geode->addDrawable(createWall(bb.corner(0),                                  bb.corner(4),                                  bb.corner(1),                                  wall));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

可以知道它是通过某个节点的包围盒来创建的,那么包围盒的corner分别是哪些点呢?也就是说这里的corner(0)到corner(7)分别指的是包围盒的哪些。查看源码可以得知:

//BoundingBox源码inline const vec_type corner(unsigned int pos) const{ return vec_type(pos&1?_max.x():_min.x(),pos&2?_max.y():_min.y(),pos&4?_max.z():_min.z());}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

也就是说corner(0)到corner(7)遵循x、y、z从小到大排列,同时x优先y优先z的顺序,具体来说corner(0-7)如下图所示:

Corner顺序

通过上图以及createWall被调用的情况(前面是 0、4、1),我们可以知道该函数 createWall中的前三个参数 v1、v2、v3分别指的是一个四边形的 左下点、左上点和右下点。(如果这点不清除那么代码阅读起来会有很大的障碍)通过阅读createWall的代码可以知道,该函数主要是用来绘制立方体的一个面,这个面被细分成100x100个四边形小方格来绘制。

3.2 绘制立方体

通过6个面的绘制组装成一个立方体,立方体绘制的代码如下:

    osg::StateSet* rootStateSet = new osg::StateSet;    root->setStateSet(rootStateSet);    osg::StateSet* wall = new osg::StateSet;    wall->setMode(GL_CULL_FACE,osg::StateAttribute::ON);    osg::StateSet* floor = new osg::StateSet;    floor->setMode(GL_CULL_FACE,osg::StateAttribute::ON);    osg::StateSet* roof = new osg::StateSet;    roof->setMode(GL_CULL_FACE,osg::StateAttribute::ON);    osg::Geode* geode = new osg::Geode;    // create front side.    geode->addDrawable(createWall(bb.corner(0),                                  bb.corner(4),                                  bb.corner(1),                                  wall));    // right side    geode->addDrawable(createWall(bb.corner(1),                                  bb.corner(5),                                  bb.corner(3),                                  wall));    // left side    geode->addDrawable(createWall(bb.corner(2),                                  bb.corner(6),                                  bb.corner(0),                                  wall));    // back side    geode->addDrawable(createWall(bb.corner(3),                                  bb.corner(7),                                  bb.corner(2),                                  wall));    // floor    geode->addDrawable(createWall(bb.corner(0),                                  bb.corner(1),                                  bb.corner(2),                                  floor));    // roof    geode->addDrawable(createWall(bb.corner(6),                                  bb.corner(7),                                  bb.corner(4),                                  roof));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

绘制六个面(设置了面的拣选,让背面被剔除掉),这些面绘制顺序是让背面朝向外,设置之后可以看到立方体内部。

3.3 绘制光源

场景中的光源绘制是在createLights函数中完成的,这个函数绘制了两个光源,一个光源固定在立方体的左上角(corner(4))的位置,另一个光源是一个移动的光源,移动的路径是立方体的8个角点组成的。

3.4 模型动画

osgLight中添加了一个模型,通过该模型计算出一个包围盒,模型中添加了动画效果,主要是通过ModelTransformCallback实现的。实现如下:

class ModelTransformCallback : public osg::NodeCallback{    public:        ModelTransformCallback(const osg::BoundingSphere& bs)        {            _firstTime = 0.0;            _period = 4.0f;            _range = bs.radius()*0.5f;        }        virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)        {            osg::PositionAttitudeTransform* pat = dynamic_cast<osg::PositionAttitudeTransform*>(node);            const osg::FrameStamp* frameStamp = nv->getFrameStamp();            if (pat && frameStamp)            {                if (_firstTime==0.0)                {                    _firstTime = frameStamp->getSimulationTime();                }                double phase = (frameStamp->getSimulationTime()-_firstTime)/_period;                phase -= floor(phase);                phase *= (2.0 * osg::PI);                osg::Quat rotation;                rotation.makeRotate(phase,1.0f,1.0f,1.0f);                pat->setAttitude(rotation);                pat->setPosition(osg::Vec3(0.0f,0.0f,sin(phase))*_range);            }            // must traverse the Node's subgraph            traverse(node,nv);        }        double _firstTime;        double _period;        double _range;};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

主要是修改位置姿态节点osg::PositionAttitudeTransform类,该类与osg::MatrixTransform类似,主要区别在于osg::PositionAttitudeTransform比较直观,通过设置缩放、平移量和旋转实现。它的矩阵 Matrix = SRT(顺序是缩放、旋转、平移),在NodeCallback中一直去修改平移和旋转实现动画的效果。

osg::MatrixTransform和osg::PositionAttitudeTransform的几点区别: 
1. osg::MatrixTransform按照我们给的顺序组合各种变换,比如我们先定义平移、在定义旋转和缩放,那么MatrixTransform的矩阵是 
M = TRS,也就是所它会严格按照我们指定的顺序执行操作。指定的顺序不同时产生的结果差异巨大。 
2. osg::PositionAttitudeTransform同时几个接口来获得平移、旋转和缩放矩阵,分别是:

1.setPosition指定平移量2.setAttitude指定旋转量3.setScale指定缩放量
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

不管我们设置的顺序如何,它的结果矩阵M=SRT(先缩放再旋转最后平移)总是按固定的顺序进行。除此之外osg::PositionAttitudeTransform还可以设置旋转和缩放的轴心位置(一般来说旋转和缩放是以原点为轴心进行的),但是PositionAttitudeTransform提供了让我们以其他位置为轴心进行旋转和缩放。

  1. 如果我们想用MatrixTranform实现与PositionAttitudeTransform同样的效果,那么就必须设置三个矩阵相乘的顺序是SRT。如果PositionAttitudeTransform设置了轴心位置,那么在作平移和旋转变换的时候还需要注意应该先平移到轴心位置,再旋转(和缩放),再平移回去。
0 0
原创粉丝点击