1. 程式人生 > >三維場景中常用的路徑動畫

三維場景中常用的路徑動畫

# 三維場景中常用的路徑動畫 ## 前言 在三維場景中,除了用逼近真實的模型代表現實中的裝置、標識物外,通常還會使用一些動畫來表示模型在現實中一些行為和作用。常見的動畫比如路徑動畫、旋轉動畫、發光動畫、流動動畫等。本文將為大家介紹幾種常用的路徑動畫。首先,最簡單的自然是直線路徑動畫。 ## 直線路徑動畫 比如以下場景,地鐵需要從上一站A駛入當前站B,在此過程中,我們將AB組合成一條路徑(假設路徑為直線),使用動畫,不停的設定地鐵(模型)的在路徑上的位置,就可以實現地鐵從A站-B站的動畫過程。 ```javascript const points = [A, B]; // 建立路徑 let path = new mono.Path(); points.forEach((point, i) => {   const { x, y, z } = point;   if (i == 0) {     path.moveTo(x, y, z);   } else {     path.lineTo(x, y, z);   } }); // 動畫 const instance = new mono.Animate({     form: 0,     to:1,     dur:3000,     delay,     reverse:false,     repeat: 1,     easing,     onPlay,     onUpdate: (val) => { // 獲取路徑上的點       const point = path.getPointAt(val);       // 設定實體位置       entity.setPosition(point); },     onDone, }); instance.play(); ``` 動畫效果: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8d5e8c1c315a4e3586bf5b15600b869d~tplv-k3u1fbpfcp-zoom-1.image) 至此,直線路徑動畫就實現了。那麼現在想想,現實場景中不可能只有直線運動這種場景,比如小車巡檢,就屬於一個折線場景,那麼我們就需要使用折線動畫來完成。 ## 折線路徑動畫 小車在房間內不間斷的通過巡檢監控,記錄裝置狀態及檢測相關資料。模擬小車巡檢動畫,我們需要採集巡檢小車核心點位:A、B、C、D。同樣的將ABCD組合成路徑,不停的設定小車(模型)位置 ```javascript const points = [A, B, C, D]; // 建立路徑 let path = new mono.Path(); points.forEach(...); // 動畫 const instance = new mono.Animate({ ... onUpdate: (val) => { // 獲取路徑上的點 const point = path.getPointAt(val); // 設定實體位置 entity.setPosition(point); }, onDone, }); instance.play(); ``` 動畫效果:折線路徑 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9e181a0878f84d09bf5867dc94f66da4~tplv-k3u1fbpfcp-zoom-1.image) 當然,巡檢過程可能是一個迴圈的閉合路徑,所以可以滿足使用四個點建立閉環路徑,行形成閉環路徑動畫 ### 折線路徑閉環動畫 ```javascript const points = [A, B, C, D]; // 建立路徑 let path = new mono.Path(); points.forEach(...); // 閉環路徑 path.closePath() // 動畫 const instance = new mono.Animate({ ... }); instance.play(); ``` 動畫效果:閉環路徑 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3ab2663d3c58432899dd352a72583710~tplv-k3u1fbpfcp-zoom-1.image) 上面的折線動畫是完成了,但是轉彎的時候似乎略顯生硬,接下來我們再嘗試如何讓轉彎更自然。 ### 圓潤的折線路徑動畫 其實很簡單,在已有的折線動畫基礎上,對路徑先進行一步拐角處理,讓路徑整體顯得很趨於自然。 ``` const points = [A, B, C, D]; // 建立路徑 let path = new mono.Path(); points.forEach(...); // 閉環路徑 path.closePath() // 獲取平滑路徑, 讓轉彎更自然 path = mono.PathNode.prototype.adjustPath(path, 20, 1); // 動畫 const instance = new mono.Animate({ ... }); instance.play(); ``` 動畫效果:轉彎更加的自然 ![自然彎道.gif](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5c6840cb09a24aa281bb83b6ca856cc5~tplv-k3u1fbpfcp-zoom-1.image) 實現了圓潤的折線路徑動畫後,貌似看起來已經完工了。其實再仔細觀察下,可以發現,在轉彎的時候,模型沒有同步轉向,那麼我們需要如何處理呢。 ### 模型與路徑動畫同步旋轉 在折線動畫中,將模型繞對應的旋轉旋轉方向即可 ```javascript const points = [A, B, C, D]; // 建立路徑 let path = new mono.Path(); points.forEach(...); // 閉環路徑 獲取平滑路徑, 讓轉彎更自然 ... // 旋轉向量 const rotate = new mono.Vec3(); // 動畫 const instance = new mono.Animate({ onUpdate: (val) => { // 位置 ... // 模型同步旋轉 const tangent = path.getTangentAt(val);       var normal = new mono.Vec3(0, 0, -1);       rotate.rotationTowards(normal, tangent); entity.setRotation(rotate); } }); instance.play(); ``` 動畫效果:可以看到小車上的攝像頭是一直朝向裝置 ![同步.gif](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ce26f96215974845ad99678794f9915a~tplv-k3u1fbpfcp-zoom-1.image) 那麼,直線路徑動畫和折線路徑動畫介紹完了。從上面動畫截圖中可以看出,我們是在一個固定的位置檢視動畫,那麼,能讓鏡頭沿著路徑一起移動麼 ### 鏡頭沿路徑動畫一起移動 顯然,鏡頭是可以沿著路徑同時移動的。通常用於巡航(自動巡檢)中.主要是在折線動畫的基礎上,同步設定鏡頭動畫的位置和朝向點。 ```javascript const points = [....]; // 建立路徑 let path = new mono.Path(); points.forEach(...); // 閉環路徑 獲取平滑路徑, 讓轉彎更自然 ... // 鏡頭初始位置   const pos = camera.p(),     target = camera.t();   const length = pos.clone().sub(target).length(); // 動畫 const instance = new mono.Animate({ onUpdate: (val) => { // 模型 ... // 鏡頭沿路徑動畫       const tangent = path.getTangentAt(value);       point = path.getPointAt(value);       ntarget = point.clone().add(tangent.multiplyScalar(length)); camera.p(point);       camera.lookAt(ntarget); } }); instance.play(); ``` 動畫效果: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/201e8ce2f6b14e7aac58b10a062be2b7~tplv-k3u1fbpfcp-zoom-1.image) 既然能讓鏡頭沿著路徑同步移動,那麼是否能讓鏡頭與路徑保持平行移動呢 ### 鏡頭與路徑保持平行一起移動 保持平行移動,其實是在點位的基礎上,將鏡頭位置設定到對應距離點位置。以下是基於動畫鏈完成的某流水線作業動畫,需要路徑動畫同時,鏡頭同步移動。對動畫鏈有興趣的可參考前文《[基於路徑集合的三維動畫鏈](https://mp.weixin.qq.com/s/8bkA9aKKxLbC1D8ZuAVwdg)》 ```javascript const points = [....]; // 建立路徑 let path = new mono.Path(); points.forEach(...); // 閉環路徑 獲取平滑路徑, 讓轉彎更自然 ... // 鏡頭相對於目標動畫模型的距離 const dis = 550 // 動畫 const instance = new mono.Animate({ onUpdate: (val) => { // 模型 ... // 鏡頭平行X軸動畫 point = path.getPointAt(value); camera.setPosition(point.clone().add(new mono.Vec3(0, dis, dis)));       camera.lookAt(point); } }); instance.play(); ``` 動畫效果: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/04c4cc7d312a4810b31fa7be191e7c93~tplv-k3u1fbpfcp-zoom-1.image) ## 案例說明 上面舉例說明動畫的示意圖,來自兩個案例,一個是地鐵站三維視覺化,可以認為是一個軌道交通方面的;另外一個是實驗室車間 流水線視覺化,主要用於流水線,裝置監控等三維視覺化呈現。 ## 結語 至此,路徑動畫已經介紹的差不多了。利用常用的動畫能夠讓整個三維場景更豐滿,寫實。希望在專案中可以多多利用起來。 關注公眾號“ITMan彪叔” 可以及時收到更多有價值的文章。另外如果對視覺化感興趣,可以和我交流,微信541