WebGL & Three.js 入門

1卡骂、簡(jiǎn)介

WebGL 是在瀏覽器中實(shí)現(xiàn)三維效果的一套規(guī)范钞楼,而 Three.js 可以看成是瀏覽器對(duì) WebGL 規(guī)范實(shí)現(xiàn)的一套封裝, 能夠讓 Web 開(kāi)發(fā)者使用 JavaScript 語(yǔ)言直接和顯卡(GPU)進(jìn)行通信振湾。其中得 GLSL 是GPU 部分對(duì)應(yīng)的編程語(yǔ)言暇务,可以用 GLSL 編寫(xiě)著色器程序,并配合 JavaScript 共同實(shí)現(xiàn) 3D 效果拿撩。一個(gè)簡(jiǎn)單的 Three.js 程序包含以下幾個(gè)部分:

<html>
    <head>
        <title>My first Three.js app</title>
        <style>
            body { margin: 0; }
            canvas { width: 100%; height: 100% }
        </style>
    </head>
    <body>
        <script src="http://wow.techbrood.com/libs/three.r73.js"></script>
        <script>
            // 1衣厘、建立場(chǎng)景
            var scene = new THREE.Scene();
           // 2、建立相機(jī)
            var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
            camera.position.z = 5;
           // 3压恒、建立渲染器
            var renderer = new THREE.WebGLRenderer();
            renderer.setSize( window.innerWidth, window.innerHeight );
            document.body.appendChild( renderer.domElement );
           // 4影暴、建立物體
            var geometry = new THREE.BoxGeometry( 1, 1, 1 );
            var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
            var cube = new THREE.Mesh( geometry, material );
            scene.add( cube );

            // 5、開(kāi)始繪制
            var render = function () {
                requestAnimationFrame( render );
                cube.rotation.x += 0.1;
                cube.rotation.y += 0.1;
                renderer.render(scene, camera);
            };

            render();
        </script>
    </body>
</html>

2探赫、概念介紹

ThreeJS-1

ThreeJS-2
  • 場(chǎng)景

在 Threejs 中場(chǎng)景就只有一種型宙,用THREE.Scene來(lái)表示,要構(gòu)件一個(gè)場(chǎng)景也很簡(jiǎn)單伦吠,只要new一個(gè)對(duì)象就可以了妆兑,代碼如下:

var scene = new THREE.Scene();

場(chǎng)景是所有物體的容器,如果要顯示一個(gè)蘋果毛仪,就需要將蘋果對(duì)象加入場(chǎng)景中搁嗓。

  • 相機(jī)

相機(jī)決定了場(chǎng)景中哪個(gè)角度的景色會(huì)顯示出來(lái),在 Threejs 中有多種相機(jī)箱靴,這里介紹兩種腺逛,它們是:
透視相機(jī)(THREE.PerspectiveCamera)和正投影相機(jī)(THREE.OrthographicCamera),透視相機(jī)跟人眼差不多刨晴,有近大遠(yuǎn)小的效果屉来,而正投影相機(jī)則沒(méi)有這個(gè)效果路翻,所有東西顯示都是一樣大

var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
  • 渲染器

渲染器決定了渲染的結(jié)果應(yīng)該畫(huà)在頁(yè)面的什么元素上面,并且以怎樣的方式來(lái)繪制茄靠。ThreeJS 框架提供了好幾種渲染器對(duì)象茂契,分別使用不同的底層技術(shù)實(shí)現(xiàn),比如:
WebGLRenderer使用 WebGL 技術(shù)慨绳;CanvasRenderer使用 Canvas 2D 技術(shù)掉冶;CSS2DRenderer和CSS3DRenderer則是使用 CSS 技術(shù);

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
  • 物體 Mesh
    Mesh 好比一個(gè)包裝工脐雪,它將『可視化的材質(zhì)』粘合在一個(gè)『數(shù)學(xué)世界里的幾何體』上厌小,形成一個(gè)『可添加到場(chǎng)景的對(duì)象』。
    當(dāng)然战秋,創(chuàng)建的材質(zhì)和幾何體可以多次使用(若需要)璧亚。而且,包裝工不止一種脂信,還有 Points(點(diǎn)集)癣蟋、Line(線/虛線) 等,比如添加一個(gè)幾何體到場(chǎng)景中:
