4
头图

最终的效果如右边所示(你可以使用鼠标、手指或者键盘来控制这个机器人的旋转):

机器人预览

本项目基于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>

绘图对象

如果没有安装,需要提前安装好依赖包:

npm install --save image3d

这个绘图对象上有很多方法,通过这个对象上的方法,就可以完成各种操作了:

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...


你好2007
179 声望4 粉丝

走一步,再走一步。