Three.js是一款webGL框架柬讨,由于其易用性被廣泛應(yīng)用罚舱。Three.js在WebGL的api接口基礎(chǔ)上继薛,又進(jìn)行的一層封裝,所以不用擔(dān)心他得性能,和主機(jī)游戲一樣都是支持硬件加速的诫隅。它是由居住在西班牙巴塞羅那的程序員Ricardo Cabbello Miguel(https://ricardocabello.com/) 開發(fā)的,Three.js以簡單帐偎、直觀的方式封裝了3D圖形編程中常用的對(duì)象逐纬。Three.js在開發(fā)中使用了很多圖形引擎的高級(jí)技巧,極大地提高了性能肮街。Three.js還是完全開源的。
里面有很多圖形學(xué)的概念判导,比如坐標(biāo)變換嫉父,光照計(jì)算,同樣可以創(chuàng)建自己的Shader,調(diào)用底層的圖形接口眼刃,框架具有相當(dāng)高的靈活性绕辖。
Webgl和Three.js的關(guān)系
Webgl和Three.js的關(guān)系,相當(dāng)于JavaScript和Jquery的關(guān)系
創(chuàng)建一個(gè)場景
為了真正能夠讓你的場景借助three.js來進(jìn)行顯示擂红,我們需要以下幾個(gè)對(duì)象:場景仪际、相機(jī)和渲染器,這樣我們就能透過攝像機(jī)渲染出場景昵骤。
//創(chuàng)建場景
const scene = new THREE.Scene();
//創(chuàng)建一個(gè)立方體
const geometry = new THREE.BoxGeometry( 1, 1, 1 ); //幾何形狀
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); //材質(zhì)
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
scene以樹結(jié)構(gòu)存放所有可見的和不可見的三維物體树碱,包括光源等等
//創(chuàng)建一個(gè)攝像機(jī)
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.z = 5;
攝像機(jī)決定了我們從什么位置,什么角度觀察三維物體
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
渲染器負(fù)責(zé)將我們的看到的場景樹渲染成二維圖像
const animate = ()=> {
requestAnimationFrame( animate );
//因?yàn)镴avaScript是單線程的,所以用requestAnimationFrame來請(qǐng)求瀏覽器定時(shí)回調(diào)這里的這個(gè)animate()
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
//在循環(huán)中調(diào)用renderer的render()函數(shù)來渲染每一幀圖像
}
animate();
三角網(wǎng)Mesh
立方體是用Mesh(三角網(wǎng))表示的
因?yàn)槿切蔚娜齻€(gè)點(diǎn)可以空間中唯一地確定一個(gè)平面变秦,所以也是最常見的用于表示三維物體的一種方式
Geometry
Geometry代表幾何形狀成榜,由下面的一個(gè)個(gè)三角形和構(gòu)成他們的所有頂點(diǎn)組成
three.js里內(nèi)置了很多幾何形狀
http://www.webgl3d.cn/threejs/docs/#api/zh/geometries/CircleGeometry
//創(chuàng)建場景
const scene = new THREE.Scene();
var geometry = new THREE.CircleBufferGeometry( 5, 32 );
var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
var circle = new THREE.Mesh( geometry, material );
scene.add( circle );
//創(chuàng)建一個(gè)攝像機(jī)
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 50;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const animate = () => {
requestAnimationFrame(animate);
circle.rotation.x += 0.01;
circle.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
Material
Material代表三維物體幾何材質(zhì),不同的材質(zhì)在光照下會(huì)呈現(xiàn)不一樣的效果蹦玫,通過材質(zhì)可以給物體表面設(shè)定不同的顏色赎婚,光澤度,或者給物體加上貼圖
基礎(chǔ)網(wǎng)格材質(zhì)(MeshBasicMaterial) 不參與光照計(jì)算樱溉,不會(huì)產(chǎn)生陰影挣输,使用這種材質(zhì)三維物體看上不去很不真實(shí)。
要想有光照效果可以使用下面的兩種材質(zhì):
- Phong網(wǎng)格材質(zhì)(MeshPhongMaterial)
- Lambert網(wǎng)格材質(zhì)(MeshLambertMaterial)
可以用shininess屬性來調(diào)節(jié)物體表面光澤度
也可以使用map添加貼圖
const material = new THREE.MeshBasicMaterial({
map:new THREE.TextureLoader().load('1.png'),
}); //材質(zhì)
MeshStandardMaterial
和MeshPhysicalMaterial
類是PBR物理材質(zhì)福贞,可以更好的模擬光照計(jì)算撩嚼,相比較高光網(wǎng)格材質(zhì)MeshPhongMaterial
渲染效果更逼真。
emissive默認(rèn)黑色挖帘,設(shè)置為白色 發(fā)光顏色
emissiveMap 自發(fā)光貼圖
roughnessMap 粗糙度貼圖 設(shè)定表面不同位置的粗糙程度
normalMap 法線貼圖 給每個(gè)像素點(diǎn)設(shè)置不同的法向量 法線會(huì)影響光照的計(jì)算 可以用它模擬物體表面凹凸不平的效果
displacementMap 高度貼圖 它會(huì)上下偏移物體表面的頂點(diǎn)坐標(biāo)绢馍,從而做到真正的物體表面的起伏
aoMap 環(huán)境光遮罩貼圖 他會(huì)讓被遮蔽的區(qū)域看起來更暗,進(jìn)一步提升場景的真實(shí)感
//創(chuàng)建場景
const scene = new THREE.Scene();
var geometry = new THREE.SphereBufferGeometry( 5, 32, 32 );
var texLoader = new THREE.TextureLoader()
const material = new THREE.MeshPhongMaterial({
emissive:0xffffff,
// // 發(fā)光貼圖
emissiveMap: texLoader.load("wenli.png"),
// 法線貼圖
normalMap: texLoader.load("faxian.png"),
// 粗糙度貼圖
roughnessMap: texLoader.load("cucao.png"),
// //高度貼圖
displacementMap:texLoader.load("weiyi.png"),
//光罩貼圖肠套,會(huì)讓深坑得地方更暗舰涌,更有真實(shí)感
aoMap:texLoader.load("aoMap.png"),
}); //材質(zhì)
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
//創(chuàng)建一個(gè)攝像機(jī)
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 17;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const animate = () => {
requestAnimationFrame(animate);
//因?yàn)镴avaScript是單線程的,所以用requestAnimationFrame來請(qǐng)求瀏覽器定時(shí)回調(diào)這里的這個(gè)animate()
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
//在循環(huán)中調(diào)用renderer的render()函數(shù)來渲染每一幀圖像
}
animate();
幾何轉(zhuǎn)換
創(chuàng)建Mesh之后,我們可以通過position修改幾何物體在空間的位置
const material = new THREE.MeshPhongMaterial({
emissive:0xffffff,
// // 發(fā)光貼圖
emissiveMap: texLoader.load("wenli.png"),
// 法線貼圖
normalMap: texLoader.load("faxian.png"),
// 粗糙度貼圖
roughnessMap: texLoader.load("cucao.png"),
// //高度貼圖
displacementMap:texLoader.load("weiyi.png"),
//光罩貼圖你稚,會(huì)讓深坑得地方更暗瓷耙,更有真實(shí)感
aoMap:texLoader.load("aoMap.png"),
}); //材質(zhì)
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
cube.position.set(4,0,0)
scale用來轉(zhuǎn)換物體的大小 rotation旋轉(zhuǎn)物體
const material = new THREE.MeshPhongMaterial({
emissive:0xffffff,
// // 發(fā)光貼圖
emissiveMap: texLoader.load("wenli.png"),
// 法線貼圖
normalMap: texLoader.load("faxian.png"),
// 粗糙度貼圖
roughnessMap: texLoader.load("cucao.png"),
// //高度貼圖
displacementMap:texLoader.load("weiyi.png"),
//光罩貼圖朱躺,會(huì)讓深坑得地方更暗,更有真實(shí)感
aoMap:texLoader.load("aoMap.png"),
}); //材質(zhì)
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
cube.scale.multiplyScalar(2)
攝像機(jī)
攝像機(jī)決定了我們應(yīng)當(dāng)從什么角度觀察這個(gè)三維場景
three.js中提供了兩種不同類型的攝像機(jī)
- PerspectiveCamera 透視投影
- OrthographicCamera 正交投影
http://www.webgl3d.cn/threejs/examples/#webgl_camera
PerspectiveCamera
PerspectiveCamera和我們?nèi)搜鄢上裨眍愃聘橥矗吹降奈矬w呈遠(yuǎn)小近大的透視效果长搀。
創(chuàng)建相機(jī)的時(shí)候先創(chuàng)建視錐
在渲染的時(shí)候,計(jì)算機(jī)會(huì)將視錐中的所有三維物體投影到二維屏幕上
const camera = new THREE.PerspectiveCamera(
75, //fov 代表垂直方向上視角的大小
window.innerWidth / window.innerHeight, //aspect ratio 代表投影平面的縱寬比
0.1, //near 代表相機(jī)能看到的最近的平面
1000 //far 代表相機(jī)能看到的最遠(yuǎn)的平面鸡典,超出這個(gè)平面的場景會(huì)被自動(dòng)裁剪掉
);
OrthographicCamera
OrthographicCamera正交投影相機(jī)源请,會(huì)將空間中的所有物體平行投影到投影面上,所以不會(huì)呈現(xiàn)近大遠(yuǎn)小的效果
一般應(yīng)用在像CAD這種需要精確測量物體尺寸的應(yīng)用場景中
比如用正交投影可以輕易的渲染出物體的三視圖等等
正交相機(jī)的視錐(Frustum)是一個(gè)長方體彻况,所以定義正交相機(jī)要先定義前后左右上下這6個(gè)面的位置
const camera = new THREE.OrthographicCamera(
-2,//left
2,//right
1.5,//top
-1.5,//bottom
1,//near
10 //far
);
一樣使用position屬性修改相機(jī)的位置
//三種修改position的方法
camera.position.set(0,1,5)
camera.position.y += 2
camera.translateZ(2)
camera.updateMatrix()
//更新相機(jī)的變換矩陣
參考資料
1.奇樂編程
2.http://www.yanhuangxueyuan.com/threejs/docs/index.html#manual/zh/introduction/Creating-a-scene