OpenSceneGraph 图元绘制

本文详细介绍了如何使用OpenSceneGraph(osg)在OpenGL中构建几何图形,包括顶点、颜色、法线数据的管理,以及osg::Geometry、osg::Node、osg::Geode和Drawable的使用。还涵盖了图元数组、渲染状态设置、纹理映射和OSG的纹理处理技术。
摘要由CSDN通过智能技术生成

构建几何图形

保存要渲染的数据


//osg::Vec3 是一个三维浮点数数组;可以用来保存顶点和法线数据;
//osg::Vec4用于保存颜色数据;而 osg::Vec2 可以用于保存 2D 纹理坐标。

//模板数组:osg::Vec2Array,osg::Vec3Array 以及 
//osg::Vec4Array(数组中的每一个数据如osg::Vec3())

osg::ref_ptr<osg::Node> createSceneGraph()
{
	// 创建一个用于保存几何信息的对象
	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;

	// 创建四个顶点的数组
	osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
	geom->setVertexArray(v.get());  //将v设置为顶点数组
	v->push_back(osg::Vec3(-1.f, 0.f, -1.f));    
   //为对应的顶点的xyz坐标创建独立的三元向量(Vec3),并将其压入对应数组
	v->push_back(osg::Vec3(1.f, 0.f, -1.f));	
	v->push_back(osg::Vec3(1.f, 0.f, 1.f));
	v->push_back(osg::Vec3(-1.f, 0.f, 1.f));

	// 创建四种颜色的数组
	osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
	geom->setColorArray(c.get());		//创建颜色数组
	geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);		
        //设置Geometry类中颜色的绑定方式,
																//osg::Geometry::BIND_PER_VERTEX,即每种颜色对应一个顶点
	c->push_back(osg::Vec4(1.f, 0.f, 0.f, 1.f));          //(r,g,b,透明度)
	c->push_back(osg::Vec4(0.f, 1.f, 0.f, 1.f));
	c->push_back(osg::Vec4(0.f, 0.f, 1.f, 1.f));
	c->push_back(osg::Vec4(1.f, 1.f, 1.f, 1.f));

	// 为唯一的法线创建一个数组
	osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
	geom->setNormalArray(n.get());				//创建法线数组
	geom->setNormalBinding(osg::Geometry::BIND_OVERALL);  
        //设置Geometry类中颜色的绑定方式

//osg::Geometry::BIND_OVERALL,即整个 Geometry 几何体对应唯一的一个法线数据

	n->push_back(osg::Vec3(0.f, -1.f, 0.f));   //设置法线


	// 由保存的数据绘制四个顶点的多边形
	geom->addPrimitiveSet(
		new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

//addPrimitiveSet() - 这个方法用于设置 Geometry 类数据渲染的方法。
//其参数为一个osg::PrimitiveSet 指针
//(DrawArrays类为PrimitiveSet的子类之一)。
//PrimitiveSet 是一个无法直接实例化的虚基类。一个 Geometry 类
//可以添加多个 PrimtiveSet 对象。
	
//osg::DrawArrays()  第一个参数:确定 渲染的图形(QUADS四边形)
(osg::PrimitiveSet::POINTS点,osg::PrimitiveSet::TRIANGLE_STRIP三角形等) 
//第二个参数是顶点数组中的要使用的第一个顶点的下标,而第三个参数是将要使用的顶点元素的总数

//OSG 定义了 osg::Drawable 类,用于保存要渲染的数据。
//Drawable 是一个无法直接实例化的虚基类,osg::Geometry是其子类之一

//setVertexArray()和 setNormalArray()均使用一个 
//Vec3Array 指针作为输入参数,而 
//setColorArray()使用一个 Vec4Array 指针


//Geode 类派生自 Node 类。(在定义上,所有的 OSG 节点均
派生自 Node 类。)

//向 Geode 类添加几何体(Drawable)并返回 Geode 

    osg::ref_ptr<osg::Geode> geode = new osg::Geode;  //叶节点(Geode)
    geode->addDrawable(geom.get());     //将渲染数据与节点绑定
    return geode.get();
}

Drawables 类: 用于保存要渲染的数据,Drawable 是一个无法直接实例化的虚基类,osg::Geometry是其子类之一。

osg::Geometry的类方法:

  • setVertexArray(); setColorArray(); setNormalArray();—用于指定顶点数组,颜色,以及法线数据,setVertexArray()setNormalArray()均使用一个 Vec3Array 指针作为输入参数,而 setColorArray()使用一个 Vec4Array 指针

  • setColorBinding()setNormalBinding() —这些方法用于设置osg::Geometry类中颜色和法线数据的绑定方式,颜色绑定方式为 osg::Geometry::BIND_PER_VERTEX,即每种颜色对应一个顶点。而法线的绑定方式为osg::Geometry::BIND_OVERALL,即整个 Geometry 几何体对应唯一的一个法线数据。

  • addPrimitiveSet() —这个方法用于设置osg::Geometry类数据渲染的方式(绘制方式),一个 Geometry 类可以添加多个 PrimtiveSet 对象。addPrimitiveSet()方法允许用户程序设定OSG如何绘制Geometry类保存的几何数据

图元数组

PrimitiveSet类本身并不能记录顶点索引的信息,因此需要使用其派生类DrawArraysDrawElements(两者都叫图元数组)。

DrawArrays类

osg::DrawArrays* array = new osg::DrawArrays(mode,first,count)

image.png

对于参数mode: osg::PrimitiveSet::图元类型

image.png
image.png

DrawElements类

