type
status
date
slug
summary
tags
category
icon
password
纹理做好表
纹理也需要输入坐标,片段着色器会对这些坐标进行插值
纹理环绕方式
纹理的值范围和前面三角形中顶点坐标一样,都是0到1,但是通过设置它的纹理环绕方式来设定超出范围的纹理

这些选项都可以通过glTexParameter对单独的坐标轴设置
第一个参数指定纹理目标,这里使用的是2D纹理,因此是GL_TEXTURE_2D,第二个参数需要指定设置的选项和应用的纹理轴,第三个参数是上面四种环绕方式中的一个
纹理分辨率问题
如果选择GL_CLAMP_TO_BORDER选项,我们还需要指定一个边缘的颜色。这需要使用glTexParameter函数的
fv
后缀形式,用GL_TEXTURE_BORDER_COLOR作为它的选项,并且传递一个float数组作为边缘的颜色值:纹理的分辨率并不一定跟游戏的分辨率匹配,通常会出现低分辨率的纹理渲染到很大的物体或者高分辨率的纹理渲染到很小的物体。这时一般通过纹理过滤去处理,其中GL_NEAREST和GL_LINEAR是比较常见的。
GL_NEAREST(也叫邻近过滤,Nearest Neighbor Filtering)是OpenGL默认的纹理过滤方式。当设置为GL_NEAREST的时候,OpenGL会选择中心点最接近纹理坐标的那个像素。下图中你可以看到四个像素,加号代表纹理坐标。左上角那个纹理像素的中心距离纹理坐标最近,所以它会被选择为样本颜色:

GL_LINEAR(也叫线性过滤,(Bi)linear Filtering)它会基于纹理坐标附近的纹理像素,计算出一个插值,近似出这些纹理像素之间的颜色。一个纹理像素的中心距离纹理坐标越近,那么这个纹理像素的颜色对最终的样本颜色的贡献越大。下图中你可以看到返回的颜色是邻近像素的混合色:

当很大的物体应用到低分辨率时候可以发现LINEAR的效果会好一些,当然如果喜欢8-bit风格,GL_NEAREST也是一种选择。

可以通过glTexParameteri指定放大和缩小的时候设置纹理过滤选项
另一种情况,对于一个世界中有成百上千个物体,远处物体的纹理如果和近处物体的纹理使用相同的分辨率v,那么远处的物体很难获得正确的颜色值,有时会出现对很大的纹理但是只采样一个颜色,这回导致采样不准确,因此使用MipMap解决这个问题。简单来说就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。多级渐远纹理背后的理念很简单:距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个。由于距离远,解析度不高也不会被用户注意到。同时,多级渐远纹理另一加分之处是它的性能非常好。让我们看一下多级渐远纹理是什么样子的:

可以通过OpenGL的glGenerateMipmap为纹理图像创建多级渐远纹理。
过滤方式 | 描述 |
GL_NEAREST_MIPMAP_NEAREST | 使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样 |
GL_LINEAR_MIPMAP_NEAREST | 使用最邻近的多级渐远纹理级别,并使用线性插值进行采样 |
GL_NEAREST_MIPMAP_LINEAR | 在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样 |
GL_LINEAR_MIPMAP_LINEAR | 在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样 |
多级纹理通常用于纹理被缩小的情况下,如果用于纹理被放大的情况GL_TEXTURE_MAG_FILTER则会保发错GL_INVALID_ENUM
渲染纹理
要将纹理渲染到物体上,首先需要将图片加载进来,这里通过stb_image来完成
通过stbi_load加载图片
第一个参数是图片的位置,第二三四个参数是输出的图片的宽高和颜色通道个数,第五个参数是希望返回的通道数(常用:0=保持原样,3=RGB,4=RGBA)
图片加载进来了,需在OpenGL生成纹理。
然后绑定
接下来使用前面加载的图片生成纹理
- 第一个参数指定了纹理目标(Target)。设置为GL_TEXTURE_2D意味着会生成与当前绑定的纹理对象在同一个目标上的纹理(任何绑定到GL_TEXTURE_1D和GL_TEXTURE_3D的纹理不会受到影响)。
- 第二个参数为纹理指定多级渐远纹理的级别,如果你希望单独手动设置每个多级渐远纹理的级别的话。这里我们填0,也就是基本级别。
- 第三个参数告诉OpenGL我们希望把纹理储存为何种格式。我们的图像只有
RGB
值,因此我们也把纹理储存为RGB
值。这里的值可以根据前面读取的nrChannels决定,如果是3则是GL_RGB,如果是4则是GL_RGBA.
- 第四个和第五个参数设置最终的纹理的宽度和高度。我们之前加载图像的时候储存了它们,所以我们使用对应的变量。
- 下个参数应该总是被设为
0
(历史遗留的问题)。
- 第七第八个参数定义了源图的格式和数据类型。我们使用RGB值加载这个图像,并把它们储存为
char
(byte)数组,我们将会传入对应值。
- 最后一个参数是真正的图像数据。
生成之后释放不在用到的图片即可。
接下来在顶点数据后面加上纹理顶点
并告诉OpenGL怎么解析它
shader也要更新以下
VertexShader
FragmentShader
在渲染前绑定纹理即可
你好,借钱!

如果发现图片颠倒过来是因为OpenGL的0.0坐标在图片底部,而图片的0.0坐标在顶部。在加载图片之前调用以下函数即可
前面没有给sample2D赋值是因为一个纹理的默认纹理单元是0,是默认激活的。纹理单元是纹理的位置值,可以通过glUniform1i设置
可以通过glActiveTexture来激活对应的纹理单元,激活之后glBindTexture就会绑定到当前激活的纹理单元,因为GL_TEXTURE0默认被激活,因此前面使用的时候就没有激活它。
OpenGL至少有16个纹理单元可以使用,最多32个。
可以通过mix集合两个纹理,第三个值是线性插值,如果是1,就返回第二个输入,0就返回第一个输入,其他就会混合两者。
另外需要通过glUniform1i来设置每个采样器这个采样器属于哪个纹理单元
- Author:lltouchingfish
- URL:https://tangly1024.com/article/204be847-332a-80b7-bb84-c362ea5d20dd
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!