iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 20
0

前情請參考上兩篇文章:

0. 今日工事

  • 色:紋理(Texture)中的 image map
  • 象:材質(Material)中的 heightMap

1. 色:紋理(Texture)

上一篇最後聊到該如何從左邊的金屬質感,轉換為右邊帶有土色、顆粒感的砂石表面。

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

首先,最明顯的就是顏色的問題了。在 3D 的世界裡面,無法像是一般的網頁渲染(render)直接用 js 或是 css 來設定顏色,必定要透過 fragment shader(若不清楚這啥請看這裡)才能達到的這樣的做用。我記得我曾經覺得幹嘛要這麼麻煩,為什麼不給我一個Object3D.color之類的東西就好了?傻孩子,他當然可以設計這樣的一個 api,讓你的物件是單色顯示,甚至還可以幫你設計好 shader 去簡單產生各種陰影。但是那樣的話彈性就太低了也不太能做什麼變化,webgl 為的是更大的夢啊!

https://ithelp.ithome.com.tw/upload/images/20180109/20107828nhtNFyAmSQ.png
圖片來源:Intro to WebGL with Three.js

(請看上圖)以 Three.js 的架構來說(與很多 3D 軟體原理都是類似的),所有在場景裡面的物件都是一個或是多個 Mesh。而每個 Mesh 則是由一個 Geometry 與一個 Material 所組成。Geometry 顧名思義就是他最初的幾何結構,像是這裏枯山水的地面就是一個PlaneGeometry。而 Material 底層其實就是一個包好的 GPU Program(由一個 vertex shader 與一個 fragment shader 所組成,可以把送進來的 geometry 算出最後的樣子)。我在這裡使用的是是轉化過後的MeshPhongMaterial

材質(Material)紋理(Texture)在 IT 邦裡面,已經有許多人都解釋過,可以參考他們的文章:

  1. DAY 19. Three.js 材質 Material
  2. webGL 修羅道 - 3D 紋理貼圖
  3. 直接去看 docs也是很好的方法。這樣懂才是透徹的了解吧(?)

圖中沒有表現出來,但是物件的 Mesh 數量我會強調一個或是多個是因為一般使用預設的 geometry(像是BoxGeometry, CircleGeometry)的時候都是一個,但是在使用 loader 載入外部的 3D 檔案時,就可能會是手一個 Mesh、一個 Mesh,合併成一個 object(在設定.obj載入的物件陰影的時候這個知識非常重要)。

講這麼多,我就只是要把這張圖片給整個放上去就對了!至於他是怎麼

https://ithelp.ithome.com.tw/upload/images/20180109/20107828GsGRHX6tqK.jpg

import sand from './textures/sand-3.jpg';
...

// 產生 geometru
const geometry = new THREE.PlaneBufferGeometry(...);

// 將圖片 load 進 Texture 物件裡面
const textureLoader = new THREE.TextureLoader(manager);
const texture = textureLoader.load(sand);

// 產生 material,並標注使用 map(texture 當作圖片時的稱呼)
const material = new THREE.ShaderMaterial({
    ...
    
    // 告訴 shader 你要使用 map
    defines: {
        USE_MAP: '',
    }
    ...
});

// 將 texture 放盡 material
material.uniforms.map.value = texture;

// 建立 mesh 物件
groundMesh = new THREE.Mesh(geometry, material);

看起來就會是這樣了:

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

2. 象:材質(Material)中的 vertex shader

不過如此的效果,我總是看得那平滑的曲面覺得不大平靜。砂石本該有的粗糙被 sin 波運算的光滑表面也遮蓋了。我最初想到的解法是利用 morph map 的方式Geometry.morphTargets的方式去產生變化,因為有些動畫特效就是利用微小的 morph 進行。
想了一下子,之後突然發現:根本就可以自己在昨天說的GPUComputationRenderer所產生的heightMap去加上 2D 的 noise,去做表面突起的感覺啊!

glsl-noise是 webgl 社群的重要人物 hughsk所撰寫,非常輕便好用!而 glslify則是 GLSL 的模組化工具,可以讓你真的像是 node module 去require人家的功能!

// heightmap.frag

// 使用 glsligy 引入 glsl-noise
#pragma glslify: cnoise2 = require(glsl-noise/classic/2d)
...

// 在要輸出 height 之前,加上一個 noise 去代表砂石碎屑的凸起表面
heightmapValue.x += cnoise2(uv * 2000.0) * 2.0;
gl_FragColor = heightmapValue;

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

表面顆粒感出來!至於石頭怎麼突然冒出來了?就讓我自己慢慢說下去吧。

3. 請愛CYBER の audio / VISUAL

編註:原本標題為「webの 禪師!運氣挪心山!動力之枯朽山水!」,是因為要寫得是關於石頭 3D model 的載入與動畫控制,但是發現漏掉了地板表面 texture 與 noise 的篇章,所以就此改為「webの 禪師!運氣弄四海!Texture 與 Material 的好用之處!」,來寫我運用這些技巧的邏輯,以此為誌。

我來繼續玩弄表面,加上更多花紋!

附上 source code

關於作者

Vibert Thio

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


上一篇
§d19§ webの 禪師!運氣弄四海!玄妙之表面功夫!
下一篇
§d21§ webの 禪師!花紋數學家!棋盤、小溪與潛動!
系列文
aesthEtic,CYBERの audio / VISUAL,網頁中的聲音與影像研究30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
微中子
iT邦新手 4 級 ‧ 2018-01-08 23:35:31

挪山跟挪心山有什麼差異嗎?

你 follow 很緊!
故事很長,不過短短來說,枯山水中挪山是一種狀態,心裡把石頭動了起來就是動了。而山過於具象,感覺畫面已經太過具象了,所以心就顯得更重要了!

另外方面,砂石則該是水紋、波動、浪高滔滔。昨天本想直接切入石頭與模型,最後決定先談談水,所以上一篇就改掉了變成「運氣弄四海!玄妙之表面功夫!」

編註:原本標題為「webの 禪師!運氣挪心山!動力之枯朽山水!」,是因為要寫得是關於石頭 3D model 的載入與動畫控制,但是發現漏掉了地板表面 texture 與 noise 的篇章,所以就此改為「webの 禪師!運氣弄四海!Texture 與 Material 的好用之處!」,來寫我運用這些技巧的邏輯,以此為誌。

我要留言

立即登入留言