webGL之three.js入門2



 

入門建議:

webGL中文翻譯教程,基於NeHe的openGL教程:http://www.hiwebgl.com/?p=42 。

WebGL中文網 http://www.hewebgl.com/ ,里面有THREEJS教程,THREEJS初級教程免費 ,其余要收費。但是初級教程也很不錯。

three.js官方網站:www.threejs.org/  ,three.js-master包里面有很多很有趣的例子,雖然官方沒有給出文檔,但是學習一段時間后,自己就能看懂代碼了。

推薦書籍:【美】Andreas Anyuru的《WebGL高級編程  --開發Web 3D圖形》,【美】Kouichi Matsuda Rodger的《WebGL編程指南》,【美】Jos Dirksen的《Three.js 開發指南》,看這幾本差不多就能寫出像樣的東西了。當然,想深入挖掘的的同學也可以看看opengl、計算機圖形學、矩陣論等相關方面的書。


一、基本需要

初始化:

1.渲染器(renderer)——渲染物體的,在web瀏覽器中必須有一個平台顯示3d效果

2.照相機(camera)——視角,展現在我們面前的

3.場景(scene)

4.燈光(light)

5.物體(object)

渲染部分:

1.renderer.render(scene, camera);

2.requestAnimationFrame(animate); 

 

1.初始化渲染器:

three.js的渲染器主要有WebGLRenderer和CanvasRenderer,

渲染的效果不同有細微差異,我們使用的是WebGLRenderer,當使用渲染器時,一般在html頁面上加入<div>標簽——>這里的div標簽是<div id="canvasframe"></div>

renderer = new THREE.WebGLRenderer({antialias: true});//開啟WebGL抗鋸齒

width = document.getElementById('canvasframe').clientWidth;

height = document.getElementById('canvasframe').clientHeight;

renderer.setSize(width, height);

document.getElementById('canvasframe').appendChild(renderer.domElement);

你也可以不需要div標簽創建渲染器

代碼:

var renderer = new THREE.WebGLRenderer(); 
renderer.setSize(window.innerWidth, window.innerHeight); 
document.body.appendChild(renderer.domElement);

2.照相機

Camera是三維世界中的觀察者,為了觀察這個世界,首先我們要描述空間中的位置。 

Three中使用采用常見的右手坐標系定位。

three.js提供兩類照相機,一類是OrthographicCamera(正交相機),一類是PerspectiveCamera(透視相機)

 

正交投影與透視投影的區別如上圖所示,左圖是正交投影,物體發出的光平行地投射到屏幕上,遠近的方塊都是一樣大的;右圖是透視投影,近大遠小,符合我們平時看東西的感覺。 

camera = new THREE.PerspectiveCamera(60, width / height, 1, 10000);

camera.position.set(lengthX,lengthY, 100);

camera.up = new THREE.Vector3(0,0,1);

THREE.PerspectiveCamera(fov, aspect, near, far)

fov:視角度數,可以理解為眼睛睜開大小,度數越大,你看到的物體越多,物體越小

aspect:是照相機水平方向和豎直方向長度的比值,一般等於width/height

near和far:是相機最近和最遠的距離,均為正值,far>>near

 

camera.position.set(x,y,z);//照相機的位置

camera.up = new THREE.Vector3(0,0,1);

cmmera.up哪個軸是向上的,three.js默認是右手坐標軸,即y軸向上,這里我們讓z軸向上

camera.position = new THREE.Vector3(0,0,1)和camera.up.set(0,0,1)一樣的效果。

 

正交投影相機:

 

注:圖中的”視點”對應着Three中的Camera。 
這里補充一個視景體的概念:視景體是一個幾何體,只有視景體內的物體才會被我們看到,視景體之外的物體將被裁剪掉。這是為了去除不必要的運算。 
正交投影相機的視景體是一個長方體,OrthographicCamera的構造函數是這樣的:OrthographicCamera( left, right, top, bottom, near, far ) 
Camera本身可以看作是一個點,left則表示左平面在左右方向上與Camera的距離。另外幾個參數同理。於是六個參數分別定義了視景體六個面的位置。

可以近似地認為,視景體里的物體平行投影到近平面上,然后近平面上的圖像被渲染到屏幕上。

透視投影相機

 

透視投影相機的視景體是個四棱台,它的構造函數是這樣的:PerspectiveCamera( fov, aspect, near, far ) 
fov對應着圖中的視角,是上下兩面的夾角。aspect是近平面的寬高比。在加上近平面距離near,遠平面距離far,就可以唯一確定這個視景體了。 
透視投影相機很符合我們通常的看東西的感覺,因此大多數情況下我們都是用透視投影相機展示3D效果。

