青少年勵(lì)志成長發(fā)育three.js小筆記

? ? ? ? 之前用qunee做了一個(gè)2.5d的機(jī)房監(jiān)控,丑的閃瞎我的卡姿蘭大眼,后來含淚用three.js做個(gè)3d的換掉,結(jié)果依然好看不到哪去(畢竟恐怖的直男審美),錯(cuò)怪qunee了,不是它丑,是我丑。記筆記了記筆記了。

? ? ? ? 引用下Mono大佬的文章,圖片資源都是順手從這拿的html5,不只是看上去很美

一、步驟

1.畫布

首先準(zhǔn)備一塊畫布框,并對(duì)渲染器做設(shè)置

var renderer;

function initRender(){

? ? renderer = new THREE.WebGLRenderer({antialias: true}); //創(chuàng)建渲染器對(duì)象,antialias抗鋸齒有效

? ? renderer.setSize( window.innerWidth, window.innerHeight );//設(shè)置渲染器寬高

? ? document.body.appendChild( renderer.domElement );//追加到頁面中

? ? renderer.setClearColor(0xFFFFFF, 1.0);設(shè)置清除色

}

常用渲染器對(duì)象有CanvasRenderer和WebGLRenderer,它們的區(qū)別前者是繪制場景使用的是canvas 2d context,而后者是WebGL(仿佛是句廢話),相較而言,后者的性能要優(yōu)于前者

2.相機(jī)

var camera;

function initCamera(){

? ? camera = new THREE.PerspectiveCamera( 45, window.innerWidth/window.innerHeight, 0.1, 1000);//創(chuàng)建遠(yuǎn)景相機(jī)

? ? camera.position.z = 100; //設(shè)置相機(jī)位置(set)

? ? camera.position.y = 40;

? ? camera.position.x = 50;

? ? camera.lookAt({x:0,y:0,z:0});//設(shè)置視野位置

}

參數(shù)分別表示視野角度、縱橫比、相機(jī)相對(duì)于物體的最近、最遠(yuǎn)距離

相機(jī)中常見的有OrthographicCamera(正交相機(jī))和PerspectiveCamera(遠(yuǎn)景相機(jī),也叫透視投影),它們的區(qū)別我盜兩張圖感受一下就知道了

遠(yuǎn)景相機(jī)
正交相機(jī)

3.場景

一個(gè)三維的空間

var scene;

function initScene(){

? ? scene = new THREE.Scene();

}

4.光源

光源的作用很明顯,現(xiàn)實(shí)生活中光是有顏色的,在人的眼中,物體的顏色是由光源照射后決定的,就好像賣豬肉都要打個(gè)燈,看上去仿佛很新鮮。

var light;

function initLight(){

? ? light = new THREE.DirectionalLight((0xFF0000,1.0,0));//平行光

? ? light.position.set(x,y,z);//設(shè)置光源坐標(biāo)

? ? scene.add(light);//將光源添加到場景中

}

常見光源有AmbientLight(環(huán)境光):這種光源的顏色和強(qiáng)度會(huì)加在照射范圍內(nèi)的所有對(duì)象上

? ? ? ? ? ? ? ? ? DirectionalLight(平行光):是一種從特定方向照射的光源,它產(chǎn)生的光線都是平行的

? ? ? ? ? ? ? ? ? PointLight(點(diǎn)光源):有特定位置的光源,照射到各個(gè)角落

? ? ? 有光源就有陰影,這樣才能顯示出3d的效果,可以通過對(duì)castShadow設(shè)置true來表示該光源是可以產(chǎn)生陰影的,再由物體receiveShadow=true接收陰影。對(duì)陰影研究不多,任性的跳過。

5.物體

? ? ? 追加物體這一塊要考慮物體的網(wǎng)格和材質(zhì)。就那什么什么兔子來著,就是由不知道多少個(gè)三角形網(wǎng)格拼接而成的模型兔子,網(wǎng)格越密集,精確度越高(畢竟我是畫過cad、做過流固體耦合的男人,hhh)

