OSG 学习第三天:渲染状态

OSG 渲染状态


前言:撸了两天代码,决定换一种学习方式试试。


渲染状态(Rendering State)  

OSG支持绝大部分的OpenGL 固定功能管道(fixed function pipeline)渲染,例如 Alpha 检验,Blending 融合, 剪切平面,颜色蒙板,面拣选(face culling),深度和模板检验,雾效,点和线 的光栅化(rasterization),等等。OSG 的渲染状态也允许应用程序指定顶点着色(vertex shader)和片段着色(fragment shader)。 用户的应用程序需要在 osg::StateSet 中设置渲染状态。

OSG 将渲染状态分成两个部分,渲染属性(attribute)和渲染模式(mode)。 
渲染属性也就是控制渲染特性的状态变量。例如,雾的颜色,或者 Blend 融合函 数都是 OSG 的状态属性。
OSG 中的渲染模式和 OpenGL 的状态特性几乎是一一 对应的,这些特性在 OpenGL 中通过函数 glEnable()和 glDisable()进行控制。用程序可以设置模式量以允许或禁止某个功能,例如纹理映射、灯光等。简单来说,渲染模式是指渲染的某个功能,而渲染属性是这个功能的控制变量和参数。

渲染的步骤如下:
1.设置渲染属性(Attribute)
如果要设置一项属性,首先将要修改的属性类实例化。设置该类的数值,然 后用 osg::StateSet::setAttribute()将其关联到 StateSet。下面的代码段用于实现面剔 除(face culling)的属性: 
// 获取变量 geom 的 StateSet 指针。
osg::StateSet* state = geom->getOrCreateStateSet();
 // 创建并添加 CullFace 属性类。 
osg::CullFace* cf = new osg::CullFace( osg::CullFace::BACK ); 
state->setAttribute( cf ); 
在上面的代码段中,geom 是一个 Geometry 几何类对象(当然也可以是任何 其它派生自 Drawable 和 Node 的对象)。获取 geom 的 StateSet 指针后,代码创建 了一个新的 osg::CullFace 对象,并将其关联到状态量。

2.设置渲染模式(Mode)
用户可以使用 osg::StateSet::setMode()允许或禁止某种模式。例如,下面的代 码将打开雾效模式的许可:
// 获取一个 StateSet 实例。
 osg::StateSet* state = geom->getOrCreateStateSet(); 
// 允许这个 StateSet 的雾效模式。 
state->setMode( GL_FOG, osg::StateAttribute::ON ); 
setMode()的第一个输入参数可以是任何一个在 glEnable()或 glDisable()中合 法的 OpenGL 枚举量 GLenum。第二个输入参数可以是 osg::StateAttribute::ON 或 osg::StateAttribute::OFF。
 
3.设置渲染属性和模式
OSG 提供了一个简单的可以同时设置属性和模式的单一函数接口。在许多 情况下,属性和模式之间都存在显著的关系。例如,CullFace 属性的对应模式为 GL_CULL_FACE。如果要将某个属性关联到一个 StateSet,同时打开其对应模式 的许可,那么可以使用 osg::StateSet::setAttributeAndModes()方法。下面的代码段 将关联 Blend 融合检验的属性,同时许可颜色融合模式。 
// 创建一个 BlendFunc 属性。 
osg::BlendFunc* bf = new osg::BlendFunc(); 
// 关联 BlendFunc 并许可颜色融合模式 
state->setAttributeAndMode( bf ); 
setAttributeAndModes()的第二个输入参数用于允许或禁止第一个参数中渲 染属性对应的渲染模式。其缺省值为 ON。这样用户的应用程序只需用一个函数, 就可以方便地指定某个渲染属性,并许可其对应的渲染模式。 


附上书上的一段代码:
//渲染状态(ClipeNode)
#include <osgViewer/Viewer>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/ClipNode>
#include <osg/PolygonMode>
#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>
#include <osg/AnimationPath>

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <osgUtil/Optimizer>

#include <iostream>


