Web 技术研究所

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

SimpleWebGL.2.0 帧缓冲投影演示

  帧缓冲做投影在之前的文章中已经介绍过了,这回咱用SimpleWebGL来做。顺便来说说SimpleWebGL中一些东西的使用方法。这个库的封装其实只是对WebGL的对象化(原生WebGL是面向过程的),并引入了命名空间与着色器数据接口等很好用的东西来方便操作。
  之前我都把演示的链接与效果图放文章结尾的,导致一开始看不到效果有些人就没兴趣看文章。我打算今后把效果图和演示链接放靠前的位置了。下面就是效果图和演示连接。
  SimpleWebGL.2.0 帧缓冲投影演示
  着色器程序的代码我就不说了,如果不理解就回到之前的文章看看帧缓冲投影的原理柔化阴影。下面直接从命名空间开始。 new SimpleWebGL(canvas).namespace(function(){
  eval(this.EXTRACT);
  //程序主体部分
});
  这就是创建一个SimpleWebGL对象,并打开一个命名空间。其实只是调用namespace这个方法来执行一个函数而已。在这个函数中,this指向SimpleWebGL的实例,所以外面的new SimpleWebGL我就不把它放入变量了,因为代码基本都放在这个命名空间中。然后在这个命名空间中有一个eval,参数是this.EXTRACT。它的作用是把SimpleWebGL实例中定义的构造器释放到当前命名空间这个作用域下,这样就不会污染到全局作用域。使用eval可以省去一大堆的构造器引用带来的麻烦,不过有些人很忌讳这玩意儿。不要紧,有其它方法也可以导入构造器。那就是给这个命名空间的function添加参数,不过这个方法只能逐个导入,像下面这样。
