【问题标题】:How to draw 3 rectangles with WebGL2如何使用 WebGL2 绘制 3 个矩形
【发布时间】:2019-08-06 08:16:54
【问题描述】:

我几乎可以手动写出 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 个 cmets。

  1. 不知道gl.createVertexArraygl.bindVertexArray的目的是什么。This解释一下。
  2. 不知道如何构造vertexArray 中的顶点。
  3. 不知道如何构造indexArray 中的索引。

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

想知道是否可以展示如何绘制 3 个具有不同颜色的矩形(通过 vertexArray 传递)。我想象在vertexArray 中交错位置/颜色,但我不知道如何正确地做到这一点,也不知道如何将数据与indexArray 相关联。通过“正确”,我的意思是我不直观地理解顶点的Float32Array 和索引的Uint32Array 的内容。如果是x, y,或者在这种情况下是x, 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
]

但它什么也没做。

【问题讨论】:

    标签: javascript webgl shader webgl2


    【解决方案1】:

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

    第 5 个参数指定连续通用顶点属性集之间的字节偏移量。在您的情况下,每组属性包含 6 个值 (x y r g b a),类型为 float。所以字节偏移量是 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           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>

    【讨论】:

    • 想知道颜色是否应该是 4*4 而不是 3*4,因为 rgba.我还没有画出来,但这似乎很接近!
    • 我仍然不明白,在vertexArray 我只有xy,但不知何故索引知道它是三角形?我不明白。
    • @user10869858 gl.TRIANGLES in gl.drawElements 表示由 3 个连续的 indies 形成三角形基元。我试图在答案中指出这一点。
    猜你喜欢
    • 2016-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-27
    • 1970-01-01
    • 2016-08-10
    相关资源
    最近更新 更多