Web 技术研究所

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

WebGL(柒) 绘制多对象

  俗话说独木不成林,要构成一个完整的3D场景当然需要同时绘制许多对象才行了。同时绘制多个对象也有不同的实现方式,可以把多个对象构造成一个更复杂的对象来一次性绘制,也可以直接调用多次绘制方法。这篇文章咱就来说说如何同时绘制多个对象。
  其实,我们早就知道绘制多个对象的方法了。还记得立方体吗?绘制立方体,实际上就是绘制了多个矩形对象。只不过我们把立方体上的所有矩形对象的顶点都放在同一个数组中而已。这就是把基础对象变成复杂对象来一次性绘制的方法。使用这个方法,我们也可以构造多个立方体的顶点数据放入同一个数组中来绘制。我们使用的是TRIANGLES图元,这个图元是每三个顶点形成一个三角形,而且三角形之间是互不关联的。所以我们完全可以绘制出多个互不关联的立方体。虽然它们在顶点上是互不关联的,但是它们毕竟是在同一个数组中,或者说是在同一次绘制中,所以它们使用的着色器全局变量(uniform)是相同的。这时候如果要对单独对象进行矩阵变换之类的操作就变得很麻烦。我们就变得需要为单个顶点传入矩阵来变化。这显然不符合科学发展观!
  对于需要做矩阵变换的对象,我们通常会使用单独绘制的方法。单独绘制,也就是调用多次draw*。每次调用draw*时可以设置不同的uniform。这样就省去了之前那种方法把矩阵绑定到顶点上那样野蛮的操作。但是仔细想想就会发现不对劲了,之前旋转立方体的例子中使用计时器来不断执行draw*操作。在那个例子中,每次调用draw*都会清除原来已经绘制的东西,按照这个逻辑,调用多次draw*就无法绘制出多个对象。为了说明这个问题我才写突然在上一篇写了看似和WebGL关系不大的文章“JavaScript的消息机制”。draw*方法的工作和当前处理的消息有关,在同一个消息处理过程中多次调用draw*就可以绘制出多个对象,在新的消息中执行draw*时就会清除原来已经绘制的东西。我们之前的计时器不断绘制就是每次产生新的计时器消息,每次在新的计时器消息中调用draw*,所以才会清除原来绘制的东西。下面来个例子,这回咱来绘制一坨立方体。前面的代码我就不贴了出来了,只贴绘图的一部分。
var a=0;
setInterval(function(){
  //计算旋转参数
  var s=Math.sin(a),c=Math.cos(a);a+=0.02;
  //二重循环绘制多个元素
  for(i=-2;i<=2;i++)for(j=-2;j<=2;j++){
    //更具循环变量和旋转参数构造变化矩阵(平移·旋转)
    webgl.uniformMatrix4fv(tra,false,[
      c*c,-s,s*c,0, s*c,c,s*s,0, -s,0,c,0, i*5,j*5,-14,1
    ]);
    //绘制
    webgl.drawElements(webgl.TRIANGLES,36,webgl.UNSIGNED_SHORT,0);
  };
},16);

  整个二重循环中的所有绘制都是在同一个计时器消息(事件)中执行的,所以所有的对象都可以绘制出来。从效果上看可能会觉得立方体形状变得有些诡异了。那是投射矩阵闹的,由于视点不同造成的而已,不用纠结~ 下面是完整的实例

  WebGL绘制多对象
网名:
34.203.245.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^