前端开发

webgl基础:绘制多边形

2021-01-25  本文已影响0人  yancy_1012

hi~ everybody. 又到了愉快的分享时刻了。

在前面两节内容中给大家分享了如何通过 webgl 来绘制一个点,并且介绍了着色器的一些基础知识。

当然了,仅仅只有文字的描述是不能勾起大家学习 webgl 的欲望的,还需要自己动手实现下。观察自己写的代码是如何运作的。

好了,之前的内容仅仅是绘制一个点,可能内容上略显简单了, 今天就来介绍下如何绘制多边形。

本节内容中涉及到较多的方法介绍,可先忽略。待有需要的时候查阅。

1.通过js控制图形

学习绘制多边形之前,我们先来看一个问题 -- 如何通过js来控制图形的大小、颜色……等内容

在之前的代码中,都是将这些信息固定的写在了着色器的源码中。类似于以下内容:

// 顶点着色器源代码
const VERTEX_SHADER_SOURCE = '' +
      'void main() {' +
      ' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);' +
      ' gl_PointSize = 10.0;' +
      '}'

// 片元着色器源代码
const FRAGMENT_SHADER_SOURCE = '' +
      'void main() {' +
      ' gl_FragColor = vec4(1.0,0.0,0.0,1.0);' +
      '}'

那如何用js来控制这些信息呢?字符串模板吗?nonono,当然是不行的,因为webgl有自己的渲染管线,之前也给大家介绍过,所以通过字符串模板的形式肯定是不可以的。

接下来就来看下,如何通过js来控制图形信息。

1.1 动态传入信息

动态传入图形信息总共分以下四步进行:

实例演示:

1. 定义一个着色器变量,
// 这里我们需要定义一个着色器变量 a_PointSize 
// 变量的类型是 float 因为变量的引用是在 gl_PointSize 中引用的,gl_Position 的类型是 float
// 其他的信息固定
const VERTEX_SHADER_SOURCE = '' +
      'attribute float a_PointSize;' + 
      'void main() {' +
      ' gl_Position = vec4(0.0,0.0,0.0,1.0);' +
      ' gl_PointSize = a_PointSize;' +
      '}'

const FRAGMENT_SHADER_SOURCE = '' +
      'void main() {' +
      ' gl_FragColor = vec4(1.0,0.0,0.0,1.0);' +
      '}'
2. 获取变量信息
// 初始化着色器,并获取程序对象
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE);
// 获取着色器变量
const a_Position = gl.getAttribLocation(program, 'a_Position')

// 初始化着色器方法
function initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE) {
  const vertexShader = gl.createShader(gl.VERTEX_SHADER)
  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)

  gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE)
  gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE)

  gl.compileShader(vertexShader)
  gl.compileShader(fragmentShader)

  const program = gl.createProgram()

  gl.attachShader(program, vertexShader)
  gl.attachShader(program, fragmentShader)

  gl.linkProgram(program)
  gl.useProgram(program)

  return program
}

这里将初始化着色器的方法做了一层封装。方便之后取用。

拓展1:

3. 传入数据

当准备工作就绪之后,就可以通过 js 传入数据了。

gl.vertexAttrib1f(a_PointSize, 20.0);

这里通过 gl.vertexAttrib1f(location, v1) 方法传入一个数据。

注意:因为是 a_PointSize变量是float类型 所以,这里需要传入的是 20.0 而不是 20

接下来的拓展内容里,会对 gl.vertexAttrib1f 进行详细的介绍。

4. 绘制图形
// 添加蓝色底色
gl.clearColor(0.0,0.0,1.0,1.0)
gl.clear(gl.COLOR_BUFFER_BIT)
// 绘制一个点。
gl.drawArrays(gl.POINTS, 0, 1)

拓展2:

相对于 gl.vertexAttrib1f 来说,它还有以下几个同族函数:

gl.vertexAttrib1f(location, x);
gl.vertexAttrib2f(location, x, y);
gl.vertexAttrib3f(location, x, y, z);
gl.vertexAttrib4f(location, x, y, z, w);

gl.vertexAttrib1fv(location, value);
gl.vertexAttrib2fv(location, value);
gl.vertexAttrib3fv(location, value);
gl.vertexAttrib4fv(location, value);

以上方法功能类似,都是属于赋值的方法。只不过是传入的参数不同。

栗子:

如果要给一个 vec4 类型的 a_Position 的变量赋值。所有方法的设置和结果如下。

gl.vertexAttrib1f(a_Position, 1.0);                                     // [1.0, 0.0, 0.0, 1.0]
gl.vertexAttrib2f(a_Position, 1.0, 1.0);                            // [1.0, 1.0, 0.0, 1.0]
gl.vertexAttrib3f(a_Position, 1.0, 1.0, 1.0);                   // [1.0, 1.0, 1.0, 1.0]
gl.vertexAttrib4f(a_Position, 1.0, 1.0, 1.0, 1.0);      // [1.0, 1.0, 1.0, 1.0]

gl.vertexAttrib1fv(a_Position, [1.0]);                                  // [1.0, 0.0, 0.0, 1.0]
gl.vertexAttrib2fv(a_Position, [1.0, 1.0]);                         // [1.0, 1.0, 0.0, 1.0]
gl.vertexAttrib3fv(a_Position, [1.0, 1.0, 1.0]);                // [1.0, 1.0, 1.0, 1.0]
gl.vertexAttrib4fv(a_Position, [1.0, 1.0, 1.0, 1.0]);       // [1.0, 1.0, 1.0, 1.0]

好了,烦人的前缀知识分享完了,恭喜你,能看到这里说明你有很大的耐心了。希望接下来的内容能存储到你的知识体系中。

2.绘制多边形

2.1 相关概念介绍

绘制多边形,需要了解两个概念:

这两个内容至关重要,在绘制多边形甚至之后的使用过程中都少不了这两个步骤。

2.2 绘制多边形的步骤

1. 创建缓冲区对象 -- gl.createBuffer()
const buffer = gl.createBuffer();

此方法比较简单,没有参数,返回一个创建好的缓冲区对象。

2. 绑定缓冲区对象 -- gl.bindBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);

gl.bindBuffer(target, buffer);

3. 将数据写入缓冲区对象 -- gl.bufferData()
// 首先创建一个类型化数组
const data = new Float32Array([
        -0.5,  0.5,
    -0.5, -0.5,
     0.5,  0.5,
     0.5, -0.5
])
// 将数据写入缓冲区对象
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);

gl.bufferData(target, data, usage);

4. 将缓冲区对象分配给一个着色器变量 --gl.vertexAttribPointer()
// 首先获取着色器变量
const a_Position = gl.getAttribLocation(program, 'a_Position')

// 将缓冲区对象分配给一个着色器变量
gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);

gl.vertexAttribPointer(location, size, type, normalized, stride, offset);

5. 开启attribute变量 -- gl.enableVertexAttribArray()
gl.enableVertexAttribArray(a_Position);

gl.enableVertexAttribArray(location);

完整版栗子:

const ctx = document.getElementById('canvas');
const gl = ctx.getContext('webgl');

const VERTEX_SHADER_SOURCE = '' +
      'attribute vec4 a_Position;' +
      'void main() {' +
      ' gl_Position = a_Position;' +
      ' gl_PointSize = 10.0;' +
      '}'

const FRAGMENT_SHADER_SOURCE = '' +
      'void main() {' +
      ' gl_FragColor = vec4(1.0,0.0,0.0,1.0);' +
      '}'

// 获取程序对象
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE);

// 创建缓冲区
const buffer = gl.createBuffer();
// 创建类型化数组
const data = new Float32Array([
  -0.5,  0.5,
  -0.5, -0.5,
  0.5,  0.5,
  0.5, -0.5
])
// 绑定缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
// 向缓冲区写入数据
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
// 获取 attribute 变量
const a_PointSize = gl.getAttribLocation(program, 'a_Position')
// 指定顶点数据
gl.vertexAttribPointer(a_PointSize, 2, gl.FLOAT, false, 0, 0);
// 启用 attribute 变量
gl.enableVertexAttribArray(a_PointSize)
// 绘制多边形
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)

这样,一个精美的四边形就出现在屏幕上了。

通过给 gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4) 传入不同的绘制方式,会有意想不到的效果哟~

考考你:

本文中,定义着色器变量我们使用的 attribute ,还知道其他几个变量 uniform, varying 的使用方法吗?

好了,今天的内容就分享到这里了。Bye~

上一篇下一篇

猜你喜欢

热点阅读