3.場景

一般只需要scene = new THREE.Scen();新建場景就可以了

源代碼中加入了scene.fog = new THREE.FogExp2(0xcccccc,0.002);使場景產生霧效果

FogExp2(hex,density)

hex,霧的顏色如果設置為黑色,遠處的物體將呈現黑色

density:定義霧增長速度如何密集。默認為0.00025。

4.燈光

有幾種燈光,常用的有AmbintLight(環境光),directionalLight(平行光),PointLigth(點光源),spotLight(聚光燈),半球光HemisphereLight,其他的你可以在官方文檔里查找使用,初始化都比較簡單,以程序里的平行光為例

light = new THREE.DirectionalLight( 0xffffff );

light.position.set( 1, 1, 1 );

scene.add( light );

設置平行光顏色為白色,在坐標(1,1,1)的位置,平行光類似太陽關照,添加到場景中

5.物體

有了相機,總要看點什么吧?在場景中添加一些物體吧。 
Three中供顯示的物體有很多,它們都繼承自Object3D類,這里我們主要看一下Mesh和Points兩種。

Mesh

我們都知道,計算機的世界里,一條弧線是由有限個點構成的有限條線段連接得到的。線段很多時,看起來就是一條平滑的弧線了。 
計算機中的三維模型也是類似的,普遍的做法是用三角形組成的網格來描述,我們把這種模型稱之為Mesh模型。

 

 

這是那只著名的斯坦福兔子。它在3D圖形中的地位與數字圖像處理領域中著名的lena是類似的。 
看這只兔子,隨着三角形數量的增加,它的表面越來越平滑/准確。

在Three中,Mesh的構造函數是這樣的:Mesh( geometry, material ) 
不止是Mesh,創建很多物體都要用到這兩個屬性。下面我們來看看這兩個重要的屬性。

 

普通的物體有兩種屬性,一個是它的材質material,一個是它的模型geometry(就是它長什么樣子)。

var material = new THREE.MeshLambertMaterial({color:color });

var geometry = new THREE.CylinderGeometry(radius,radius,height,radius*100,0,false);

geometry.applyMatrix( new THREE.Matrix4().setRotationFromEuler( new THREE.Vector3( Math.PI / 2, Math.PI, 0 ) ) );

mesh = new THREE.Mesh(geometry,material);

scene.add(mesh);

Geometry,形狀

相當直觀。Geometry通過存儲模型用到的點集和點間關系(哪些點構成一個三角形)來達到描述物體形狀的目的。 
Three提供了立方體(其實是長方體)、平面(其實是長方形)、球體、圓形、圓柱、圓台等許多基本形狀; 
你也可以通過自己定義每個點的位置來構造形狀; 
對於比較復雜的形狀,我們還可以通過外部的模型文件導入

material——材質

材質其實是物體表面除了形狀以為所有可視屬性的集合,例如色彩、紋理、光滑度、透明度、反射率、折射率、發光度。 
這里講一下材質(Material)、貼圖(Map)和紋理(Texture)的關系。 
材質上面已經提到了,它包括了貼圖以及其它。 
貼圖其實是‘貼'和‘圖',它包括了圖片和圖片應當貼到什么位置。 
紋理嘛,其實就是‘圖'了。 
Three提供了多種材質可供選擇,能夠自由地選擇漫反射/鏡面反射等材質。

three.js有多種材質可選

 

 

Lambert材質:Lambert 材質(MeshLambertMaterial)是符合 Lambert 光照模型的材質。大部分物體的漫反射效果都適用的。就是說光的顏色和它本身的顏色是啥,它就照成啥

THREE.MeshLambertMaterial({color:color });

phong材質也比較適合管道:與lambert材質不一樣的地方是,它加入了鏡面反射的效果,也就是會有光斑

  

var material = new THREE.MeshPhongMaterial({

color:color,

specular:0xffffff,

shininess:100

});

spcular:光斑的顏色

shininess:光斑大小,值越小,光斑越不明顯,不能設為0,30是默認值(0-100)就可。

其他材質的學習可以參照three.js官網和入門指南。(官網在這快有一個很好的例子,可以嘗試一下)

 

THREE.CylinderGeometry(radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded)函數創建了一個圓柱體,這個函數默認在原點(0,0,0)坐標創建,中心點也在原點,並且方向方向向y軸,你可以通過position和rotation屬性分別改變它的位置和旋轉角度,rotation屬性要注意的一點是它里面的3個值分別表示弧度。

