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
已創建的紋理對象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 的效果:
- 先用選區工具選中
- 使用填充工具,設置好重複鋸齒,按住 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
下的效果
第一種:
第二種:
第三種:
第四種: