OSG实例化渲染:Instancing

4 篇文章 0 订阅

实例化的两种方式

当实例数量较少时选择通过uniform数组 + gl_InstanceID方式实现;当数据较大时超过uniform限定时选择通过顶点数组的方式实现,需要用到的相关opengl函数glVertexAttribDivisor(int a, int b)。

方式二:vbo + glVertexAttribDivisor

	{
		//----------------instance test-------------------
		root->removeChild(0, root->getNumChildren());
		osg::ref_ptr<osg::Geometry> drawInstance = new osg::Geometry;
		osg::Vec3 vtxCoords[] = {
			osg::Vec3(-1.0, 2.0, -1.0),
			osg::Vec3(1.0, 2.0, -1.0),
			osg::Vec3(-1.0, 2.0,  1.0)
		};
		osg::Vec3 offsets[] = {
			osg::Vec3(-2.0, 0.0, 0.0),
			osg::Vec3( 2.0, 0.0, 0.0),
			osg::Vec3(0.0, 0.0, 2.0)
		};
		osg::Vec3 colors[] = {
			osg::Vec3(1.0, 0.0, 0.0),
			osg::Vec3(0.0, 1.0, 0.0),
			osg::Vec3(0.0, 0.0, 1.0)
		};
		int vCount = sizeof(vtxCoords) / sizeof(osg::Vec3);
		drawInstance->setVertexAttribArray(0, new osg::Vec3Array(vCount, vtxCoords), osg::Array::BIND_PER_VERTEX);
		drawInstance->setVertexAttribArray(1, new osg::Vec3Array(3, offsets), osg::Array::BIND_PER_VERTEX);
		drawInstance->setVertexAttribArray(2, new osg::Vec3Array(vCount, colors), osg::Array::BIND_PER_VERTEX);
		drawInstance->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 3, 3));
		{
			drawInstance->setUseDisplayList(false);
			drawInstance->setUseVertexBufferObjects(true);

			osg::BoundingBox bb(-3., -3., -3., 3., 3., 3.);
			drawInstance->setInitialBound(bb);

			osg::StateSet* pStateSet = drawInstance->getOrCreateStateSet();
			pStateSet->setAttribute(new osg::VertexAttribDivisor(1, 1));

			const std::string vs = {
			"#version 330 compatibility \n"
			"layout(location = 0) in vec3 aPos; \n"
			"layout(location = 1) in vec3 aOffset; \n"
			"layout(location = 2) in vec3 aColor; \n"
			" \n"
			"out vec4 fColor; \n"
			" \n"
			"void main() \n"
			"{ \n"
			"	gl_Position = gl_ModelViewProjectionMatrix * vec4(aPos + aOffset, 1.0); \n"
			"	fColor = vec4(aColor, 1.0); \n"
			"} \n"
			" \n"
			};

			const std::string fs = {
			"#version 330 compatibility \n"
			" \n"
			"in vec4 fColor; \n"
			" \n"
			"void main() \n"
			"{ \n"
			"	gl_FragColor = fColor; \n"
			"} \n"
			" \n"
			};

			osg::ref_ptr<osg::Program> program = new osg::Program;
			program->addShader(new osg::Shader(osg::Shader::VERTEX, vs));
			program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fs)); 
			pStateSet->setAttributeAndModes(program, osg::StateAttribute::ON);
		}

		root->addChild(drawInstance);
	}

效果截图:
在这里插入图片描述
注意事项:
1、禁用显示列表并启用顶点缓存对象。

drawInstance->setUseDisplayList(false);
drawInstance->setUseVertexBufferObjects(true);

2、glVertexAttribDivisor函数的设置:这个函数告诉了OpenGL该什么时候更新顶点属性的内容至新一组数据。它的第一个参数是需要的顶点属性,第二个参数是属性除数(Attribute Divisor)。默认情况下,属性除数是0,告诉OpenGL我们需要在顶点着色器的每次迭代时更新顶点属性。将它设置为1时,我们告诉OpenGL我们希望在渲染一个新实例的时候更新顶点属性。而设置为2时,我们希望每2个实例更新一次属性,以此类推。我们将属性除数设置为1,是在告诉OpenGL,处于位置值2的顶点属性是一个实例化数组。

osg::StateSet* pStateSet = drawInstance->getOrCreateStateSet();
pStateSet->setAttribute(new osg::VertexAttribDivisor(1, 1));

3、顶点属性的绑定;主要用于与glVertexAttribDivisor第一个参数匹配

drawInstance->setVertexAttribArray(0, new osg::Vec3Array(3, vtxCoords), osg::Array::BIND_PER_VERTEX);
drawInstance->setVertexAttribArray(1, new osg::Vec3Array(3, offsets), osg::Array::BIND_PER_VERTEX);
drawInstance->setVertexAttribArray(2, new osg::Vec3Array(3, colors), osg::Array::BIND_PER_VERTEX);

4、注意初始化包围盒,否则可能因为系统效率优化直接将shader生成几何体实例剔除掉,导致看不见

osg::BoundingBox bb(-3., -3., -3., 3., 3., 3.);
drawInstance->setInitialBound(bb);

5、动态修改数组时,需要调用函数dirty以通知gpu,实现数据更新

osg::ref_ptr<osg::Vec3Array> offsets = new osg::Vec3Array;
...修改
offsets->dirty()

6、多个实例化渲染时,模型不能共享!!!如下:

osg::ref_pt<osgDB::Options> _options = new osgDB::Options("roads_designer");
_options->setObjectCacheHint(osgDB::Options::CACHE_ALL);
auto group1 = new InstanceGroup(10, 11);
group1->addChild(osgDB::readRefNodeFile("roads/qiao/qiaodun.ive", _options));
auto group2 = new InstanceGroup(10, 11);
group2->addChild(osgDB::readRefNodeFile("roads/qiao/qiaodun.ive", _options));

// XXX,以上情况会导致,group1失效,只有group2有效渲染。原因是_options使得group1 和group2之间共享了相同的模型

7、通常更新方式
type one:

offsets->assign(waveKeyPoints->begin(), waveKeyPoints->end());
offsets->dirty();
//intial->eg: instance = new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4, offsets->size());
instance->setNumInstances(offsets->size());

type two:

//eg: drawInstance = new osg::Geometry;
drawInstance->removePrimitiveSet(0, drawInstance->getNumPrimitiveSets());
drawInstance->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4, offsets->size()));

type three

//初始化时创建足够多的实例,然后only更新数组
for (int i = 0; i < waveKeyPoints->size(); ++i) {
    osg::Vec3 p = waveKeyPoints->at(i);
    offsets->at(i) = p;
}
offsets->dirty();

方式一:uniform + gl_InstanceID

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值