OpenSceneGraph基础:Helloworld

OpenSceneGraph的基本流程(main函数):

转载请注明http://blog.csdn.net/boksic 如有疑问欢迎留言

int main() {
	Group *scene = startupScene();

	osgViewer::Viewer viewer;
	viewer.setSceneData(scene);
	viewer.setCameraManipulator(new osgGA::TrackballManipulator);
	viewer.realize();

	while (!viewer.done()) {		
		viewer.frame();
		update(0.005); // do the update advancing 5ms
	} 

	return 0;
}

  • startupScene函数是自己建立的场景初始化函数,返回值是包含了场景图形数据的Group类
  • 接着初始化Viewer类,以及提供了模型操作功能的TrackballManipulator
  • 最后就是最为重要的渲染部分-Viewer的循环,每帧都会调用自定义的update函数

场景初始化(startupScene)

建立模型数据

这里使用的是程序内部初始化数据,包含了顶点坐标,面索引以及顶点颜色

(部分网上教程里还使用了顶点的颜色索引colorIndexArray,但该功能因为非常影响性能,现在的OSG中已废除了该功能。所以顶点与色彩应按对应关系初始化)

	// 顶点
	osg::Vec3Array *vertexArray = new osg::Vec3Array();
	vertexArray->push_back(osg::Vec3(-2, -2, 0)); // front left 
	vertexArray->push_back(osg::Vec3(+2, -2, 0)); // front right 
	vertexArray->push_back(osg::Vec3(+2, +2, 0)); // back right 
	vertexArray->push_back(osg::Vec3(-2, +2, 0)); // back left 
	vertexArray->push_back(osg::Vec3(0, 0, 2*sqrt(2))); // peak
	vertexArray->push_back(osg::Vec3(0, 0, -2*sqrt(2))); // lower peak

	// 面,全部按逆时针顺序索引顶点
	osg::DrawElementsUInt *faceArray = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
	faceArray->push_back(0); // face 0
	faceArray->push_back(1);
	faceArray->push_back(4);
	faceArray->push_back(1); // face 1
	faceArray->push_back(2);
	faceArray->push_back(4);
	faceArray->push_back(2); // face 2
	faceArray->push_back(3);
	faceArray->push_back(4);
	faceArray->push_back(3); // face 3
	faceArray->push_back(0);
	faceArray->push_back(4);
	faceArray->push_back(0); // face 4
	faceArray->push_back(5);
	faceArray->push_back(1);
	faceArray->push_back(2); // face 5
	faceArray->push_back(1);
	faceArray->push_back(5);
	faceArray->push_back(3); // face 6
	faceArray->push_back(2);
	faceArray->push_back(5);
	faceArray->push_back(0); // face 7
	faceArray->push_back(3);
	faceArray->push_back(5);

	// 色彩
	osg::Vec4Array *colorArray = new osg::Vec4Array();
	colorArray->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); //index 0
	colorArray->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); //index 1
	colorArray->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); //index 2
	colorArray->push_back(osg::Vec4(1.0f, 0.0f, 1.0f, 1.0f)); //index 3
	colorArray->push_back(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f)); //index 4 
	colorArray->push_back(osg::Vec4(1.0f, 1.0f, 0.5f, 1.0f)); //index 5

将建立的数据存为osg里的对象:

	osg::Geometry *geometry = new osg::Geometry();
	geometry->setVertexArray(vertexArray);
	geometry->setColorArray(colorArray);
	geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
	geometry->addPrimitiveSet(faceArray);

Osg中定义了Drawables虚基类用于存储形状数据,该类派生出了3个子类

  1. DrawPixels,封装opengl的glDrawPixels
  2. ShapeDrawable,用于绘制OSG自带的简单集合体
  3. Geometry,功能最为广泛的子类,本例当中就是使用该类

Geometry的setVertexArray() , setColorArray() , setNormalArray()等函数用于设置坐标,颜色,法线等数据。setColorBinding()用于设置颜色绑定方式,本例中的BIND_PER_VERTEX即每个顶点对应一个颜色。addPrimitiveSet()则告诉OSG如何利用这些数据绘制图形,前面我们使用了DrawElementsUInt为PrimitiveSe的派生类来按照三角形绘制数据,这点与OpenGL下的代码非常相似。

建立叶节点:

	Geode *pyramidObject = new Geode();
	pyramidObject->addDrawable(geometry);
Geode类派生自Node节点类,Geode即Geometry Node,用于保存几何信息。该类的addDrawable()函数可用来将Drawables类的数据关联起来。

建立组节点

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

    for (int i = 0; i < 1000; i++) {
        tr[i] = new osg::PositionAttitudeTransform;
        tr[i]->setPosition(osg::Vec3(((float)rand() / RAND_MAX * 4) * 1000, ((float)rand() / RAND_MAX * 4) * 1000, 0));
        tr[i]->addChild(pyramidObject);

        root->addChild(tr[i]);
    }

    return root;
}

组节点类Group继承自Node,OSG编程的核心,可通过addChild()添加子节点,也可以拥有父节点。

Group有几个派生类,其中一个是Tranform类用于几何变换,不过Transform是虚基类,实际使用MatrixTransform或PositionAttitudeTransform这两个子类。本例中的tr是一个PositionAttitudeTransform类对象的数组,该类可以通过setPosition来设置位置或者通过四元数来实现旋转。

本程序建立了1000个实现随机分布的Transform子节点,每个节点都添加了前面的叶节点作为几何数据。

初始化的部分就结束了。


场景更新

float t= 0;
void update(float dt) {
	// keep track of the time
	t+= 0.02*dt;


	double ro = (3 / 4)*(3.1415926 / 2);

	//float myRand = ((float)rand() / RAND_MAX);

	for (int i = 0; i < 1000; i++) {
		osg::Vec3d currentPosition = tr[i]->getPosition();
		osg::Vec3d *newPosition;


 
			newPosition = new osg::Vec3d(sin(3 * t*i + ro) * (10 + i), sin(4 * t*i) ,i);//+ dt * (i + 1) / 10
	  
		tr[i]->setPosition(osg::Vec3(newPosition->x(), newPosition->y(), newPosition->z()));
	}
}

更新部分通过全局变量t来控制时间,使用Transform节点的setPosition来控制模型位置,本例实现的是一个随时间变化的丽莎如图形:

OpenSceneGraph基础:Helloworld_第1张图片


或者改变参数实现其他效果:

OpenSceneGraph基础:Helloworld_第2张图片





你可能感兴趣的:(OpenSceneGraph基础:Helloworld)