new SimpleWebGL(canvas).namespace(function(
  //导入构造器
  Program,VertexShader,FragmentShader,ArrayBuffer
){
  //程序主体部分
});
  这些构造器的顺序并不重要,只要名字对上即可。有时候程序并不使用所有的构造器,也可以通过这种方式导入需要用到的构造器。这篇文章的例子需要用到几乎所有构造器,所以我就直接使用eval导入了。
  接着是程序数据的部分,第一个数据box,由于有很多顶点数组,代码很长,我就不说它了。拿第二个数据出来吧
  ground={
    position:new ArrayBuffer([-3,0,-3, -3,0,3, 3,0,-3, 3,0,3]),
    normal:new ArrayBuffer([0,1,0, 0,1,0, 0,1,0, 0,1,0]),
    textureMap:new ArrayBuffer([0,0, 1,0, 0,1, 1,1]),
    mMatrix:[1,0,0,0, 0,1,0,0, 0,0,1,0, 0,-3,-13,1],
    element:new ElementBuffer([0,1,2, 1,2,3])
  }
  这就是一个普通的JavaScript对象,只是里面带着绘制这个东西所需要用到的数据。这个ground是演示中的挡板对象,它的位置与旋转是固定的,所以把模型矩阵也写入其中。box那个对象由于需要旋转,所以模型矩阵就不放入其中,而是在绘制时动态传递。然后是顶点等一些参数,在这里它们都是以缓冲区的形式存放的,ArrayBuffer和ElementBuffer对象的构造参数是数组,这和原生WebGL类似,只是SimpleWebGL把它对象化了而已。之所以在定义数据时候就使用缓冲区对象是因为缓冲区对象是显存对象,定义时就已经把数据放入显存,之后的绘制只要引用指针即可。所以每一种数据只需要定义一次,他们可以重复使用,无论绘制多少次对象都使用这些数据。
  下面这个是导入贴图,这里直接使用的图片,所以它的参数是图片对象。当然也可以是其它对象或者直接使用数据数组,不过使用数据数组时后面还需要跟上宽度和高度。第二个参数是贴图的颜色类型,还记得原生WebGL中texImage2D函数中的RGB参数吗?就是这货了,当然如果需要透明度也可以使用RGBA。另外在SimpleWebGL中,原生WebGL的一大堆常量都使用字符串来传递。
  var image=new Image;
  image.src="/images/BTNTornado.jpg";
  image.onload=function(){
    new Texture2D(image,"RGB").bind(1);
  };
  创建了贴图对象后,后面还调用了bind(1)。bind就不用说了吧?这个bind的参数是指定哪个贴图空间。也就是原生WebGL中调用bindTexture之前调用的activeTexture。当然,除了bind外还有unbind等一些列方法,具体可以看接口描述。
  接着是创建着色器程序。
  var program=new Program(
    new VertexShader(vSource),new FragmentShader(fSource)
  ).link().use()
  既然封装了库就不用原来那么麻烦的一个个去create,在命名空间中引入这些对象直接new即可。一个着色器程序需要片段着色器和顶点着色器两个子程序,所以它的构造参数就是这俩。而片段着色器和顶点着色器都需要着色器语言的源码,所以他们的参数是源码。这里为了方便使用,源码未必需要字符串,可以直接指定到HTML元素上自动获取它的textContent。后面的link和use也不用说了吧?原生WebGL中也必须有这一步,不过我对link方法做了其它功能的封装,当调用link时会自动计算着色器程序源码中的数据接口,以便之后的data方法使用。
  下面这个是帧缓冲对象,由于它需要一个贴图数据和一个渲染缓冲区对象,所以就以这两个为构造参数。当然,这些对象的构造参数也可以不传。在创建对象之后再调用其它方法来传入,具体可以看接口描述。里面的渲染缓冲区对象也是类似,封装只是把一些重要的参数提取出来以便操作而已。
  var framebuffer=new Framebuffer(
    new Renderbuffer("DEPTH_COMPONENT16",512,512),
    new Texture2D(null,"RGBA",512,512).bind(2)
  ).unbind();
  后面是绘制的方法
  this.setting("DEPTH_TEST","LESS").color(0.3,0.3,0.3,1)
  .play(function(time){
    //绘制的过程
  });
  其实绘制只要调用program对象的draw就行了,不过我们通常做的是动画,有帧在跳动。所以这里封装了帧,调用play方法即可得到一个被持续调用的函数,它还有个time参数。而在绘制前,一般需要设置一些全局的配置,比如开启深度测试或混合模式以及clear的颜色数据等,这些参数的配置和原生的WebGL基本相同,只是封装了语法,常量用字符串传递而已。
  最后是真正的绘制部分
    //绘制到帧缓冲
    framebuffer.bind(),this.clear("COLOR","DEPTH");
    program.data({type:2}).data(ground).draw(ground.element)
    .data("mMatrix",m).data(box).draw(box.element);
    //绘制到屏幕
    framebuffer.unbind(),this.clear("COLOR","DEPTH");
    program.data({type:0}).data(ground).draw(ground.element)
    .data({type:1,mMatrix:m}).data(box).draw(box.element);
  这个演示是做投影的,所以数据需要先绘制到帧缓冲中,所以这里调用了帧缓冲对象的bind方法。而后面的部分由于要绘制到屏幕上,所以对帧缓冲对象unbind了。clear方法我就不说啥了,和原生WebGL基本一样。然后是我前面说过的data方法,程序在link时构造了着色器的接口,之后只需要调用data,就可以往着色器传入数据。data的参数可以是一个着色器中接口的名字和相应的值,比如这里对mMatrix这个接口传入m这个变量。也可以是一个包含一系列接口名和数据的标准JavaScript对象,比如这里的data(box)。这也是为什么之前直接在box和ground对象上绑定静态数据的原因。绑定数据后调用draw即可执行绘制,这个draw方法包含了原生WebGL的drawArrays和drawElements,通过参数来识别。如果第一个参数是ElementBuffer则使用drawElements,如果第一个参数是一个数字,表示需要绘制的顶点数量就使用drawArrays。默认使用TRIANGLES图元,如果有需要也可以在后面的参数指定其它图元,当然这些常量是字符串形式传入的。
  到这里,整个程序就结束了,比起之前使用原生WebGL来做这个效果用了两百多行代码,使用SimpleWebGL当然省了不少代码。更重要的是整个代码逻辑比原生WebGL清晰的多了。
  如果需要知道具体的方法的参数还是参考接口描述。如果遇到什么问题不妨告诉我以便修复吧,这是个新写的库,一定会存在许多问题。得慢慢修复,慢慢完善才行。
网名:
3.80.55.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^