webgl入門(2)-初識webgl和著色器

weixin_34162695發表於2018-12-20

前言

原書中第2章非常長,如果整理成一個文件的話,得看好多天。為了瀏覽方便,我將其拆分成若干小節,方便大家學習。

webgl採用HTML5中引入的canvas元素來定義頁面的繪圖區域。如果沒有WegGL,js只能在canvas上繪製二維圖形。

在這一章中,我們將通過建立若干個示例程式,一步步的介紹一些核心的webgl函式。

1.最短的webgl程式:清空繪圖區

我們要開始編寫最短的webgl程式,這個程式的主要功能是使用背景色清空canvas標籤的繪圖區。(這裡的清空,是指用背景色填充的意思)

html程式碼如下;

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>webgl學習</title>
</head>

<body>
  <canvas id="canvas" width="400" height="400"></canvas>
  <script src="./index.js"></script>
</body>

</html>
複製程式碼

js程式碼如下:


// 獲取canvas
var canvas = document.getElementById('canvas')
// 獲取webgl繪圖上下文
var gl = canvas.getContext('webgl')

if (!gl) {
  console.log('Failed to get the rendering context')
}
// 指定清空canvas的顏色
gl.clearColor(0.0, 0.0, 0.0, 1.0)

// 清空canvas
gl.clear(gl.COLOR_BUFFER_BIT)

複製程式碼

示例程式的執行步驟如下:

  1. 獲取canvas元素
  2. 獲取webgl的繪圖上下文
  3. 設定背景色
  4. 清空canvas

點選檢視效果

2. 程式解析

2.1 獲取canvas元素

我們通過getElementById獲取canvas元素

var canvas = document.getElementById('canvas')
複製程式碼

2.2 為webgl獲取繪圖上下文

這裡傳入的引數是‘webgl’而不是‘3d’。我們以前使用canvas畫2d圖形的時候傳入的是‘2d’。所以這裡要注意下,不要傳錯了。

var gl = canvas.getContext('webgl')
複製程式碼

2.3 設定canvas的背景色

gl.clearColor(0.0, 0.0, 0.0, 1.0)
複製程式碼

gl.clearColor採用RGBA的方式設定背景色:

gl.clearColor(red,green,blue,alpha)
複製程式碼
引數 含義
red 指定紅色值(從0.0到1.0)
green 指定綠色值(從0.0到1.0)
blue 指定藍色值(從0.0到1.0)
alpha 指定透明度(從0.0到1.0)
返回值
錯誤

如果任何值小於0或者大於1,那麼就會被截斷為0.0或者1.0

示例程式執行gl.clearColor(0.0, 0.0, 0.0, 1.0),背景色就被指定為了黑色。

我們一般指定顏色時,顏色的值是0到255之間的,但是由於webgl是繼承自OpenGL,所以它遵循傳統OpenGL顏色分量的取值範圍。

一旦指定的背景色,背景色就會駐存在WegGL系統中,在下一次呼叫gl.clearColor之前都不會改變。如果你將來還想用同一個顏色清空繪圖區,就沒必須要再指定一次背景色。

2.4 清空canvas

gl.clear(gl.COLOR_BUFFER_BIT);
複製程式碼

函式引數是gl.COLOR_BUFFER_BIT,這是因為WebGL中,gl.clear()方法實際上繼承自OpenGL,它基於多基本緩衝區模型。這比二維繪圖上下文複雜的多。清空繪圖區域,實際上在清空顏色緩衝區,傳遞引數gl.COLOR_BUFFER_BIT就是告訴WebGL清空顏色緩衝區。除了顏色緩衝區,WebGL還有其他種類的緩衝區,比如深度緩衝區和模板緩衝區。

gl.clear(buffer)的用法

buffer是指定待清空的顏色緩衝區,位操作符OR(|)可用於指定多個緩衝區

引數 含義
gl.COLOR_BUFFER_BIT 顏色緩衝區
gl.DEPTH_BUFFER_BIT 深度緩衝區
gl.STENCIL_BUFFER_BIT 指定模板緩衝區
返回值
錯誤 INVALID_VALUE 緩衝區不是以上三種型別

3. 繪製一個點

之前的章節,我們學習如何建立一個wegl程式,以及如何使用一些簡單的webgl函式。這一節我們將進一步在一個示例程式中繪製一個最簡單的圖形,一個點。

注意這裡的html比上一次的html多了一些script。這些script是一些工具函式,避免重複的寫大量的程式碼。程式碼很簡單,可以直接開啟檢視。這裡就不解釋了。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>webgl學習</title>
</head>

<body>
  <canvas id="canvas" width="400" height="400"></canvas>
  <!-- 引入幾個webgl幫助函式,這裡的程式碼很簡單,你可以直接點選檢視 -->
  <script src="https://mycode04-1252305175.cos.ap-guangzhou.myqcloud.com/webgl-lib/lib/webgl-utils.js"></script>
  <script src="https://mycode04-1252305175.cos.ap-guangzhou.myqcloud.com/webgl-lib/lib/webgl-debug.js"></script>
  <script src="https://mycode04-1252305175.cos.ap-guangzhou.myqcloud.com/webgl-lib/lib/cuon-utils.js"></script>
  <script src="./index.js"></script>