? ? ? 幾何模型對(duì)象有一大堆,因?yàn)槎际且恍┓椒秸臋C(jī)器,所以用的到一般都是BoxGeometry(盒子模型)、CylinderGeometry(圓柱體模型)、PlaneGeometry(平面模型)等等。

? ? ? 就比如var geometry=newTHREE.BoxGeometry(1,1,1);這就創(chuàng)建了一個(gè)長寬高1,1,1的正方體的網(wǎng)格模型。

? ? ? 之后應(yīng)該選擇模型的材質(zhì),找了下文檔,發(fā)現(xiàn)了那么多材質(zhì),可以根據(jù)實(shí)際情況選擇不同的材質(zhì),比如機(jī)房設(shè)備都是金屬,我選擇MeshPhongMaterial這種表面有光澤的材質(zhì)。

材質(zhì)

? ? ? 再然后有些物體要添加一些貼圖,也就是紋理。如果對(duì)多個(gè)面添加不同的紋理,可以load每張圖片或者圖片放在一張上使用UV映射。

? ? ? var texture=new THREE.TextureLoader().load(圖片路徑);

? ? ? texture.wrapS=THREE.RepeatWrapping;

? ? ? texture.wrapT=THREE.RepeatWrapping;

? ? ? texture.repeat.set(4,4);

? ? ? material.map = texture;//將紋理添加到材質(zhì)中

? ? ? 網(wǎng)格和材質(zhì)都創(chuàng)建完后,開始使用Mesh類創(chuàng)建模型:var cube = new THREE.Mesh(geometry,material);也可以對(duì)模型的position做設(shè)置,記得將模型加入到場景中scene.add(cube);


? ? ? 最后舉個(gè)完整的例子,畫個(gè)滅火器:

air3D.prototype.createFire = function(x,z){

? //滅火器

? ? var fire_body_material = new THREE.MeshPhongMaterial({map:THREE.ImageUtils.loadTexture("./image/room/fire_extinguisher_side.jpg")});

? ? var fire_body = new THREE.CylinderGeometry(0.5,0.5,2.5);

? ? var fire_body_cube = new THREE.Mesh(fire_body,fire_body_material);

? ? fire_body_cube.position.y = 4;

? ? // scene.add(fire_body_cube);

? ? var fire_top_material = new THREE.MeshPhongMaterial({color:'#B81F18'});

? ? var fire_top = new THREE.SphereGeometry(0.5);

? ? var fire_top_cube = new THREE.Mesh(fire_top,fire_top_material);

? ? fire_top_cube.position.y = 5.25;

? ? // scene.add(fire_top_cube);

? ? var fire_on_material = new THREE.MeshPhongMaterial({color:'#FFF504'});

? ? var fire_on = new THREE.SphereGeometry(0.2);

? ? var fire_on_cube = new THREE.Mesh(fire_on,fire_on_material);

? ? fire_on_cube.position.y = 5.8;

? ? // scene.add(fire_on_cube);

? ? var handle_material = new THREE.MeshPhongMaterial({color:'#846f6f'});

? ? var handle1 = new THREE.CylinderGeometry(0.1,0.08,1.2);

? ? var handle_cube1 = new THREE.Mesh(handle1,handle_material);

? ? handle_cube1.rotation.x += -0.45*Math.PI;

? ? handle_cube1.position.y = 5.8;

? ? // scene.add(handle_cube1);

? ? var handle2 = new THREE.CylinderGeometry(0.08,0.08,2);

? ? var handle_cube2 = new THREE.Mesh(handle2,handle_material);

? ? handle_cube2.rotation.x += -0.05*Math.PI;

? ? handle_cube2.position.z = 0.7;

? ? handle_cube2.position.y = 4.75;

? ? // scene.add(handle_cube2);

? var fireObj = new THREE.Object3D();

? fireObj.add(fire_body_cube);

? fireObj.add(fire_top_cube);

? fireObj.add(fire_on_cube);

? fireObj.add(handle_cube1);

? fireObj.add(handle_cube2);

? this.scene.add(fireObj);

? objects.push(fireObj);

? fireObj.position.y = -2.65;

? fireObj.position.x = x;

? fireObj.position.z = z;

? fireObj.rotation.y += -0.5*Math.PI;

};

