WebGL學習筆記(六):紋理貼圖


只可以繪制純色的模型是不夠的,為了呈現出更真實的模型,我們還需要通過紋理貼圖給模型進行上色。

丟失上下文

GPU作為一種公用資源,是會被多個進程同時使用的,在資源不足的情況下(比如PC或手機系統進入休眠狀態前或被喚醒后),我們持有的上下文會出現丟失的情況,為了保證程序運行的健壯性,我們必須在丟失上下文之后做出處理。

Canvas為我們提供了兩個事件來監聽,上下文的丟失和恢復,具體使用看下面的代碼:

 1 var canvas = document.getElementById("myGLCanvas");
 2 // 監聽上下文丟失的事件
 3 canvas.addEventListener("webglcontextlost", function (event) {
 4     // 取消默認行為
 5     event.preventDefault();
 6     // 停止繼續繪圖的代碼
 7 }, false);
 8 // 監聽上下文恢復的事件
 9 canvas.addEventListener("webglcontextrestored", function () {
10     // 重新初始化的代碼
11     // 需要注意的是 Canvas 通過 getContext 方法獲得的上下文對象不需要重新獲取, 還可以繼續使用之前獲取的上下文對象
12     // 開始繼續繪圖的代碼
13 }, false);

模擬丟失上下文

我們要測試丟失上下文的處理代碼是否正常,就需要觸發丟失上下文,我們可以使用下面的js庫來模擬上下文的丟失:

https://github.com/KhronosGroup/WebGLDeveloperTools

可以參考其目錄下的src\debug\lost-context-simulator-test.html示例來使用。

2D映射和立方體映射

我們需要將2D圖片貼到3D模型上,需要使用到2D的圖片,采用UV坐標來確定3D的面上的一個點可以對應2D圖片上的一個像素或多個像素(采樣),下面是uv坐標的坐標系:

(s對應u、t對應v),范圍[0-1]。

立方體映射,是一個包含了6個2D圖片的映射,一般用來實現環境映射,或者實現環境反射,下面的示例可以很好的展現環境反射的應用:

https://threejs.org/examples/#webgl_materials_envmaps

另外立方體映射還常用於創建天空盒(SkyBox)。

紋理大小

我們提交到GPU的圖片尺寸的高和寬必須是2的n次方,即(2、4、8、16、32、64、128、256...),不過在OpenGL ES 2.0和WebGL中,我們也可以使用高寬非2的n次方的圖片,即NPOT(Non Power Of Two);

如果我們使用了非2的n次方的圖片,會有下面的一些限制:

  • 不能使用MipMap映射;
  • 在着色器中采樣紋理貼圖時:紋理過濾方式只能用最近點或線性, 不能使用重復模式。

具體請看:https://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences

關於y軸翻轉

我們先看看DOM里的Image對象的坐標系和WebGL紋理的坐標系的區別:

可以發現,兩個坐標系的y軸剛好是相反的,所以為了使坐標系一致,我們需要使用下面的代碼來翻轉y軸:

gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);

紋理過濾

我們的紋理圖片和將要渲染的區域尺寸是不一定完全一致的,當紋理小於渲染區域時需要紋理伸展,當紋理大於渲染區域時需要紋理收縮;

MipMap

當紋理進行伸展過大和收縮過大時,會出現模糊和鋸齒,為了解決這個問題,我們可以使用多套尺寸的紋理,來對應不同尺寸的渲染區域,GPU會根據渲染區域的大小自動選擇;

優點

  • 模型無論是遠離還是離攝像機較近時,顯示都會比較自然;
  • 渲染效率更高;

缺點

  • 內存使用會增大為單張圖片的1/3;

創建MipMap的方法

  • 提交紋理之后,調用gl.generateMipmap方法WebGL會自動生成指定紋理的MipMap;
  • 通過外部工具,直接將所有的MipMap生成好之后,手動進行提交,該方法一般用於比較特殊的情況,比如不同級別的MipMap紋理圖像不一致的情況;

紋理坐標包裝

  • GL_REPEAT: 超出紋理范圍的坐標整數部分被忽略,形成重復效果。
  • GL_MIRRORED_REPEAT: 超出紋理范圍的坐標整數部分被忽略,但當整數部分為奇數時進行取反,形成鏡像效果。
  • GL_CLAMP_TO_EDGE:超出紋理范圍的坐標被截取成0和1,形成紋理邊緣延伸的效果。

activeTexture和bindTexture

gl.activeTexture

激活當前的操作貼圖,指定后續代碼操作的貼圖是哪一個,參數是枚舉gl.TEXTURE0到gl.TEXTURE7(最大值請查看gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS,最少是8);

后面會調用bindTexture來綁定當前的操作貼圖,如果沒有調用activeTexture就調用了bindTexture,則默認激活0號紋理單元(可以理解為默認調用了gl.activeTexture(gl.TEXTURE0)代碼);

gl.bindTexture

綁定指定紋理到activeTexture激活的紋理單元中,同時可以指定該紋理的類型;

更多詳細信息可以參考這里:https://www.jianshu.com/p/1829b4acc58d

示例

https://hammerc.github.io/dou3d-ts/learning/learningNotes/lesson_4/index.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM