关于WEBGL的那点破事

时间:2022-11-11 12:42:26

序章?

想来学习WEBGL也一年有余了,多多少少有些心得也有些感想,然后又突然想开始写写博客,那我人生的第一篇博客就来谈谈这些心得与感想吧。

一开始接触WEBGL的缘由那是相当简单,仅仅是因为需要。那是大二的时候,学校突然跟我们说,这里有一堆项目,你们如果想参加的话就赶快报名。当时一群人就那么当看见项目里面有黄金似的报名去了,我当时看这情况,虽然不是很明白到底怎么回事,但总觉得很厉害的样子,于是也跟风报名去了。然后?然后项目就升级了到现在都没结题,平时还没什么事做。。

总而言之,我就这么接触WEBGL了。

之后就是学习过程了,这个我就不说了,说多了会得出我很懒的结论,这样不太好所以还是不说了。

WEBGL实在是个相当底层的东西,接口说起来其实不多,常用的也就那几个,然后这个特点直接导致了如果没有图形学基础的话,原生WEBGL学起来是在是有够复杂的。什么你说你直接three.js 搞起?好吧请当我什么都没说。。

我才不会跟人说当时我学WEBGL的时候从原生的跳到three.js,然后因为许多东西搞不懂就又从three.js跳回原生的WEBGL呢。。


为什么学WEBGL?

WEBGL接口很低级,相关资料偏少,学习起来有一定的难度,一出问题调试起来,我就呵呵了;

WEBGL性能上毫无疑问输给了OPENGL;

WEBGL似乎没有关于灯光的效果的接口函数,具体效果需要编写着色器程序来实现;

WEBGL甚至没有相机的概念,要用的时候还得自己定义;

WEBGL没有相机的概念就算了,它竟然连三维物体的转换函数都没有,还得利用第三方库去进行各种矩阵运算,对没错,就是这样,连矩阵堆栈都要自己定义是怎样!

那为什么我还要学WEBGL啊?

项目需要啊!(滚!)

其实是这样的:

WEBGL虽然性能上比不上OPENGL,但仍然拥有相当高的性能;

WEBGL通过对着色器的编程,甚至可以掌控所有显示到屏幕上的像素的颜色;

