从零开始手撸WebGL3D引擎0(开始探险之旅)

纸上得来终觉浅,绝知此事要躬行 ---- 陆游
【从零开始手撸WebGL3D引擎0(开始探险之旅)】本系列的目的是实现一个基于WebGL的渲染框架,并以此为基础进行图形效果实践。之所以选择WebGL而不是OpenGL,一是因为开发环境配置比较简单,而且WebGL是比较简洁纯粹的API,Javascript的群众基础也比较好。虽然是以学习实践为目的,我还是尽量让这个框架具有实用性,可以用来开发一些小型3D游戏。当然相对于结果,这个项目的过程更有意义,在这个过程中,我们从零开始,从基础概念和原理着手,一步一步搭建出渲染框架,相信通过这个过程,我们对WebGL(OpenGL),3D图形学基础概念,一些Shader效果的实现会有较为深刻的理解。
WebGL简介
WebGL官网
简单说,WebGL 1.0和OpenGL ES 2.0很接近,存粹的基于Shader的渲染,如果你去看WebGL 1.0的API,你会发现并不多。Webgl1.0参考卡片总结的很好,可以从全局视角看WebGL提供了哪些东西。大概总结一下其中常用的一些东西:
  • WebGL Context
    WebGL上下文保存了一组OpenGL的状态。WebGL是一个状态机,通过WebGL API去设置这些状态,比如当前使用的shader program, 当前绑定的buffer,当前激活的纹理单元等等。而这些状态就存储在Context中。可以从Canvas对象获取WebGL的Context。
  • Buffer Objects
    Buffer是GPU显存中的缓冲区,通过WebGL buffer相关的API可以从CPU内存向GPU显存传输顶点和索引数据。通过设置当前的Buffer,WebGL进行绘制。
  • Porgrams and Shaders
    Shader是WebGL的核心,大部分API都是为了给Shader提供数据。和Shader相关的概念有program, shader, uniform, attribute
  • Texture Objects
    纹理对象很重要,因为基本上各种渲染效果都需要纹理的支持,在后续的实践中,我们会尝试使用diffuse map, normal map, specular map, noise map, mask map, cube map等等纹理。其实纹理已经不仅仅是一张贴图了,你可以理解为一个二维数组对象,而且是支持采样插值的。
  • Framebuffer
    WebGL的渲染最终输出到frame buffer中, frame buffer包含color buffer, depth buffer和stencil buffer。WebGL可以用指定的值清除指定的buffer。
  • Draw call
    通过gl.drawArrays或gl.drawElements,执行绘制操作。
  • FBO (Framebuffer object)
    除了渲染到屏幕,WebGL还可以渲染到FBO上
  • 状态开启关闭和查询
    gl.Enable, gl.Disable, gl.isEnabled等方法,提供了全局状态的开关。例如:BLEND, CULL_FACE, DEPTH_TEST等状态。
这儿只列了一部分,看着挺多东西的,其实分分类也没多少。另外还有一半的内容是关于GLSL的,即Shader的语法和内置函数。其实相比于图形API,其背后的原理的理解,算法的实现等才是更难掌握的。本次探索我们是从基础出发,我觉得基础打扎实很重要,但是我不可能事无巨细的解释原理,我会给出一些参考资料,我们的重点还是框架的实现。
构建工具
基本现代浏览器都支持WebGL1.0, 所以理论上,只要有一个浏览器加一个文本编辑器,我们就可以直接写WebGL程序了。但是对于我们的目的,既然是写一个框架,就应该将这个框架独立出来,我使用rollup.js作为框架的打包工具。为了简单,测试程序也用rollup.js构建了,其实rollup.js更适合构建库,应用建议还是gulp+browseify或webpack吧。但是实话说,这不是我的强项,我主业还是开发游戏,虽然搞过几年H5游戏,但是都用的是引擎提供的构建工作流,但是这不影响我们开始这个基于rollup.js的框架的开发。
项目和系列文章思路
项目已经放到github上 mini3d.js
作为一个学习型的框架,且是业余时间的探索,简单能Hold住是第一要素,希望不要烂尾,所以名字更要低调一些。
主开发分支是master,我会列出一系列的milestone,在master上开发,如果基本达到milestone的状态,就会为milestone建立一个分支。目前的milestone分支只有一个:ms1_rotate_cube。正如其名,只是一个旋转的方块,但是已经解决了很多的基础问题。一般实现了一个milestone,我才会放出一系列的文章,这些文章是对实现milestone过程中解决的问题的记录,包括基础原理的解释,框架实现时的取舍等等。现在第一个milestone基本达到目标,所以下面会开始写几篇介绍mini3d.js现阶段实现功能的原理和实现思路的文章。当然随时mini3d.js的进化,我们会不断的修改之前的设计,所以把这些milestone建立成分支,可方便与这些文章对照。下一篇正式开始,从rollup.js搭建一个最基本的webGL程序开始。

    推荐阅读