阅读 168

WebGL第三十课:多个绘制对象的参数调节-颜色

本文标题:WebGL第三十课:多个绘制对象的参数调节-颜色 复制代码

友情提示

这篇文章是WebGL课程专栏的第30篇,强烈建议从前面开始看起。因为花了大量的工夫来讲解向量的概念和矩阵运算。这些基础知识会影响你的思维。

本课代码直接跳转获取:三十课代码

引子

在上篇文章中,我们可以看到,如果想更改多个绘制对象中的某一个对象的参数时,我们直接重新申请的gl中的buffer,然后重新把所有的顶点数据传入到buffer中,进而绘制。

这种办法主要是针对顶点数据不得不改的时候,比如说,你本来画的是一个格子形状的东西,但是后面需要变成球形的东西。这种时候直接替换新的顶点数据是可以的。

但是,有的时候,我们并不是想要把格子-->球形,仅仅是想换一下格子的颜色。就为了这个,整个替换顶点数据当然不好。

那怎么办呢?使用 shader 中的 uniform 变量,即可。

program uniform buffer 厘清关系

在这里,回顾一下,program 和 uniform 和 buffer 的关系。

当我们绘制三角形的时候,简单这么说:当你调用绘制api(例如gl.drawArrays)之前,必须要选定一个 program,然后调用绘制api,这个时候,program 就开始跑。
怎么跑呢?
答:迭代当前buffer中的数据,例如坐标啦,颜色啦,啥的,然后在屏幕上绘制一个点,每三个点,就用插值法,绘制中间的区域,也就是绘制一个三角形,这样就将一个buffer中的数据都绘制完成。在这个过程之前,你可以设置一下uniform变量,那么在这个绘制过程中,这个变量就会保持不变。当某一个buffer的数据绘制结束之后,你可以随时更改uniform变量,然后接着绘制。

你发现了吗?也就是说不同buffer的数据,可以共用一个 program,但是在切换buffer的时候,我们可以对uniform变量进行修改,从而得到我们的目的,那就是,不同绘制对象的某些参数,可以自由独立的控制,例如可以控制颜色。

你又发现了吗?这样写,不用重新生成buffer数据。真是个好办法!

利用 uniform 来设置颜色

首先第一步要在 fragment_shader里加一个uniform变量,按照习惯,我们命名为:u_color

由于颜色是RGB三个数组成的,这个 u_color应该是一个vec3类型:

    uniform vec3 u_color; 复制代码

然后需要在 js 代码里,获取这个uniform变量引用:

    u_color = gl.getUniformLocation(program, "u_color"); 复制代码

这块可以留意一下,获取一个变量的引用,是需要传program的,这也恰恰说明了,uniform是属于program的。

如何给这个变量传值呢?如下:

        gl.uniform3f(u_color, this.color.R, this.color.G, this.color.B); 复制代码

这里注意下,由于 u_color 变量是 vec3 类型,所以传值的时候,需要使用 uniform3f 这个api,后面需要传三个参数,分别代表 vec3 的第一个元素,第二个元素,第三个元素。

这里三个值分别代表 颜色 RGB。

好了,我们要想这个 u_color 生效,还需要真正的设置一下颜色:

      gl_FragColor = vec4(u_color, 1.0); 复制代码

看一下上面的代码,我们完全用这个uniform变量来设置颜色,而忽略buffer中的 color 部分了。所以,我们在构造buffer的时候,不用把颜色传递进去了。

    这里说一点,buffer中到底应不应该带颜色,取决于你的需求,大部分时候,buffer中是应该带上颜色的。      我们可以使用uniform这种动态的变量,和buffer中的静态颜色,进行叠加计算,从而得出好玩的效果。     这点后面再说。 复制代码

绘制多个格子

在上篇文章,我们定义了一个 GridObject 的class,来描述一个格子的行为。

其中 render 方法,根据本文提出的新做法,需要修改如下:

    render(gl, program) {         gl.bindBuffer(gl.ARRAY_BUFFER, this.glbuffer);         if (this.modelUpdated) {             this.modelUpdated = false;             if (this.a_PointVertex == null) {                 this.a_PointVertex = gl.getAttribLocation(program, 'a_PointVertex');             }         }         //////////////////////////         gl.vertexAttribPointer(this.a_PointVertex, 2, gl.FLOAT, false, 0, 0);         gl.enableVertexAttribArray(this.a_PointVertex);         gl.uniform3f(u_color, this.color.R, this.color.G, this.color.B); // 设置颜色uniform         gl.drawArrays(gl.TRIANGLES, 0, this.pointCount);                 // 绘制当前格子的buffer     } 复制代码

我们可以看到,主要就是在绘制之前,要修改一下 u_color。

如果有两个 GridObject 对象,前后分别调用 render 的话,那么设置uniform和绘制的顺序如下:

  • 第一个格子 设置 program 中的 u_color

  • 第一个格子 进行绘制 第一个格子 自己的buffer

  • 第二个格子 设置 program 中的 u_color

  • 第二个格子 进行绘制 第二个格子 自己的buffer

如果有更多的格子,只要按照这个顺序,去写逻辑,那么每个格子之间是不会乱的,而自始至终,u_color 就是一个变量,被所有的格子所共用。

还是用滑竿来做个小实验

    <p>         <b>第一个格子的颜色R:</b>         <input id="gridcolorR" type="range" min="0" max="1" value="0" step="0.01" oninput="gl_draw()" />         <b id="gridcolorRvalue">0</b>     </p>     <p>         <b>第一个格子的颜色G:</b>         <input id="gridcolorG" type="range" min="0" max="1" value="0" step="0.01" oninput="gl_draw()" />         <b id="gridcolorGvalue">0</b>     </p>     <p>         <b>第一个格子的颜色B:</b>         <input id="gridcolorB" type="range" min="0" max="1" value="0" step="0.01" oninput="gl_draw()" />         <b id="gridcolorBvalue">0</b>     </p> 复制代码

在 gl_draw 这个回调函数里,设置一下第一个格子的颜色, 然后绘制两个格子:

    gridOne.color.R = gridColorRDom.value;     gridOne.color.G = gridColorGDom.value;     gridOne.color.B = gridColorBDom.value;     gridOne.render(gl, program);     gridTwo.render(gl, program); 复制代码

效果如下:

colorgrid.gif


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


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