赞
踩
OpenGL初级篇(三)
编写、编译、管理着色器是件麻烦事。所以写一个着色器类来较轻松完成上述工作,它可以从硬盘读取着色器,然后编译并链接它们,并对它们进行错误检测。
使用着色器类
顶点和片段着色器储存为两个叫做shader.vs和shader.fg的文件。具体储存步骤为:
1、创建空的txt文件
2、在txt文件内编写着色器代码
3、命名该着色器文件,可以用.vs和.fg作为扩展名
使用C++文件流读取着色器内容时,在读取着色器文件时需注意使用绝对路径。
OpenGL创建纹理的步骤:
1、生成纹理名称
2、绑定纹理
3、设置纹理环绕方式
4、纹理过滤
5、加载纹理数据
6、生成纹理
7、释放纹理内存
绑定纹理后,设置纹理环绕方式,使用glTexParameteri()对单独一个坐标轴设置(s、t(如果是使用3D纹理则还有一个r)它们和x、y、z是等价的):
第一个参数指定纹理目标;因为使用2D纹理,因此纹理目标是GL_TEXTURE_2D。第二个参数指定设置的选项与应用的纹理轴。此时配置的是WRAP选项,并且指定S和T轴。第三个参数传递一个环绕方式,此时先设置为默认环绕方式。
纹理坐标不依赖于分辨率(Resolution),它可以是任意浮点值,所以OpenGL需要知道怎样将纹理像素(Texture Pixel)映射到纹理坐标。比如有一个很大的物体但是纹理的分辨率很低时这就变得很重要了。OpenGL也有对于纹理过滤的选项。纹理过滤有很多个选项,最重要的两种是:GL_NEAREST和GL_LINEAR。
GL_NEAREST(也叫邻近过滤,Nearest Neighbor Filtering) 是OpenGL默认的纹理过滤方式。当设置为GL_NEAREST的时候,OpenGL会选择中心点最接近纹理坐标的那个像素。下图中可以看到四个像素,加号代表纹理坐标。左上角那个纹理像素的中心距离纹理坐标最近,所以它会被选择为样本颜色:
GL_LINEAR(也叫线性过滤,(Bi)linear Filtering) 它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色。一个纹理像素的中心距离纹理坐标越近,那么这个纹理像素的颜色对最终的样本颜色的贡献越大。下图中可以看到返回的颜色是邻近像素的混合色:
GL_NEAREST产生了颗粒状的图案,能够清晰看到组成纹理的像素,而GL_LINEAR能够产生更平滑的图案,很难看出单个的纹理像素。GL_LINEAR可以产生更真实的输出。
接着需要调整顶点着色器使其能够接受顶点坐标为一个顶点属性,并把坐标传给片段着色器:
片段着色器接下来会把输出变量TexCoord作为输入变量。
片段着色器也能访问纹理对象,GLSL有一个供纹理对象使用的内建数据类型,叫做采样器(Sampler),它以纹理类型作为后缀,比如sampler1D、sampler2D、sampler3D。可以声明一个uniform sampler2D把一个纹理添加到片段着色器中,稍后会把纹理赋值给这个uniform:
使用GLSL内建的texture()来采样纹理的颜色,它第一个参数是纹理采样器,第二个参数是对应的纹理坐标。texture函数会使用之前设置的纹理参数对相应的颜色值进行采样。这个片段着色器的输出就是纹理的(插值)纹理坐标上的(过滤后的)颜色。
告诉OpenGL新的顶点格式:
只剩下在调用glDrawElements()之前绑定纹理了,它会自动把纹理赋值给片段着色器的采样器:
OpenGL应用程序可以把纹理坐标值赋给任何图元的任何顶点。一般来说,应用程序赋给顶点的u、v纹理坐标值在[0.0, 1.0]范围内的闭区间。但是,如果把纹理坐标设置在范围之外会发生什么?OpenGL默认的行为是重复这个纹理图像,但OpenGL提供了更多的选择,创建某些特殊纹理效果:
例如,设想应用程序创建了一个正方形的图元并把纹理坐标指定为(0.0, 0.0), (2.0, 0.0), (0.0, 2.0)和(2.0, 2.0),把纹理寻址模式设置为重复纹理寻址模式会使纹理在s和t方向都重复两次。
GL_REPEAT是OpenGL对纹理的默认行为,该模式使OpenGL在纹理坐标的整数边界重复使用该纹理图像。
GL_MIRRORED_REPEAT和GL_REPEAT一样,重复纹理图像,但每次重复图片是镜像放置的。
设置为GL_CLAMP_TO_EDGE模式,纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。也就是说,这种模式只应用纹理一次,然后就重复使用纹理边缘处像素的颜色。
设置为GL_CLAMP_TO_BORDER模式,超出的坐标为用户指定的边缘颜色。
如果设置为GL_CLAMP_TO_BORDER模式,还需要指定一个边缘的颜色。这需要使用glTexParameterfv() ,用GL_TEXTURE_BORDER_COLOR作为它的选项,并且传递一个float数组作为边缘的颜色值:
创建好texture2后,需要分别对纹理的ID进行指定,下面的示例语句分别使用两种语句进行指定,实现的效果一样:
使用glUniform1i,可以给纹理采样器分配一个位置值,这样的话能够在一个片段着色器中设置多个纹理。一个纹理的位置值通常称为一个纹理单元(Texture Unit)。
接着激活对应的纹理单元。可以使用glActiveTexture()激活纹理单元,传入我们需要使用的纹理单元,
激活纹理单元后,调用glBindTexture() 会绑定这个纹理到当前激活的纹理单元。
注意:纹理单元GL_TEXTURE0默认总是被激活,所以前面使用纹理贴图的示例里当我们使用glBindTexture()时,无需激活任何纹理单元。
OpenGL至少保证有16个纹理单元供编译人员使用,也就是说可以激活从GL_TEXTURE0到GL_TEXTRUE15。它们都是按顺序定义的,也可以通过GL_TEXTURE0 + 8的方式获得GL_TEXTURE8,这种编写方式在需要循环一些纹理单元时很有用。
需要编译片元着色器来接收另一个采样器:texture2
最终输出颜色现在是两个纹理的结合。GLSL内建的mix函数需要接受两个值作为参数,并对它们根据第三个参数进行线性插值。如果第三个值是0.0,它会返回第一个输入;如果是1.0,会返回第二个输入值。设置为0.2表示会返回80 % 的第一个输入颜色和20 % 的第二个输入颜色,即返回两个纹理的混合色。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。