osg::DrawElements* array = new osg::DrawElementsUInt(mode,first,count)

与DrawArrays类类似,但是不再传入顶点数组的要渲染的第一个点的下标和要渲染的顶点总个数,而是直接传入所有要渲染的顶点的下标

优势: 用户可以自己选择要渲染的顶点,而DrawArrays类只能选择第一个要渲染的顶点的后面的一连串点。

image.png

DrawElements类的三个子类: DrawElementsUByte、DrawElementsUInt、DrawElementsUShort 表示要传入的索引(下标)值的数据类型不同

image.png

快速法线生成工具

osgUtil::SmoothingVisitor类是OSG自带的一个快速法线生成工具,对于复杂图形的法线计算很方便。

引入头文件 #include<osgUtil/SmoothingVisitor>

调用:

osgUtil::SmoothingVisitor smv;
smv.smooth(保存绘制体的对象名)

图元纹理与属性

OSG将渲染状态分成两个部分,渲染属性(attribute)和渲染模式(mode)。
渲染属性也就是控制渲染特性的状态变量。例如,雾的颜色,或者Blend融合函数都是OSG的状态属性,渲染模式:例如纹理映射、灯光,
渲染模式是指渲染的某个功能,而渲染属性是这个功能的控制变量和参数

渲染状态(Rendering State)

用户的应用程序需要在osg::StateSet类中设置渲染状态:

添加渲染属性:

//获取变量geom的StateSet指针。(geom是一个Geometry几何类对象,当然也可以是
//任何其它派生自Drawable和Node的对象)

osg::StateSet* state = geom->getOrCreateStateSet(); 

//创建并添加CullFace属性类。参数有FRONT,BACK,FRONT_AND_BACK,
//用于指定剔除表面是正面还是反面

osg::CullFace* cf = new osg::CullFace( osg::CullFace::BACK );   


state->setAttribute( cf );    //将属性添加至gemo中

允许或禁止渲染模式:

//可以使用osg::StateSet::setMode()允许或禁止某种模式(渲染模式)
// 获取一个StateSet实例。

osg::StateSet* state = geom->getOrCreateStateSet();

// 允许这个StateSet的雾效模式。

state->setMode(GL_FOG, osg::StateAttribute::ON);  

//第一个参数:openGL中的枚举量(这里是烟雾fog的意思),第二个输入参数可以是
//osg::StateAttribute::ON或osg::StateAttribute::OFF,表示该模式打开或关闭。


//OSG提供了一个简单的可以同时设置属性和模式的单一函数接口
//例如CullFace属性的对应模式为GL_CULL_FACE
//如果要将某个属性关联到一个StateSet,同时打开其对应模式的许可,

//那么可以使用osg::StateSet::setAttributeAndModes()方法

// 创建一个BlendFunc属性。

osg::BlendFunc* bf = new osg::BlendFunc();

// 关联BlendFunc并许可颜色融合模式
state->setAttributeAndMode(bf);

渲染属性与模式:
image.png
image.png
image.png
image.png
image.png
image.png

image.png

纹理和纹理属性

捕获.PNG

纹理简单来说就是将图片贴在模型表面,也可以理解为"皮肤"。
二维纹理通常为矩形,当遇见非矩形的模型时,往往需要手动设置纹理的各个顶点的坐标,这就叫纹理坐标

OSG共有8个纹理映射通道,又叫纹理单元(0~7),每个纹理单元可以独立设置不同的纹理坐标,以同时实现不同的图像映射结果,达到多重纹理的效果。

捕获.PNG

osg::ref_ptr<osg::Vec2Array>texcoords = new osg::Vec2Array;
//纹理坐标数组

texcoords->push_back(……)   
//存放纹理坐标

geom->setTexCoordArray(0,texcoords.get())
//为描绘体添加纹理坐标,参数1为用户选定的纹理单元,参数2为纹理坐标数组

OSG中使用texture类来表示和处理纹理,其中的类方法如下:

image.png
image.png
上面S,T,R代表X,Y,Z轴

texture类的派生类Texture2D类(常用):

image.png

image.png
二维纹理(Texture2D)要求图像的宽度和高度必须是2的幂次方

OSG用Texture1D类来表示和处理一维纹理,类方法Texture1D::setTextureWidth(int ) 用来表示一维纹理的宽度

例程代码:

void createTexture2D(osg::StateSet& ss)     //ss为一个StateSet实例
{
    osg::ref_ptr<osg::Texture2D>texture = new osg::Texture2D;
    //用于存放二维纹理
    
    texture->setImage(osgDB::readImageFile("clockface"));
    //将图片存入
    
    texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
    texture->setFilter(osg::Texture::MAG_FILTER,osg::Texture::LINEAR);
    //设置纹理滤波方式
    
    texture->setWrap(osg::Texture::WRAP_S,
                     osg::Texture::CLAMP_TO_BORDER);
    texture->setWrap(osg::Texture::WRAP_T,
                     osg::Texture::CLAMP_TO_BORDER);
    //设置纹理边界截取方式,osg::Texture::REPEAT为重复纹理绘制                 
                     
    texture->setBorderColor(osg::Vec4(1.0,1.0,0.0,1.0));
    //设置纹理边框颜色
    
    ss.setTextureAttributeAndModes(0,texture.get());
    //关联其纹理并许可对应模式
}

渲染状态也可以进行回调,与节点回调类似。
image.png
image.png
image.png

fog->setStart(1.0);fog->setEnd(2000.0);函数用于设置雾的起始距离和终止距离。

  • 27
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

freejackman

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值