阅读 79

WebGL第二十九课:针对多个绘制对象的代码重构

引子

前面的文章中,我们大多数都是在绘制一个对象,也就是说一个画面里,只调用了一次 drawArrays这个api来绘制。

那么如果,我们有多个独立的东西需要绘制的话,我们肯定就需要多次单独调用drawArrays这个api。

本次文章的目的就是用一个尽量舒服的代码结构,来完成多个绘制目标的初始化,进而渲染。

单个绘制目标

我们这次课用来做例子的单个目标,选定为一个小格子(矩形)。也就是说,我们要画出多个小格子,并且可以自由控制其中的任何一个格子,例如,大小,位置等等,而不影响其他格子的状态。

那么单个格子的模型,根据我们的管理,使用6个点,两个三角形来表示。

同时这个格子,具有一些可以调节的参数:

  • 宽 width

  • 高 height

  • x坐标

  • y坐标

  • 颜色

上面五个参数都是一个float类型,你可能会问颜色不是三个float吗?

好吧,为了简化操作,我们RGB三个数值选取一样的,所以就用一个float完事。。。。。。

下面的代码,使用了 js 里的 class 语法,这样写起来清晰一点:

class GridObject {     // 宽 高 x坐标 y坐标     // 左下角为基准点     constructor(width, height, posx, posy, color) {         this.width = width;         this.height = height;         this.posx = posx;         this.posy = posy;         this.color = color;     } } 复制代码

那么这些数据最终是要传送给gl的,我们肯定会在gl里申请一个buffer,来存储这部分数据,问题就来了:

单个格子是否使用单独的buffer?

这个答案不唯一。我们这次就用单个的buffer来存储单个的格子,而不是所有格子都用一个buffer

所以在constructor里,添加相应的变量:

constructor(......) {         ......         this.glbuffer = null;        // 存储数据的buffer         this.a_PointVertex = null;   // vertex_shader中 坐标 数据的引用          this.a_Color = null;         // vertex_shader中 颜色 数据的引用 } 复制代码

那么数据既然已经准备好了,我们就想办法,让他变成gl所需要的格式,这里不再反复提及,平坦化数据如下:

         this.data = [             // 第一个三角形             this.posx, this.posy, this.color, // 左下角点             this.posx + this.width, this.posy, this.color, // 右下角点             this.posx + this.width, this.posy + this.height, this.color, // 右上角点             // 第二个三角形             this.posx + this.width, this.posy + this.height, 1 - this.color, // 右上角点             this.posx, this.posy + this.height, 1 - this.color, // 左上角点             this.posx, this.posy, 1 - this.color, // 左下角点         ];         this.dataArr = new Float32Array(this.data);         this.pointCount = 6; // 一个格子固定六个点 两个三角形 复制代码

上面颜色部分值得一提的是,两个三角形的颜色互补,这是为了更好的观察他们。

生成数据既然好了,那么我们就将数据传入到gl中:

        this.glbuffer = gl.createBuffer(); // 创建新的buffer         gl.bindBuffer(gl.ARRAY_BUFFER, this.glbuffer);         gl.bufferData(gl.ARRAY_BUFFER, this.dataArr, gl.STATIC_DRAW); 复制代码

以上是数据生成和传入部分,那么渲染部分怎么来搞呢。

对于单个格子来说,只需要管理自己的绘制逻辑即可

  • 第一点:将当前gl中的上下文切换到当前对象相应的变量。

  • 第二点:vertex_shader 中attribute的设置。

  • 第三点:利用drawArraysapi,进行绘制。

第一点其实就一句话:

        gl.bindBuffer(gl.ARRAY_BUFFER, this.glbuffer); // 告诉下面的代码,我现在操作或者引用的buffer,是this.glbuffer,不是别的格子的buffer 复制代码

第二点, vertex_shader 里,a_PointVertex用来接收数据元的前两个数据, a_Color 用来接收数据元的第三个数据:

        this.a_PointVertex = gl.getAttribLocation(program, 'a_PointVertex');         gl.vertexAttribPointer(this.a_PointVertex, 2, gl.FLOAT, false, 12, 0);         gl.enableVertexAttribArray(this.a_PointVertex);                           this.a_Color = gl.getAttribLocation(program, 'a_Color');         gl.vertexAttribPointer(this.a_Color, 1, gl.FLOAT, false, 12, 8);         gl.enableVertexAttribArray(this.a_Color); 复制代码

最后就是绘制:

        gl.drawArrays(gl.TRIANGLES, 0, this.pointCount); 复制代码

注意上面,我们绘制的点的个数,就是 this.pointCount , 就是6个。

到了这里,我们已经把 GridObject 的大概职能搞定。

多个绘制目标

我们可以在程序初始化的时候,实例化多个 GridObject 的对象,然后分别对这些对象进行设置参数,生成数据,渲染即可。

为了观察方便,我们不妨设置两个下面的对象:

    gridOne = new GridObject(0.5, 0.5, 0, 0, 0.3);     gridOne.genData(gl);     gridTwo = new GridObject(0.5, 0.5, -0.5, -0.5, 0.3);     gridTwo.genData(gl); 复制代码

上面第一个格子,是(0,0)处;
第二个格子,是(-0.5, -0.5)处;

绘制之后的效果如下:

image.png

这和我们的预期是一致的。

利用滑竿来修改参数

我们绘制多个单独的对象的目的就是为了:可以单独的修改其中一个,而不影响另一个。

我们设置一个滑竿,来修改第一个格子的颜色。

html部分:

    <p>         <b>第一个格子的颜色:</b>         <input id="gridcolor" type="range" min="0" max="1" value="0" step="0.05" oninput="gl_draw()" />         <b id="gridcolorvalue">0</b>     </p> 复制代码

js 部分:

    gridColorDom = document.getElementById("gridcolor"); // 获取dom          gridOne.color = gridColorDom.value; // 将滑竿的值设置到第一个格子中的color中去 复制代码

问题就来了,重新设置颜色之后,需要清除当前的buffer,然后根据现有的各个参数,重新攒一个buffer出来, 所以GridObject应该包含这么一个方法:

 genData(gl) {         this.data = [             // 第一个三角形             this.posx, this.posy, this.color, // 左下角点             this.posx + this.width, this.posy, this.color, // 右下角点             this.posx + this.width, this.posy + this.height, this.color, // 右上角点             // 第二个三角形             this.posx + this.width, this.posy + this.height, 1 - this.color, // 右上角点             this.posx, this.posy + this.height, 1 - this.color, // 左上角点             this.posx, this.posy, 1 - this.color, // 左下角点         ];         this.dataArr = new Float32Array(this.data);         this.pointCount = 6; // 一个格子固定六个点 两个三角形         if (this.glbuffer != null) { // 先删掉原来的buffer             gl.deleteBuffer(this.glbuffer);             this.a_PointVertex = null;             this.a_Color = null;         }         this.glbuffer = gl.createBuffer(); // 创建新的buffer         gl.bindBuffer(gl.ARRAY_BUFFER, this.glbuffer);         gl.bufferData(gl.ARRAY_BUFFER, this.dataArr, gl.STATIC_DRAW);         this.modelUpdated = true;     } 复制代码

从上述代码可以看出,每次GridObject对象有参数修改之后,都应该调用这个方法,重新生成buffer。

所以在每次滑竿修改之后,应该这样:

    gridOne.color = gridColorDom.value; // 设置颜色值     gridOne.genData(gl);                // 重新生成buffer 复制代码

放出效果如下:

gridobject.gif

如图所见,我们的滑竿控制了第一个格子的颜色,第二个格子岿然不动。成功~


作者:庖丁解牛
链接:https://juejin.cn/post/7025531238957973541

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