LearnGL - 05.1 - Texture Wrap Mode


LearnGL - 学习笔记目录

本人才疏学浅,如有什么错误,望不吝指出。

上一篇:LearnGL - 05 - Texture,对纹理的使用有了一个大致的了解。

这一篇:我们将记录在纹理上做一些有趣的应用:

  • 了解 纹理作为的 Wrap Mode
  • 使用多张纹理,对部分纹理座标移动,部分纹理做遮罩,实现:类似2D UI流光效果

Wrap Mode

直译:环绕模式。我个人认为是一个:座标折叠的模式。

设置它可以配置纹理座标超出 [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 已创建的纹理对象ID
  • pname 指定的枚举符号常量的参数
  • *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 的效果:

  • 先用选区工具选中
  • 使用填充工具,设置好重复锯齿,按住 Ctrl + 鼠标水平或垂直移动来填充
    在这里插入图片描述

不同的 WrapMode 运行效果

执行下面的代码

#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: 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);
}

C++应用层设置 uniform

	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 下的效果

第一种:
在这里插入图片描述
第二种:
在这里插入图片描述
第三种:
在这里插入图片描述

第四种:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章