WEBGL程序调试时可以极度挑战你的耐心(―_―#!);

回到正题。。最重要的一点是,WEBGL可以在支持它的浏览器上,实现不需要插件就能运行的三维程序;

就冲最后一点,WEBGL学了也不会吃亏啊。


学习资料有那些?

为了方便想学习WEBGL的看官,就介绍一下我用过的一些资料及教材。

目前网上有一个似乎叫做HiWebGL的系列,有中译版本的,不过没有图形学基础的同学我不太推荐,因为我当时就是没图形学基础就去看的,结果看完之后我的状况就是:虽然不知道是怎么回事,但总感觉很厉害的样子。

现在O'Reilly也出有一本名为《WEBGL》的动物书,封面是个奇怪的不明物种,现在似乎还没有中译版(更正,最近中译版出来了)。很坑的是,虽然它封面写的是WEBGL,但实际上介绍的却是Three.js框架,而且除了Three.js框架外,里面介绍的例子还使用了大量的第三方工具库,让读者几乎没有可能接触到WEBGL的原生接口,以及一些不懂是在不太好的图形学原理。看完了原生WebGL想去了解Three.js框架的同学,我感觉可以入手这本书。

最后就是我有老老实实看完的一本书了,真的有看完哦不骗你。。书名是《WebGL Beginner's Guide》书中除了一些运算用的工具库之外,几乎没有用到别的什么奇怪的东西。书中有很详细的介绍一个原生WEBGL应用的结构,几乎从零开始介绍WEBGL原生接口的使用方法以及使用原因。着色器编程也花了不少的篇幅介绍。最重要的是,开头就介绍了WEBGL的渲染管线,而且几乎每一章都有适当地介绍相关的图形学知识。这对没有图形学基础的初学者是相当的合适啊~!好吧至少对我来说的确是相当的合适。。。这书依然没有中译版哦~,似乎。



要做什么才画得出来一个球?

那么最简单的一个WEBGL程序需要做什么呢?

初始化画板什么的,就略过吧。

首先要编写着色器程序,并编译链接。着色器程序包含两个部分,一个是顶点着色器,一个是片元着色器。最简单的着色器程序用顶点着色器计算三维物体顶点的位置在哪,同时用片元着色器设定每个片元的颜色。

然后要初始化三维物体的Buffers,具体说来就是用WEBGL提供的接口新建一些Buffer,并向其打入数据。

再然后就是初始化灯光(A:喂你不是说没有灯光接口嘛! 我:闭嘴!)。初始化灯光干的事情其实是利用WEBGL提供的接口设置着色器程序中某些常量型数据的值,具体说来就是名为uniform的变量。严格的说,这个步骤干的并不仅仅是初始化灯光这件事

接下来做的就是设置视口,清除缓冲区,设置投影锥,进行矩阵运算并把矩阵数据打入到着色器程序中。当有多个着色器程序是,当然要先切换着色器。

上面的都干完了之后,就进入绘制阶段了,这个阶段做的事情其实不多,也就把前面所定义的缓冲区的引用传递给着色器,并使用索引缓冲区进行网格片面的绘制就完了。

如果上面的步骤一切正常的话,希望绘制的场景就会显示在浏览器的canvas画板上了。

(喂!怎么没看见设置相机?)

(就说没有相机对象了,给我闭嘴!)


为什么我的程序就是不正常?

初学WEBGL的时候很是容易碰到各种各样的问题,一个不小心写的程序出来的效果就诡异的跟什么一样,我在学习过程中碰到过的状况也不少了,就果断分享被折磨后得到的经验吧!


状况1: 场景只有背景色,其他什么都没有

解决方案:

先看看JS代码是否有错(这真不是废话);

看看三维物体的缓冲区打入数据时是否发生错误,API参数是否设置正确,打入数据前是否有绑定;

看看绘制阶段的缓冲区引用传递操作是不是有问题,相应API函数的第二个参数最有嫌疑,还应该看看绑定操作有没有做,做的对不对;

仔细检查下着色器程序是不是有奇怪的地方,或者是有没有切换到正确的着色器程序;

检查下相机是不是位置设置在了物体的内部,或者是指向了错误的方向。

(喂你不刚说了没相机么?)

(就说了是自己定义的,再不闭嘴砍你喔)


状况2:我明明贴了材质,为什么那东西还是黑的?

解决方案:

总之先刷新一下( 就说我不会随便说废话的了);

检查所使用的材质是否合法,WEBGL只支持长宽都为2的n次方的材质;

检查材质坐标是不是正确的传递到了着色器程序中;

检查着色器程序的相关代码有没有问题;

检查绘制之前是否绑定了材质;

最后就是看看你是不是把材质贴到物体内侧了。



状况3:我明明用了很多个材质,为什么最后画出来的东西用的都是同一个材质?

解决方案:

这肯定是绘制新的物体时没有用gl.bindTexture()函数绑定相应的材质了。


状况4:我明明设置了透明效果,为什么被挡住的部分还是消失了?

解决方案:

没有完美的解决方案。这个并不是程序的错误导致的,而是WEBGL所使用的机制导致的。想知道具体原理可以参考http://*.com/questions/8763603/transparent-textures-behaviour-in-webgl ;具体解决方案的话,可以参考以下:

首先绘制不透明的物体(在相当多的情况中可以解决问题)

余下的透明物体,距离相机最远的最先绘制

以上。什么你问我相交的物体怎么办?我怎么知道啊~我也只是个菜鸟啊~


状况5:我的场景明明正确显示了,为什么还会有一堆Index outof Range的提示?

解决方案:

这种情况问题多半出在着色器程序上,着色器程序编译链接的时候,似乎会为了效率起见,剔除掉对最终结果没有任何贡献的变量。如果你是懒人,那么这种情况放着不管就好了。如果是在受不了那堆提示,那就好好检查下着色器程序,手动剔除掉没用的代码,再适当的修改WEBGL代码就好。


总之到现在为止遇到的状况也就上面这几种了,以后还有遇到奇怪情况的话,解决后会来更新这一部分的。


----于2013/06/17----

状况6:材质坐标什么的我调来又调去的,怎么材质就是贴的乱七八糟的,就是不出现需要的效果?

可能的解决方案:

检查下你的材质坐标是跟哪个坐标一一对应生成的,如果是跟索引数组意义对应生成的话,那试试改成与定点坐标意义对应看看,很可能就bingo了.



居然有调试器?

最后再介绍个调试器,名叫WebGL Inspector,是Chrome下的一个插件,这东西可是调试WEBGL程序的神器哦~谁用谁知道。。


最后~

大概也没什么想说的了。熬夜不好就先睡了。