效果大概是這樣:


丑陋的滅火器

? ? 有些不規(guī)則的模型,不知道別人是怎么操作的,我是單獨(dú)繪制各個(gè)部位的模型,然后創(chuàng)建Object3D對(duì)象。還有一種二元操作也可以創(chuàng)建一些規(guī)

則的模型,比如insert(相交)、union(聯(lián)合)、subtract(相減),我機(jī)房大門就是一塊大的BoxGeometry? subtract掉一塊小的BoxGeometry,

但是之后我就不知道怎么給指定面添加紋理了(迷茫。。。)。

6.渲染

init();

render();

function render() {

? ? requestAnimationFrame( render );

? ? renderer.render( scene, camera );

}

function init(){

? ? initRender();

? ? initScene();

? ? initCamera();

? ? initLight();

? ? initObject();

}

? ? 可以在render()中添加代碼實(shí)現(xiàn)動(dòng)畫,對(duì)于three.js,動(dòng)畫就是每一秒的多次繪制。requestAnimationFrame的作用和setInterval很相似,不同的是setInterval需要指定fps,而requestAnimationFrame則是自動(dòng)設(shè)定,setInterval在一些特殊情況下,例如瀏覽器處理繁忙時(shí),fps就可能會(huì)低于設(shè)定值,一般低于20就容易出現(xiàn)卡頓的情況。

二、補(bǔ)充

1.? 模型的拾取,思路還不太清晰,容我復(fù)習(xí)一下線性代數(shù)冷靜冷靜(。。。),從源碼中扒的

air3D.prototype.onRightClick = function(event){

? ? event.preventDefault();

? ? var t = air3DObj;

? ? var raycaster = new THREE.Raycaster();

? ? var rect = t.renderer.domElement.getBoundingClientRect();

? ? var mouse = new THREE.Vector2();

? ? mouse.x = ( (event.clientX - rect.left) / rect.width ) * 2 - 1;

? ? mouse.y = - ( (event.clientY - rect.top) / rect.height ) * 2 + 1;

? ? raycaster.setFromCamera(mouse,t.camera);

? ? var intersects = raycaster.intersectObjects(t.scene.children);

? ? if(intersects.length>0){

? ? ? ? var obj = intersects[0].object;

? ? }

};

2.項(xiàng)目中的問題,多次刪除添加后瀏覽器奔潰,scene.remove(cube)只是從場景中刪除,記得清除geometry數(shù)據(jù)

3.調(diào)用OrbitControls.js后會(huì)出現(xiàn)dom沒法選中的現(xiàn)象,因?yàn)樗J(rèn)監(jiān)聽的是document,記得創(chuàng)建時(shí)添加場景的canvas(renderer.domElement)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,071評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,360評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,895評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,123評(píng)論 0 286
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,643評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,559評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,742評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評(píng)論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,981評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評(píng)論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,354評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,707評(píng)論 2 370

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

  • Three.js是一個(gè)3DJavaScript庫,基于右手坐標(biāo)系,可以創(chuàng)建簡單或是比較復(fù)雜的三維圖形并應(yīng)用豐富多彩...
    呆呆的木木閱讀 24,596評(píng)論 42 59
  • 1,前天晚上突然想找個(gè)工作,投了簡歷,今天去面試了。不為工資,不問時(shí)間,只看公司人多不多,妹子多不多。條件越不好的...
    畢缽羅子閱讀 174評(píng)論 0 1
  • 八月接近尾聲,開學(xué)季來了。不管你愿不愿意,開學(xué)的時(shí)間都會(huì)如期而至,我們又將重返講臺(tái)。 每年的開學(xué)時(shí)節(jié),心里總有...
    楊正歡閱讀 198評(píng)論 0 0