var geometry = new THREE.CubeGeometry(1,1,1); 
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var cube = new THREE.Mesh(geometry, material); 
scene.add(cube);

CubeGeometry 表示一個(gè)幾何體

var point1 = new THREE.Vecotr3(4,8,9);
// or
var point1 = new THREE.Vector3();
point1.set(4,8,9)

創(chuàng)建一條線:線由點(diǎn)組成(準(zhǔn)確來(lái)說(shuō)由點(diǎn)疯搅,材質(zhì)和顏色組成),所以先創(chuàng)建點(diǎn)埋泵,再組合點(diǎn)(通過(guò)Geometry組織點(diǎn))幔欧,Threejs 中沒(méi)有提供單獨(dú)畫(huà)點(diǎn)的函數(shù),它必須被放到一個(gè)THREE.Geometry形狀中

// 方式 1
var geometry = new THREE.Geometry();
var material = new THREE.LineBasicMaterial( { vertexColors: true } );
var color1 = new THREE.Color( 0x444444 ), color2 = new THREE.Color( 0xFF0000 );

// 線的材質(zhì)可以由2點(diǎn)的顏色決定
var p1 = new THREE.Vector3( -100, 0, 100 );
var p2 = new THREE.Vector3(  100, 0, -100 );
// vertices 保存點(diǎn)丽声,colors 保存對(duì)應(yīng)點(diǎn)的顏色
geometry.vertices.push(p1);
geometry.vertices.push(p2);
geometry.colors.push( color1, color2 );

var line = new THREE.Line( geometry, material, THREE.LinePieces );

// 方式 2
var geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3( - 500, 0, 0 ) );
geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) );

for ( var i = 0; i <= 20; i ++ ) {
    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
    line.position.z = ( i * 50 ) - 500;
    scene.add( line );
}

操作線的某一維坐標(biāo)本質(zhì)是做平移

  • 坐標(biāo)系

Threejs使用的是右手坐標(biāo)系礁蔗,x軸正方向向右,y軸正方向向上恒序,z軸由屏幕從里向外

  • 運(yùn)動(dòng)原理

要么是攝像機(jī)移動(dòng)(camera.position)瘦麸,要么是物體移動(dòng)(object.position)

  • 光源

1谁撼、環(huán)境光
環(huán)境光是經(jīng)過(guò)多次反射而來(lái)的光歧胁,無(wú)法確定其最初的方向。環(huán)境光是一種無(wú)處不在的光厉碟。環(huán)境光源放出的光線被認(rèn)為來(lái)自任何方向喊巍。因此,當(dāng)你僅為場(chǎng)景指定環(huán)境光時(shí)箍鼓,所有的物體無(wú)論法向量如何崭参,都將表現(xiàn)為同樣的明暗程度。

var light = new THREE.AmbientLight( 0xff0000 );
scene.add( light );

2款咖、點(diǎn)光源
由這種光源放出的光線來(lái)自同一點(diǎn)何暮,且方向輻射自四面八方

PointLight( color, intensity, distance )

3奄喂、聚光燈
這種光源的光線從一個(gè)錐體中射出,在被照射的物體上產(chǎn)生聚光的效果海洼。使用這種光源需要指定光的射出方向以及錐體的頂角α

THREE.SpotLight( hex, intensity, distance, angle, exponent )
  • 材質(zhì)

材質(zhì)的本質(zhì)就是光

  • 紋理

紋理的本質(zhì)就是圖片或者說(shuō)貼圖跨新,紋理主要用于豐富材質(zhì),
1坏逢、用圖片創(chuàng)建一個(gè)紋理:

// 創(chuàng)建一個(gè)幾何平面
var geometry = new THREE.PlaneGeometry( 500, 300, 1, 1 );
// 設(shè)置紋理坐標(biāo)
geometry.vertices[0].uv = new THREE.Vector2(0,0);
geometry.vertices[1].uv = new THREE.Vector2(2,0);
geometry.vertices[2].uv = new THREE.Vector2(2,2);
geometry.vertices[3].uv = new THREE.Vector2(0,2);
// 加載紋理
var texture = THREE.ImageUtils.loadTexture("textures/a.jpg",null,function(t)
{
});
// 將紋理運(yùn)用到材質(zhì)
var material = new THREE.MeshBasicMaterial({map:texture});
// 結(jié)合幾何體和材質(zhì)
var mesh = new THREE.Mesh( geometry,material );
scene.add( mesh );

