纹理的基础知识
纹理是一种数据存储形式,不仅可以方便地访问特定的数据条目,还可以将多个条目混合(插入)在一起。
在 OpenGL 中,纹理可以用于很多事情,但最常见的是它将图像映射到多边形(例如三角形)。为了将纹理映射到三角形(或另一个多边形),我们必须告诉每个顶点它对应的纹理部分。我们将纹理坐标分配给多边形的每个顶点,然后在该多边形中的所有片段之间进行插值。纹理坐标在 x 和 y 轴上的范围通常为 0 到 1,如下图所示:
此三角形的纹理坐标如下所示:
GLfloat texCoords[] = {
0.0f, 0.0f, // Lower-left corner
1.0f, 0.0f, // Lower-right corner
0.5f, 1.0f // Top-center corner
};
将这些坐标放入 VBO(顶点缓冲区对象)并为着色器创建新属性。你应该已经具有顶点位置的至少一个属性,因此为纹理坐标创建另一个属性。
生成纹理
首先要做的是生成一个纹理对象,该对象将由一个 ID 引用,该 ID 将存储在 unsigned int 纹理中 :
GLuint texture;
glGenTextures(1, &texture);
之后必须绑定所有后续纹理命令将配置此纹理:
glBindTexture(GL_TEXTURE_2D, texture);
加载图片
要加载图像,你可以创建自己的图像加载器,也可以使用图像加载库,例如 c ++中的 SOIL (简单 OpenGL 图像库)或 java 中的 TWL PNGDecoder 。
使用 SOIL 加载图像的示例如下:
int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
现在你可以将此图像指定给纹理对象:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
之后你应该取消绑定纹理对象:
glBindTexture(GL_TEXTURE_2D, 0);
包裹纹理坐标的参数
如上所示,纹理的左下角有 UV(st)
坐标(0,0),纹理的右上角有坐标(1,1),但网格的纹理坐标可以在任何范围。要处理这个问题,必须定义纹理坐标如何包裹到纹理。
对纹理卷绕参数坐标可以与设置 glTextureParameter 使用 GL_TEXTURE_WRAP_S
,GL_TEXTURE_WRAP_T
和 GL_TEXTURE_WRAP_R
。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
可能的参数是:
-
GL_CLAMP_TO_EDGE
使纹理坐标被限制在 [1 / 2N,1 - 1 / 2N]范围内,其中 N 是方向上纹理的大小。 -
GL_CLAMP_TO_BORDER
与GL_CLAMP_TO_EDGE
相同,但在夹紧的情况下,取出的纹理元素数据被GL_TEXTURE_BORDER_COLOR
指定的颜色替换。 -
GL_REPEAT
导致纹理坐标的整数部分被忽略。纹理是平铺的。
GL_MIRRORED_REPEAT
:如果纹理坐标的整数部分是偶数,则忽略它。相反,如果纹理坐标的整数部分是奇数,则纹理坐标设置为 1 -frac(s)
。fract(s)
是纹理坐标的小数部分。这会导致纹理每隔一次镜像一次。
GL_MIRROR_CLAMP_TO_EDGE
使纹理坐标重复为GL_MIRRORED_REPEAT
,对于纹理的一次重复,此时要被钳位的坐标如GL_CLAMP_TO_EDGE
。
注意 GL_TEXTURE_WRAP_S
,GL_TEXTURE_WRAP_T
和 GL_TEXTURE_WRAP_R
的默认值是 GL_REPEAT
。
应用纹理
最后要做的是在绘制调用之前绑定纹理:
glBindTexture(GL_TEXTURE_2D, texture);