-
1 # 趣味兒科技
-
2 # 智慧電子DIY
WebGL為不同的平臺/硬體提供了統一的封裝,遮蔽了OpenGL ES2.0在各平臺差異。後續我們會繼續談談OpenGL ES2.0在Android/iOS平臺的更多差異。這回我們分析WebKit的原始碼,談談WebGL與Cavans不同,WebGL又多做了哪些呢,效能提升在哪裡呢。
在H5中渲染機制我們可以使用多種方式來繪製圖形【本文以iOS版本的WebKit為例】DOM+CSS:為前端提供了強大圖形渲染技術,門檻低上手快,對硬體要求較高。
Canvas2D:元素本身並沒有繪製能力,它僅僅是2D圖形的容器,必須使用指令碼來完成實際的繪圖任務。getContext("2d") 方法可返回一個物件CanvasRenderingContext(後續簡稱canvas),該物件提供了用於在畫布上繪圖的方法和屬性,可用於在畫布上繪製圖片、文字、圖形、顏色等,並提供常見的圖形轉換API,進行圖片的縮放、旋轉、畫素再加工能力,最終透過OpenGL渲染到螢幕上。
Canvas3D:同2D一樣,本身沒有渲染能力,透過getContext("webgl")方法可以返回一個基於OpenGL ES2.0上下文的物件WebGLRenderingContext(後續簡稱webgl),透過webgl可以直接訪問GPU硬體資源,對碼農要求更高,最佳化空間更大。
2D領域Canvas VS WebGLCanvas使用CoreGraphics渲染影象
WebKit的實現程式碼
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
對應GraphicsContext.cpp中的
void GraphicsContext::drawNativeImage(imagePtr, imageSize, styleColorSpace, destRect, srcRect, op, blendMode, orientation) { ······ // Flip the coords. CGContextTranslateCTM(context, 0, adjustedDestRect.height()); CGContextScaleCTM(context, 1, -1); // Adjust the color space. image = Image::imageWithColorSpace(image.get(), styleColorSpace); // Draw the image. CGContextDrawImage(context, adjustedDestRect, image.get()); CGContextRestoreGState(context); ······ }
WebGL直接使用OpenGL ES2.0渲染圖片:
在《 07. WebApp2.0時代啟程:倒立者贏,從CPU到GPU,一張圖片的旅行 》中,這裡不重新做說明了。
Canvas與WebGL的對比
CoreGraphics是執行在CPU上的圖形庫
它在iOS中已經深入的融合到UIView和UILayer框架中,架構圖如下:
WebGL只是對OpenGL ES2.0的輕量級封裝
js程式碼
gl.bindTexture(gl.TEXTURE_2D, texID);
在WebKit中對應於C++程式碼:
void GraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture) { makeContextCurrent(); if (m_state.activeTexture == GL_TEXTURE0 && target == GL_TEXTURE_2D) m_state.boundTexture0 = texture; ::glBindTexture(target, texture); }
圖形渲染WebGL完勝Canvas
CPU在RAM中處理完圖片後,仍需要上傳到GPU中才可以顯示,同時,GPU圖形渲染速度比CPU提升10倍以上。
Canvas的不可替代和WebGL的優勢Canvas提供高階的圖形渲染API
直接使用DOM物件繪製圖形
var canvas = document.getElementById("myCanvas"); var cxt=canvas.getContext("2d"); var img = new Image() img.src = "flower.png" cxt.drawImage(img, 0, 0);
而WebGL需要負責的程式碼實現:
gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === CONST.SCALE_MODES.LINEAR ? gl.LINEAR : gl.NEAREST);
可以渲染文字
使用 fillText(),在畫布上寫文字 "Hello world!" 和 "w3school.com.cn":
JS程式碼為:
var canvas=document.getElementById("myCanvas"); var ctx=canvas.getContext("2d"); ctx.font="20px Georgia"; ctx.fillText("Hello World!",10,50); ctx.font="30px Verdana"; // 建立漸變 var gradient=ctx.createLinearGradient(0,0,c.width,0); gradient.addColorStop("0","magenta"); gradient.addColorStop("0.5","blue"); gradient.addColorStop("1.0","red"); // 用漸變填色 ctx.fillStyle=gradient; ctx.fillText("w3school.com.cn",10,90);
WebGL無此API,WebKit也是透過FreeType透過CPU來實現文字的載入與渲染。如果需要渲染文字,需要生成一個Canvas物件,在Canvas繪製完成之後,在直接渲染到WebGL空間。
高效的上下文切換
多個Canvas例項可以輕鬆切換,因為在CPU中他只是一個靜態的Bitmap。而WebGL上線文最好只有一個,切換上線文需要更改GPU硬體管線的狀態和flushbuffer,頻繁的切換會消耗大量的CPU資源。
WebGL的優勢
GPU的framebuffer直接push到Display
CPU需要將渲染好的記憶體Bitmap上傳給GPU,然後透過display link到螢幕上。WebGL避免了CPU到GPU的大量的資料傳輸,只需要傳送指令給GPU即可。
支援批次渲染
支援vertexArray和IndiceArray,多個精靈共享一張文理,只需要將vertext資料緩衝到頂點資料,透過glDrawElements可以一次批次渲染。
支援非同步操作
Canvas的API每次都是同步操作,每次渲染必然同步到framebuffer中,不利於效能最佳化。WebGL可以自定義渲染機制和時機
回覆列表
隨著GPU功能的越來越強大,現在越來越多的應用程式利用CPU+GPU異構的形式,來提高應用程式的計算速度。而OpenGL作為圖形API發揮著重大的作用,OpenGL中CPU傳送資料到GPU的方式一般有以下幾種:
(1)紋理取樣方式,透過紋理不僅可以將影象資料傳入到GPU中,也可以將一些其他資料透過紋理的形式,傳送到GPU中。例如法線貼圖,就是利用法線以紋理的形式,傳送到GPU的。在工作過程中,也遇到過將類似伽馬矯正資料,透過紋理形式傳送到GPU中,然後來進行處理。
(2)透過Uniform這種glsl變數的形式。比如透過glUniformMatrix4fv這樣的函式,將一個矩陣或者向量傳輸到GPU中。
(3)各種buffer方式,緩衝物件是主要的從CPU傳送資料到GPU的方式,在渲染引擎中,頂點屬性引數(頂點座標、法線座標、紋理座標及頂點顏色等)都是透過緩衝物件的形式。