2域帐、用 canvas 創(chuàng)建紋理

var geometry = new THREE.CubeGeometry(150, 150, 150);
texture = new THREE.Texture( canvas);
var material = new THREE.MeshBasicMaterial({map:texture});
texture.needsUpdate = true;
mesh = new THREE.Mesh( geometry,material );
scene.add( mesh );

需要注意的是在定義了紋理之后,我們將texture.needsUpdate設(shè)置為了true是整,如果不設(shè)置為true肖揣,那么紋理就不會(huì)更新,很可能你看到的是一個(gè)黑色的正方體浮入,原因是紋理沒(méi)有被載入之前龙优,就開(kāi)始渲染了,而渲染使用了默認(rèn)的材質(zhì)顏色

  • 模型

模型是由面組成事秀,面分為三角形和四邊形面陋率。三角形和四邊形面組成了網(wǎng)格模型。在Three.js中用THREE.Mesh來(lái)表示網(wǎng)格模型秽晚。THREE.Mesh可以和THREE.Line相提并論,區(qū)別是THREE.Line表示的是線條赴蝇。THREE.Mesh表示面的集合菩浙。

THREE.Mesh = function ( geometry, material )

第一個(gè)參數(shù)geometry:是一個(gè)THREE.Geometry類型的對(duì)象,他是一個(gè)包含頂點(diǎn)和頂點(diǎn)之間連接關(guān)系的對(duì)象。

第二個(gè)參數(shù)Material:就是定義的材質(zhì)句伶。有了材質(zhì)就能夠讓模型更好看劲蜻,材質(zhì)會(huì)影響光照、紋理對(duì)Mesh的作用效果考余。

// VTK loader 使用示例
var material = new THREE.MeshLambertMaterial( { color:0xffffff, side: THREE.DoubleSide } );
var loader = new THREE.VTKLoader();
loader.addEventListener( 'load', function ( event ) {
     var geometry = event.content;
     var mesh = new THREE.Mesh( geometry, material );
     mesh.position.setY( - 0.09 );
     scene.add( mesh );
});
loader.load( "models/vtk/bunny.vtk" );
  • 相機(jī)控制
    通過(guò)鼠標(biāo)控制相機(jī) TrackballControls
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 1e10 );
camera.position.z = 0.2;
controls = new THREE.TrackballControls( camera );

controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5;
controls.panSpeed = 2;

controls.noZoom = false;
controls.noPan = false;

controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
  • 陰影

陰影是增強(qiáng)三維場(chǎng)景效果的重要因素先嬉,但 Three.js 出于性能考慮,默認(rèn)關(guān)閉陰影

// 啟用陰影
renderer.shadowMap.enabled = true
// 并不是所有類型的光源能產(chǎn)生投影楚堤,不能產(chǎn)生投影的光源有:環(huán)境光(AmbientLight)疫蔓、半球光(HemisphereLight)
spotLight.castShadow = true
// 平面和立方體都能接受陰影
plane.receiveShadow = true
cube.receiveShadow = true
// 球體的陰影可以投射到平面和球體上
sphere.castShadow = true
// 更改渲染器的投影類型,默認(rèn)值是 THREE.PCFShadowMap
renderer.shadowMap.type = THREE.PCFSoftShadowMap
// 更改光源的陰影質(zhì)量身冬,默認(rèn)值是 512
spotLight.shadow.mapSize.width = 1024 
spotLight.shadow.mapSize.height = 1024
  • 霧化
// Fog( hex, near, far )衅胀,線性霧化。
// near 表示哪里開(kāi)始應(yīng)用霧化效果(攝像機(jī)為 0)
// far 表示哪里的霧化濃度為 1酥筝。若某物體在該距離后滚躯,則其表現(xiàn)為霧的顏色。當(dāng)霧的顏色和渲染器的背景色相同時(shí),則表現(xiàn)為消失(實(shí)為顏色相同)掸掏。
scene.fog = new THREE.Fog( 0xffffff, 0.015, 100 )

// FogExp2( hex, density )茁影,指數(shù)霧化
// density 是霧化強(qiáng)度
scene.fog = new THREE.FogExp2( 0xffffff, 0.01 )

