此系列文章只列举例子中的知识点,不写其他。
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提供的是线性插值,所以关键点也不能给的太少啊,不然插值结果会跟你想的差太多。
其他
这个例子在看的时候,自己敲了一遍,发现了一个盲点:
- osg::Quat(osg::inDegree(30.), 0,0,1)
- osg::Quat(osg::inDegree(30.), osg::Vec3(0,0,1))
这两个是完全不一样的!!
一开始的时候就是想当然的写成了(1),结果飞机的姿态始终不对,对着代码看了半天也没发现是哪的原因。最后看了osg::Quat的源码才发现不同-_____-
(1)是直接指定四元数中的x,y,z,w;(2)是指定旋转的角度和旋转轴。切记!切记!!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。