1

如何基于模型数据绘制一个3D机器人

 2 years ago
source link: https://segmentfault.com/a/1190000041226945
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

如何基于模型数据绘制一个3D机器人

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK