OSG 使用整理(4):使用普通纹理着色

发布时间 2023-06-11 22:41:12作者: 王小于的啦

osg中使用普通纹理着色

1.1   普通纹理

  • osg::Image类存储OpenGL纹理对象载入与使用的图像数据,其中方法data()将原始图像数据作为uchar* 指针返回,可以直接修改内存中数据,方法getPixelFormat方法返回像素格式,getDataType返回每个像素通道数据类型,方法allocateImage为图片预先分配一块缓存。
  • osg中使用纹理需要:设置Geometry的纹理坐标;创建合适的纹理对象;为图片绑定到纹理对象上;将相应的纹理对象设置到属性状态集合StateSet中。osg::Texture类封装了所有的纹理类型,子类osg::Texture1D、osg::Texture2D和osg::TextureCubMap封装了不同的OpenGL纹理映射技术,方法setImage将图片数据写入纹理对象中。

  示例为使用2D纹理贴图,创建四边形并调用setTexCoordArray()方法来将纹理坐标绑定到每个顶点。纹理坐标在x和y轴上,范围为0到1之间(注意我们使用的是2D纹理图像)。使用纹理坐标获取纹理颜色叫做采样(Sampling)。OpenGL中纹理坐标起始于(0, 0),也就是纹理图片的左下角,终始于(1, 1),即纹理图片的右上角。下面的图片展示了我们是如何把纹理坐标映射到三角形上的。

 

 1 #include <osg/Texture2D>
 2 #include <osg/Geometry>
 3 #include <osgDB/ReadFile>
 4 #include <osgViewer/Viewer>
 5 
 6 void main()
 7 {
 8 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
 9 vertices->push_back( osg::Vec3(-0.5f, 0.0f,-0.5f) );
10 vertices->push_back( osg::Vec3( 0.5f, 0.0f,-0.5f) );
11 vertices->push_back( osg::Vec3( 0.5f, 0.0f, 0.5f) );
12 vertices->push_back( osg::Vec3(-0.5f, 0.0f, 0.5f) );
13 osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
14 normals->push_back( osg::Vec3(0.0f,-1.0f, 0.0f) );
15 osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array;
16 texcoords->push_back( osg::Vec2(0.0f, 0.0f) );
17 texcoords->push_back( osg::Vec2(0.0f, 1.0f) );
18 texcoords->push_back( osg::Vec2(1.0f, 1.0f) );
19 texcoords->push_back( osg::Vec2(1.0f, 0.0f) );
20 osg::ref_ptr<osg::Geometry> quad = new osg::Geometry;
21 quad->setVertexArray( vertices.get() );
22 quad->setNormalArray( normals.get() );
23 quad->setNormalBinding( osg::Geometry::BIND_OVERALL );
24 quad->setTexCoordArray( 0, texcoords.get() );
25 quad->addPrimitiveSet( new osg::DrawArrays(GL_QUADS, 0, 4) );
26 
27 osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
28 osg::ref_ptr<osg::Image> image =
29     osgDB::readImageFile( "Images/lz.rgb" );
30 texture->setImage( image.get() );
31 
32 osg::ref_ptr<osg::Geode> root = new osg::Geode;
33 root->addDrawable( quad.get() );
34 root->getOrCreateStateSet()->setTextureAttributeAndModes(
35     0, texture.get() );
36 
37 osgViewer::Viewer viewer;
38 viewer.setSceneData( root.get() );
39 return viewer.run();
40 }

  纹理环绕方式指超过采样坐标范围超过[0,1]时,该怎么处理,OpenGL中有以下几种方式:

  GL_REPEAT                对纹理的默认行为。重复纹理图像。

  GL_MIRRORED_REPEAT       和GL_REPEAT一样,但每次重复图片是镜像放置的。

  GL_CLAMP_TO_EDGE      纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。

  GL_CLAMP_TO_BORDER     超出的坐标为用户指定的边缘颜色。

 

  可以使用glTexparametri命令分别设置s轴t轴环绕方式。osg中封装了setWrap方法。

       纹理过滤指模型大小超过纹理分辨率时,使用的纹理映射方式。通常有邻近过滤和线性过滤两种,邻近过滤(GL_NEAREST)会使用中心点最靠近纹理坐标的那个像素,而线性过滤使用纹理坐标附近的所有像素按照距离加权计算的平均值。

                                                                                                       

 

  同样可以使用glTexparametri命令分别设置纹理放大或者缩小时的过滤方式。osg中封装了setFilter方法。

1.2   凹凸纹理

  凹凸纹理用于使用一张纹理修改模型表面的法线A,以便为模型提供更多细节,这种方法不会改变模型顶点位置,只是让模型看起来好像是凹凸不平的。主要有两种方式,一种是使用高度纹理来模拟表面位移,然后得到要给修改后的法线值;一种是使用一张法线纹理来直接存储表面法线。

1.3   shader中使用纹理

  要在shader中使用纹理,首先需要设置顶点的纹理坐标。osg::Geometry类中通过方法setTexCoordArray设置顶点纹理坐标数组。而osg预定义了一些几何体,如球、圆柱、胶囊体、圆锥体等,osg::Shape类方法BuildShapeGeometryVisitor()中创建几何顶点时,已经设置了纹理坐标数组。示例为使用纹理对预定义球体贴图,因为可以在shader中对纹理采样的颜色做处理,因此可以生成大量效果。

 1 //绘制多个预定义的几何体
 2 osg::ref_ptr<osg::Geode> createShape()
 3 {
 4 osg::ref_ptr<osg::ShapeDrawable> shpere= new osg::ShapeDrawable;
 5 sphere->setShape(new osg::Shpere(osg::Vec3(0,0,0),radius);
 6 sphere->setColor(osg::Vec4(0,122,254,255);
 7 //vert shader
 8 const char* vertCode=“#version 330 core\n”
 9 “layout(location = 0 ) in vec3 Postion;\n”
10 “uniform mat4 osg_ModelViewProjectionMatrix;\n”
11void main()\n”
12 “{ \n”
13 “  gl_Position=osg_ModelViewProjectionMatrix*vec4(Postion,1.0);\n”
14 “}\n”;
15 
16 //frag shader
17 const char* fragCode=“#version 330 core\n”
18 “uniform sample2D texture0;\n”
19out vec4 fragColor;\n”
20void main()\n”
21 “{ \n”
22 “  fragColor=texture(texture0,gl_TexCoord[0].xy);\n”
23 “}\n”;
24 
25 osg::ref_ptr<osg::Shader> vertShader = new osg::Shader(osg::Shader::VERTEX);
26 osg::ref_ptr<osg::Shader> fragShader = new osg::Shader(osg::Shader::FRAGMENT);
27 osg::ref_ptr<osg::Program> program= new osg::Program;
28 program->addShader(vertShader);
29 program->addShader(fragShader);             
30 auto ss= sphere ->getOrCreateStateSet();
31 ss ->setAttributeAndModes(program);
32 //读取纹理图片
33 auto texture= new osg::Texture2D(osgDB::readImageFile("C:\\55.jpg");
34 ss ->setTextureAttribute( 0, texture));
35 ss ->setTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::ON);
36 //创建一个叶节点
37 osg::ref_ptr<osg::Geode> geode = new osg::Geode();
38 geode->addDrawable(sphere);
39 return geode.get() ;
40 }