TAT.vorshen 教你用webgl快速创建一个小世界
In Web开发 on 2017年03月15日 by view: 1,890
3

Webgl的魅力在于可以创造一个自己的3D世界,但相比较canvas2D来说,除了物体的移动旋转变换完全依赖矩阵增加了复杂度,就连生成一个物体都变得很复杂。

什么?!为什么不用Threejs?Threejs等库确实可以很大程度的提高开发效率,而且各方面封装的非常棒,但是不推荐初学者直接依赖Threejs,最好是把webgl各方面都学会,再去拥抱Three等相关库。

上篇矩阵入门中介绍了矩阵的基本知识,让大家了解到了基本的仿射变换矩阵,可以对物体进行移动旋转等变化,而这篇文章将教大家快速生成一个物体,并且结合变换矩阵在物体在你的世界里动起来。


注:本文适合稍微有点webgl基础的人同学,至少知道shader,知道如何画一个物体在webgl画布中

为什么说webgl生成物体麻烦

我们先稍微对比下基本图形的创建代码
矩形:
canvas2D

webgl(shader和webgl环境代码忽略)

完整代码地址:https://vorshen.github.io/simple-3d-text-universe/rect.html
结果:

圆:
canvas2D

webgl

完整代码地址:https://vorshen.github.io/simple-3d-text-universe/circle.html
结果:

总结:我们抛开shader中的代码和webgl初始化环境的代码,发现webgl比canvas2D就是麻烦很多啊。光是两种基本图形就多了这么多行代码,抓其根本多的原因就是因为我们需要顶点信息。简单如矩形我们可以直接写出它的顶点,但是复杂一点的圆,我们还得用数学方式去生成,明显阻碍了人类文明的进步。
相比较数学方式生成,如果我们能直接获得顶点信息那应该是最好的,有没有快捷的方式获取顶点信息呢?
有,使用建模软件生成obj文件。

Obj文件简单来说就是包含一个3D模型信息的文件,这里信息包含:顶点、纹理、法线以及该3D模型中纹理所使用的贴图
下面这个是一个obj文件的地址:
https://vorshen.github.io/simple-3d-text-universe/assets/a1.obj

简单分析一下这个obj文件


前两行看到#符号就知道这个是注释了,该obj文件是用blender导出的。Blender是一款很好用的建模软件,最主要的它是免费的!


Mtllib(material library)指的是该obj文件所使用的材质库文件(.mtl)
单纯的obj生成的模型是白模的,它只含有纹理坐标的信息,但没有贴图,有纹理坐标也没用


V 顶点vertex
Vt 贴图坐标点
Vn 顶点法线


Usemtl 使用材质库文件中具体哪一个材质


F是面,后面分别对应 顶点索引 / 纹理坐标索引 / 法线索引

这里大部分也都是我们非常常用的属性了,还有一些其他的,这里就不多说,可以google搜一下,很多介绍很详细的文章。
如果有了obj文件,那我们的工作也就是将obj文件导入,然后读取内容并且按行解析就可以了。
先放出最后的结果,一个模拟银河系的3D文字效果。
在线地址查看:https://vorshen.github.io/simple-3d-text-universe/index.html

在这里顺便说一下,2D文字是可以通过分析获得3D文字模型数据的,将文字写到canvas上之后读取像素,获取路径。我们这里没有采用该方法,因为虽然这样理论上任何2D文字都能转3D,还能做出类似input输入文字,3D展示的效果。但是本文是教大家快速搭建一个小世界,所以我们还是采用blender去建模。

具体实现

1、首先建模生成obj文件

这里我们使用blender生成文字

2、读取分析obj文件

代码核心的地方都进行了注释,注意这里的正则只去匹配我们obj文件中含有的字段,其他信息没有去匹配,如果有对obj文件所有可能含有的信息完成匹配的同学可以去看下Threejs中objLoad部分源码

3、将obj中数据真正的运用3D对象中去

这里我们考虑到兼容obj文件中f(ace)行中4个值的情况,导出obj文件中可以强行选择只有三角面,不过我们在代码中兼容一下比较稳妥

4、旋转平移等变换

物体全部导入进去,剩下来的任务就是进行变换了,首先我们分析一下有哪些动画效果
因为我们模拟的是一个宇宙,3D文字就像是星球一样,有公转和自转;还有就是我们导入的obj文件都是基于(0,0,0)点的,所以我们还需要把它们进行平移操作
先上核心代码~

一眼望去uMMatrix(模型矩阵)里面有三个矩阵,为什么有三个呢,它们的顺序有什么要求么?
因为矩阵不满足交换率,所以我们矩阵的平移和旋转的顺序十分重要,先平移再旋转和先旋转再平移有如下的差异
(下面图片来源于网络)
先旋转后平移:
先平移后旋转:
从图中明显看出来先旋转后平移是自转,而先平移后旋转是公转
所以我们矩阵的顺序一定是 公转 * 平移 * 自转 * 顶点信息(右乘)
具体矩阵为何这样写可见上一篇矩阵入门文章
这样一个3D文字的8大行星就形成啦

4、装饰星星

光秃秃的几个文字肯定不够,所以我们还需要一点点缀,就用几个点当作星星,非常简单
注意默认渲染webgl.POINTS是方形的,所以我们得在fragment shader中加工处理一下

结语

需要关注的是这里我用了另外一对shader,此时就涉及到了关于是用多个program shader还是在同一个shader中使用if statements,这两者性能如何,有什么区别
这里将放在下一篇webgl相关优化中去说

本文就到这里啦,有问题和建议的小伙伴欢迎留言一起讨论~!

原创文章转载请注明:

转载自AlloyTeam:http://www.alloyteam.com/2017/03/teach-you-to-use-webgl-to-quickly-create-a-small-world/

  1. Apolo 2017 年 4 月 5 日

    声明: 我是专门從别人转载的文章跟过来的。

    有两点要说:
    1. canvas 画矩形, 只需要 fillRect 就够了,为什么要写两个语句画蛇添足?
    2. canvas 画圆, 不需要 beginPath 吗? 你画两个圆试试看?
    你真的用canvas做过东西吗? 还是哪里瞎看了什么破教程就来瞎分享了?

    能不能稍微有点水平再发点教学,别祸害小白了好吗???
    真是无知者无畏。现在中文的技术贴还能看? 都是你们搞烂的吧?

  2. 快乐平方 2017 年 3 月 16 日

    虽然webgl强大,但还是canvas简单

  3. 小小小无路 2017 年 3 月 16 日

    还是有点迷糊。。。看不太懂

发表评论