OpenGL 程式設計/現代 OpenGL 教程 2D
即使您不打算製作 3D 遊戲,並且堅持使用 2D,OpenGL 仍然會提供寶貴的工具。
在過去,2D 圖形卡透過允許程式設計師將點陣圖和精靈直接儲存在卡中,以及一些用於執行基本複製(位塊傳輸)的原語來提供硬體加速,這些複製操作可以帶或不帶 alpha 混合。
如今,這些功能正在被 OpenGL 及其(更通用的)紋理所取代。在 OpenGL 中進行 2D 程式設計基本上是顯示面向螢幕的紋理,其 z 座標始終設定為 0。這還引入了 2D 加速的急需標準化(例如,在 GNU/Linux + X11 下幾乎無法獲得 2D 加速)。
這種技術被幾個圖形庫使用,包括 SFML、ClanLib 或 Gnash。
我們將使用正投影矩陣,其中沒有透視(遠處的物體看起來和近處的物體一樣大 - 您可能已經在技術製圖中或透過在 Blender 中鍵入 Numpad 5 看到過這一點)。
GLM 提供 glm::ortho 來計算這種投影。由於我們將直接操作畫素,讓我們使用物理螢幕的畫素大小,而不是之前使用的 [-1, 1]。
此外,我們已經看到 OpenGL 的垂直軸是從下到上的,而傳統的 2D 螢幕是從上到下的,所以讓我們反轉 Y 軸
// glm::ortho(left, right, bottom, top, [zNear, zFar])
glm::mat4 projection = glm::ortho(0, screen_width,
screen_height, 0);
但是,由於我們正在進行現代程式設計,我們不應該忘記舊式的 2D 座標嗎?事實是,大多數圖形格式也是從上到下的。TGA 和 BMP 是從下到上的,但幾乎所有其他格式,尤其是格式庫(JPG、PNG 等)都會為您提供從上到下的圖片。我們在紋理教程中看到 OpenGL 對紋理使用從下到上的方式,因此它會將它們上下顛倒地顯示!
反轉 OpenGL 螢幕意味著我們的圖片可以按原樣上傳到 OpenGL 圖形卡,並以正確的方向顯示。另一種方法是反轉紋理座標。
唯一需要注意的是,圍繞 Z 軸的旋轉角度也需要反轉。
但也許反轉座標的主要原因是大多數使用者期望 Y 座標從上到下:例如檢查 Gimp 和 Dia;還要檢查其他 2D 遊戲框架和庫。一個值得注意的例外是 Inkscape(向量繪圖),其座標從左下角開始,就像 OpenGL 一樣。
圖形卡過去有奇特的限制,例如只允許使用 2 的冪尺寸。
在 OpenGL ES 2 中,只有在以下情況下才允許使用非 2 的冪紋理
GL_TEXTURE_MIN_FILTER不使用 mipmapGL_TEXTURE_WRAP_S和GL_TEXTURE_WRAP_T都設定為GL_CLAMP_TO_EDGE
否則紋理將始終返回黑色[1]。
讓我們對我們的紋理做同樣的事情。
為了以最簡單的方式將紋理“位塊傳輸”到 OpenGL 緩衝區,可以使用帶有紋理的一對三角形進行繪製
/* code here */
但是,您可以透過不呼叫 glClear 並使用髒矩形等技術來執行增量顯示更新 - 儘管現在 GPU 通常足夠快,可以避免實現這種最佳化。
幀緩衝區/渲染緩衝區/重複使用作為紋理/…?
待辦事項
由於我們在 2D 中工作,我們可以移除
- 背面剔除是不必要的
- 深度測試是不必要的
我們可以移除頂點中的 z 座標以節省空間。保留 w 座標為 1,以便我們可以使用變換矩陣。
說到變換矩陣,GLM 只提供 4x4 變換矩陣。為了將變換矩陣從 4x4 縮減為 3x3,我們可以
- 程式設計一組新的函式來使用 3x3 矩陣。
- 刪除第 3 行和第 3 列
這是一個 3D 仿射矩陣
xx yx zx tx xy yy zy ty xz yz zz tz 0 0 0 1
這是一個 2D 仿射矩陣
xx yx tx xy yy ty 0 0 1
我們可以將 3D->2D 轉換編碼為
#define GLM_SWIZZLE
#include <glm/glm.hpp>
...
glm::mat3 mvp2D(mvp[0].xyw(), mvp[1].xyw(), mvp[3].xyw());
gl_Position 仍然是一個 vec4,所以
gl_Position = mvp * vec4(v_coord, 1.0);
v_coord.z 的值並不重要,因為無論我們使用哪個 z,正投影檢視始終以相同的方式顯示紋理。
您可以透過調整投影來執行縮放效果。例如,這是一個逐步的縮小效果
float scale = glutGet(GLUT_ELAPSED_TIME) / 1000.0 * .2; // 20% per second
glm::mat4 projection = glm::ortho(0.0f, 1.0f*screen_width*scale, 1.0f*screen_height*scale, 0.0f);
OpenGL 有一個特殊的規則來在畫素螢幕的中心繪製片段,稱為“菱形退出規則”[2] [3]。
因此,建議在繪製 2D 線之前在 X、Y 中新增一個小小的平移,這樣就不會錯過最後一個畫素
glm::translate(glm::mat4(1), glm::vec3(0.375, 0.375, 0.));
待辦事項:提供一個例子
注意:這似乎僅限於繪製基本圖形,我在操作紋理時無法重現任何問題。
- 來自 OpenGL 華夏公益教科書示例的“2d”:https://gitlab.com/wikibooks-opengl/modern-tutorials/tree/master/2d
- GLtron 專案中 2D 位塊傳輸的簡單實現
- GNU FreeDink 專案中帶有可選調色盤模擬的 2D 位塊傳輸的 AGPL 許可實現
- SDL2 和 SFML 都提供了一個 OpenGL 加速的 2D API。
- ↑ "glTexParameter". Khronos.org. Retrieved 2015-08-19.
- ↑ "OpenGL ES 通用配置檔案規範版本 2.0.25" (PDF). Khronos.org. 2010-11-02. 檢索於 2011-11-12. - 第 3.4.1 節 基本線段光柵化
- ↑ "OpenGL 常見問題解答和故障排除指南 v1.2001.11.01 - 9.030 如何在我的 3D 渲染之上繪製 2D 控制元件?". 檢索於 2011-11-12. - 如果需要精確的畫素化,您可能需要在模型檢視矩陣中新增一個小的平移