Three.js相機(jī)Camera控件知識(shí)梳理
1. 相機(jī)類型
Three.js 主要提供了兩種類型的相機(jī):正交相機(jī)(OrthographicCamera)和透視相機(jī)(PerspectiveCamera)。
1.1 正交相機(jī)
正交相機(jī)(OrthographicCamera)使用正交投影進(jìn)行渲染。在正交投影中,物體的大小不會(huì)隨著距離的增加而減小,這意味著所有物體在渲染時(shí)保持相同的尺寸,不受距離的影響。這種相機(jī)在制作 2D 游戲和 CAD 工具等應(yīng)用中非常有用。
創(chuàng)建正交相機(jī)的代碼如下:
const camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far); // 正投影相機(jī)案例 const width = window.innerWidth; //canvas畫布寬度 const height = window.innerHeight; //canvas畫布高度 const k = width / height; //canvas畫布寬高比 const s = 600;//控制left, right, top, bottom范圍大小 const camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 8000);
參數(shù)(屬性) | 含義 |
---|---|
left | 渲染空間的左邊界 |
right | 渲染空間的右邊界 |
top | 渲染空間的上邊界 |
bottom | 渲染空間的下邊界 |
near | near屬性表示的是從距離相機(jī)多遠(yuǎn)的位置開始渲染,一般情況會(huì)設(shè)置一個(gè)很小的值。 默認(rèn)值0.1 |
far | far屬性表示的是距離相機(jī)多遠(yuǎn)的位置截止渲染,如果設(shè)置的值偏小小,會(huì)有部分場景看不到。 默認(rèn)值2000 |
1.2 透視相機(jī)
透視相機(jī)(PerspectiveCamera)使用透視投影進(jìn)行渲染。在透視投影中,物體的大小會(huì)隨著距離的增加而減小,這使得遠(yuǎn)離相機(jī)的物體看起來更小,符合現(xiàn)實(shí)世界中的透視效果。這種相機(jī)在制作 3D 游戲和仿真應(yīng)用中非常常見。
創(chuàng)建透視相機(jī)的代碼如下:
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); //透視相機(jī)案例 // width和height用來設(shè)置Three.js輸出的Canvas畫布尺寸(像素px) const width = 800; //寬度 const height = 500; //高度 // 30:視場角度, width / height:Canvas畫布寬高比, 1:近裁截面, 3000:遠(yuǎn)裁截面 const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
參數(shù) | 含義 |
---|---|
fov | 相機(jī)視錐體豎直方向視野角度 |
aspect | 相機(jī)視錐體水平方向和豎直方向長度比,一般設(shè)置為Canvas畫布寬高比width / height |
near | 相機(jī)視錐體近裁截面相對(duì)相機(jī)距離 |
far | 相機(jī)視錐體遠(yuǎn)裁截面相對(duì)相機(jī)距離,far-near構(gòu)成了視錐體高度方向 |
2. 相機(jī)屬性
Three.js 中的相機(jī)具有一些基本屬性,這些屬性決定了相機(jī)的視角和視野。
2.1 視角(FOV)
僅透視相機(jī)具有視角屬性(FOV)。視角表示相機(jī)的垂直視野范圍,單位為度。較大的視角值會(huì)導(dǎo)致更大的視野,但可能會(huì)產(chǎn)生畸變。較小的視角值則會(huì)產(chǎn)生更窄的視野和更低的畸變。
2.2 寬高比(Aspect)
僅透視相機(jī)具有寬高比屬性。寬高比表示相機(jī)水平視野范圍與垂直視野范圍的比值。通常,寬高比應(yīng)該與渲染目標(biāo)(如 Canvas 或 WebGLRenderTarget)的寬高比相同,以避免圖像被拉伸或壓縮。
2.3 近裁剪面(Near)和遠(yuǎn)裁剪面(Far)
近裁剪面和遠(yuǎn)裁剪面定義了相機(jī)的渲染范圍。位于近裁剪面之前的物體和位于遠(yuǎn)裁剪面之后的物體都不會(huì)被渲染。為了提高渲染性能,通常應(yīng)該盡量將近裁剪面和遠(yuǎn)裁剪面之間的距離設(shè)置得較小。
3. 不同方向的投影視圖
3.1 x軸方向觀察
// 通過UI按鈕改變相機(jī)觀察角度 document.getElementById('x').addEventListener('click', function () { camera.position.set(500, 0, 0); //x軸方向觀察 camera.lookAt(0, 0, 0); //重新計(jì)算相機(jī)視線方向 })
3.2 y軸方向觀察
// 通過UI按鈕改變相機(jī)觀察角度 document.getElementById('y').addEventListener('click', function () { camera.position.set(0, 500, 0); //y軸方向觀察 camera.lookAt(0, 0, 0); //重新計(jì)算相機(jī)視線方向 })
3.3 z軸方向觀察z軸方向觀察
// 通過UI按鈕改變相機(jī)觀察角度 document.getElementById('z').addEventListener('click', function () { camera.position.set(0, 0, 500); //z軸方向觀察 camera.lookAt(0, 0, 0); //重新計(jì)算相機(jī)視線方向 })
4. 相機(jī)動(dòng)畫(.position和.lookAt())
通過相機(jī)對(duì)象Camera
的.position
屬性和.lookAt()
方法,可實(shí)現(xiàn)一段相機(jī)動(dòng)畫。
4.1 相機(jī)運(yùn)動(dòng)動(dòng)畫
改變相機(jī)的位置.position
,三維場景在canvas畫布上呈現(xiàn)不同的效果,如果連續(xù)改變相機(jī)的位置.position
,就可以獲得一個(gè)動(dòng)畫效果。
課件案例源碼是一個(gè)工廠模型,相機(jī)在空中俯視工廠,如果在渲染循環(huán)中不停地改變相機(jī)位置,這時(shí)候產(chǎn)生的視覺效果,就好比你在天上運(yùn)動(dòng),看地面的效果。
// 渲染循環(huán) function render() { camera.position.z -= 0.3;//相機(jī)直線運(yùn)動(dòng)動(dòng)畫 renderer.render(scene, camera); requestAnimationFrame(render); } render();
4.2 相機(jī)圓周運(yùn)動(dòng)相機(jī)圓周運(yùn)動(dòng)
在渲染循環(huán)中,改變相機(jī)位置,在XOZ平面上繞著y軸圓周運(yùn)動(dòng)。
// 渲染循環(huán) let angle = 0; //用于圓周運(yùn)動(dòng)計(jì)算的角度值 const R = 100; //相機(jī)圓周運(yùn)動(dòng)的半徑 function render() { angle += 0.01; // 相機(jī)y坐標(biāo)不變,在XOZ平面上做圓周運(yùn)動(dòng) camera.position.x = R * Math.cos(angle); camera.position.z = R * Math.sin(angle); renderer.render(scene, camera); requestAnimationFrame(render); } render();
4.3 執(zhí)行l(wèi)ookAt()計(jì)算相機(jī)視線方向
改變.position
屬性后,如果不執(zhí)行.lookAt()
方法,相機(jī)的觀察方向默認(rèn)不變。
如果你希望相機(jī)圓周運(yùn)動(dòng)的同時(shí),改變相機(jī)視線方向,保持相機(jī)鏡頭始終指向坐標(biāo)原點(diǎn)或其它位置,需要每次改變.position
屬性后,重新執(zhí)行一遍.lookAt()
方法
function render() { angle += 0.01; camera.position.x = R * Math.cos(angle); camera.position.z = R * Math.sin(angle); // .position改變,重新執(zhí)行l(wèi)ookAt(0,0,0)計(jì)算相機(jī)視線方向 camera.lookAt(0,0,0); requestAnimationFrame(render); } render();
5. 相機(jī)控件OrbitControls
通常需要為用戶提供一種直觀的方式來瀏覽和操作場景。OrbitControls 是 Three.js 提供的一種常用的相機(jī)控制器,允許用戶通過鼠標(biāo)或觸摸屏操作來旋轉(zhuǎn)、平移和縮放場景。
5.1 OrbitControls使用
- 旋轉(zhuǎn):拖動(dòng)鼠標(biāo)左鍵
- 縮放:滾動(dòng)鼠標(biāo)中鍵
- 平移:拖動(dòng)鼠標(biāo)右鍵
OrbitControls本質(zhì)上就是改變相機(jī)的參數(shù),比如相機(jī)的位置屬性,改變相機(jī)位置也可以改變相機(jī)拍照?qǐng)鼍爸心P偷慕嵌?,?shí)現(xiàn)模型的360度旋轉(zhuǎn)預(yù)覽效果,改變透視投影相機(jī)距離模型的距離,就可以改變相機(jī)能看到的視野范圍。
// 引入軌道控制器擴(kuò)展庫OrbitControls.js import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; // 設(shè)置相機(jī)控件軌道控制器OrbitControls const controls = new OrbitControls(camera, renderer.domElement); // 如果OrbitControls改變了相機(jī)參數(shù),重新調(diào)用渲染器渲染三維場景 controls.addEventListener('change', function () { renderer.render(scene, camera); //執(zhí)行渲染操作 console.log('camera.position',camera.position); });//監(jiān)聽鼠標(biāo)、鍵盤事件 //相關(guān)限制方法: controls.enablePan = false; //禁止平移 controls.enableZoom = false;//禁止縮放 controls.enableRotate = false; //禁止旋轉(zhuǎn) // 縮放范圍 controls.minZoom = 0.5; controls.maxZoom = 2; // 上下旋轉(zhuǎn)范圍 controls.minPolarAngle = 0; controls.maxPolarAngle = Math.PI/2; // 左右旋轉(zhuǎn)范圍 controls.minAzimuthAngle = -Math.PI/2; controls.maxAzimuthAngle = Math.PI/2; //更新方法 function animate() { requestAnimationFrame(animate); // 更新控制器 controls.update(); // 渲染場景 renderer.render(scene, camera); }
6. 相機(jī)控件MapControls
在某些 Three.js 應(yīng)用中,例如地圖、地形或者 GIS 類型的項(xiàng)目,需要為用戶提供一種直觀且符合習(xí)慣的方式來瀏覽和操作場景。MapControls 是一個(gè)類似于 Google Maps 風(fēng)格的相機(jī)控制器,允許用戶通過鼠標(biāo)和觸摸屏操作來平移、縮放和旋轉(zhuǎn)場景。
6.1 MapControls使用
- 平移:鼠標(biāo)左鍵拖動(dòng)
- 旋轉(zhuǎn):鼠標(biāo)右鍵拖動(dòng)
- 縮放:鼠標(biāo)中鍵滾動(dòng)
MapControls本質(zhì)上就是改變相機(jī)的參數(shù),比如相機(jī)的位置屬性、相機(jī)目標(biāo)觀察點(diǎn)。
// 引入相機(jī)控件`MapControls` import { MapControls } from 'three/addons/controls/OrbitControls.js'; const controls = new MapControls(camera, renderer.domElement); controls.addEventListener('change', function () { // 鼠標(biāo)右鍵旋轉(zhuǎn)時(shí)候,查看.position變化 // 鼠標(biāo)左鍵拖動(dòng)的時(shí)候,查看.position、.target的位置會(huì)變化 console.log('camera.position',camera.position); console.log('controls.target',controls.target); }); //相關(guān)限制方法: controls.enablePan = false; //禁止平移 controls.enableZoom = false;//禁止縮放 controls.enableRotate = false; //禁止旋轉(zhuǎn) //相機(jī)位置與觀察目標(biāo)點(diǎn)最小值 controls.minDistance = 200; //相機(jī)位置與觀察目標(biāo)點(diǎn)最大值 controls.maxDistance = 500; // 上下旋轉(zhuǎn)范圍 controls.minPolarAngle = 0; controls.maxPolarAngle = Math.PI/2; // 左右旋轉(zhuǎn)范圍 controls.minAzimuthAngle = -Math.PI/2; controls.maxAzimuthAngle = Math.PI/2; //更新方法 function animate() { requestAnimationFrame(animate); // 更新控制器 controls.update(); // 渲染場景 renderer.render(scene, camera); }
7. 窗口變化的自適應(yīng)渲染
在開發(fā) Three.js 項(xiàng)目時(shí),我們需要考慮到不同的設(shè)備和屏幕尺寸。當(dāng)用戶調(diào)整瀏覽器窗口大小時(shí),我們希望場景能夠自適應(yīng)地進(jìn)行調(diào)整,以保持正確的比例和尺寸。
要實(shí)現(xiàn)自適應(yīng)渲染,我們需要在瀏覽器窗口大小發(fā)生變化時(shí)更新相機(jī)和渲染器的設(shè)置。首先,我們需要為 window
對(duì)象添加一個(gè) resize
事件監(jiān)聽器:
window.addEventListener('resize', onWindowResize);
接下來,我們定義 onWindowResize
函數(shù)。在這個(gè)函數(shù)中,我們需要完成以下任務(wù):
- 更新相機(jī)的寬高比(
aspect
)。 - 更新相機(jī)的投影矩陣。
- 更新渲染器的大小。
7.1 正投影相機(jī)OrthographicCamera自適應(yīng)渲染
// onresize 事件會(huì)在窗口被調(diào)整大小時(shí)發(fā)生 function onWindowResize(){ // 重置渲染器輸出畫布canvas尺寸 renderer.setSize(window.innerWidth,window.innerHeight); // 重置相機(jī)投影的相關(guān)參數(shù) k = window.innerWidth/window.innerHeight;//窗口寬高比 camera.left = -s*k; camera.right = s*k; camera.top = s; camera.bottom = -s; // 渲染器執(zhí)行render方法的時(shí)候會(huì)讀取相機(jī)對(duì)象的投影矩陣屬性projectionMatrix // 但是不會(huì)每渲染一幀,就通過相機(jī)的屬性計(jì)算投影矩陣(節(jié)約計(jì)算資源) // 如果相機(jī)的一些屬性發(fā)生了變化,需要執(zhí)行updateProjectionMatrix ()方法更新相機(jī)的投影矩陣 camera.updateProjectionMatrix (); };
7.2 透視投影相機(jī)PerspectiveCamera自適應(yīng)渲染
// onresize 事件會(huì)在窗口被調(diào)整大小時(shí)發(fā)生 function onWindowResize(){ // 重置渲染器輸出畫布canvas尺寸 renderer.setSize(window.innerWidth,window.innerHeight); // 全屏情況下:設(shè)置觀察范圍長寬比aspect為窗口寬高比 camera.aspect = window.innerWidth/window.innerHeight; // 渲染器執(zhí)行render方法的時(shí)候會(huì)讀取相機(jī)對(duì)象的投影矩陣屬性projectionMatrix // 但是不會(huì)每渲染一幀,就通過相機(jī)的屬性計(jì)算投影矩陣(節(jié)約計(jì)算資源) // 如果相機(jī)的一些屬性發(fā)生了變化,需要執(zhí)行updateProjectionMatrix ()方法更新相機(jī)的投影矩陣 camera.updateProjectionMatrix (); };
以上就是Three.js相機(jī)Camera的詳細(xì)內(nèi)容,更多關(guān)于Three.js相機(jī)Camera的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
TypeScript對(duì)象解構(gòu)操作符在Spartacus實(shí)際項(xiàng)目開發(fā)中的應(yīng)用解析
這篇文章主要為大家介紹了TypeScript對(duì)象解構(gòu)操作符在Spartacus實(shí)際項(xiàng)目開發(fā)中的應(yīng)用解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07JavaScript使用JSON.stringify()方法帶參及不帶參示例詳解
這篇文章主要介紹了JavaScript使用JSON.stringify()方法帶參及不帶參示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07微信小程序 action-sheet詳解及實(shí)例代碼
這篇文章主要介紹了微信小程序 action-sheet詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2016-11-11