WebGL簡易教程(一):第一個簡單示例

1. 概述

不得不說如今三維圖形渲染技術更新換代實在是太快,OpenGL不少資料還沒來得及學習就已經有點落伍了。NeHe的學習教程還有以前用的《OpenGL編程指南》第七版(也就是紅寶書)都很是好,惋惜它們都是從固定管線開始講起的;而如今可編程管線的技術已是很是常見的基礎技術了。後來我還看過《OpenGL編程指南》第八版(白皮書),這本教程是從可編程管線(着色器)開始講起的,看的時候就以爲沒有前面的基礎打底,顯得很是的晦澀,遠不如紅寶書易懂。羞愧的說,我已經屢次入門失敗了。前端

這也正是我寫這篇教程的緣由,但願從繁雜的資料中總結真正有用的知識(固然也但願能幫助到你)。我以爲WebGL是學習OpenGL系列三維圖形渲染技術很好的入門點。WebGL是OpenGL的瀏覽器版本,基本上能夠認爲是OpenGL的子集,能被WebGL保留而不剔除的技術,必須是三維圖形渲染技術的精華。在這裏給你們強烈推薦《WebGL編程指南》這本書,我這篇教程正是在這本書的基礎之上總結出來的。web

在學習OpenGL/WebGL的時候,我還感受到不少資料舉得例子每每都太簡單了,確實是一看就懂,可是在實際遇到的問題的時候卻每每解決不了。我仍是認爲在實際中解決問題,更能加深對知識的理解。正好最近我在研究GIS中地形的繪製,那麼我就經過一步一步繪製地形的示例,來總結WebGL的相關知識。若是你不懂GIS這些術語也沒關係,只須要知道我這裏的最終目的是想繪製的是一個大地高程模型,是一個包含XYZ座標的點集,表達了地形的狀況。編程

2. 示例:繪製一個點

編寫WebGL程序跟編寫Web前端程序的步驟是同樣的,包含HTML和JavaScript兩個部分,經過瀏覽器進行調試。canvas

1) HelloPoint1.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Draw a point (1)</title>
  </head>

  <body onload="main()">
    <canvas id="webgl" width="400" height="400">
    Please use a browser that supports "canvas"
    </canvas>

    <script src="../lib/webgl-utils.js"></script>
    <script src="../lib/webgl-debug.js"></script>
    <script src="../lib/cuon-utils.js"></script>
    <script src="HelloPoint1.js"></script>
  </body>
</html>

這一段HTML很是簡單,從實際表現上來講就是建立了一個畫布<canvas>。<canvas>是HTML5引入的的一個繪製標籤,能夠在畫布中繪製任意圖形。WebGL正是經過<canvas>元素進行繪製的。
除此以外,這段代碼還經過<script>標籤引入了幾個外部JS文件。其中lib目錄中的幾個JS文件是一些通用的組件(來自《WebGL編程指南》的源碼),能夠先暫時不用關心其具體實現;最後一個導入的HelloPoint1.js正是咱們編寫的繪製模塊。而在<body>標籤中定義的onload事件屬性綁定的正是HelloPoint1.js中的main()函數。瀏覽器

2) HelloPoint1.js

// 頂點着色器程序
var VSHADER_SOURCE = 
  'void main() {\n' +
  '  gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n' + // Set the vertex coordinates of the point
  '  gl_PointSize = 10.0;\n' +                    // Set the point size
  '}\n';

// 片元着色器程序
var FSHADER_SOURCE =
  'void main() {\n' +
  '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the point color
  '}\n';

function main() {
  // 獲取 <canvas> 元素
  var canvas = document.getElementById('webgl');

  // 獲取WebGL渲染上下文
  var gl = getWebGLContext(canvas);
  if (!gl) {
    console.log('Failed to get the rendering context for WebGL');
    return;
  }

  // 初始化着色器
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to intialize shaders.');
    return;
  }

  // 指定清空<canvas>的顏色
  gl.clearColor(0.0, 0.0, 0.0, 1.0);

  // 清空<canvas>
  gl.clear(gl.COLOR_BUFFER_BIT);

  // 繪製一個點
  gl.drawArrays(gl.POINTS, 0, 1);
}

這段JS代碼的主要內容就是前面提到的main函數,一旦HTML被瀏覽器加載成功,這段腳本就會執行。在main函數中主要有一下幾步:函數

