如何基於模型資料繪製一個3D機器人

你好2007發表於2022-01-05

最終的效果如右邊所示(你可以使用滑鼠、手指或者鍵盤來控制這個機器人的旋轉):

機器人預覽

本專案基於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...

相關文章