OSG学习:纹理映射(一)——多重纹理映射

以下内容来自: 

1、《OpenSceneGraph三维渲染引擎编程指南》肖鹏 刘更代 徐明亮 清华大学出版社 

2、《OpenSceneGraph三维渲染引擎设计与实践》王锐 钱学雷 清华大学出版社

3、自己的总结

 

下载完整工程OSG_9_TextureMultiple

创建C++项目后,首先需要配置OSG环境,具体步骤看OSG学习:WIN10系统下OSG+VS2017编译及运行第六步:新建OSG项目测试。

 

直接来看例子:

// stdafx.h 

#include <osg/Node>  
#include <osg/Geometry>  
#include <osg/Geode> //是个几何节点,可以说是一个几何Group节点,一般的可绘制几何体都是通过它来传向root进行渲染,是OSG几何绘制的最高管理节点  
#include <osg/Group> //对节点起到组织作用,一般作为父节点或者根节点出现

#include <osg/Texture2D> //二维纹理映射类
#include <osg/TexGen> //指定用于自动生成纹理坐标的函数,可以设置纹理的计算方式是以物体坐标空间还是相机坐标空间来进行不同的计算
#include <osg/TexEnv> //设置当前纹理映射方式 

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

#include <osgViewer/Viewer>  

#include <osgUtil/Optimizer> 
//.cpp

/*
多重纹理映射
标准的二维纹理映射处理是一次把一幅纹理图像应用到一个多边形上
多重纹理映射允许应用几个纹理
在操作管理栈中依次把他们应用到同一个多边形上
多重纹理存在一些列的纹理单元
每个纹理单元执行单独的纹理操作
并把它的结果传递给下一个纹理单元
直到所有纹理单元的操作完成为止
最终显示处理后的效果
多重纹理能实现高级渲染技巧:光照、贴花、合成、细节纹理等

步骤:
指定用户几何体的纹理坐标
创建多个纹理属性对象并保存纹理多个图形数据
为StateSet设置合适的纹理属性和模式

对于不同的纹理属性对象需要指定不同的纹理单元及纹理坐标
否则就不会启用该纹理单元
或者该纹理单元会被覆盖
*/
static void textureMultiple(osg::Node *node, osg::Image *image)
{
	if (image)
	{
		//创建二维纹理
		osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
		texture->setImage(image);

		/*
		纹理坐标的自动生成模式:
		enum Mode
		{
			OBJECT_LINEAR, //物体线性,纹理贴图与移动物体保持固定
			EYE_LINEAR, //产生移动物体的动态轮廓线
			SPHERE_MAP, //球体贴图
			NORMAL_MAP, //发现贴图,用于立方图纹理
			REFLECTION_MAP, //反射贴图
		}
		*/
		osg::ref_ptr<osg::TexGen> texgen = new osg::TexGen;
		texgen->setMode(osg::TexGen::SPHERE_MAP);

		/*
		纹理映射模式(处理纹理图像数据与物体本身的融合):
		enum Mode
		{
			DECAL, //贴花
			MODULATE, //调整
			BLEND, //混合
			REPLACE, //替换,覆盖
			ADD
		}
		*/
		osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv;
		texenv->setMode(osg::TexEnv::BLEND);
		//设置混合模式BLEND操作的颜色
		texenv->setColor(osg::Vec4(0.6f, 0.6f, 0.6f, 0.0f));

		//启用单元1自动生成纹理坐标,并使用纹理
		//纹理单元可理解为纹理的索引
		//一个纹理单元与一个纹理图像相互对应绑定,控制着该纹理图像的处理步骤
		//一个纹理单元在一个纹理通道中维护纹理的各种状态,如滤波、环绕方式、环境、纹理坐标
		//在Mipmap中,多重纹理包含一组连续的纹理单元,Mipmap类似于数据金字塔
		//即当可视化对象距离视角越近,图像像素越高,看到的图像也就越清晰,当距离视角较远时,像素质量降低
		osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
		stateset->setTextureAttributeAndModes(1, texture.get(), osg::StateAttribute::ON);
		stateset->setTextureAttributeAndModes(1, texgen.get(), osg::StateAttribute::ON);

		//设置纹理环境
		stateset->setTextureAttribute(1, texenv.get());

		//设置纹理状态
		node->setStateSet(stateset.get());
	}
}

int main()
{
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("cow.osg");
	//读取贴图
	osg::ref_ptr<osg::Image> image = osgDB::readImageFile("Images/primitives.gif");

	//多重纹理映射
	textureMultiple(node, image);

	osg::ref_ptr<osg::Group> root = new osg::Group();
	root->addChild(node.get());

	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();

	viewer->setSceneData(root.get());
	viewer->realize();

	return viewer->run();
}

贴图:primitives.gif (编译好的文件里有)

结果:

 

 

 

可参考文章:纹理映射[转] 该文章为转载文章,但未注明出处。

当使用一个长宽不等的osg::Texture2D纹理时,需要计算每个顶点对应纹理的UV坐标。这可以通过以下公式来计算: 对于一个顶点的纹理坐标(u,v),其中u和v的值都应该在0到1之间,可以使用以下公式: u = (vertex.x - min_x) / (max_x - min_x) v = (vertex.y - min_y) / (max_y - min_y) 其中,vertex是当前顶点的位置,min_x、min_y、max_x和max_y是纹理在x和y方向上的最小和最大坐标。这些值可以通过osg::Texture2D::getImage()方法获得,然后使用getImage()->s()和getImage()->t()方法分别获得图像的宽度和高度。 代码示例: ``` osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D(); texture->setImage(image); float min_x = 0.0f, min_y = 0.0f, max_x = (float)image->s(), max_y = (float)image->t(); // 计算每个顶点对应的纹理坐标 osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()); osg::Vec2Array* texcoords = new osg::Vec2Array(vertices->size()); for(int i = 0; i < vertices->size(); i++) { osg::Vec3& vertex = (*vertices)[i]; (*texcoords)[i].set((vertex.x() - min_x) / (max_x - min_x), (vertex.y() - min_y) / (max_y - min_y)); } geometry->setTexCoordArray(0, texcoords); ``` 在上述示例中,geometry是一个osg::Geometry对象,它包含了需要进行纹理映射的顶点信息。我们首先使用osg::Texture2D::setImage()方法将纹理图像设置到纹理对象中,然后通过getImage()方法获取纹理图像的宽度和高度。接着,我们使用osg::Geometry对象的getVertexArray()方法获取顶点数组,并通过计算得到每个顶点对应的纹理坐标,最后将纹理坐标数组设置到geometry对象中的第0个纹理单元中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值