前言
最近在學(xué)習(xí)three.js总处,以下是我的筆記暗甥。
相關(guān)概念了解
1.WebGL與Three.js
1.1什么是WebGL
WebGL是基于OpenGL ES 2.0的Web標(biāo)準(zhǔn)题篷,可以通過HTML5 Canvas元素作為DOM接口訪問匙赞。
聽起來挺像回事兒的,但是這是什么意思呢练湿?
如果你了解OpenGL猴仑,那么我解釋起來就比較輕松了。WebGL可以看做是將OpenGL ES(OpenGL for Embedded Systems鞠鲜,OpenGL嵌入式版本宁脊,針對(duì)手機(jī)断国、游戲機(jī)等設(shè)備相對(duì)較輕量級(jí)的版本)移植到了網(wǎng)頁平臺(tái)贤姆,像Chrome、Firefox這些現(xiàn)代瀏覽器都實(shí)現(xiàn)了WebGL標(biāo)準(zhǔn)稳衬,使用JavaScript就可以用你熟悉的霞捡、類似OpenGL的代碼編寫了。
如果你不了解OpenGL薄疚,那也沒關(guān)系碧信,因?yàn)檎鏣hree.js不需要你了解OpenGL或WebGL一樣,本書也不需要你預(yù)先知道這些知識(shí)街夭。你可以把WebGL簡單地認(rèn)為是一種網(wǎng)絡(luò)標(biāo)準(zhǔn)砰碴,定義了一些較底層的圖形接口,至于究竟多底層板丽,稍后我們和Three.js代碼對(duì)比來看呈枉。本書不會(huì)過多涉及WebGL的相關(guān)知識(shí),如果讀者想學(xué)習(xí)的話埃碱,市場上有不少相關(guān)書籍可供參考猖辫。
現(xiàn)在,我們知道了WebGL是一個(gè)底層的標(biāo)準(zhǔn)砚殿,在這些標(biāo)準(zhǔn)被定義之后啃憎,Chrome、Firefox之類的瀏覽器實(shí)現(xiàn)了這些標(biāo)準(zhǔn)似炎。然后辛萍,程序員就能通過JavaScript代碼,在網(wǎng)頁上實(shí)現(xiàn)三維圖形的渲染了羡藐。如果這對(duì)你來說還是太抽象贩毕,別著急,稍后我們會(huì)用具體的例子來說明传睹。
1.2什么是WebGL
Three.js究竟能用來干什么呢耳幢?
Three.js封裝了底層的圖形接口,使得程序員能夠在無需掌握繁冗的圖形學(xué)知識(shí)的情況下,也能用簡單的代碼實(shí)現(xiàn)三維場景的渲染睛藻。我們都知道启上,更高的封裝程度往往意味著靈活性的犧牲,但是Three.js在這方面做得很好店印。幾乎不會(huì)有WebGL支持而Three.js實(shí)現(xiàn)不了的情況冈在,而且就算真的遇到這種情況,你還是能同時(shí)使用WebGL去實(shí)現(xiàn)按摘,而不會(huì)有沖突包券。當(dāng)然,除了WebGL之外炫贤,Three.js還提供了基于Canvas溅固、SVG標(biāo)簽的渲染器,但由于通常WebGL能夠?qū)崿F(xiàn)更靈活的渲染效果兰珍,所以本書主要針對(duì)基于WebGL渲染器進(jìn)行說明侍郭。
1.1.3 WebGL vs. Three.js
畫一個(gè)這個(gè)圖
three 寫法
var renderer = new THREE.WebGLRenderer({
canvas: document.getElementById('mainCanvas')
});
renderer.setClearColor(0x000000); // black
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, 4 / 3, 1, 1000);
camera.position.set(0, 0, 5);
camera.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(camera);
var material = new THREE.MeshBasicMaterial({
color: 0xffffff // white
});
// plane
var planeGeo = new THREE.PlaneGeometry(1.5, 1.5);
var plane = new THREE.Mesh(planeGeo, material);
plane.position.x = 1;
scene.add(plane);
// triangle
var triGeo = new THREE.Geometry();
triGeo.vertices = [new THREE.Vector3(0, -0.8, 0),
new THREE.Vector3(-2, -0.8, 0), new THREE.Vector3(-1, 0.8, 0)];
triGeo.faces.push(new THREE.Face3(0, 2, 1));
var triangle = new THREE.Mesh(triGeo, material);
scene.add(triangle);
renderer.render(scene, camera);
WebGL代碼
var gl;
function initGL(canvas) {
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
}
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var str = "";
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3) {
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
}
var mvMatrix = mat4.create();
var pMatrix = mat4.create();
function setMatrixUniforms() {
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
var triangleVertexPositionBuffer;
var squareVertexPositionBuffer;
function initBuffers() {
triangleVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
var vertices = [
0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
triangleVertexPositionBuffer.itemSize = 3;
triangleVertexPositionBuffer.numItems = 3;
squareVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
vertices = [
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
squareVertexPositionBuffer.itemSize = 3;
squareVertexPositionBuffer.numItems = 4;
}
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [-1.5, 0.0, -7.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);
}
function webGLStart() {
var canvas = document.getElementById("lesson01-canvas");
initGL(canvas);
initShaders();
initBuffers();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
drawScene();
}
總結(jié):從上面的代碼我們不難發(fā)現(xiàn),使用原生WebGL接口實(shí)現(xiàn)同樣功能需要5倍多的代碼量掠河,而且很多代碼對(duì)于沒有圖形學(xué)基礎(chǔ)的程序員是很難看懂的亮元。由這個(gè)例子我們可以看出,使用Three.js開發(fā)要比WebGL更快更高效唠摹。尤其對(duì)圖形學(xué)知識(shí)不熟悉的程序員而言爆捞,使用Three.js能夠降低學(xué)習(xí)成本,提高三維圖形程序開發(fā)的效率
參考:
three.js入門指南