3D世界

前言
最近在學(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è)圖

image

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入門指南

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勾拉,一起剝皮案震驚了整個(gè)濱河市煮甥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌望艺,老刑警劉巖苛秕,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異找默,居然都是意外死亡艇劫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門惩激,熙熙樓的掌柜王于貴愁眉苦臉地迎上來店煞,“玉大人,你說我怎么就攤上這事风钻∏牦埃” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵骡技,是天一觀的道長鸣个。 經(jīng)常有香客問我羞反,道長,這世上最難降的妖魔是什么囤萤? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任昼窗,我火速辦了婚禮,結(jié)果婚禮上涛舍,老公的妹妹穿的比我還像新娘澄惊。我一直安慰自己,他們只是感情好富雅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布掸驱。 她就那樣靜靜地躺著,像睡著了一般没佑。 火紅的嫁衣襯著肌膚如雪毕贼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天图筹,我揣著相機(jī)與錄音帅刀,去河邊找鬼。 笑死远剩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的骇窍。 我是一名探鬼主播瓜晤,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼腹纳!你這毒婦竟也來了痢掠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤嘲恍,失蹤者是張志新(化名)和其女友劉穎足画,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佃牛,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡淹辞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了俘侠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片象缀。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖爷速,靈堂內(nèi)的尸體忽然破棺而出央星,到底是詐尸還是另有隱情,我是刑警寧澤惫东,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布莉给,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏颓遏。R本人自食惡果不足惜胁黑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望州泊。 院中可真熱鬧丧蘸,春花似錦、人聲如沸遥皂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽演训。三九已至弟孟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間样悟,已是汗流浹背拂募。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窟她,地道東北人陈症。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像震糖,于是被迫代替她去往敵國和親录肯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355