osg::ref_ptr<osg::Node> createClipeNode(osg::ref_ptr<osg::Node> subgraph)
{
	osg::ref_ptr<osg::Group> root = new osg::Group();

	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();

	//多边形线形绘制模式,正面和反面都绘制
	osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode();
	polymode->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::FILL);

	//启用多边形线形绘制模式,并指定状态继承属性为OVERRIDE
	stateset->setAttributeAndModes(polymode,osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

	//多边形线形绘制节点
	osg::ref_ptr<osg::Group> wrieframe_subgraph = new osg::Group;
	//设置渲染状态
	wrieframe_subgraph->setStateSet(stateset.get());
	wrieframe_subgraph->addChild(subgraph.get());

	root->addChild(wrieframe_subgraph.get());
	/*
	osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform;
	//更新回调,实现动态裁剪
	osg::ref_ptr<osg::NodeCallback> nc = new osg::AnimationPathCallback(subgraph->getBound().center(),
		osg::Vec3(0.0f, 0.0f, 1.0f), osg::inDegrees(45.0f));
	transform->setUpdateCallback(nc.get());

	//创建裁剪节点
	osg::ref_ptr<osg::ClipNode> clipnode = new osg::ClipNode;
	osg::BoundingSphere bs = subgraph->getBound();
	bs.radius() *= 0.4f;

	//设置裁剪节点的包围圈
	osg::BoundingBox bb;
	bb.expandBy(bs);

	//根据前面指定的包围盒创建6个裁剪平面
	clipnode->createClipBox(bb);
	//禁用拣选
	clipnode->setCullingActive(false);

	transform->addChild(clipnode.get());
	root->addChild(transform.get());

	//创建未被裁剪的节点
	osg::ref_ptr<osg::Group> clippedNode = new osg::Group;
	clippedNode->setStateSet(clipnode->getStateSet());
	clippedNode->addChild(subgraph.get());

	root->addChild(clippedNode.get());
	*/
	return root.get();
}


int main()
{
	//创建Viewer对象
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
	//osg::ref_ptr<osg::Group> root = new osg::Group();
	osg::ref_ptr<osg::Node> root = new osg::Node();
	
	//加载模型
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("cessna.osg");

	root = createClipeNode(node.get());

	//优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	//设置场景数据
	viewer->setSceneData(root.get());
	//初始化并创建窗口
	viewer->realize();
	//开始渲染
	viewer->run();

	return 0;
}

运行出来是一个飞机的模型,大家也可以把注释代码打开看看效果;

改变一下模式,看看输出什么样的飞机:
polymode->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE);   //线
polymode->setMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::POINT);  //点


  
  



下面简单介绍贴二维纹理映射:

创建二维纹理的步骤如下:
1.指定用户几何体的纹理坐标
2.创建纹理属性对象并保存纹理图形数据
3.为StateSet设置合适的纹理属性和模式

附上一段代码:
#include <osgViewer/Viewer>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/Image>
#include <osg/TexGen>
#include <osg/Texture1D>
#include <osg/TexEnv>
#include <osg/StateSet>

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <osgUtil/Optimizer>


//创建一个四边形节点
osg::ref_ptr<osg::Node> createNode()
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode();
	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();

	//设置顶点
	osg::ref_ptr<osg::Vec3Array> vc = new osg::Vec3Array();
	vc->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
	vc->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));
	vc->push_back(osg::Vec3(1.0f, 0.0f, 1.0f));
	vc->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));

	geom->setVertexArray(vc.get());

	//设置纹理坐标
	osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array();
	vt->push_back(osg::Vec2(0.0f, 0.0f));
	vt->push_back(osg::Vec2(1.0f, 0.0f));
	vt->push_back(osg::Vec2(1.0f, 1.0f));
	vt->push_back(osg::Vec2(0.0f, 1.0f));

	//第一个参数是纹理单元号, 第二个参数是纹理坐标数组
	geom->setTexCoordArray(0, vt.get());

	//设置法线  法线和光照有关
	osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array();
	nc->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));

	geom->setNormalArray(nc.get());
	//法线绑定方式:用一条法线绑定所有的顶点
	geom->setNormalBinding(osg::Geometry::BIND_OVERALL);

	//添加图元
	geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));

	//绘制
	geode->addDrawable(geom.get());

	return geode.get();
}

//创建二维纹理状态对象
osg::ref_ptr<osg::StateSet> createTexture2DState(osg::ref_ptr<osg::Image> image)
{
	//创建状态集对象
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();

	//创建二维纹理对象
	osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();
	texture->setDataVariance(osg::Object::DYNAMIC);
	//设置贴图
	texture->setImage(image.get());
	stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);

	return stateset.get();
}


int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
	osg::ref_ptr<osg::Group> root = new osg::Group();

	//读取贴图文件
	osg::ref_ptr<osg::Image> image = osgDB::readImageFile("Images/primitives.gif");
	osg::ref_ptr<osg::Node> node = createNode();

	//创建状态集对象
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
	stateset = createTexture2DState(image.get());

	//使用二维纹理
	node->setStateSet(stateset.get());

	root->addChild(node.get());

	//优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	//设置场景数据
	viewer->setSceneData(root.get());
	//初始化并创建窗口
	viewer->realize();
	//开始渲染
	viewer->run();

	return 0;
}

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值