iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 19
0

沒看過先看上集,即將揭曉答案...

https://ithelp.ithome.com.tw/upload/images/20180107/20107828f5EAD26LtT.png

上圖,是幾乎一整天的磨練,打造的基礎模型。

0. 今日工事

  • example の 神秘波紋
  • fragment shader 之乾坤大挪移
  • 視覺神經移植手術
  • 砂石的表面功夫

1. example の 神秘波紋

人對於物理萬物的理解方式總是狹隘的。我們都將從 example 的大海裡面沈沈浮浮。

常常當我想不到夠好的方法的時候,大量閱讀 example 總是能夠給我驚喜。而就像平常的日子一般,我又前往大海裡面尋找我要的那種波紋。沈思靜坐煉仙丹的時候翻過一遍官網的 examples,當時候覺得並無適合的出發點。所以又繼續尋覓。

驚奇的發現這個厲害的小組 Little Workshop,他們完全使用 webgl 去實驗許多新的世界。像是底下圖片當中的一系列,就是用演算去創造無限地景的效果。

https://ithelp.ithome.com.tw/upload/images/20180109/20107828MXS70fU2Ca.png

繼續發現,就看到這個很神的地景生成。只要點點滑鼠就可以拖拉出整個山水場景,超級美麗而且智慧。

然而,一切都不如預期的複雜或是找不到原始碼。就在這個時候,突然看到 water 的波紋,發現他裡面就有我要找的!使用THREE.PlaneBufferGeometry當做基底,並利用簡單的算法去產生水的波紋。

https://ithelp.ithome.com.tw/upload/images/20180109/20107828UoId4kj0Gf.png

當然,雖然山水同為大自然母親,但是我追求的枯山水中的枯跟這個完全天差地遠。我知道我可能找到了山徑的路口,蜿蜒而上吧!走,去實驗。

2. fragment shader 之乾坤大挪移

緣分在於,之前其實就已經概覽過這個水紋的例子,但是當時候覺得他使用一個由作者 yomboprime 自己所撰寫的一個算圖器GPUComputationRenderer來創造波紋。當中使用一些很神奇的方法,像是概念上許多人都聽過的 ping-pong rendering。理論上,就是把每次 fragment 算完最後的整張資料可以丟給下一個 frame 繼續運算,就像是有了一個記憶之前狀況的變數一般(這在 webgl 上面是非常麻煩的事情)。

...The renderer has actually two render targets per variable, to make ping-pong. Textures from the current frame are used as inputs to render the textures of the next frame...
作者 yomboprime 在註解當中寫道

我在整份 code 裡面找到他產生水位高低的核心區域,並插入自己想的高度運算法則:

...

// heightmapValue.x == 水位的高度
// heightmapValue.y == 各點移動的速度
// heightmapValue.z, heightmapValue.w 沒有使用

// uv 代表的就是現在計算的點的位置
// 所以 len1, len2 代表與波紋中心的距離
float len1 = length(uv - vec2(0.1, 0.2));
float len2 = length(uv - vec2(0.8, 0.4));

// 剩下就是簡單的數學了!直接帶入 sin 去興風作浪
if (len1 < 0.05) {
    heightmapValue.x = 0.1;
} else if (len1 < 0.2 && len1 > 0.05) {
    heightmapValue.x = pow(sin(len1 * 100.0), 0.5) * 10.0;
} else if (len2 < 0.1 && len2 > 0.03) {
    heightmapValue.x = pow(sin(len2 * 200.0), 0.5) * 10.0;
} else {
    // 沒有被震動到的部分,就產生單一方向的波紋(利用單一軸的數字)
    heightmapValue.x = pow(sin(uv.x * 200.0), 0.5) * 10.0;
}

gl_FragColor = heightmapValue;

也就得到昨天最後的結果了!假如還記得昨天卡關的地方,就是在於陰影的效果處理不好。這邊的關鍵差異在於,他是使用 Three.js 內部預設寫好的材質與打光效果,並把他拉出來修改一點點東西去移植到他的需求上面,而我也是進行類似的過程再一遍。他核心的 ping-pong 我甚至沒用到(計畫可能可以用上做一些炫砲視覺),只是利用他 fragment shader 裡面計算水位的邏輯,來產生我的平面。如此一來,陰影就自動被處理掉啦!

https://ithelp.ithome.com.tw/upload/images/20180107/20107828RZpzyCVryl.png

3. 視覺神經移植手術

但原始碼當中使用了許多 plugin 與直接 include 的 script,使得整份 dependencies 較為複雜,執行上也遇到許多問題。雖然我認為不用詳述,因為太多其他人不需要知道的細節與腦殘的行為。但是簡述一下也無妨,畢竟假如有人真的遇到了類似的問題,又很剛好看到這篇廢文就可以找我討論!

  1. THREE.OrbitControls

    • 尚未放到 THREE 的穩定 release 當中
    • 透過直接 include,並放到 THREE 的 field 裡面
    • 需要使用特殊的方法來 import 跟打包
  2. defines 的 USE_MAP 使用

    • 情境是使用THREE.ShaderMaterial來改造預設有的THREE.MeshPhongMaterial
    • 若是想要使用 texture map,去製造最後的材質需要在 uniforms 裡面加上 map
    • 另外,還需要設定環境的 defines 中的 USE_MAP。雖然看起來很理所當然,但是我可是找了很久的啊媽啊
  3. ShaderMaterial.lights 一定要設定為 true,才可以打光(預設為 false)

4. 砂石的表面功夫

雖然說,這種金屬感的水面也是一種美麗的形式,可是我希望的是不斷的追求,活著就是得為自己創造些什麼意義對吧?所以該怎麼從光滑的表面轉化為砂石般的顆粒質感呢?需要考慮到 shader 的算法加上 javascript 丟資料的方式下,時間軸、uniforms、常數們該怎麼考慮呢?

我當機立斷,振筆疾書就列了幾個可能的手法:

  1. Three.js 預設材質中的參數
  2. 波紋的密度與波浪規律
  3. 最後輸出前的材質貼圖(texture map)
  4. Ambient Occlusion(由廖得凱大大提示)
  5. 模擬砂石的表面的粒子效果

https://ithelp.ithome.com.tw/upload/images/20180109/201078287RS4V45tSK.png

(1)到(3)都算是比較好實作的幾個方向,我也花一點時間就將整個平面改善到一個程度。但是最後是如何產生完整的枯山水庭園效果呢?關鍵差異在於哪個面向?如何產生前面基礎模型的表面功夫...?

這裡放上最新進度的預告,是最新的冥想空間。山的挪移、海的浪潮。

7. 請愛CYBER の audio / VISUAL

走走走,浪也走了起來,山也搖了起來,我們都起來擺動著啊。
欲知詳情,請待下回分曉。

附上 source code

關於作者

Vibert Thio

致力於將對於技術的深度研究轉化為新型態藝術創作的能量,並思考技術的拓展/侷限與其對於藝術論述/呈現的影響。專長為數位藝術創作、音像程式設計、互動設計,喜愛即時運算的臨場感與不可預測。


上一篇
§d18§ webの 禪師!枯山水造景師!沈思靜坐煉仙丹。
下一篇
§d20§ webの 禪師!運氣弄四海!Texture 與 Material 的好用之處!
系列文
aesthEtic,CYBERの audio / VISUAL,網頁中的聲音與影像研究30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言