// 霧化效果默認(rèn)是全局影響的,若某個(gè)材質(zhì)不受霧化效果影響丧凤,則可為材質(zhì)的 fog 屬性設(shè)置為 false(默認(rèn)值 true)
var material = new THREE.Material({
    fog: false
})
  • 渲染器剔除模式

在 Three.js 中呼胚,材質(zhì)默認(rèn)只應(yīng)用在正面(THREE.FrontSide),即當(dāng)你旋轉(zhuǎn)物體(或攝像機(jī))查看物體的背面時(shí)息裸,它會(huì)因?yàn)槲幢粦?yīng)用材質(zhì)而變得透明(即效果與 CSS3 backface-visibility: hidden 一樣)蝇更。因此,當(dāng)你想讓物體正反兩面均應(yīng)用材質(zhì)呼盆,則需要在創(chuàng)建材質(zhì)時(shí)聲明 side 屬性為 THREE.DoubleSide:

var material = new THREE.MeshBasicMaterial({
    side: THREE.DoubleSide // 其他值:THREE.FrontSide(默認(rèn)值)年扩、THREE.BackSide
})

這個(gè)模式應(yīng)用在3D看房時(shí)比較好用


3D看房
  • 聲音 Audio

音頻也是 3D 的,它會(huì)受到攝像機(jī)的距離影響:
1访圃、聲源離攝像機(jī)的距離決定著聲音的大小厨幻。
2、聲源在攝像機(jī)左右側(cè)的位置分別決定著左右揚(yáng)聲器聲音的大小腿时。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末况脆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子批糟,更是在濱河造成了極大的恐慌格了,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件徽鼎,死亡現(xiàn)場(chǎng)離奇詭異盛末,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)否淤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門悄但,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人石抡,你說(shuō)我怎么就攤上這事檐嚣。” “怎么了啰扛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵嚎京,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我侠讯,道長(zhǎng)挖藏,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任厢漩,我火速辦了婚禮,結(jié)果婚禮上岩臣,老公的妹妹穿的比我還像新娘溜嗜。我一直安慰自己宵膨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布炸宵。 她就那樣靜靜地躺著辟躏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪土全。 梳的紋絲不亂的頭發(fā)上捎琐,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音裹匙,去河邊找鬼瑞凑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛概页,可吹牛的內(nèi)容都是我干的籽御。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼惰匙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼技掏!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起项鬼,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤哑梳,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后绘盟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體涧衙,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年奥此,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弧哎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡稚虎,死狀恐怖撤嫩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蠢终,我是刑警寧澤序攘,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站寻拂,受9級(jí)特大地震影響程奠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜祭钉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一瞄沙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦距境、人聲如沸申尼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)师幕。三九已至,卻和暖如春诬滩,著一層夾襖步出監(jiān)牢的瞬間霹粥,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工疼鸟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留后控,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓愚臀,卻偏偏與公主長(zhǎng)得像忆蚀,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子姑裂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • webGL的3D世界主要由三大要素構(gòu)成:場(chǎng)景(scene)馋袜、相機(jī)(camera)和渲染器(renderer),三者...
    YomonAh閱讀 2,811評(píng)論 0 1
  • Threejs中文文檔 郭隆邦技術(shù)博客 2018-09-21 20:40:17 關(guān)注 Three.js中文文檔 今...
    情人波閱讀 14,021評(píng)論 0 7
  • 本文主要是講解 Three.js 的相關(guān)概念舶斧,幫助大家對(duì) Three.js 以及相關(guān)知識(shí)形成比較完整的理解欣鳖。今年來(lái)...
    Simon王小白閱讀 8,450評(píng)論 2 9
  • Three.js是一個(gè)3DJavaScript庫(kù),基于右手坐標(biāo)系茴厉,可以創(chuàng)建簡(jiǎn)單或是比較復(fù)雜的三維圖形并應(yīng)用豐富多彩...
    呆呆的木木閱讀 24,402評(píng)論 42 59
  • 我不想生活在城市里 因?yàn)槲遗?太久了會(huì)讓我窒息 我向往田野竹籬 因?yàn)槲襾?lái)自 樸實(shí)無(wú)華的土地 童年的快樂(lè) 如靜靜流趟...
    春三月閱讀 1,039評(píng)論 18 42