本人才疏学浅,如有什么错误,望不吝指出。
上一篇:LearnGL - 05 - Texture,对纹理的使用有了一个大致的了解。
这一篇:我们将记录在纹理上做一些有趣的应用:
直译:环绕模式。我个人认为是一个:坐标折叠的模式。
设置它可以配置纹理坐标超出 [0~1] 时的坐标如何处理。
OpenGL 4.5- 使用:glTexParameter
OpenGL 4.5+ 使用:glTextureParameteri
函数原型:
void glTexParameterfv( GLenum target,
GLenum pname,
const GLfloat * params);
void glTextureParameterfv( GLuint texture,
GLenum pname,
const GLfloat *paramtexture.);
target
纹理目标类型texture
已创建的纹理对象IDpname
指定的枚举符号常量的参数*params/*paramtexture
是要接受的浮点数组数据明显使用 glTextureParameterfv
结构会清晰很多,因为他可以指定要设置的纹理对象ID。
下面的代码也使用者个 API。
有好几种模式:
GL_CLAMP_EDAGE
UV 超出[0~1]范围的将截距到边缘颜色GL_CLAMP_TO_BORDER
UV 超出[0~1]范围的将截距到边缘颜色GL_REPEAT
UV 超出[0~1]范围的将重复开始的小数部分,相当于 uv = (uv % 1.0f);
GL_MIRRORED_REPEAT
UV 超出[0~1]范围的将重复开始的小数部分,相当于 uv = (uv % 1 == 0) ? (uv % 1.0f) : (1 - (uv % 1.0f))
用 GIMP 对之前的图片处理边界虚线,方便查看 UV Wrap Mode 的效果:
执行下面的代码
#define WRAP_MODE 4
#if WRAP_MODE == 1
glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // UV 超出[0~1]范围的将截距到边缘颜色
glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#elif WRAP_MODE == 2
glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);// UV 超出[0~1]范围的将截距到边缘颜色
glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
const GLfloat yellow[] = { 1.0f,1.0f,0.0f,0,1.0f }; // 黄色边缘色
glTextureParameterfv(texture, GL_TEXTURE_BORDER_COLOR, yellow); // 黄色
#elif WRAP_MODE == 3
glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_REPEAT); // UV 超出[0~1]范围的将重复开始的小数部分,相当于 uv = (uv % 1.0f);
glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_REPEAT);
#elif WRAP_MODE == 4
glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);// UV 超出[0~1]范围的将重复开始的小数部分,相当于 uv = (uv % 1 == 0) ? (uv % 1.0f) : (1 - (uv % 1.0f))
glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
#endif
我们给着色器添加了一个 uniform: uniform vec4 uv_scale_offset;
// jave.lin - testing_tex_shader.vert - 测试纹理的顶点着色器
#version 450 compatibility
uniform vec4 uv_scale_offset; // 添加 uv 的缩放与偏移,处理 uv 滚动动画
attribute vec3 vPos;
attribute vec2 vUV;
varying vec2 fUV;
void main() {
gl_Position = vec4(vPos, 1.0);
vec2 uv = vUV;
uv = uv_scale_offset.xy * vUV.xy + uv_scale_offset.zw; // 应用 uv 缩放、偏移
fUV = uv;
}
// jave.lin - testing_tex_shader.frag - 测试纹理的片段着色器
#version 450 compatibility
varying vec2 fUV;
uniform sampler2D tex;
void main() {
gl_FragColor = texture(tex, fUV);
}
bool uvAnima = true; // 是否需要 uv动画
vec4 uv_scale_offset = { 1,1,0,0 }; // 纹理坐标的缩放与偏移1
vec4 uv_scale_offset_FROM = { 1,1,0,0 }; // 纹理坐标的缩放与偏移2
vec4 uv_scale_offset_TO = { 2,2,-0.5,-0.5 }; // 纹理坐标的缩放与偏移3
while (!glfwWindowShouldClose(window)) { // 检测是否需要关闭窗体
glfwGetFramebufferSize(window, &width, &height); // 获取窗口大小
glViewport(0, 0, width, height); // 设置Viewport
glClearColor(0.1f, 0.2f, 0.1f, 0.f); // 设置清理颜色缓存时,填充颜色值
glClear(GL_COLOR_BUFFER_BIT); // 清理颜色缓存
shaderProgram->use(); // 使用此着色器程序
if (uvAnima) { // 如果有动画
float time = (float)glfwGetTime(); // 获取时长
#define ANIMATION_TYPE 4 // 动画类型
#if ANIMATION_TYPE == 1
time = sin(time) * 0.5 + 0.5; // 用sin函数的值从 -1~1 变换到 0~1
lerp(uv_scale_offset_FROM, uv_scale_offset_TO, uv_scale_offset, time); // 再使用该 t 来作为 lerp 插值的t
#elif ANIMATION_TYPE == 2
uv_scale_offset[2] = time; // 水平移动 uv 中 u
#elif ANIMATION_TYPE == 3
uv_scale_offset[3] = time; // 垂直移动 uv 中 v
#elif ANIMATION_TYPE == 4
uv_scale_offset[2] = time; // 水平与垂直一起移动
uv_scale_offset[3] = time * 0.5f; // 垂直移动稍微慢一些
#endif
}
else {
memcpy(uv_scale_offset, uv_scale_offset_TO, sizeof(vec4)); // 复制数据
}
shaderProgram->setVec4(uv_so_uniform_location, // 设置 uv 缩放及偏移的变量
uv_scale_offset[0],
uv_scale_offset[1],
uv_scale_offset[2],
uv_scale_offset[3]
);
glBindVertexArray(vertex_array_object); // 先绘制 VAO[0] 的 VBO,EBO,VAF,ENABLED
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (GLvoid*)0); // 参数1:绘制三角图元;参数2:取6个索引来绘制三角图元(每个三角图元需要3个,所以可以画两个三角图元);参数3:将 GL_ELEMENT_ARRAY_BUFFER 每个元素视为 uint 类型;参数4:设置索引缓存的字节偏移量。也可以设置为另一个 缓存数据的指针,即:使用另一个数据。
glfwSwapBuffers(window); // swap buffer, from backbuffer to front buffer
glfwPollEvents(); // 处理其他的系统消息
}
#define ANIMATION_TYPE 4
宏定义 1~4 可以指定 4 中类型的纹理动画。
下面是在 Wrap Mode 为: GL_MIRRORED_REPEAT
下的效果