Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

WebGL(叁) 关于图元与绘制索引

  在3D绘图中,图元是一个重要的概念,任何3D元素都是由图元组成的。上一篇文章中,我们也使用了TRIANGLES这个图元来绘制了一个三角形。其实在WebGL中基本图元只有三大类,它们分别是,点、线和三角形。无论需要画什么样的图形都只能用这些图元去拼凑。
  这里是所有WebGL中的图元列表:
    POINTS:只绘制顶点
    LINE_STRIP:把每个顶点按顺序用线连起来
    LINE_LOOP:同上,并且头尾相连
    LINES:每两个顶点相连
    TRIANGLE_STRIP:从第三个顶点开始,每个顶点与前两个顶点相连形成三角形
    TRIANGLE_FAN:从第三个顶点开始,每个顶点与第一个和上一个顶点连成三角形
    TRIANGLES:每三个顶点连成三角形
  也许文字描述的不直观吧,咱来看图,这张图片是谷歌上找到的。

  对于绘制面,我们能用的只有三角形。如果想绘制一个立方体,就必须先用两个三角形构成一个矩形,再用6个矩形拼出立方体。而绘制三角形的方法不止一种可以用TRIANGLES也可以用TRIANGLE_STRIP(注意TRANGLE_FAN无法绘制出立方体),使用TRIANGLES每个矩形需要6个顶点,绘制立方体总共需要36个顶点,不过这个方法每个三角形是独立的,操作和管理上会比较方便;另一种方法是使用TRIANGLE_STRIP,这就比较复杂了,不过最少的情况只需要14的顶点就可以拼出立方体。下图是这个步骤

  这么做虽然顶点的数量少了,但是这个方法绘制的顶点位置很乱,操作起来不方便。如果没有特殊情况,是不推荐这么做的。这篇文章只是说说简单的图元构造,由于我们还有很多东西没说,这一篇就不给出立方体的实例了。把立方体留在下一篇吧~
  不仅是立方体,这些三角形图元还可以拼凑出球体。这个就有点复杂了,球体一般是按照经纬线切的,不明白的话脑子里想想地球仪的样子。切的越细球体表面就越平滑,顶点的使用量也就越大。这个内容以后会说道,估计不会太早,现在先理解下这个模糊的概念就够了。
  另外,线和点的绘制操作也需要注意一些问题。使用POINTS绘制顶点时可以在顶点着色器程序中使用gl_PointSize这个内置属性来设置顶点的大小。这可能在粒子系统中会用到,基本粒子实际上即使一组顶点。另外还有个兼容性问题,在Windows上,绘制线的时候无法指定线宽。OpenGL本身有glLineWidth这个方法,而且在WebGL中也有这个方法。但是在Windows虽然调用不会失败,但是也不会生效,无论是在Chrome还是在FireFox上测试都无效。但是Linux上有效,我觉得这应该是操作系统的限制问题。这个问题之前就有人提出过,如果有兴趣可以看看文章最后的第一参考资料。也许在以后的WebGL版本中会修复这个问题吧。
  如果我们用TRIANGLES绘制矩形就需要两个三角形也就是6个顶点。但是其中两个顶点是两个三角形共用的,实际上也只是4个顶点而已,因为有两个重复。那么顶点可以复用吗?也就是一个顶点使用多次?这个是可以做到的,这就是绘制索引(drawElements),这个方法的原意是绘制“元素”的。其实就是用索引来指定元素,在顶点数据源中根据索引的顺序取出相应的顶点。而不是像原来的drawArrays一样把整个顶点数据源都遍历一遍。比如我们要绘制一个矩形,我们只需要修改上一篇的例子中的两个地方,下面是代码 //开始的一大坨代码

//定义一个顶点数组,为了构造矩形需要四个顶点
var dat=[-0.5,-0.5,0,1 ,-0.5,0.5,0,1 ,0.5,-0.5,0,1 ,0.5,0.5,0,1];

//中间的一大坨代码

//把索引放入显存
var index=webgl.createBuffer();
webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER,index);
webgl.bufferData(
  webgl.ELEMENT_ARRAY_BUFFER,
  new Uint16Array([0,1,2,1,2,3]),
  webgl.STATIC_DRAW
);
//绘制索引(注意索引数据必须在当前工作缓冲区中)
webgl.drawElements(webgl.TRIANGLES,6,webgl.UNSIGNED_SHORT,0);
  因为要用到索引数据,我们也需要把它放入缓冲区。这个操作和昨天的代码类似,但是要注意这个数据的用途是作为索引,所以我们需要的操作类型是ELEMENT_ARRAY_BUFFE。还有索引是自然数吧,所以我们使用无符号整型来储存。最后是绘制索引,注意drawElements的参数列表和drawArrays的差别很大。第一个参数是图元类型,第二个参数就是索引的长度了,然后是索引的数据类型,最后是索引的开始下标,或者称为偏移量。我定义索引时使用的是16位的无符号整型,这个类型对应的就是UNSIGNED_SHORT。除了这些显式传递的参数以外,drawElements还有一个特别的地方。你会发现在参数列表中我们只传入了索引长度,并没有指定索引数据。其实这个方法会去当前工作缓冲区中取索引数据。也就是说,在调用这个方法之前,我们最后一次bindBuffer操作的必须是索引所在的缓冲区,要不然就找不到索引数据了。
  好啦,这篇就说这么多。注意测试代码是修改上一篇中提供的代码的,因为改动不多,所以我就不重新弄一份了。如果有什么问题就提问吧~

参考:
  https://code.google.com/p/angleproject/issues/detail?id=334
  http://www.opengl.org/wiki/Primitive
网名:
34.203.245.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^