WebGL程式設計指南(1)簡介

CopperDong發表於2018-04-24

   書本原始碼 https://download.csdn.net/download/qfire/10371055

   2009年,Khronos建立了WebGL工作小組,開始基於OpenGL ES著手建立WebGL規範,並於2011年釋出了WebGL規範的第1個版本。本書主要基於第1版的WebGL規範編寫,後續更新目前都是以草案的形式釋出,如有需要,也可參考。www.khronos.org/registry/webgl/specs/1.0/

1.1 WebGL程式的結構

   

1.2 Canvas是什麼?

   在HTML5出現之前,如果你想在網頁上顯示影像,只能使用HTML提供的原生方案<img>標籤。用這個標籤顯示影像雖然簡單,但只能顯示靜態的圖片,不能進行實時繪製和渲染。因此,後來出現了一些第三方解決方案,如Flash Player等。HTML5的出現改變了一切,它引入了<canvas>標籤,允許JavaScript動態繪製圖形。

例項

       清空

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8"/>
	<title>Clear canvas</title>
</head>
<body onload="main()">
	<canvas id="webgl" width="400" height="400">
		Please use the browser supporting "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="HelloCanvas.js"></script>
</body>
</html>
function main() {
	var canvas = document.getElementById('webgl');
	var gl = getWebGLContext(canvas);
	if (!gl) {
		console.log("Failed to get the rendering context for WebGL");
		return;
	}
	//RGBA
	gl.clearColor(0.0, 0.0, 0.0, 1.0);
	//清空
	gl.clear(gl.COLOR_BUFFER_BIT);
	//繪製點
	//gl.drawColor(1.0, 0.0, 0.0, 1.0);
	gl.drawPoint(0, 0, 0, 10);  //點的位置和大小
}

       繪製一個10個畫素大的紅色的點,WebGL處理的是三維圖形,所以我們有必要為這個點指定三維座標。

       WebGL依賴於一種新的稱為著色器的繪圖機制。著色器提供了靈魂且強大的繪製二維或三維圖形的方法,所有WebGL程式必須使用它。著色器不僅強大,而且更復雜,僅僅通過一條簡單的繪圖命令是不能操作它的。

//頂點著色器程式
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() {
	var canvas = document.getElementById('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 initialize shaders.');
		return ;
	}
	//RGBA
	gl.clearColor(0.0, 0.0, 0.0, 1.0);
	//清空
	gl.clear(gl.COLOR_BUFFER_BIT);
	//繪製點
	gl.drawArrays(gl.POINTS, 0, 1);  //點的位置和大小
}

WebGL需要兩種著色器。

  • 頂點著色器(Vertex shader):頂點著色器是用來描述頂點特性(如位置、顏色等)的程式。
  • 片元著色器(Fragment shader):進行逐片元處理過程如光照的程式。片元是一個WebGL術語,你可以將其理解為畫素。




vec4(x, y, z, w);齊次座標(x, y, z, w)等價於三維座標(x/w, y/w, z/w),齊次座標的存在,使得用矩陣乘法來描述頂點變換成為可能,三維圖形系統在計算過程中,通常使用齊次座標來表示頂點的三維座標。

gl.drawArrays()可以用來繪製各種圖形


1.3 WebGL座標系統

    


   '  gl_Position = vec4(0.5, 0.5, 0.0, 1.0); \n' + //設定座標

   '  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n' + //設定顏色

注:WebGL不需要交換顏色緩衝區

1.4 繪製一點例項

   將位置資訊從JavaScript程式中傳給頂點著色器。有兩種方式可以做到:attribute變數和uniform變數。attribute變數傳輸的是那些與頂點相關的資料,而uniform變數傳輸的是那些對於所有頂點都相同(或與頂點無關)的資料。


//頂點著色器程式
var VSHADER_SOURCE = 
   'attribute vec4 a_Position;\n' +
   'void main() {\n' + 
   '  gl_Position = a_Position; \n' + //設定座標
   '  gl_PointSize = 10.0; \n' + //設定尺寸
   '}\n';
//片元著色器程式
var FSHADER_SOURCE = 
   'void main() {\n' +
   '  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n' + //設定顏色
   '}\n';
   

function main() {
	var canvas = document.getElementById('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 initialize shaders.');
		return ;
	}
	//獲取attribute變數的儲存位置
	var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
	if (a_Position < 0) {
		console.log("failed to get the storage location of a_Position");
		return;
	}
	gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
	//RGBA
	gl.clearColor(0.0, 0.0, 0.0, 1.0);
	//清空
	gl.clear(gl.COLOR_BUFFER_BIT);
	//繪製點
	gl.drawArrays(gl.POINTS, 0, 1);  //點的位置和大小
}



//頂點著色器程式
var VSHADER_SOURCE = 
   'attribute vec4 a_Position;\n' +
   'void main() {\n' + 
   '  gl_Position = a_Position; \n' + //設定座標
   '  gl_PointSize = 10.0; \n' + //設定尺寸
   '}\n';
//片元著色器程式
var FSHADER_SOURCE = 
   'precision mediump float;\n' +
   'uniform vec4 u_FragColor;\n' + //uniform變數
   'void main() {\n' +
   '  gl_FragColor = u_FragColor;\n' + //設定顏色
   '}\n';
  
function main() {
	var canvas = document.getElementById('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 initialize shaders.');
		return ;
	}
	//獲取attribute變數的儲存位置
	var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
	if (a_Position < 0) {
		console.log("failed to get the storage location of a_Position");
		return;
	}
	var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
	if (u_FragColor < 0) {
		console.log("failed to get the storage location of u_FragColor");
		return;
	}
	//註冊滑鼠
	canvas.onmousedown = function(ev) { click(ev, gl, canvas, a_Position, u_FragColor)};
	gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
	//RGBA
	gl.clearColor(0.0, 0.0, 0.0, 1.0);
	//清空
	gl.clear(gl.COLOR_BUFFER_BIT);
	//繪製點
	//gl.drawArrays(gl.POINTS, 0, 1);  //點的位置和大小
}

var g_points = [];   //
var g_colors = [];
function click(ev, gl, canvas, a_Position, u_FragColor) {
	var x = ev.clientX;
	var y = ev.clientY;
	var rect = ev.target.getBoundingClientRect();
	x = ((x-rect.left) - canvas.width/2)/(canvas.width/2);
	y = (canvas.height/2 - (y-rect.top))/(canvas.height/2);
	//將座標儲存到g_points陣列中
	g_points.push([x, y]);
	//將點的顏色儲存到g_colors陣列中
	if (x >= 0.0 && y >= 0.0) { //第一象限
		g_colors.push([1.0, 0.0, 0.0, 1.0]);  //紅色
	} else if (x < 0.0 && y < 0.0) { // 第三象限
		g_colors.push([0.0, 1.0, 0.0, 1.0]);  //綠色
	} else {
		g_colors.push([1.0, 1.0, 1.0, 1.0]);  //白色
	}
	//清空
	gl.clear(gl.COLOR_BUFFER_BIT);
	var len = g_points.length;
	for (var i=0; i<len; i++) {
		var xy = g_points[i];
		var rgba = g_colors[i];
		//將點的位置傳輸到a_Position變數中
		gl.vertexAttrib3f(a_Position, xy[0], xy[1], 0.0);
		//將點的顏色傳輸到u_FragColor變數中
		gl.uniform4f(u_FragColor, rgba[0], rgba[1], rgba[2], rgba[3]);
		//繪製點
		gl.drawArrays(gl.POINTS, 0, 1);
	}
}


相關文章