如何使用WebGL2绘制3个矩形

时间:2019-03-15 09:30:53

标签: javascript webgl shader webgl2

我能够用手工将完整的样板写到WebGL2,并且可以完成很多工作。

const canvas = document.createElement('canvas')
document.body.appendChild(canvas)

const gl = canvas.getContext('webgl2', { antialias: true })
const width = 800
const height = 500

canvas.width = width
canvas.height = height

const vertexShader = gl.createShader(gl.VERTEX_SHADER)
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)

gl.shaderSource(vertexShader, `#version 300 es

in vec3 position;
in vec4 color;

out vec4 thecolor;

void
main() {
  gl_Position = vec4(position, 1.0);

  thecolor = color;
}
`)

gl.shaderSource(fragmentShader, `#version 300 es
precision mediump float;

in vec4 thecolor;

out vec4 color;

void
main() {
  color = thecolor;
}
`)

gl.compileShader(vertexShader)
var success = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)
if (!success) throw new Error(gl.getShaderInfoLog(vertexShader))

gl.compileShader(fragmentShader)
var success = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)
if (!success) throw new Error(gl.getShaderInfoLog(fragmentShader))

const program = gl.createProgram()

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

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

const positionAttribute = gl.getAttribLocation(program, 'position')
const colorAttribute = gl.getAttribLocation(program, 'color')

gl.viewport(0, 0, width, height)
gl.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

// I don't know what the purpose of this is.
const positionVAO = gl.createVertexArray()
gl.bindVertexArray(positionVAO)

const vertexBuffer = gl.createBuffer()
const indexBuffer = gl.createBuffer()

const vertexArray = [
  // don't know how to structure this on my own.
]

const indexArray = [
  // don't know how to structure this either.
]

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexArray), gl.DYNAMIC_DRAW)

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW)

gl.enableVertexAttribArray(positionAttribute)
gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 0, 0)

gl.enableVertexAttribArray(colorAttribute)
gl.vertexAttribPointer(colorAttribute, 4, gl.FLOAT, false, 0, 0)

gl.drawElements(gl.TRIANGLES, indexArray.length, gl.UNSIGNED_SHORT, 0)

但是,其中有3条评论。

  1. 我不知道gl.createVertexArraygl.bindVertexArray的目的是什么。 This对此进行了解释。
  2. 不知道如何在vertexArray中构造顶点。
  3. 不知道如何构造indexArray中的索引。

我已经看过许多教程,但是它们通常掩盖了顶点/索引的创建和定义。他们并没有真正解释他们是如何设计或构造它们的,或者为什么是这样,所以我还不能真正重建它。我想将drawElements与索引一起使用,而不是drawArrays

想知道是否可以显示如何绘制3个矩形,每个矩形具有不同的颜色(通过vertexArray传递)。我正在想象将vertexArray中的位置/颜色进行交织,但是我不知道如何正确地做到这一点,也不知道如何将数据与indexArray关联。 “适当地”是指我对直角的Float32Array和索引的Uint32Array并没有直观的了解。如果是x, yx, y, r, g, b, a(在这种情况下,则是什么)。我不了解矩形是如何闭合的,其“表面”是彩色的。想知道是否可以帮助解释和演示这张由3种不同颜色的矩形组成的图。这将有助于巩固如何绘制WebGL!

我试图绘制它们的方法是:

const vertexArray = [
  1, 1, 1, 1, 1, 1, // x y r g b a
  0, 1, 1, 1, 1, 1,
  1, 0, 1, 1, 1, 1,
  0, 0, 1, 1, 1, 1
]

const indexArray = [
  1,
  2,
  3,
  4
]

但是它什么也没做。

1 个答案:

答案 0 :(得分:1)

关键是gl.vertexAttribPointer的最后2个参数。

第5个参数指定连续的通用顶点属性集之间的字节偏移。在您的情况下,每组属性均由类型为 float 的6个值(x y r g b a)组成。因此字节偏移为6 * 4 = 24。

第6个参数指定数组中第一个通用顶点属性的第一个组成部分的字节偏移(如果绑定了命名数组缓冲区对象)。
顶点坐标的偏移为0,因为这是前2个值。
颜色属性的偏移量为2 * 4 = 8,因为颜色属性从第3个位置开始。