(1) 準備工做

document.getElementById('webgl'):文檔對象模型DOM的函數,獲取到HTML頁面的<canvas>元素。學習

getWebGLContext(canvas):獲取WebGL渲染上下文,保存在gl變量中。由於不一樣瀏覽器獲取函數不太同樣,因此經過組件cuon-utils提供的函數來統一行爲。webgl

(2) 着色器

initShaders:初始化着色器。debug

首先要知道什麼是着色器。若是你只學習過固定管線或者其餘的二維繪圖組件(如GDI),就會很是困惑着色器是什麼,爲何要用着色器。好比說在固定管線中,繪製點就是drawPoint,繪製線就drawLine。而在WebGL中,繪製工做則主要被分解成頂點着色器和片元着色器兩個步驟了。

在啓動JS程序後,繪製工做首先進入的是頂點着色器,在頂點着色器中描述頂點特性(如位置、顏色等),頂點就是三維空間的點,好比三角形的三個頂點;而後進入到片元着色器,在片元着色器中逐片元處理像素(如光照、陰影、遮擋)。最後片元傳入到顏色緩衝區,進行顯示。渲染過程以下:

WebGL渲染管線

這個過程是一個相似水流的流向過程,因此這個過程被稱爲渲染管線(Pipeline)。而且,這個過程是須要咱們去編程控制的,好比觀察者的視角變化須要在頂點着色器去調控;光線對顏色的變化須要在片元着色器去調控等;所以,這個過程就是可編程管線。經過着色器程序,三維圖像渲染就更加的靈活強大。

在initShaders()函數中,傳入了預先定義的JS字符串VSHADER_SOURCE和FSHADER_SOURCE。須要說明是,着色器程序是以字符串的形式嵌入到JS文件中運行的。這個函數一樣是cuon-utils組件提供的,調用以後就告訴WebGL系統着色器已經創建好了並能夠隨時使用。

(3) 頂點着色器

頂點着色器的定義以下:

// 頂點着色器程序
var VSHADER_SOURCE = 
  'void main() {\n' +
  '  gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n' + // Set the vertex coordinates of the point
  '  gl_PointSize = 10.0;\n' +                    // Set the point size
  '}\n';

前面說到頂點着色器程序是嵌入在JS中的程序,因此雖然傳入的是字符串,但其實本質是着色器描述語言(GLSL:OpenGL Shading Language)。既然是語言也就有本身的函數與變量定義。main()函數是每一個着色器程序定義的入口。在main函數中,將頂點的座標賦值給內置變量gl_Position,點的尺寸賦值給內置變量gl_PointSize。

注意這裏的gl_Position是必須賦值的,不然着色器不會正常工做。賦值的類型是vec4,也就是一個四維矢量。通常來講,描述點位只須要三維矢量就能夠了,可是不少狀況下須要四個份量的齊次座標。齊次座標(x,y,z,w)等價於三維座標(x/w,y/w,z/w)。因此若是第四個份量是1,那麼就是普通的三維座標;若是第四份量爲0,就表示無窮遠的點。

(4) 片元着色器

片元着色器的定義以下:

// 片元着色器程序
var FSHADER_SOURCE =
  'void main() {\n' +
  '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the point color
  '}\n';

如同頂點着色器同樣,片元着色器將點的顏色賦值給gl_FragColor變量,gl_FragColor是片元着色器惟一的內置變量,控制像素在屏幕上的最終顏色。

(5) 清空緩衝區

gl.clearColor():設置清空的背景色。
gl.clear(gl.COLOR_BUFFER_BIT): 清空顏色緩衝區。

(6) 繪製操做

gl.drawArrays(gl.POINTS, 0, 1):繪製一個點。
頂點着色器只是指定了繪製的頂點,還須要指定頂點到底成點、成線仍是成面,gl.drawArrays()就是這樣一個函數,這裏告訴WebGL系統應該繪製一個點。

3. 結果

最終的運行結果很簡單,在Chrome打開HelloPoint1.html,頁面顯示了一個繪製一個點的窗口:
WebGL示例顯示結果

4. 參考

原本部分代碼和插圖來自《WebGL編程指南》,源代碼連接:https://share.weiyun.com/5VjlUKo ,密碼:sw0x2x。會在此共享目錄中持續更新後續的內容。

相關文章
相關標籤/搜索