目的是示範在WebGL上跑自制shader(着色器)。 架構使用three.js, 搭建hello world參見:
- three.js
注意,WebGL 1.0使用的shader隻支援GLSL 1.0.17, 這是因為WebGL是基于OpenGL ES 2.0的,是給相對于桌上型電腦性能較低的手持裝置用的。 是以如果在網上找到的GLSL的例子,在WebGL上可能不管用,要注意版本。 GLSL 1.0與現行最高的4版本比起差別還是比較多的,比如老版本裡叫attribute, varying的變量到高版本裡叫in, out了。 具體WebGL學習參見:
- Learn WebGL
先上代碼: Github: demaxism/
shader-threejs使用: git clone代碼後進入檔案夾, 啟動web server, 比如我用node:
http-server .
浏覽器打開
http://127.0.0.1:8080/
後,點選Simple Shader按鈕。

代碼解釋: v_shader和f_shader是我們要加載的vertex shader和fragment shader,以字元串形式儲存。 vertex shader的工作比較好了解,是對單個頂點的處理,頂點就是三維模型資料裡的頂點。 built-in uniform和attribute有:
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
還有些其他内置變量,詳見:
- WebGL Program Doc
v_shader裡, position是頂點的local坐标(Model坐标),以下這步把local坐标轉換成camera坐标:
vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
也可以拆解成: Model坐标 X ModelMatrix = World坐标;World坐标 X ViewMatrix = Camera坐标。
接下來這步把camera坐标轉換成投影坐标
gl_Position = projectionMatrix * modelViewPosition;
詳見:
- Opengl-tutorial Basic/Matrices
varying vec3 localPos;
...
localPos = position;
這裡我把Model坐标以varying的形式傳給fragment shader.
在fragment shader裡,接受了來自vertex shader的localPos, 還有個uniform變量time。它在每幀(每次渲染完成)内是全局不變的。 gl_FragColor是fragment shader唯一的輸出。 所有的處理都服務于它。
在vertex shader處理完後, polygon被栅格化(rasterized)成一個個fragment, fragment和pixel的差別開始有些難了解,其實可以了解成fragment是pixel的candidate。 比如有多個polygon在垂直于螢幕方向疊在一起,這些polygon都會産生fragment,但有些會因為深度靠後而被丢棄。
varying vec3 localPos在fragment shader裡是被線性補間的。 在vertex shader裡隻輸出了模型的各頂點到localPos, 每個polygon隻有三個localPos, 但由于這個polygon會被栅格化成許多小fragment,于是各個fragment拿到的localPos是補間生成的。
最後three的init()裡不要忘了加上:
this.animate = this.animate.bind(this);
不然的話在回調調用這個animate時,内部的this會失效(不再指向自己),是以這裡就把this綁定給自己。