(文章很长,如果想直接看源码不想听我啰嗦的话,请直接跳到最后下载源码)
如果要做针对模型的算法,获取模型中所有图元(由于OSG多边形只支持三角形图元,而且自己做的科研也是针对三角网模型的,本文就针对三角形模型来说明)的坐标、纹理、法向量等数据,然后再进行处理是非常重要的,但是网上关于获取图元属性的教程实在太少,而且有的说的也不是很清楚,自己在做科研的过程中,探索以后,记录在此,希望能帮助到有需要的同学。
首先要知道,在osg中几何图元是被几何体(osg::Geometry)管理的,osg::Geometry提供了管理几何图元osg::PrimitiveSet的数组,用来添加和删除这些图元,这些图元共同构成了几何体对象。要访问图元的属性,应该就要在geometry中找,查看geometry的函数,发现有两个访问者函数:
virtual void accept(PrimitiveFunctor& pf) const;
virtual void accept(PrimitiveIndexFunctor& pf) const;
根据命名我们可以看出,这两个函数对应着图元的访问和图元索引的访问。Geometry的父类Drawable也有这两个函数。因为在Node中,我们很容易拿到Drawable,所以我们要获取图元的属性,应该是要给Drawable传入访问器,然后在访问器的apply中获取图元的属性了。
通过查文档,我们发现Drawale支持四个visitor来获取Drawable的信息,分别是:
virtual void accept(AttributeFunctor&);
virtual void accept(ConstAttributeFunctor&) const;
virtual void accept(PrimitiveFunctor&) const;
virtual void accept(PrimitiveIndexFunctor&) const;
我们要访问图元的属性和索引,主要用到的是AttributeFunctor还有PrimitiveIndexFunctor。首先看AttributeFunctor类的定义:
class AttributeFunctor
{
public:
virtual ~AttributeFunctor() {}
virtual void apply(AttributeType,unsigned int,GLbyte*) {}
virtual void apply(AttributeType,unsigned int,GLshort*) {}
virtual void apply(AttributeType,unsigned int,GLint*) {}
virtual void apply(AttributeType,unsigned int,GLubyte*) {}
virtual void apply(AttributeType,unsigned int,GLushort*) {}
virtual void apply(AttributeType,unsigned int,GLuint*) {}
virtual void apply(AttributeType,unsigned int,float*) {}
virtual void apply(AttributeType,unsigned int,Vec2*) {}
virtual void apply(AttributeType,unsigned int,Vec3*) {}
virtual void apply(AttributeType,unsigned int,Vec4*) {}
virtual void apply(AttributeType,unsigned int,Vec4ub*) {}
virtual void apply(AttributeType,unsigned int,double*) {}
virtual void apply(AttributeType,unsigned int,Vec2d*) {}
virtual void apply(AttributeType,unsigned int,Vec3d*) {}
virtual void apply(AttributeType,unsigned int,Vec4d*) {}
};
不出所料,就是在不同的apply函数中,可以获取不同类型的属性信息。
再看PrimitiveIndexFunctor的实现:
class PrimitiveIndexFunctor
{
public:
virtual ~PrimitiveIndexFunctor() {}
virtual void setVertexArray(unsigned int count,const Vec2* vertices) = 0;
virtual void setVertexArray(unsigned int count,const Vec3* vertices) = 0;
virtual void setVertexArray(unsigned int count,const Vec4* vertices) = 0;
virtual void setVertexArray(unsigned int count,const Vec2d* vertices) = 0;
virtual void setVertexArray(unsigned int count,const Vec3d* vertices) = 0;
virtual void setVertexArray(unsigned int count,const Vec4d* vertices) = 0;
virtual void drawArrays(GLenum mode,GLint first,GLsizei count) = 0;
virtual void drawElements(GLenum mode,GLsizei count,const GLubyte* indices) = 0;
virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices) = 0;
virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices) = 0;
virtual void begin(GLenum mode) = 0;
virtual void vertex(unsigned int pos) = 0;
virtual void end() = 0;
void useVertexCacheAsVertexArray()
{
setVertexArray(_vertexCache.size(),&_vertexCache.front());
}
std::vector<Vec3> _vertexCache;
bool _treatVertexDataAsTemporary;
};
可以看到,里面有函数drawElements函数,有openGL知识的通过应该知道这个函数时用来使用索引绘图的,里面通过各类参数应该可以拿到顶点的信息。但是在文档中我们看发现这个类是一个类中的函数都没有实现(如下图所示)
所以我们再去看看他的子类是否有实现,进一步看文档我们可以发现,PrimitiveIndexFunctor类有以下三个子类:
我们要处理的是三角形,再去看看TriangleIndexFunctor,
virtual void setVertexArray (unsigned int, const Vec2 *)
virtual void setVertexArray (unsigned int, const Vec3 *)
virtual void setVertexArray (unsigned int, const Vec4 *)
virtual void setVertexArray (unsigned int, const Vec2d *)
virtual void setVertexArray (unsigned int, const Vec3d *)
virtual void setVertexArray (unsigned int, const Vec4d *)
virtual void begin (GLenum mode)
virtual void vertex (unsigned int vert)
virtual void end ()
virtual void drawArrays (GLenum mode, GLint first, GLsizei count)
virtual void drawElements (GLenum mode, GLsizei count, const GLubyte *indices)
virtual void drawElements (GLenum mode, GLsizei count, const GLushort *indices)
virtual void drawElements (GLenum mode, GLsizei count, const GLuint *indices)
我们发现里面仍然有drawElements函数,所以我们就直接用这个类来获取模型中三角形索引的信息。从文档中得知:TriangleIndexFunctor是一个类模板,而且它继承自自身模板参数T,在模板参数中必须实现T::operator()(const unsigned& v1, const unsigned& v2, const unsigned& v3)这个函数,每绘制一个三角形