關(guān)于從入門three.js到做出3d地球這件事(第二篇: 開發(fā)必備的輔助技能)

來源:lulu_up
https://segmentfault.com/a/1190000039683111
本篇介紹
開發(fā)3d效果的時候, 不能每次都通過刷新頁面來更新圖像, 我們工程師當(dāng)然會發(fā)明出相應(yīng)的工具輔助開發(fā)工作, 這一篇我們一起學(xué)習(xí)三個好用的工具, 讓我們的開發(fā)更暢快。
上篇我們講解了three.js的基本配置代碼, 想看的同學(xué)可以訪問這個鏈接: 關(guān)于從入門three.js到做出3d地球這件事(第一篇: 通俗易懂的入門)
一. 相機(jī)的配置
這里介紹的是透視相機(jī)
介紹工具之前我們先把相機(jī)的關(guān)鍵概念系統(tǒng)的學(xué)一遍, 因為以后我們要利用相機(jī)做很多有趣的事。???? 這里以上一篇繪制的最基本的坐標(biāo)系為例進(jìn)行說明, 如下圖:
第一: position 相機(jī)位置
位置屬性很重要很常用, 不同的位置呈現(xiàn)出不同的景色, 我們可以把相機(jī)理解為我們在3d世界中的眼睛, 而調(diào)整相機(jī)的位置就相當(dāng)于我們走到不同的角度去看這個3d世界。???? 看過上一篇你會知道我們的相機(jī)實例叫camera, 我們對他的position屬性進(jìn)行設(shè)置就可以調(diào)整位置。
第一種設(shè)置方式
camera.position.x = 2;
camera.position.y = 2;
camera.position.z = 10;
上面就是分別調(diào)節(jié)了相機(jī)的x, y, z軸的距離, 我們看到的景象變成了下面的樣子。
第二種設(shè)置方式
position身上有set方法可以設(shè)置, 三個參數(shù)對應(yīng)的是x, y, z。
camera.position.set(2, 2, 10)
效果與上面的一樣。
第三種設(shè)置方式
position可以直接設(shè)置x, y, z屬性, 本身又有set方法, 那么position屬性本身到底是個什么那? 讓我們打印出來看看。
isVector3: true也就是說它是一個Vector實例, 那么Vector是什么?
我們以后會經(jīng)常和這個單詞打交道, 讓我們一起記住它。
先不細(xì)聊向量
因為向量是個很重要的概念, 我們后面會單獨大篇幅的詳談, 這里咱們單純的理解為new THREE.Vector3(2, 2, 10)是生成了一個點, 參數(shù)就是這個點的xyz坐標(biāo), 而我們相機(jī)的position屬性就是這樣一個對象。
注意: 直接賦值是無效的
camera.position = new THREE.Vector3(2, 2, 10) 無效
需要利用add方法來實現(xiàn)camera.position.add(new THREE.Vector3(2, 2, 10)) 有效
別被唬住
上面展示了大部分常用的設(shè)置position的方法, 我在初學(xué)three.js的時候被網(wǎng)上各種寫法弄暈了所以這里特意列出大部分寫法, 希望當(dāng)你再看其它資料的時候就不會被亂七八糟的寫法唬住了。
第二: lookAt 相機(jī)看向哪里
這個概念簡直太重要了, 如其字面意思就是看向哪里, 上面相機(jī)位置已經(jīng)調(diào)整完畢, 那么我們要調(diào)整相機(jī)拍攝哪里了。
默認(rèn)是(0,0,0)的位置如下圖:
當(dāng)我們看向坐標(biāo)系的 (3, 3, 0)位置也就是右上角:
從它的效果我們可以發(fā)現(xiàn), 這個屬性非常適合在3d游戲中調(diào)整人物的方向時改變圖像, 如果你要做第一人稱游戲一個人在城市里奔跑的效果, 那無非就是不斷的改變相機(jī)的position與lookAt就能做到了。
設(shè)置方式
這里可以直接設(shè)置: camera.lookAt(3, 3, 0);
還可以利用向量來設(shè)置: camera.lookAt(new THREE.Vector3(3, 3, 0));
第三: up 誰為相機(jī)上方
先來一張默認(rèn)的情況, 不難看出綠的是y, 紅的是x, z正對著我們所以暫時看不到:
我們設(shè)置一下camera.up.set(1, 0, 0);
上面x的值成為了最大, 所以他變成了上方的坐標(biāo)軸, 當(dāng)然如我們設(shè)一個亂亂的值camera.up.set(1, 0.5, 0); 那么效果如下:
這個屬性的設(shè)置方式就是set方法或者camera.up = new THREE.Vector3(1, 0.5, 0);
可以利用這個屬性模擬第一人稱游戲里任務(wù)摔倒了看這個世界....
坑點
我當(dāng)前版本的three.js想要up屬性生效需要在設(shè)置完up屬性之后再主動指定一下camera.lookAt(0, 0, 0);否則up屬性不生效;
二. GUI的使用
上面講了這么多, 我們現(xiàn)在想讓場景動起來, 所以需要不斷的渲染出3d圖像, 我們利用requestAnimationFrame反復(fù)調(diào)用渲染函數(shù)就能實現(xiàn)動畫效果了。
const animate = function () {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
-全名dat.gui.js他的功能是為屬性生成一個可調(diào)節(jié)值的面板, 方便我們不斷修改數(shù)值而不用刷新頁面如下圖:
鼠標(biāo)拖動調(diào)節(jié)
-引入GUI<script src="https://cdn.bootcdn.net/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>引入之后我們?nèi)侄嗔艘粋€dat屬性。
const gui = new dat.GUI();
// 1: 定義一個我們要改變的對象
const pames = {
x: 0
}
// 2: 把這個值放入控制器
gui.add(pames, "x", 0, 5).name("x軸的距離")
參數(shù)解答
傳入要改變的對象。 要改變這個對象身上的哪個屬性。 最小值 最大值 .name('顯示在調(diào)節(jié)欄的名稱')
在每次渲染的時候更新一下相機(jī)的x軸位置。
const animate = function () {
camera.position.x = pames.x
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
知道上面這些就可以應(yīng)付很多的場景了, 一個工具而已不用深究啦。
全部代碼
<html>
<script src="https://cdn.bootcdn.net/ajax/libs/three.js/r122/three.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/dat-gui/0.7.7/dat.gui.min.js"></script>
<script>
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 20;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x00FFFF, .5);
document.body.appendChild(renderer.domElement);
const axisHelper = new THREE.AxisHelper(2)
scene.add(axisHelper)
const pames = {
x: 0
}
function createUI() {
var gui = new dat.GUI();
gui.add(pames, "x", 0, 5).name("x軸的距離")
}
const animate = function () {
camera.position.x = pames.x
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
createUI()
animate();
</script>
</body>
</html>
三. tween的使用
tween.js是用來做流暢動畫的庫, 比我們自己寫動畫方便多了tween官網(wǎng)地址。
下面編寫了一個相機(jī)平滑的向右上角移動的代碼。
const tween = new TWEEN.Tween(camera.position).to({
x: 10,
y: 10
}, 2000).repeat(Infinity).start();
// tween.stop() // 可以停止動畫
const animate = function () {
TWEEN.update();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
new TWEEN.Tween("這里傳入要改變的對象")。.to( x: 10 y: 10}, 2000), 在2000毫秒時將x與y屬性變成10。.repeat(Infinity), 這個動無限循環(huán)。.start();, 開始執(zhí)行動畫。.stop();, 停止動畫。TWEEN.update();, 每次調(diào)用渲染函數(shù)都要調(diào)用一下動畫的更新函數(shù)。
效果如下(思否暫時無法傳gif圖片, 但我已經(jīng)向高老板反應(yīng)了):

下面是動圖, 顯示可能有問題。
這個庫大概的原理就是每次調(diào)用update方法的時候判斷一下該動畫已經(jīng)執(zhí)行了多久時間, 然后算出當(dāng)前時間目標(biāo)對象的值應(yīng)該變?yōu)槎嗌? 當(dāng)然它還會對性能有所優(yōu)化。
全部代碼如下:
<html>
<style>
* {
padding: 0;
margin: 0;
}
</style>
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/three.js/r122/three.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/tween.js/18.6.4/tween.umd.js"></script>
<script>
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 20;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x00FFFF, .5);
document.body.appendChild(renderer.domElement);
const axisHelper = new THREE.AxisHelper(2)
scene.add(axisHelper)
const tween = new TWEEN.Tween(camera.position).to({
x: 10,
y: 10
}, 2000).repeat(Infinity).start()
const animate = function () {
TWEEN.update()
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
四. 軌道控制器的使用
這個就厲害了, 讓我們可以使用鼠標(biāo)轉(zhuǎn)動我們的相機(jī), 仿若進(jìn)入到3d世界一般。

隨著我們按住鼠標(biāo)并且移動, 視角就隨之變化仿佛身臨其境一般。
// 將軌道控制器的代碼放在對應(yīng)的文件夾里面, 如果你沒找到就用下面我分享的文件。
<script src="./utils/OrbitControls.js"></script>
引入成功頁面THREE身上會出現(xiàn)OrbitControls方法, 我們需要傳入相機(jī)與渲染的容器。
const orbitControls = new THREE.OrbitControls(camera, renderer.domElement);
orbitControls.target = new THREE.Vector3(0, 0, 0);//控制焦點
cdn上我沒查到, 想要獲取代碼的同學(xué)可以復(fù)制我的筆記內(nèi)容到項目中 three.js軌道控制器點擊預(yù)覽
直接在頁面引入與通過npm包的方式引入有區(qū)別, 到了講在vue里的使用的時候我們再詳細(xì)說。
全部代碼如下: (要有./utils/OrbitControls.js的代碼, 沒有的話來我筆記下載)
<html>
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/three.js/r122/three.min.js"></script>
<script src="./utils/OrbitControls.js"></script>
<script>
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 10;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x00FFFF, .5)
// 軌道控制器
orbitControls = new THREE.OrbitControls(camera, renderer.domElement);
// orbitControls.target = new THREE.Vector3(0, 0, 0);
// 軌道控制器
document.body.appendChild(renderer.domElement);
const axisHelper = new THREE.AxisHelper(2)
scene.add(axisHelper)
var animate = function () {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
</script>
</body>
</html>
end.
下一篇將會介紹 光源, 與 陰影的玩法了, 希望與你一起進(jìn)步。
