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

第一種:
在這裏插入圖片描述
第二種:
在這裏插入圖片描述
第三種:
在這裏插入圖片描述

第四種:
在這裏插入圖片描述

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