若是想要產生 3D 的石頭,立馬會想到兩種分別的途徑:
很明顯的,第一個花的時間相較於第二個一定少很多。既然現在 portotype 就先以快速達到目標為主!
上次已經有用 Three.js 的 example 練習過,不過當時使用的方法是直接載範例來改,所以只有動動參數和插入一點點材質改動。現在 karesansui 已經放到了整個 module system 裡面(詳情看 source code),不能像之前一樣<script>
一堆東西讓他跑。
剛開使遇到這個問題,我就直接去找尋 es6 版本的 Three.js 的 Object Loader 和 Material Loader。很容易就搜尋到了他們,分別是 three-mtl-loader 和 three-object-loader。
但是因為是小的開發者自行移植的工具,所以 dependencies 並沒有時常更新,issue 很多也都卡著沒解掉。dependencies 改完之後,實際使用上面卻遇到很多狀況,像是.mtl
檔案可以 load 進來,但是和 .obj
卻沒有接好,有些地方爛掉。
最後決定使用直接 import 的方式,但是又不想要直接去複製貼上。所以就找到這個 gist。透過設定 alias 和可以去 importnode_modules/three
裡面的程式碼。因為程式碼都是直接加在THREE
的 field 裡面,所以 import 的方式需要特別注意:
在 webpack.common.config.js
:
resolve: {
alias: {
// 可以自行設定常用到的資料夾
'three/loaders': path.join(__dirname, 'node_modules/three/examples/js/loaders'),
'three/controls': path.join(__dirname, 'node_modules/three/examples/js/controls'),
// ...
}
},
//...
plugins:[
new webpack.ProvidePlugin({
'THREE': 'three'
}),
//...
]
3D 場景的index.js
:
import 'three';
import 'three/loaders/OBJLoader';
import 'three/loaders/MTLLoader';
import 'three/controls/TrackballControls';
import 'three/controls/OrbitControls';
console.log(THREE.OBJLoader);
接下來照著 example 或是上次經驗一樣的步驟就可以載入模型了!
什麼是 tweening,根據來歷不明網站的隨意定義:
Short for in-betweening, the process of generating intermediate frames between two images to give the appearance that the first image evolves smoothly into the second image.
in-betweening,就是介於兩個狀態:起始與結束之間。而動畫上,常常會使用 keyframes 定義畫面中特定時間點的樣子,之間就用 tweening 的效果去填滿。在底層的程式上,概念更為簡單,其實就是一個變數在一定時間裡面如何 從 0 變為 1的效果:
除了上述線性與指數的變化,還可以設計許多更調皮的動態:
這個數字雖然是簡單的 0 ~ 1,但是只要經過運算,就可以達到無限可能的區間變化。像是驅動石頭的移動與轉動,或是地板紋路的浮現等等。
市面上常見的 JavaScript tweening library 有兩個:
CreateJS/TweenJS 是在 CreateJS 底下的子專案。因為規模比較大型,連 event 處理的程式碼都是與其他工具共用。這也還好,但我比較擔心的是他很久沒更新了,之前使用過的經驗又遇到很多怪 bug,非常不流暢。也難怪下載量如此的低。
相較之下,第一個 tweenjs/tween.js 比較輕量,src 根本就只有一個檔案,一切都很簡單易懂容易看,我又常常用。無懸念。實際使用的概念如下(值得說一下的事情是,其實兩個套件的 API 設計如出一徹):
// Start at (0, 0)
var coords = { x: 0, y: 0 };
// Create a new tween that modifies
var tween = new TWEEN.Tween(coords)'coords'.
// Move to (300, 200) in 1 second.
.to({ x: 300, y: 200 }, 1000)
// Use an easing function to make the animation smooth.
.easing(TWEEN.Easing.Quadratic.Out)
// Start the tween immediately
.start();
// Setup the animation loop.
function animate(time) {
requestAnimationFrame(animate);
// 記得要設定 update,TWEEN 內部才能跑起來
TWEEN.update(time);
}
requestAnimationFrame(animate);
再來就是實際控制了!
先來實做一個點擊旋轉的功能!
demo site
只要點擊石頭就會可愛的轉動喔!
// 已經把模型的 object 載入 rock 這個變數當中
let rockAngle = 0;
let rockRotateAni;
function initAnimations() {
// 設定 tween 操控的變數
const rockRotate = { value: 0 };
rockRotateAni = new TWEEN.Tween(rockRotate)
// 選擇一個會有點回彈的效果
.easing(TWEEN.Easing.Back.Out)
// rockRotate.value 會從 0 跑到 1
.to({ value: 1 }, 900)
.onUpdate((rockRotate) => {
// 這個 callback 的第一個 argument 就是變化中的 rockRotate
const rate = rockAngle + Math.PI * (rockRotate.value * 0.5);
rock.rotation.y = rate;
})
.onComplete(() => {
// 到達終點之後,將終點設為下次的起點
rockAngle = rock.rotation.y;
// 將 rockRotate 回歸預設
rockRotate.value = 0;
});
}
...
// in the callback of click on rock event
rockRotateAni.start();
講到這,應該可以很好想像下面的山是怎麼浮現與消失的了吧!
demo site
只要按空白鍵就可以讓山消失/出現
一樣的邏輯跟手法,只是改動的參數換成rock.position
。但是有一個不一樣的地方:我的構想裡面,石頭的出現與消失應該是一連串的動作。消失的 Tween 是rockPositionAni
,在他結束之後,重新浮現的 Tween rockPositionAniBack
回直接銜接執行開始呼叫start
。tweenjs 已經有設計一個 API 達到這樣的效果,就是chain
:
// Rocks
let rockPosition;
const rockScale = 70;
const rockPositionY = -11;
let rockScaleAni;
...
const position = { value: 1 };
const rockPositionAniBack = new TWEEN.Tween(position)
.easing(rockEasingOut)
.to({ position: 1 }, 400)
.onUpdate((position) => {
rock.position.setY(lerp(
1, 0,
rockPositionY,
rockPositionYDisplace,
position.value));
});
const rockPositionAni = new TWEEN.Tween(position)
.easing(rockEasingIn)
.to({ value: 0 }, 900)
.onUpdate((position) => {
rock.position.setY(lerp(
1, 0,
rockPositionY,
rockPositionYDisplace,
position.value));
})
// 在結束之後馬上執行下一個
.chain(rockScaleAniBack);
附上 source code
對於視覺上的 prototype 已經到一個階段了!當然還有很多可以玩的東西,不過既然主題是「CYBER の audio / VISUAL」,就應該把音響開動了,你說是吧?
關於作者
Vibert Thio
致力於將對於技術的深度研究轉化為新型態藝術創作的能量,並思考技術的拓展/侷限與其對於藝術論述/呈現的影響。專長為數位藝術創作、音像程式設計、互動設計,喜愛即時運算的臨場感與不可預測。