因此顶点数组的规范必须为:

const vertexArray = [
    1, 1, 1, 1, 1, 1, // x y r g b a
    0, 1, 1, 1, 1, 1,
    1, 0, 1, 1, 1, 1,
    0, 0, 1, 1, 1, 1
]

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexArray), gl.DYNAMIC_DRAW)

gl.enableVertexAttribArray(positionAttribute)
gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 6*4, 0)

gl.enableVertexAttribArray(colorAttribute)
gl.vertexAttribPointer(colorAttribute, 4, gl.FLOAT, false, 6*4, 2*4)

您要绘制2个三角形:

2           0    
  +--------+         0: (1, 1)
  |       /|         1: (0, 1)
  |    /   |         2: (1, 0)
  | /      |         3: (0, 0)
  + -------+
3           1

每个三角形包含3个索引,因此索引数组必须为:

const indexArray = [ 0, 2, 3, 0, 3, 1 ]

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW)

如果使用primitive类型TRIANGLES绘制此图片,

gl.drawElements(gl.TRIANGLES, indexArray.length, gl.UNSIGNED_SHORT, 0)

然后这将形成两个具有坐标的三角形:

1st : (1, 1) -> (1, 0) -> (0, 0)
2nd : (1, 1) -> (0, 0) -> (0, 1)

当然可以改为绘制三角形条(TRIANGLE_STRIP)或三角形扇形(TRIANGLE_FAN

const indexArray = [ 2, 0, 3, 1 ]
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW)
gl.drawElements(gl.TRIANGLE_STRIP, indexArray.length, gl.UNSIGNED_SHORT, 0)
const indexArray = [ 0, 2, 3, 1 ]
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW)
gl.drawElements(gl.TRIANGLE_FAN, indexArray.length, gl.UNSIGNED_SHORT, 0)

var canvas = document.getElementById('my_canvas');

const gl = canvas.getContext('webgl2', { antialias: true })
const width = 800
const height = 500

canvas.width = width
canvas.height = height

const vertexShader = gl.createShader(gl.VERTEX_SHADER)
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)

gl.shaderSource(vertexShader, `#version 300 es

in vec3 position;
in vec4 color;

out vec4 thecolor;

void
main() {
  gl_Position = vec4(position, 1.0);

  thecolor = color;
}
`)

gl.shaderSource(fragmentShader, `#version 300 es
precision mediump float;

in vec4 thecolor;

out vec4 color;

void
main() {
  color = thecolor;
}
`)

gl.compileShader(vertexShader)
var success = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)
if (!success) throw new Error(gl.getShaderInfoLog(vertexShader))

gl.compileShader(fragmentShader)
var success = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)
if (!success) throw new Error(gl.getShaderInfoLog(fragmentShader))

const program = gl.createProgram()

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

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

const positionAttribute = gl.getAttribLocation(program, 'position')
const colorAttribute = gl.getAttribLocation(program, 'color')

gl.viewport(0, 0, width, height)
gl.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

// I don't know what the purpose of this is.
const positionVAO = gl.createVertexArray()
gl.bindVertexArray(positionVAO)

const vertexBuffer = gl.createBuffer()
const indexBuffer = gl.createBuffer()

const vertexArray = [
   1, 1, 1, 1, 0, 1, // x y r g b a
   0, 1, 1, 0, 1, 1,
   1, 0, 0, 1, 1, 1,
   0, 0, 1, 1, 0, 1
]

const indexArray = [0, 2, 3, 0, 3, 1]

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexArray), gl.DYNAMIC_DRAW)

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), gl.STATIC_DRAW)

gl.enableVertexAttribArray(positionAttribute)
gl.vertexAttribPointer(positionAttribute, 2, gl.FLOAT, false, 6*4, 0)

gl.enableVertexAttribArray(colorAttribute)
gl.vertexAttribPointer(colorAttribute, 4, gl.FLOAT, false, 6*4, 2*4)

gl.drawElements(gl.TRIANGLES, indexArray.length, gl.UNSIGNED_SHORT, 0)
<canvas id="my_canvas"></canvas>