概述
纹理包装模式用于指定纹理坐标超出[0.0, 1.1]范围时所发生的行为,用glTexParameter[i|f] [v]设置,这些模式可以为s、t、r坐标单独设置。GL_TEXTURE_WRAP_S和GL_TEXTURE_WRAP_T和GL_TEXTURE_WRAP_R分别定义s和t和r坐标超出[0.0, 1.0]范围时发生的行为。
包装模式选择:
纹理包装模式 | 描述 |
---|---|
GL_REPEAT | 重复纹理 |
GL_CLAMP_TO_EDGE | 限定读取纹理的边缘 |
GL_MIRRORED_REPEAT | 重复纹理和镜像 |
正常纹理坐标是[0, 1]之间,而右边的纹理坐标为[-1, 2],比正常的大了3倍,所以,一行的小方块数目为12个。
左边为正常纹理,右边为纹理坐标包装
纹理坐标包装的坐标设置:
GLfloat vVertices[] = {
-0.3f, 0.3f, 0.0f, 1.0f, // Position 0
-1.0f, -1.0f, // TexCoord 0
-0.3f, -0.3f, 0.0f, 1.0f, // Position 1
-1.0f, 2.0f, // TexCoord 1
0.3f, -0.3f, 0.0f, 1.0f, // Position 2
2.0f, 2.0f, // TexCoord 2
0.3f, 0.3f, 0.0f, 1.0f, // Position 3
2.0f, -1.0f // TexCoord 3
};
正常纹理坐标:
GLfloat vVertices[] = {
-0.3f, 0.3f, 0.0f, 1.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-0.3f, -0.3f, 0.0f, 1.0f, // Position 1
0.0f, 1.0f, // TexCoord 1
0.3f, -0.3f, 0.0f, 1.0f, // Position 2
1.0f, 1.0f, // TexCoord 2
0.3f, 0.3f, 0.0f, 1.0f, // Position 3
1.0f, 0.0f // TexCoord 3
};
源码解析
#include <stdlib.h>
#include "esUtil.h"
typedef struct
{
GLuint programObject;
GLint samplerLoc;
GLint offsetLoc;
GLuint textureId;
} myUserData;
GLubyte *GenCheckImage(int width, int height, int checkSize)
{
int x, y;
GLubyte *pixels = (GLubyte *)malloc(width * height * 3);
if (pixels == NULL) {
return NULL;
}
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
GLubyte rColor = 0;
GLubyte bColor = 0;
if ((x/checkSize)%2 == 0) {
rColor = 255 * ((y/checkSize) % 2);
bColor = 255 * (1 - ((y/checkSize) % 2));
} else {
bColor = 255 * ((y/checkSize) % 2);
rColor = 255 * (1 - ((y/checkSize) % 2));
}
pixels[(y*width + x)*3] = rColor;
pixels[(y*width + x)*3 + 1] = 0;
pixels[(y*width + x)*3 + 2] = bColor;
}
}
return pixels;
}
GLuint CreateTexture2D()
{
GLuint textureId;
int width = 256, height = 256;
GLubyte *pixels;
pixels = GenCheckImage(width, height, 64);
if (pixels == NULL) {
return 0;
}
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height,
0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return textureId;
}
int Init(MYESContext *myesContext)
{
myUserData *userData = (myUserData *)myesContext->userData;
char vShaderStr[] =
"#version 300 es \n"
"uniform float u_offset; \n"
"layout(location = 0) in vec4 a_position; \n"
"layout(location = 1) in vec2 a_texCoord; \n"
"out vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
" gl_Position.x += u_offset; \n"
" v_texCoord = a_texCoord; \n"
"} \n";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"in vec2 v_texCoord; \n"
"layout(location = 0) out vec4 outColor; \n"
"uniform sampler2D s_texture; \n"
"void main() \n"
"{ \n"
" outColor = texture(s_texture, v_texCoord); \n"
"} \n";
userData->programObject = myesLoadProgram(vShaderStr, fShaderStr);
userData->samplerLoc = glGetUniformLocation(userData->programObject, "s_texture");
userData->offsetLoc = glGetUniformLocation(userData->programObject, "u_offset");
userData->textureId = CreateTexture2D();
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
return GL_TRUE;
}
void Draw(MYESContext *myesContext)
{
myUserData *userData = (myUserData *)myesContext->userData;
GLfloat vVertices[] = {
-0.3f, 0.3f, 0.0f, 1.0f, // Position 0
-1.0f, -1.0f, // TexCoord 0
-0.3f, -0.3f, 0.0f, 1.0f, // Position 1
-1.0f, 2.0f, // TexCoord 1
0.3f, -0.3f, 0.0f, 1.0f, // Position 2
2.0f, 2.0f, // TexCoord 2
0.3f, 0.3f, 0.0f, 1.0f, // Position 3
2.0f, -1.0f // TexCoord 3
};
GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
glViewport(0, 0, myesContext->width, myesContext->height);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(userData->programObject);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), vVertices);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), &vVertices[4]);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, userData->textureId);
glUniform1i(userData->samplerLoc, 0);
// 这里是设置重复纹理
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glUniform1f(userData->offsetLoc, -0.7f);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
// 这里是设置限定读取纹理的边缘
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUniform1f(userData->offsetLoc, 0.0f);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
// 这里是设置重复纹理和镜像
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glUniform1f(userData->offsetLoc, 0.7f);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
}
void ShutDown(MYESContext *myesContext)
{
myUserData *userData = (myUserData *)myesContext->userData;
glDeleteTextures(1, &userData->textureId);
glDeleteProgram(userData->programObject);
}
int myesMain(MYESContext *myesContext)
{
myesContext->userData = malloc(sizeof(myUserData));
myesCreateWindow(myesContext, "9_3_texturewrap", 320, 240, MY_ES_WINDOW_RGB);
if (!Init(myesContext))
{
return GL_FALSE;
}
esRegisterDrawFunc(myesContext, Draw);
esRegisterShutdownFunc(myesContext, ShutDown);
return GL_TRUE;
}
参考
1. 纹理
https://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/06%20Textures/