网页游戏人气排行榜,百度seo插件,太原网站快速排名优化,已经有域名,如何建设网站1、纹理映射介绍 物体的外观不仅包括形状#xff0c;不同物体表面有着不同的颜色和图案。一个简单而有效地实现这种特性的方法就是使用纹理映射。在三维图形中#xff0c;纹理映射#xff08;Texture Mapping#xff09;的方法运用广泛#xff0c;使用该技术可以大大提高物…1、纹理映射介绍 物体的外观不仅包括形状不同物体表面有着不同的颜色和图案。一个简单而有效地实现这种特性的方法就是使用纹理映射。在三维图形中纹理映射Texture Mapping的方法运用广泛使用该技术可以大大提高物体的真实感。 OSG 是对底层 OpenGL API 的封装OpenGL 本身有非常标准而高效的纹理机制。OSG 全面支持OpenGL 的纹理映射机制因此在 OSG 中使用纹理映射机制非常简单。纹理映射主要包括一维纹理、二维纹理、三维纹理、凸凹纹理、多重纹理、Mipmap 纹理、压缩纹理和立方纹理等。本文主要针对一维纹理、二维纹理、三维纹理、多重纹理、Mipmap 纹理和立方纹理等经常使用的几种纹理加以解释说明。
下面讲解一些纹理的基础知识这些对于熟悉 OpenGL 的朋友来说应该都是再基础不过了。
1纹理坐标
enum WrapParameter
{
WRAP_S, //x 轴
WRAP_T, //y 轴
WRAP_R //z 轴
};2纹理的包装模式
enum WrapMode
{
CLAMP GL_CLAMP, //截取
CLAMP_TO_EDGE GL_CLAMP_TO_EDGE,//边框始终被忽略
CLAMP_TO_BORDER GL_CLAMP_TO_BORDER_ARB, //它使用的纹理取自图像的边框没有边框就使用
常量边框颜色
REPEAT GL_REPEAT, //纹理的重复映射
MIRROR GL_MIRRORED_REPEAT_IBM //纹理镜像的重复映射
};3纹理过滤方法
enum FilterParameter
{
MIN_FILTER, //用于缩小
MAG_FILTER //用于放大
};4纹理的过滤处理
enum FilterMode
{
LINEAR GL_LINEAR, //以周围 4 个像素的平均值作为纹理
LINEAR_MIPMAP_LINEAR GL_LINEAR_MIPMAP_LINEAR,//使用线性均和计算两个纹理的值
LINEAR_MIPMAP_NEAREST GL_LINEAR_MIPMAP_NEAREST,//线性地改写临近的纹理单元值
NEAREST GL_NEAREST, //取比较接近的像素作为纹理
NEAREST_MIPMAP_LINEAR GL_NEAREST_MIPMAP_LINEAR,//在两个纹理中选择最临近的纹理并取它
们之间的线性均和值
NEAREST_MIPMAP_NEAREST GL_NEAREST_MIPMAP_NEAREST //选择最临近的纹理单元值
};5纹理映射模式处理纹理图像数据与物体本身的融合
enum Mode
{
DECAL GL_DECAL, //贴花
MODULATE GL_MODULATE, //调整
BLEND GL_BLEND, //混合
REPLACE GL_REPLACE, //替换覆盖
ADD GL_ADD //添加
};6纹理坐标的自动生成模式
enum Mode
{
OBJECT_LINEAR GL_OBJECT_LINEAR,//物体线性纹理贴图与移动物体保持固定
EYE_LINEAR GL_EYE_LINEAR,//产生移动物体的动态轮廓线
SPHERE_MAP GL_SPHERE_MAP,//球体贴图
NORMAL_MAP GL_NORMAL_MAP_ARB, //法线贴图用于立方图纹理
REFLECTION_MAP GL_REFLECTION_MAP_ARB//反射贴图
};7贴图坐标
enum Coord
{
S, //x
T, //y
R, //z
Q //w
};8纹理的内部格式
enum InternalFormatMode
{
USE_IMAGE_DATA_FORMAT, //使用贴图本身的格式
USE_USER_DEFINED_FORMAT,//使用用户自定义的格式如 GL_R3G3B3 等格式
USE_ARB_COMPRESSION, //使用 ARB 协会出的贴图压缩格式
USE_S3TC_DXT1_COMPRESSION,//使用 S3TC_DXT1 压缩格式
USE_S3TC_DXT3_COMPRESSION,//使用 S3TC_DXT3 压缩格式
USE_S3TC_DXT5_COMPRESSION //使用 S3TC_DXT5 压缩格式
};2、二维纹理
2.1 纹理坐标和纹理数据 在所有的纹理映射中二维纹理映射的过程最简单也非常容易理解。在用户应用程序中创建二维纹理的步骤如下
1指定用户几何体的纹理坐标。 2创建纹理属性对象并保存纹理图形数据。 3为 StateSet 设置合适的纹理属性和模式。
1纹理坐标 在前面几何体的绘制时已经提到用一个二维的向量数据来保存纹理坐标。设置纹理坐标比较简单纹理坐标是与顶点一一对应的很像数学中的映射。 下面的代码段创建了一个 osg::Vec2Array 数组用于保存纹理坐标同时将其关联到 Geometry 实例的纹理单元 0。如果要对单一的 Geometry 设置多个纹理只需要将多个纹理坐标数组关联到Geometry并针对不同的数组指定不同的纹理单元即可。
//创建一个 Geometry 几何体对象
osg::ref_ptrosg::Geometry geom new osg::Geometry;
//创建一个 Vec2Array 对象以保存纹理单元 0 的纹理坐标并将其关联到 geom
osg::ref_ptrosg::Vec2Array tc new osg::Vec2Array;
geom-setTexCoordArray( 0, tc.get());
tc-push_back(osg::Vec2( 0.f, 0.f));
tc-push_back(osg::Vec2( 1.f, 0.f));
tc-push_back(osg::Vec2( 1.f, 1.f));
tc-push_back(osg::Vec2( 0.f, 1.f));osg::Geometry::setTexCoordArray()的第一个参数是纹理单元号第二个参数是纹理坐标数组。用户不需要使用类同 osg::Geometry::setTexCoordBinding()的函数输入点来绑定纹理数据。纹理坐标总是绑定到每个顶点的。在这里有一点要注意OpenGL 的早期版本并不支持多重纹理而加入多重纹理的特性之后OpenGL 仍然支持非多重纹理的函数接口以实现向下兼容。从本质上说此时 OpenGL 将非多重纹理接口解释为使用纹理单元 0 对应所有纹理数据。与 OpenGL 不同OSG 并不支持非多重纹理接口。因此用户程序必须指定一个纹理单元以对应纹理坐标数据和纹理状态。如果要使用单一纹理只需要指定到纹理单元 0 即可。
2纹理数据 在大多数应用程序中纹理数据都是从外部导入的图像文件。当没有必要导入图像时可以生成一幅纹理数据贴图。这里使用从外部导入的纹理数据图形的方法。读取图像需要使用一个新类——osg::Image。osg::Image 继承自 osg::Object 类。面的代码将实现如何读取图像
osg::ref_ptrosg::Image image new osg::Image;
image-setFileName( tree.rgb );在读取一个图像后需要创建一个纹理对象来关联图像。osg::Texture2D 属于 osg::StateAttribute 的派生类用于管理 OpenGL 纹理对象而 Image 用于管理图像像素数据。如果要使用 2D 图像文件作为纹理映射的图形只要将文件名赋给 Image 对象并将 Image 关联到 Texture2D 即可。osg::Texture2D 继承自 osg::Texture。下面的代码将实现将图像关联到 2D 纹理对象上
//将图像关联到 Texture2D 对象
osg::ref_ptrosg::Texture2D tex new osg::Texture2D;
tex-setImage( image.get() );在关联图像以后可以直接关联到渲染状态。值得注意的是大量使用纹理贴图的程序往往需要实现更紧凑的内存管理。Image 类继承自 Referenced 类而 Texture2D 内部保存了一个指向 Image 的ref_ptr指针。在第一次渲染时OSG 创建了用于保存图像数据的 OpenGL 纹理对象其结果是产生了两个纹理图像的副本一个是 Image 对象另一个由 OpenGL 拥有。简单的单环境single-context场景渲染中读者可以通过设置 Texture2D 解除对 Image 的引用来降低内存损耗。如果当前引用 Image对象的只有 Texture2D 对象那么 OSG 将释放 Image 及其内存空间。下面的代码演示了设置 Texture2D解除对 Image 引用的方法
//创建 OpenGL 纹理对象后释放内部的 ref_ptrImage删除 Image 图像
tex-setUnRefImageDataAfterApply( true );默认情况下Texture2D 不会自动释放对 Image 的引用。在多环境multi-context场景渲染中这是一种期望行为前提是纹理对象并没有在各环境中共享。
3纹理状态 用户程序可以使用纹理状态函数接口为每个纹理单元指定渲染状态。纹理状态函数接口与非纹理状态的接口类似。用户可以使用 osg::StateSet::setTextureAttribute()将一个纹理属性关联到 StateSet 对象。setTextureAttribute()的第一个参数是纹理单元第二个参数是继承自 StateAttribute 类的一种纹理属性。 合法的纹理属性类共有 6 种其中包括 5 种纹理类型osg::Texture1D、osg::Texture2D、osg::Texture3D、 osg::TextureCubeMap 和 osg::TextureRectangle和一个用于纹理坐标的生成的类osg::TexGen。 下面的代码将根据给定的 Texture2D 属性对象 tex 和渲染状态 StateSet 将 tex 关联到渲染状态并设置使用纹理单元 0。
//创建一个 Texture2D 属性
Osg::ref_ptrosg::Texture2D tex new osg::Texture2D;
//关联材质属性到材质单元 0
state-setTextureAttribute( 0, tex.get() );与上面的程序类似用户可以调用 osg::StateSet::setTextureMode()方法来设置材质渲染模式这个方法与 setMode()方法类似。用户可以使用 setTextureMode()来设置 GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3DGL_TEXTURE_CUBE_MAP、GL_TEXTURE_RECTANGLE、GL_TEXTURE_GEN_Q、GL_TEXTURE_GEN_R、GL_TEXTURE_GEN_S 以及 GL_TEXTURE_GEN_T 模式。 与 setTextureAttribute()相似setTextureMode()的第一个参数表示纹理单元。下面的代码段将禁止纹理单元 1 的 2D 纹理映射
state-setTextureMode( 1, GL_TEXTURE_2D, osg::StateAttribute::OFF );当然用户也可以使用 osg::StateSet::setTextureAttributesAndModes()来关联纹理渲染属性到StateSet同时允许相应的纹理模式。如果属性是一个 TexGen 对象那么 setTextureAttributesAndModes()将设置相应的坐标生成模式 GL_TEXTURE_GEN_Q、GL_TEXTURE_GEN_R、GL_TEXTURE_GEN_S和 GL_TEXTURE_GEN_T。对于其他纹理属性来说这一模式是隐含的。例如下面的代码中由于第二个参数传入了一个 Texture2D 对象作为纹理属性setTextureAttributesAndModes()将允许GL_TEXTURE_2D 模式
//创建一个 Texture2D 属性对象
osg::ref_ptrosg::Texture2D tex new osg::Texture2D;
//在纹理单元 0 上关联 2D 纹理属性并许可 GL_TEXTURE_2D 模式
state-setTextureAttributeAndModes( 0, tex );setTextureAttributeAndModes() 的 第 三 个 参 数 的 默 认 值 为 ON 即 允 许 纹 理 渲 染 模 式 。 与 setAttributeAndModes()类似读者可以对这个参数使用位或操作包括 OVERRIDE、PROTECTED 和INHERIT以修改纹理属性的继承特性。读者还可以通过修改 setTextureMode()和 setTextureAttribute()的第三个参数来指定这个继承标志。
2.2 示例效果
2.2.1 普通示例 备注osg默认会被图片大小非2的n次方的图片进行缩放处理。后续可与矩阵纹理进行对比 // TestOSGProject.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。#include windows.h
#include osgViewer/Viewer#include osg/Node
#include osg/Geode
#include osg/Group
#include osg/Geometry
#include osg/Image
#include osg/TexGen
#include osg/Texture1D
#include osg/TexEnv
#include osg/StateSet
#include osg/PrimitiveSet
#include osgDB/ReadFile
#include osgDB/WriteFile
#include osgViewer/ViewerEventHandlers //事件监听
#include osgGA/StateSetManipulator //事件响应类对渲染状态进行控制
#include osgUtil/Simplifier //简化几何体#include osgUtil/Optimizer#pragma comment(lib, OpenThreadsd.lib)
#pragma comment(lib, osgd.lib)
#pragma comment(lib, osgDBd.lib)
#pragma comment(lib, osgUtild.lib)
#pragma comment(lib, osgGAd.lib)
#pragma comment(lib, osgViewerd.lib)
#pragma comment(lib, osgTextd.lib)//创建一个四边形节点
osg::ref_ptrosg::Node createNode()
{osg::ref_ptrosg::Geode geode new osg::Geode();osg::ref_ptrosg::Geometry geom new osg::Geometry();//设置顶点osg::ref_ptrosg::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_ptrosg::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_ptrosg::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_ptrosg::StateSet createTexture2DState(osg::ref_ptrosg::Image image)
{//创建状态集对象osg::ref_ptrosg::StateSet stateset new osg::StateSet();//创建二维纹理对象osg::ref_ptrosg::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_ptrosgViewer::Viewer viewer new osgViewer::Viewer();osg::ref_ptrosg::Group root new osg::Group();//读取贴图文件osg::ref_ptrosg::Image image osgDB::readImageFile(Images/primitives.gif);osg::ref_ptrosg::Node node createNode();//创建状态集对象osg::ref_ptrosg::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-addEventHandler(new osgGA::StateSetManipulator(viewer-getCamera()-getOrCreateStateSet()));viewer-addEventHandler(new osgViewer::StatsHandler());viewer-addEventHandler(new osgViewer::WindowSizeHandler());viewer-setSceneData(root.get());viewer-setUpViewInWindow(600, 600, 1000, 800);return viewer-run();
}2.2.2 光照和混合模式示例 //创建二维纹理状态对象
osg::ref_ptrosg::StateSet createTexture2DState(osg::ref_ptrosg::Image image)
{//创建状态集对象osg::ref_ptrosg::StateSet stateset new osg::StateSet();//创建二维纹理对象osg::ref_ptrosg::Texture2D texture new osg::Texture2D();texture-setDataVariance(osg::Object::DYNAMIC);//设置贴图texture-setImage(image.get());//关联Texture2D纹理对象第三个参数默认为ONstateset-setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);//启用混合stateset-setMode(GL_BLEND, osg::StateAttribute::ON);//关闭光照stateset-setMode(GL_LIGHTING, osg::StateAttribute::ON);return stateset.get();
}2.2.3 光照关闭示例 //创建二维纹理状态对象
osg::ref_ptrosg::StateSet createTexture2DState(osg::ref_ptrosg::Image image)
{//创建状态集对象osg::ref_ptrosg::StateSet stateset new osg::StateSet();//创建二维纹理对象osg::ref_ptrosg::Texture2D texture new osg::Texture2D();texture-setDataVariance(osg::Object::DYNAMIC);//设置贴图texture-setImage(image.get());//关联Texture2D纹理对象第三个参数默认为ONstateset-setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);//启用混合stateset-setMode(GL_BLEND, osg::StateAttribute::ON);//关闭光照stateset-setMode(GL_LIGHTING, osg::StateAttribute::OFF);return stateset.get();
}3、多重纹理 在进行标准的二维纹理映射处理时一次把一幅纹理图像应用到一个多边形上。多重纹理允许应用几个纹理在纹理操作管线中把它们逐个应用到同一个多边形上。多重纹理存在一系列的纹理单元每个纹理单元执行单独的纹理操作并把它的结果传递给下一个纹理单元直到所有纹理单元的操作完成为止最终显示处理后的效果。 多重纹理映射非常广泛它能实现一些高级的渲染技巧如光照、贴花、合成和细节纹理等。在OSG 中实现三维纹理主要有以下几个步骤 1指定用户几何体的纹理坐标。 2创建多个纹理属性对象并保存纹理多个图形数据。 3为 StateSet 设置合适的纹理属性和模式。 看起来和二维纹理映射的区别不大简单地说就是多个二维纹理映射的叠加。但这里需要注意的是对于不同的纹理属性对象需要指定不同的纹理单元及纹理坐标否则就不会启用该纹理单元或者该纹理单元会被覆盖。
2.2 示例效果 原书上给的示例感觉不太合适不具备说明性因此自己参照learnopengl实现了多重纹理混合示例。 2.2 源码
// TestOSGProject.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。#include windows.h
#include osgViewer/Viewer#include osg/Node
#include osg/Geode
#include osg/Group
#include osg/Geometry
#include osg/Image
#include osg/TexGen
#include osg/Texture1D
#include osg/TexEnv
#include osg/StateSet
#include osg/PrimitiveSet
#include osgDB/ReadFile
#include osgDB/WriteFile
#include osgViewer/ViewerEventHandlers //事件监听
#include osgGA/StateSetManipulator //事件响应类对渲染状态进行控制
#include osgUtil/Simplifier //简化几何体#include osgUtil/Optimizer#pragma comment(lib, OpenThreadsd.lib)
#pragma comment(lib, osgd.lib)
#pragma comment(lib, osgDBd.lib)
#pragma comment(lib, osgUtild.lib)
#pragma comment(lib, osgGAd.lib)
#pragma comment(lib, osgViewerd.lib)
#pragma comment(lib, osgTextd.lib)//创建一个四边形节点
osg::ref_ptrosg::Node createNode()
{osg::ref_ptrosg::Geode geode new osg::Geode();osg::ref_ptrosg::Geometry geom new osg::Geometry();//设置顶点osg::ref_ptrosg::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_ptrosg::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());geom-setTexCoordArray(1, vt.get());//设置法线osg::ref_ptrosg::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_ptrosg::StateSet createTexture2DState()
{//读取贴图文件osg::ref_ptrosg::Image image2 osgDB::readImageFile(awesomeface.png);osg::ref_ptrosg::Image image1 osgDB::readImageFile(container.jpg);//创建状态集对象osg::ref_ptrosg::StateSet stateset new osg::StateSet();//创建二维纹理对象osg::ref_ptrosg::Texture2D texture1 new osg::Texture2D();texture1-setDataVariance(osg::Object::DYNAMIC);//设置贴图texture1-setImage(image1.get());//关联Texture2D纹理对象第三个参数默认为ONstateset-setTextureAttributeAndModes(0, texture1.get(), osg::StateAttribute::ON);//创建二维纹理对象osg::ref_ptrosg::Texture2D texture2 new osg::Texture2D();texture2-setDataVariance(osg::Object::DYNAMIC);//设置贴图texture2-setImage(image2.get());//关联Texture2D纹理对象第三个参数默认为ONstateset-setTextureAttributeAndModes(1, texture2.get(), osg::StateAttribute::ON);//启用混合stateset-setMode(GL_BLEND, osg::StateAttribute::ON);//关闭光照stateset-setMode(GL_LIGHTING, osg::StateAttribute::ON);return stateset.get();
}int main()
{osg::ref_ptrosgViewer::Viewer viewer new osgViewer::Viewer();osg::ref_ptrosg::Group root new osg::Group();osg::ref_ptrosg::Node node createNode();//创建状态集对象osg::ref_ptrosg::StateSet stateset new osg::StateSet();stateset createTexture2DState();//使用二维纹理node-setStateSet(stateset.get());root-addChild(node.get());//优化场景数据osgUtil::Optimizer optimizer;optimizer.optimize(root.get());//方便查看在多边形之间切换以查看三角网viewer-addEventHandler(new osgGA::StateSetManipulator(viewer-getCamera()-getOrCreateStateSet()));viewer-addEventHandler(new osgViewer::StatsHandler());viewer-addEventHandler(new osgViewer::WindowSizeHandler());viewer-setSceneData(root.get());viewer-setUpViewInWindow(600, 600, 1000, 800);return viewer-run();
}4、Mipmap多级渐远纹理 在一个动态的场景中当一个纹理对象迅速远离视点时纹理图像必须随着被投影的图像一起缩小。为了实现这种效果可以通过对纹理图像进行过滤适当对它进行缩小以使它映射到物体的表面时不会产生抖动或者闪烁的效果。但这时还存在一个问题就是当视点距离速度变大时单个纹理缩小为单个像素之前在经过一些过渡点时经过过滤的纹理图像会变化非常明显。同时也没有必要使用一张那么大的纹理数据了当使用一个很大的、包含很多贴图的场景时对渲染效率的影响是相当大的。 为了避免这种突然变化的现象及不必要的渲染负担可以预先指定一系列分辨率递减的纹理图像。使用 Mipmap 纹理映射必须指定全系列大小为 2 的整数次方的纹理图像其范围为从最大值到 1×1 的纹理单元。例如如果最高的纹理分辨率为 32×32那么必须指定的纹理图像为 32×32、16×16、8×8、4×4、2×2、1×1。通常来说较小的纹理图像是上一级分辨率的纹理图像的 4 个纹理单元的平均值。当然这里也没有确定的计算方法一般是这样计算的。
在 OSG 中使用 Mipmap 纹理映射主要包括下面几个步骤
1将各层的纹理图像数据按照从大到小的顺序且尺寸必须为 2 的幂次依次存放到 unsigned char*数组中将这个数组使用 setImage 送入 Image 对象。 2将各层纹理数据在数组中的偏移地址记录到一个 osg::Image::MipmapDataType 列表中用于选择正确的层次细节纹理图像。 3使用 setMipmapLevels()将 MipmapDataType 送入 Image 对象。注意这一步的次序和 setImage不能颠倒否则可能无法正确显示各级别的纹理图像。 在示例程序中可以看到清晰的纹理图像的各个层次级别细节的明显过渡这里用颜色代替了纹理。
备注OpenGL描述如下当调用glTexImage2D时当前绑定的纹理对象就会被附加上纹理图像。然而目前只有基本级别(Base-level)的纹理图像被加载了如果要使用多级渐远纹理我们必须手动设置所有不同的图像不断递增第二个参数。或者直接在生成纹理之后调用glGenerateMipmap。这会为当前绑定的纹理自动生成所有需要的多级渐远纹理。生成了纹理和相应的多级渐远纹理后释放图像的内存并解绑纹理对象是一个很好的习惯。
4.1 示例效果 4.2 源码
// TestOSGProject.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。#include windows.h
#include osgViewer/Viewer#include osg/Node
#include osg/Geode
#include osg/Group
#include osg/Geometry
#include osg/Image
#include osg/TexGen
#include osg/Texture1D
#include osg/TexEnv
#include osg/StateSet
#include osg/PrimitiveSet
#include osgDB/ReadFile
#include osgDB/WriteFile
#include osgViewer/ViewerEventHandlers //事件监听
#include osgGA/StateSetManipulator //事件响应类对渲染状态进行控制
#include osgUtil/Simplifier //简化几何体#include osgUtil/Optimizer#pragma comment(lib, OpenThreadsd.lib)
#pragma comment(lib, osgd.lib)
#pragma comment(lib, osgDBd.lib)
#pragma comment(lib, osgUtild.lib)
#pragma comment(lib, osgGAd.lib)
#pragma comment(lib, osgViewerd.lib)
#pragma comment(lib, osgTextd.lib)//创建一个四边形
osg::ref_ptrosg::Geode createQuad()
{osg::ref_ptrosg::Geode geode new osg::Geode();osg::ref_ptrosg::Geometry geom new osg::Geometry();geode-addDrawable(geom.get());//设置顶点osg::ref_ptrosg::Vec3Array vec new osg::Vec3Array;vec-push_back(osg::Vec3(-10.0f, 0.0f, -10.0f));vec-push_back(osg::Vec3(-10.0f, 0.0f, 10.0f));vec-push_back(osg::Vec3(10.0f, 0.0f, 10.0f));vec-push_back(osg::Vec3(10.0f, 0.0f, -10.0f));geom-setVertexArray(vec.get());//设置法线osg::ref_ptrosg::Vec3Array nor new osg::Vec3Array;nor-push_back(osg::Vec3f(0.0f, -1.0f, 0.0f));geom-setNormalArray(nor.get());geom-setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE_SET);//设置纹理坐标osg::ref_ptrosg::Vec2Array tex new osg::Vec2Array;tex-push_back(osg::Vec2f(0.0f, 0.0f));tex-push_back(osg::Vec2f(0.0f, 1.0f));tex-push_back(osg::Vec2f(1.0f, 1.0f));tex-push_back(osg::Vec2f(1.0f, 0.0f));geom-setTexCoordArray(0, tex.get());geom-addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));return geode.get();
}static void fillImage(unsigned char* ptr, unsigned int size)
{//黑色if (size 1){float r 0.5f;osg::Vec4 color(0.0f, 0.0f, 0.0f, 1.0f);*ptr (unsigned char)((color[0]) * 255.0f);*ptr (unsigned char)((color[1]) * 255.0f);*ptr (unsigned char)((color[2]) * 255.0f);*ptr (unsigned char)((color[3]) * 255.0f);}//白色if (size 2){osg::Vec4 color(1.0f, 1.0f, 1.0f, 1.0f);for (unsigned int r 0; r size; r){for (unsigned int c 0; c size; c){*ptr (unsigned char)((color[0]) * 255.0f);*ptr (unsigned char)((color[1]) * 255.0f);*ptr (unsigned char)((color[2]) * 255.0f);*ptr (unsigned char)((color[3]) * 255.0f);}}}//黄色if (size 4){osg::Vec4 color(0.0f, 1.0f, 0.0f, 1.0f);for (unsigned int r 0; r size; r){for (unsigned int c 0; c size; c){*ptr (unsigned char)((color[0]) * 255.0f);*ptr (unsigned char)((color[1]) * 255.0f);*ptr (unsigned char)((color[2]) * 255.0f);*ptr (unsigned char)((color[3]) * 255.0f);}}}//红色if (size 8){osg::Vec4 color(1.0f, 0.0f, 0.0f, 1.0f);for (unsigned int r 0; r size; r){for (unsigned int c 0; c size; c){*ptr (unsigned char)((color[0]) * 255.0f);*ptr (unsigned char)((color[1]) * 255.0f);*ptr (unsigned char)((color[2]) * 255.0f);*ptr (unsigned char)((color[3]) * 255.0f);}}}//粉红色if (size 16){osg::Vec4 color(1.0f, 0.0f, 1.0f, 1.0f);for (unsigned int r 0; r size; r){for (unsigned int c 0; c size; c){*ptr (unsigned char)((color[0]) * 255.0f);*ptr (unsigned char)((color[1]) * 255.0f);*ptr (unsigned char)((color[2]) * 255.0f);*ptr (unsigned char)((color[3]) * 255.0f);}}}//黄色if (size 32){osg::Vec4 color(1.0f, 1.0f, 0.0f, 1.0f);for (unsigned int r 0; r size; r){for (unsigned int c 0; c size; c){*ptr (unsigned char)((color[0]) * 255.0f);*ptr (unsigned char)((color[1]) * 255.0f);*ptr (unsigned char)((color[2]) * 255.0f);*ptr (unsigned char)((color[3]) * 255.0f);}}}//蓝绿色if (size 64){osg::Vec4 color(0.0f, 1.0f, 1.0f, 1.0f);for (unsigned int r 0; r size; r){for (unsigned int c 0; c size; c){*ptr (unsigned char)((color[0]) * 255.0f);*ptr (unsigned char)((color[1]) * 255.0f);*ptr (unsigned char)((color[2]) * 255.0f);*ptr (unsigned char)((color[3]) * 255.0f);}}}//灰白色if (size 128){osg::Vec4 color(0.5f, 0.5f, 0.5f, 1.0f);for (unsigned int r 0; r size; r){for (unsigned int c 0; c size; c){*ptr (unsigned char)((color[0]) * 255.0f);*ptr (unsigned char)((color[1]) * 255.0f);*ptr (unsigned char)((color[2]) * 255.0f);*ptr (unsigned char)((color[3]) * 255.0f);}}}//蓝色if (size 256){osg::Vec4 color(0.0f, 0.0f, 1.0f, 1.0f);for (unsigned int r 0; r size; r){for (unsigned int c 0; c size; c){*ptr (unsigned char)((color[0]) * 255.0f);*ptr (unsigned char)((color[1]) * 255.0f);*ptr (unsigned char)((color[2]) * 255.0f);*ptr (unsigned char)((color[3]) * 255.0f);}}}
}int main()
{osg::ref_ptrosgViewer::Viewer viewer new osgViewer::Viewer();osg::ref_ptrosg::Group root new osg::Group();//创建一个平面osg::ref_ptrosg::Geode geode createQuad();osg::ref_ptrosg::StateSet stateset new osg::StateSet();osg::ref_ptrosg::Image image new osg::Image();//创建一个MipmapDataType列表用来各层图片数据的偏移地址osg::Image::MipmapDataType mipmapData;//纹理的尺寸的最大值必须为2的幂次unsigned int s 256;//计算所需分配的数组的大小unsigned int totalSize 0;for (unsigned int i 0; s 0; s 1, i){if (i 0){mipmapData.push_back(totalSize);}totalSize s * s * 4;}//申请一个数据unsigned char* ptr new unsigned char[totalSize];//设置image的尺寸大小数据及数据格式image-setImage(256, 256, 256, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, ptr, osg::Image::USE_NEW_DELETE, 1);//将偏移地址传入imge对象image-setMipmapLevels(mipmapData);//向image中填充各层数据s 256;for (unsigned int i 0; s 0; s 1, i){fillImage(ptr, s);ptr s * s * 4;}//创建一个二维纹理对象osg::ref_ptrosg::Texture2D texture new osg::Texture2D;//设置贴图texture-setImage(0, image.get());//设置边界处理为REPEATEtexture-setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);texture-setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);//设置滤波texture-setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST);texture-setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);//启用二维纹理对象stateset-setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);geode-setStateSet(stateset.get());root-addChild(geode.get());//优化场景数据osgUtil::Optimizer optimizer;optimizer.optimize(root.get());//方便查看在多边形之间切换以查看三角网viewer-addEventHandler(new osgGA::StateSetManipulator(viewer-getCamera()-getOrCreateStateSet()));viewer-addEventHandler(new osgViewer::StatsHandler());viewer-addEventHandler(new osgViewer::WindowSizeHandler());viewer-setSceneData(root.get());viewer-setUpViewInWindow(600, 600, 1000, 800);return viewer-run();
}5、TextureRectangle矩阵纹理 TextureRectangle 纹理映射是在 OpenGL 后来版本中的一个扩展——ARB_texture_rectangle它也是一种二维纹理映射但它与前面介绍的二维映射有很大的区别。 使用 TextureRectangle 纹理映射时有以下几点需要注意 纹理环绕模式。它并不支持所有的纹理包装模式只能使用 CLAMP、CLAMP_TO_EDGE 或CLAMP_TO_BORDER并不支持 REPEAT。 纹理滤波。它只支持NEAREST或者LINEAR不支持Mipmap滤波使用它时不能实现Mipmap纹理。 不支持纹理边框。 对于没有图形学基础的开发人员来说TextureRectangle 比较容易理解也非常容易上手可以简单理解为一个矩形纹理。
5.1 示例效果 5.2 源码
// TestOSGProject.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。#include windows.h
#include osgViewer/Viewer#include osg/Node
#include osg/Geode
#include osg/Group
#include osg/Geometry
#include osg/Image
#include osg/TexGen
#include osg/Texture1D
#include osg/TexEnv
#include osg/TextureRectangle
#include osg/TexMat
#include osg/StateSet
#include osg/PrimitiveSet
#include osgDB/ReadFile
#include osgDB/WriteFile
#include osgViewer/ViewerEventHandlers //事件监听
#include osgGA/StateSetManipulator //事件响应类对渲染状态进行控制
#include osgUtil/Simplifier //简化几何体#include osgUtil/Optimizer#pragma comment(lib, OpenThreadsd.lib)
#pragma comment(lib, osgd.lib)
#pragma comment(lib, osgDBd.lib)
#pragma comment(lib, osgUtild.lib)
#pragma comment(lib, osgGAd.lib)
#pragma comment(lib, osgViewerd.lib)
#pragma comment(lib, osgTextd.lib)//创建一个四边形节点
osg::ref_ptrosg::Node createNode()
{osg::ref_ptrosg::Geode geode new osg::Geode();osg::ref_ptrosg::Geometry geom new osg::Geometry();//设置顶点osg::ref_ptrosg::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_ptrosg::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_ptrosg::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_ptrosg::StateSet createTexture2DState(osg::ref_ptrosg::Image image)
{//创建状态集对象osg::ref_ptrosg::StateSet stateset new osg::StateSet();//创建二维纹理对象osg::ref_ptrosg::TextureRectangle texture new osg::TextureRectangle();texture-setDataVariance(osg::Object::DYNAMIC);//设置贴图texture-setImage(image.get());//设置纹理矩阵并设置为根据矩阵纹理(TextureRectangle)的大小自动缩放//从而允许应用一个矩形纹理到一个纹理坐标不在0-1上osg::ref_ptrosg::TexMat texmat new osg::TexMat;texmat-setScaleByTextureRectangleSize(true);//启用纹理及纹理矩阵stateset-setTextureAttributeAndModes(0, texmat.get(), osg::StateAttribute::ON);stateset-setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);//关闭光照stateset-setMode(GL_LIGHTING, osg::StateAttribute::OFF);return stateset.get();
}int main()
{osg::ref_ptrosgViewer::Viewer viewer new osgViewer::Viewer();osg::ref_ptrosg::Group root new osg::Group();//读取贴图文件osg::ref_ptrosg::Image image osgDB::readImageFile(Images/primitives.gif);osg::ref_ptrosg::Node node createNode();//创建状态集对象osg::ref_ptrosg::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-addEventHandler(new osgGA::StateSetManipulator(viewer-getCamera()-getOrCreateStateSet()));viewer-addEventHandler(new osgViewer::StatsHandler());viewer-addEventHandler(new osgViewer::WindowSizeHandler());viewer-setSceneData(root.get());viewer-setUpViewInWindow(600, 600, 1000, 800);return viewer-run();
}