</body>

</html>
複製程式碼

javascript程式碼:

//  頂點著色器 注意這裡的\n不能省略。否則不符合語法
var VSHADER_SOURCE = `
  void main(){\n
    gl_Position = vec4(0.0,0.0,0.0,1.0);\n
    gl_PointSize = 10.0;\n
  }\n
`
// 片段(片元)著色器
var FSHADER_SOURCE = `
  void main(){\n
    gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n
  }\n
`

function main() {
  // 獲取canvas
  var canvas = document.getElementById('canvas')
  // 獲取webgl繪圖上下文
  var gl = canvas.getContext('webgl')

  if (!gl) {
    console.log('Failed to get the rendering context')
    retun
  }

  // 初始化著色器函式
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log("設定著色器失敗")
    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)
}

window.onload = function () {
  main()
}
複製程式碼

點選檢視效果

3.1 著色器是什麼?

要使用webgl進行繪圖必須使用著色器,在程式碼中,著色器是以字串的形式“嵌入”到js中的。

webgl的著色器分兩種

  • 頂點著色器:頂點著色器用來描述頂點的特性(如位置、顏色等)的程式,頂點是指二維或者三維空間的一個點,比如二維或者三維圖形的端點和交點。
  • 片元著色器:也叫片段著色器。負責進行逐片元處理過程如光照的程式。片元是webgl的一個術語。你可以理解它為畫素。

在三維場景中,僅僅用線條和顏色把圖形畫出來是遠遠不夠的,必須要考慮光照上去或者觀察者視角發生變化時,對場景有什麼影響。著色器可以高度靈活的完成這些工作。提供各種渲染效果。

上述程式執行流程:

  • 先執行javascript程式
  • 呼叫webgl的相關方法
  • 執行頂點著色器
  • 執行片元著色器
  • 在顏色緩衝區進行繪製
  • 清空繪圖區
  • 顏色緩衝區的內容自動在瀏覽器的canvas上顯示出來

3.2 initShaders

initShaders(),該函式定義在cuon.util.js中,是專為本書編寫的一個工具函式。其用法說明如下:

initShaders(gl,vshader,fshader)
引數取值含義
glvshader指定頂點著色器程式程式碼
fshader指定片元著色器程式程式碼
返回值true初始化著色器成功
fase初始化著色器失敗

3.3 頂點著色器

var VSHADER_SOURCE = `
  void main(){\n
    gl_Position = vec4(0.0,0.0,0.0,1.0);\n
    gl_PointSize = 10.0;\n
  }\n
`
複製程式碼

頂點著色器必須和c語言一樣,必須包含一個main函式。main前面的void表示這個函式不會有返回值。

首先將頂點位置賦值給gl_Position變數。

在將頂點尺寸賦值給gl_PointSize。

這兩個變數內建在頂點著色器中,有特殊的含義。如下:

型別和變數名 含義
vec4 gl_Position 表示頂點的位置
float gl_PointSize 表示頂點的尺寸

vec4 表示由4個浮點陣列成的向量。

注意:GLSL ES是一種強型別程式語言,比10是整型,10.0就是浮點數,傳錯型別就會報錯。

gl_Position其型別為vec4,但是我們只有3個浮點數(0.0,0.0,0.0),既x、y、z座標值。需要用某種方式把它轉為vec4型別的變數。好在著色器為我們提供了內建函式vec4(),幫助你建立vec4型別的變數。(原書中這一段有錯誤,已糾正)

在賦值gl_Position的向量中,我們新增了1.0作為第4個分量。由4個分量組成的向量稱為齊次座標。,因為它能夠提高處理三維資料的效率。所以被大量使用。雖然齊次座標是四維的,但是如果最後一個分量為1.0,那麼齊次座標就可以表示“前三個分量為座標值”的那個點。

3.4 片元著色器

片元著色器是用來設定顏色的,這裡設定為紅色。

var FSHADER_SOURCE = `
  void main(){\n
    gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n
  }\n
`
複製程式碼

gl_FragColor的用法如下:

型別和變數名 含義
vec4 gl_FragColor 指定片元顏色(RGBA格式)

3.5 繪製操作

我們使用drawArrays()進行繪製。

gl.drawArrays(gl.POINTS, 0, 1)
複製程式碼

gl.drawArrays(mode,first,count)

引數 含義
mode 指定繪製的方式,可以接受以下常量符號: gl.POINTS ,gl.LINES ,gl.LINE_STRIP ,gl.LINE_LOOP ,gl.TRIANGLES ,gl.TRIANGLE_STRIP ,gl.TRIANGLE_FAN
first 指定從哪個點開始繪製
count 指定繪製多少個點
錯誤 INVALID_ENUM 傳入的mode引數不是前述引數之一
錯誤 INVALID_VALUE 引數first或者count為負數

總結:以上我們簡單介紹了兩個webgl程式,並初步認識了著色器。後續的章節我們將學習webgl的座標系統和更多著色器的相關知識。欲知後事如何,請動動你的手指,關注下我,我會繼續帶來webgl的分享,哈哈

相關文章