鍍金池/ 教程/ HTML/ WebGL 基本原理
WebGL 文本 HTML
WebGL 文本 Canvas 2D
WebGL 2D 圖像旋轉(zhuǎn)
WebGL 圖像處理(續(xù))
WebGL 2D 矩陣
WebGL 繪制多個(gè)東西
WebGL 圖像處理
WebGL 2D 圖像轉(zhuǎn)換
WebGL 3D 透視
WebGL 是如何工作的
WebGL 文本 紋理
WebGL 2D 圖像伸縮
WebGL 場(chǎng)景圖
WebGL 3D 攝像機(jī)
WebGL 文本 使用字符紋理
WebGL 正交 3D
WebGL 基本原理
WebGL - 更少的代碼,更多的樂(lè)趣
WebGL 著色器和 GLSL

WebGL 基本原理

WebGL 的出現(xiàn)使得在瀏覽器上面實(shí)時(shí)顯示 3D 圖像成為,WebGL 本質(zhì)上是基于光柵化的 API ,而不是基于 3D 的 API。

WebGL 只關(guān)注兩個(gè)方面,即投影矩陣的坐標(biāo)和投影矩陣的顏色。使用 WebGL 程序的任務(wù)就是實(shí)現(xiàn)具有投影矩陣坐標(biāo)和顏色的 WebGL 對(duì)象即可??梢允褂谩爸鳌眮?lái)完成上述任務(wù)。頂點(diǎn)著色器可以提供投影矩陣的坐標(biāo),片段著色器可以提供投影矩陣的顏色。

無(wú)論要實(shí)現(xiàn)的圖形尺寸有多大,其投影矩陣的坐標(biāo)的范圍始終是從 -1 到 1 。下面是一個(gè)關(guān)于實(shí)現(xiàn) WebGL 對(duì)象的一個(gè)簡(jiǎn)單例子。

// Get A WebGL context
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("experimental-webgl");
?
// setup a GLSL program
var program = createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]);
gl.useProgram(program);
?
// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "a_position");
?
// Create a buffer and put a single clipspace rectangle in
// it (2 triangles)
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
-1.0, -1.0,
 1.0, -1.0,
-1.0,  1.0,
-1.0,  1.0,
 1.0, -1.0,
 1.0,  1.0]),
gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
?
// draw
gl.drawArrays(gl.TRIANGLES, 0, 6);   

下面是兩個(gè)著色器。

<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;

void main() {
  gl_Position = vec4(a_position, 0, 1);
}
</script>

<script id="2d-fragment-shader" type="x-shader/x-fragment">
void main() {
  gl_FragColor = vec4(0, 1, 0, 1);  // green
}
</script>    

它將繪出一個(gè)綠色的長(zhǎng)方形來(lái)填充整個(gè)畫(huà)板。

http://wiki.jikexueyuan.com/project/webgl/images/1.png" alt="" />

后面內(nèi)容還會(huì)更精彩,我們繼續(xù):-P

我們?cè)俅谓嫡{(diào)一下,無(wú)論畫(huà)板尺寸多大,投影矩陣坐標(biāo)的范圍只會(huì)在 -1 到 1 之間。從上面的例子中,我們可以看出我們只是將位置信息直接寫(xiě)在了程序里。 因?yàn)槲恢眯畔⒁呀?jīng)在投影矩陣中,所以并沒(méi)有其他額外的工作要做。 如果想實(shí)現(xiàn) 3D 的效果,那么可以使用著色器來(lái)將 3D 轉(zhuǎn)換為投影矩陣,這是因?yàn)?WebGL 是基于光柵的 API。

對(duì)于 2D 的圖像,也許會(huì)使用像素而不是投影矩陣來(lái)表述尺寸,那么這里我們就更改這里的著色器,使得我們實(shí)現(xiàn)的矩形可以以像素的方式來(lái)度量,下面是新的頂點(diǎn)著色器。

<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;

uniform vec2 u_resolution;

void main() {
   // convert the rectangle from pixels to 0.0 to 1.0
   vec2 zeroToOne = a_position / u_resolution;

   // convert from 0->1 to 0->2
   vec2 zeroToTwo = zeroToOne * 2.0;

   // convert from 0->2 to -1->+1 (clipspace)
   vec2 clipSpace = zeroToTwo - 1.0;

   gl_Position = vec4(clipSpace, 0, 1);
}
</script>    

下面我們將我們的數(shù)據(jù)從投影矩陣改為像素。

// set the resolution
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);

// setup a rectangle from 10,20 to 80,30 in pixels
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
10, 20,
80, 20,
10, 30,
10, 30,
80, 20,
80, 30]), gl.STATIC_DRAW);    

http://wiki.jikexueyuan.com/project/webgl/images/2.png" alt="" />

上面例子矩陣位于底部邊框,下面我們讓它位于左上邊框:

修改代碼如下:

   gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);

效果如下圖:

http://wiki.jikexueyuan.com/project/webgl/images/3.png" alt="" />

下面我們將上述關(guān)于矩陣的實(shí)現(xiàn)寫(xiě)成函數(shù)以便可以以函數(shù)調(diào)用的方式來(lái)實(shí)現(xiàn)不同尺寸的矩陣。 然而,這里的顏色應(yīng)該是可變的。

首先,我們?yōu)槠沃髟O(shè)計(jì)一個(gè)關(guān)于顏色的輸入。

<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

uniform vec4 u_color;

void main() {
   gl_FragColor = u_color;
}
</script>    

下面是實(shí)現(xiàn)繪畫(huà) 50 個(gè)尺寸和顏色均隨機(jī)的矩陣的代碼。

var colorLocation = gl.getUniformLocation(program, "u_color");
  ...
  // Create a buffer
  var buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.enableVertexAttribArray(positionLocation);
  gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

  // draw 50 random rectangles in random colors
  for (var ii = 0; ii < 50; ++ii) {
// Setup a random rectangle
setRectangle(
gl, randomInt(300), randomInt(300), randomInt(300), randomInt(300));

// Set a random color.
gl.uniform4f(colorLocation, Math.random(), Math.random(), Math.random(), 1);

// Draw the rectangle.
gl.drawArrays(gl.TRIANGLES, 0, 6);
  }
}

// Returns a random integer from 0 to range - 1.
function randomInt(range) {
  return Math.floor(Math.random() * range);
}

// Fills the buffer with the values that define a rectangle.
function setRectangle(gl, x, y, width, height) {
  var x1 = x;
  var x2 = x + width;
  var y1 = y;
  var y2 = y + height;
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
 x1, y1,
 x2, y1,
 x1, y2,
 x1, y2,
 x2, y1,
 x2, y2]), gl.STATIC_DRAW);
}    

下面就是實(shí)現(xiàn)出來(lái)的效果。

http://wiki.jikexueyuan.com/project/webgl/images/3Mwhw40.png" alt="" />

到此可以看出 WebGL 實(shí)質(zhì)上是一種輕量級(jí)的 API。但是,它可以實(shí)現(xiàn)較為復(fù)雜的 3D 效果,其復(fù)雜性由程序定制。WebGL API 本身是 2D 的且相對(duì)比較簡(jiǎn)單。