比如cylinder.rotation=new THREE.Vector3(0.1,0.2,0.3);

圓柱體繞x軸旋轉的弧度是0.1,繞y軸旋轉的弧度是0.2,繞z軸旋轉的弧度是0.3。

 

radiusTop:頂面半徑

radiusBottom:底面半徑

height:圓柱高

radiusSegments:半徑分段,就是一個圓被分成了多少份(像切蛋糕一樣),值越大,圓柱就越平滑

heightSegments:高度分段,因為我們圓柱頂面半徑,底面半徑都是相同的,所以這個值就沒有意義了,所以我們直接設為0。

openEnded 是一個布爾值,表示是否沒有頂面和底面,缺省值為 false ,表示有頂面和底面。

<——radiusSegments和heightSegments的分段的效果

 

mesh = new THREE.Mesh(geometry,material);

scene.add(mesh);

把material材質賦給geometry,在場景中添加這一個物體。

 

動畫渲染效果:

function render(){

       renderer.render( scene, camera );//把照相機給場景

}

動畫的實現是通過在每秒鍾多次重繪畫面實現的,為了衡量畫面切換速度,引入了每秒幀數FPS(Frames Per Second)的概念,是指每秒畫面重繪的次數,FPS越大,則動畫效果越平滑,當FPS小於20時,一般就能明顯感受到卡頓

requestAnimationFrame:不斷重繪

 

three.js里面除了requestAnimationFrame方法,還有setInterval(func,mesc),可以設置特定的FPS,

func:每過mesc毫秒執行的函數,如果將func定義為重繪畫面的函數,就能實現動畫效果(Threejs入門指南P88)

function animation(){

       requestAnimationFrame(animate);// 反復渲染成為3d效果

       render();//由於requestAnimationFrame只請求一幀畫面,除了在init函數中需要調用,//在被其調用的函數中需要再次調用requestAnimationFrame。

}

 

Points

講完了Mesh,我們來看看另一種Object——Points。 
Points其實就是一堆點的集合

 

二、擴展

1.小工具

開源工具還有其他很有用的小工具

①stats.js——查看web場景中的幀數等,很實用!

fps可以實時的FPS信息,從而更好地監測動畫效果

 

單擊后可以顯示每一幀的渲染時間

stats = new Stats();

stats.domElement.style.position = 'absolute';

stats.domElement.style.top = '0px';

stats.domElement.style.zIndex = 100;

container.appendChild(stats.domElement);

之后再function animation()函數里面加入stats.update()就可以了

 

②three.js里面的坐標軸,可以在場景的原點加入一個有色坐標,其中紅色是x軸,綠色是y軸,藍色是z軸,比較實用

var axisHelper = new THREE.AxisHelper( 200 );//軸長200

scene.add( axisHelper );

③顯示有線的照相機——能夠顯示照相機的角度(詳情參看three.js官網)。。

cameraOrtho = new THREE.OrthographicCamera( 0.3 * window.innerWidth / - 2, 0.3 * window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 150, 1000 );

cameraOrthoHelper
= new THREE.CameraHelper( cameraOrtho );
scene.add( cameraOrthoHelper );

④顯示網格grid

function initGrid(){
                var helper = new THREE.GridHelper( 1000, 50 );
                helper.setColors( 0x0000ff, 0x808080 );
                scene.add( helper );
            }

在場景中生成網格線。

⑤tween.js可輔助生成動畫效果,很實用。

⑥通過.obj的后綴形式把物體加入場景

一般是在3d_max中導出物體的模型.obj和材質.mtl,通過OBJMTLLoader.js和MTLLoader.js實現,代碼也很簡單,但是記住在3d_max里面會記住模型的xyz軸,所以在3d建模軟件中(一般是3dsMax或者Maya)繪制模型時候一定要把模型放在原點中心,這樣在three.js引入3d模型時,會直接放入你想放的位置

function addInterObject(x,y,z){

var loader = new THREE.OBJMTLLoader();

    loader.addEventListener( 'load', function ( obj ) {

        object = obj.content;

        object.position = new THREE.Vector3( x, y, z);

        scene.add( object );

    });

    loader.load( 'obj/interbig.obj','obj/interbig.mtl' );

}

 

需要注意的地方

①大多數部件都有這兩個屬性position(位置),rotation(旋轉)。

②在three.js中,能形成陰影的光源只有THREE.DirectionalLight與THREE.SpotLight;而相對的,能表現陰影效果的材質只有THREE.LambertMaterial與THREE.PhongMaterial。

 ③注意不同環境下的坐標系。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM