此系列文章只列举例子中的知识点,不写其他。

例子代码

PrimitiveSet

在OSG里绘制的基本对象就是这个了。

在osg里是这样对数据进行组织的:Geometry是一个可绘制图元,最基本的Geometry是由顶点,颜色,法矢组成的,而最终这些东西如何画出来,是由PrimiviteSet来决定,每个Geometry可以通过addPrimitiveSet添加多个PrimitiveSet。
```c++
osg::Geometry* geom = new osg::Geometry;
geom->setVertexArray(coords);
geom->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET);
geom->setNormalArray(normals, osg::Array::BIND_OVERALL);

geom->addPrimitiveSet(whitePrimitives.get());
geom->addPrimitiveSet(blackPrimitives.get());


从这个关系就可以推出来,顶点、颜色、法矢等都是可被多个PrimitiveSet共享使用的,在这个例子里就是这样用的。在设置颜色和法矢的时候,可以设定这两个值的绑定方式,比如BIND_PER_PRIMITIVE_SET表示ColorArray中的每个颜色对应一个PrimitiveSet;BIND_OVERALL则表示所有的PrimitiveSet都使用同一个法矢值。 常用的PrimitiveSet除了DrawArrays外,还有这个例子里用到的DrawElementsUInt使用顶点索引进行绘制PrimitiveSet。而对顶点索引的操作,与std::vector基本一致: ```c++ osg::ref_ptr<osg::DrawElementsUShort> whitePrimitives = new osg::DrawElementsUShort(GL_QUADS); osg::ref_ptr<osg::DrawElementsUShort> blackPrimitives = new osg::DrawElementsUShort(GL_QUADS); int numIndicesPerRow=numTilesX+1; for(iy=0;iy<numTilesY;++iy) { for(int ix=0;ix<numTilesX;++ix) { osg::DrawElementsUShort* primitives = ((iy+ix)%2==0) ? whitePrimitives.get() : blackPrimitives.get(); primitives->push_back(ix +(iy+1)*numIndicesPerRow); primitives->push_back(ix +iy*numIndicesPerRow); primitives->push_back((ix+1)+iy*numIndicesPerRow); primitives->push_back((ix+1)+(iy+1)*numIndicesPerRow); } }

AnimationPath

从名字上可以看出,这个类可以提供路径动画功能,采用的方式是控制点。一个完整的路径动画由一系列时间偏移量和ControlPoint组成,每个ControlPoint包含position、scale、rotate,用于表示某个时间点上模型的姿态。

要完成一个路径动画,我们只需要指定关键的控制点(ControlPoint)就可以了,AnimationPath自己会线性插值出中间的控制点。

如本例中,构造一个环形路径动画:
```c++
osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
{
// set up the animation path
osg::AnimationPath* animationPath = new osg::AnimationPath;
animationPath->setLoopMode(osg::AnimationPath::LOOP);

int numSamples = 40;
float yaw = 0.0f;
float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);
float roll = osg::inDegrees(30.0f);

double time=0.0f;
double time_delta = looptime/(double)numSamples;
for(int i=0;i<numSamples;++i)
{
    osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
    osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));

    animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));

    yaw += yaw_delta;
    time += time_delta;

}
return animationPath;

}
```

要注意,AnimationPath提供的是线性插值,所以关键点也不能给的太少啊,不然插值结果会跟你想的差太多。

其他

这个例子在看的时候,自己敲了一遍,发现了一个盲点:

  1. osg::Quat(osg::inDegree(30.), 0,0,1)
  2. osg::Quat(osg::inDegree(30.), osg::Vec3(0,0,1))

这两个是完全不一样的!!

一开始的时候就是想当然的写成了(1),结果飞机的姿态始终不对,对着代码看了半天也没发现是哪的原因。最后看了osg::Quat的源码才发现不同-_____-

(1)是直接指定四元数中的x,y,z,w;(2)是指定旋转的角度和旋转轴。切记!切记!!


chaoswong
48 声望2 粉丝

引用和评论

0 条评论