iT邦幫忙

2022 iThome 鐵人賽

DAY 18
0
Modern Web

Three.js 學習日誌系列 第 18

Day17 - Three.js與滑鼠互動操作(一)

  • 分享至 

  • xImage
  •  

Day17 - Three.js與滑鼠互動操作(一)

這裡是「Three.js學習日誌」的第17篇,本篇主旨是在講解要怎麼讓Three.js與滑鼠的動作相聯繫,例如點擊、懸停、或是移動。這系列的文章假設讀者看得懂javascript,並且有Canvas 2D Context的相關知識。

由於Three.js畢竟還是前端的一環,專案上常常會需要根據使用者的操作狀況去渲染出對應的圖像,所以我打算接著來講講Three.js與滑鼠互動操作的實作方法。

Three.js與滑鼠互動操作的實際案例有很多,舉凡我們在前一個章節提到的利用Orbit Control來操作環形攝影機軌道,又或者是偵測物件點擊的Raycasting,接著我們會透過實作幾個範例,來學習這些技巧。

範例:來自製一個陽春版本的OrbitControl吧

我們在前面一個章節有先偷偷地超車使用過了OrbitControl,但是實際上如果想要透過移動滑鼠來旋轉視角,方法可不只有OrbitControl一種。

我思考了一下,其實這個範例還蠻值得介紹的。我們可以在這個範例中學習到:

  • OrbitControl的大略原理
  • 如何自己客製化一個視角轉動特效

那就讓我們開始吧!

建立基本物件

我們這次先從一個只有一個Torus mesh(甜甜圈)的Scene開始,這邊還請容許我跳過初始化渲染環境的步驟XD。

img

const geo = new TorusGeometry(1, 0.5, 50, 50);
//TorusGeometry 的參數依序是 外半徑/內半徑/半徑軸Segment/切面軸Segment
const mat = new MeshStandardMaterial({
  color: new Color("rgba(255,0,0,0.1)"),
  transparent: true
});
const mesh = new Mesh(geo, mat);
scene.add(mesh);

codepen連結:點我

使用Helper

其實Three.js有提供很多種輔助用的ClassHelper系的函數就是其中之一,Helper通常都是用來協助我們釐清畫面上物體/燈光/攝影機當前的位置。

這邊我們要使用的是AxisHelper,它可以幫助我們看清現在坐標軸的狀態。

這邊綠軸代表的是Y紅軸則是X藍軸因為正對我們所以看不到,它代表Z

img

const axis = new AxesHelper(5); // 參數代表的是XYZ軸的長度多少,這邊我給5單位
scene.add(axis)

設定攝影機與滑鼠的相對關係

我們要做的事情其實就是根據滑鼠在螢幕上:

  • 水平移動的百分比
  • 垂直移動的百分比

來決定要讓攝影機移動到水平環形軌道的哪一個角度上,還有垂直方向軸的哪一個位置上。

我們會把畫布的最左/下方定義為-1,最右/上則為+1。而當我們知道當前滑鼠是位於水平環形軌道&垂直軸上的哪一個位置,例如(+0.3,-0.5),那我們就把它映射到-180~180度的範圍中,這邊如果用(+0.3,-0.5)來舉例,那就是讓攝影機位於水平軌道54度,垂直方向為距離坐標軸中心-0.5單位的地方。

img

這邊我們先利用addEventListener來動態把滑鼠座標記錄到變數中。

const cursor = new Vector2(); // 建立一個Vector2來記錄滑鼠位置。
//把滑鼠移動事件綁在用來渲染畫面的canvas上面
renderer.domElement.addEventListener('mousemove', (ev) => {
  const rect = renderer.domElement.getBoundingClientRect();
  // 透過把滑鼠的位置除以canvas寬度,來映射到垂直/水平 -1 ~ 1 的區間
  cursor.x = ((ev.clientX - rect.left) / rect.width - 0.5) * 2;
  cursor.y = -((ev.clientY - rect.top) / rect.height - 0.5) * 2; 
  // 因為clientY和Three.js的坐標軸方向相反,所以記得要乘以-1
})

接著我們要做的事情就是在每一圈tick loop(RequestAnimationFrame的循環)中:

  1. 把攝影機根據cursor的數值移動到水平環形軌道&垂直軸上對應的位置
  2. 強制攝影機LookAt坐標軸原點(0,0,0)
const railRadius = 5; //假設攝影機軌道半徑為5單位

const tick = () => {
    camera.position.x = Math.sin(cursor.x * Math.PI ) * railRadius;
    camera.position.z = Math.cos(cursor.x * Math.PI ) * railRadius;
    camera.position.y = cursor.y;
    camera.lookAt(new Vector3(0,0,0));
    renderer.render(scene, camera);
    requestAnimationFrame(tick);
}
tick();

img

其實蠻簡單的對吧~?
codepen 連結: 點我

小結

今天我其實不打算一下就跳太深XD,所以先點到這邊為止,明天我們會為這個範例加上一些稍微進階的操作~ 敬請各位期待。


上一篇
Day16 - 金屬球範例試作(3) - Material解密(六)
下一篇
Day18 - Three.js與滑鼠互動操作(二)
系列文
Three.js 學習日誌31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言