最終的效果如右邊所示(你可以使用滑鼠、手指或者鍵盤來控制這個機器人的旋轉):
本專案基於image3D實現。
在正式開始之前,我們需要準備好模型資料,你可以去這裡下載:model.json
如果想快速體驗最終效果,可以點選此處檢視。
著色器
首先,你需要準備好兩個著色器。
頂點著色器
<script type='x-shader/x-vertex' id='vs'>
attribute vec3 a_position; // 頂點座標
uniform mat4 u_matrix; // 變換矩陣
uniform vec3 u_LPosition; // 光的位置
attribute vec3 a_normal;
varying vec3 v_LDirection;
varying vec3 v_normal;
void main(){
// 座標新增齊次座標,為了和矩陣對齊
gl_Position=u_matrix * vec4(a_position,1);
// 點光源方向計算:點光源方向 = 點光源座標 - 頂點座標
// 頂點的位置應該使用計算過的
v_LDirection=u_LPosition-gl_Position.xyz;
v_normal=a_normal;
}
</script>
片段著色器
<script type='x-shader/x-fragment' id='fs'>
precision mediump float;
uniform vec4 u_LColor; // 光顏色
uniform vec4 u_color; // 頂點顏色
varying vec3 v_LDirection; // 光線方向
varying vec3 v_normal; // 法線方向
void main(){
// 先對方向進行序列化,使得向量長度為1
vec3 LDirection=normalize(v_LDirection);
vec3 normal=normalize(v_normal);
// 計算序列化後的光方向和法線方向的點乘
float dotValue=max(dot(LDirection,normal),0.2);
gl_FragColor=u_color*u_LColor*dotValue;
}
</script>
畫布
也就是一個canvas:
<canvas width='500' height='500'></canvas>
繪圖物件
這個繪圖物件上有很多方法,通過這個物件上的方法,就可以完成各種操作了:
import image3D from 'image3d'
// 建立3D物件並配置好畫布和著色器
let image3d = new image3D(document.getElementsByTagName('canvas')[0], {
"vertex-shader": document.getElementById("vs").innerText,
"fragment-shader": document.getElementById("fs").innerText,
depth: true
})
我們後續需要使用到畫筆等,在這裡,我們提前獲取好:
let painter = image3d.Painter() // 畫筆
let buffer = image3d.Buffer() // 資料傳遞物件-緩衝區
let camera = image3d.Camera() // 相機
設定好相機
相機camera
上有很多的方法,具體的你可以點選此處,呼叫這些方法對相機等進行調整後,資料需要傳遞給頂點著色器
:
image3d.setUniformMatrix("u_matrix", camera.value())
頂點資料
相機準備好了以後,就是資料了,也就是model.js
中的頂點資料:
不同格式的模型資料格式可能不一樣,拿我們這裡的資料舉例子,頂點的資料都包含在:model.geometries[index].data.attributes.position.array
中,因此,我們只需要把model.geometries
一個個繪製處理即可,我們以第一個幾何體為例(一個模型資料可能有一個或多個幾何體拼接而成):
let position=model.geometries[0].data.attributes.position.array
buffer.write(new Float32Array(position))
.use('a_position', 3, 3, 0)
上面的作用就是把資料position
寫入GPU並分配給著色器中的變數a_position
。
繪製
此時,GPU中已經記錄了好多的點,這些點3個連起來就是一個三角形,三角形拼接起來就是幾何體了,如何把這些三角形拼接起來?使用畫筆:
painter.drawTriangle(0, position.length / 3)
最終的效果你可以點選此處檢視。
結束語
本例子的完整程式碼存放在Github上: https://github.com/clunch-con... 。