【问题标题】:Using mat4 attribute in WebGL2在 WebGL2 中使用 mat4 属性
【发布时间】:2021-02-12 17:05:50
【问题描述】:

我正在尝试将 4x4 矩阵作为属性传递给 WebGL2 顶点着色器。在密切关注this SO answer 之后,我一直在纠结为什么我无法成功渲染并在控制台中出现glDrawArrays: attempt to access out of range vertices in attribute 0 错误。

据我了解,mat4 在 WebGL 中表示为 vec4 的 4 倍。当我在 GPU 上查询 a_modelMatrix 位置时,我可以看到它占据了从 0 到 3 的位置,所以这看起来没问题。我将作业分成这样的 4 个部分:

for (let i = 0; i < 4; ++i) {
  gl.enableVertexAttribArray(a_modelMatrix + i)
  gl.vertexAttribPointer(a_modelMatrix + i, 4, gl.FLOAT, false, 64, i * 16)
}

但还是报错。

这是我的代码:

console.clear()

const canvas = document.createElement('canvas')
const gl = canvas.getContext('webgl')

document.body.appendChild(canvas)
canvas.width = 500
canvas.height = 500

gl.viewport(0, 0, 500, 500)

const vertexShaderSrc = `
  attribute mat4 a_modelMatrix;
  attribute vec4 a_pos;

  void main () {
    gl_Position = a_modelMatrix * a_pos;
  }
`

const fragmentShaderSrc = `
  precision highp float;

  void main () {
    gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
  }
`

const vShader = makeShader(gl.VERTEX_SHADER, vertexShaderSrc)
const fShader = makeShader(gl.FRAGMENT_SHADER, fragmentShaderSrc)
const program = makeProgram(vShader, fShader)
gl.useProgram(program)


const modelMatrix = mat4.create()
const scale = vec3.create()
vec3.set(scale, 2, 2, 2)
mat4.scale(modelMatrix, modelMatrix, scale)

const a_pos = gl.getAttribLocation(program, 'a_pos')
const a_modelMatrix = gl.getAttribLocation(program, 'a_modelMatrix')

const posBuffer = gl.createBuffer()
const modelMatrixBuffer = gl.createBuffer()

gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -0.1, 0.1, 0.1, 0.1, 0.0, 0.0 ]), gl.STATIC_DRAW)
gl.vertexAttribPointer(a_pos, 2, gl.FLOAT, false, 0, 0)
gl.enableVertexAttribArray(a_pos)

gl.bindBuffer(gl.ARRAY_BUFFER, modelMatrixBuffer)
gl.bufferData(gl.ARRAY_BUFFER, modelMatrix, gl.STATIC_DRAW)

for (let i = 0; i < 4; ++i) {
  gl.enableVertexAttribArray(a_modelMatrix + i)
  gl.vertexAttribPointer(a_modelMatrix + i, 4, gl.FLOAT, false, 64, i * 16)
}

gl.drawArrays(gl.LINE_LOOP, 0, 3)

function makeShader (type, src) {
  const shader = gl.createShader(type)
  gl.shaderSource(shader, src)
  gl.compileShader(shader)
  if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    return shader
  }
  console.log(gl.getShaderInfoLog(shader))
}

function makeProgram (vShader, fShader) {
  const program = gl.createProgram()
  gl.attachShader(program, vShader)
  gl.attachShader(program, fShader)
  gl.linkProgram(program)
  if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
    return program
  }
  console.log(gl.getProgramInfoLog(shader))
}
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"&gt;&lt;/script&gt;

【问题讨论】:

    标签: javascript glsl webgl vertex-shader webgl2


    【解决方案1】:

    您必须为每个顶点坐标指定 1 个属性。顶点不能共享 1 个矩阵属性。每个顶点坐标必须有自己的模型矩阵属性:

    at_array = new Float32Array(16*no_of_vertices)
    for (let i = 0; i < no_of_vertices; i ++) 
        mat_array.set(modelMatrix, 16*i)
    gl.bufferData(gl.ARRAY_BUFFER, mat_array, gl.STATIC_DRAW)
    

    console.clear()
    
    const canvas = document.createElement('canvas')
    const gl = canvas.getContext('webgl')
    
    document.body.appendChild(canvas)
    canvas.width = 300
    canvas.height = 300
    
    gl.viewport(0, 0, 300, 300)
    
    const vertexShaderSrc = `
      attribute mat4 a_modelMatrix;
      attribute vec4 a_pos;
    
      void main () {
        gl_Position = a_modelMatrix * a_pos;
      }
    `
    
    const fragmentShaderSrc = `
      precision highp float;
    
      void main () {
        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
      }
    `
    
    const vShader = makeShader(gl.VERTEX_SHADER, vertexShaderSrc)
    const fShader = makeShader(gl.FRAGMENT_SHADER, fragmentShaderSrc)
    const program = makeProgram(vShader, fShader)
    gl.useProgram(program)
    
    
    const modelMatrix = mat4.create()
    const scale = vec3.create()
    vec3.set(scale, 2, 2, 2)
    mat4.scale(modelMatrix, modelMatrix, scale)
    
    const a_pos = gl.getAttribLocation(program, 'a_pos')
    const a_modelMatrix = gl.getAttribLocation(program, 'a_modelMatrix')
    
    const posBuffer = gl.createBuffer()
    const modelMatrixBuffer = gl.createBuffer()
    
    gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer)
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -0.3, 0.3, 0.3, 0.3, 0.0, 0.0 ]), gl.STATIC_DRAW)
    gl.vertexAttribPointer(a_pos, 2, gl.FLOAT, false, 0, 0)
    gl.enableVertexAttribArray(a_pos)
    
    gl.bindBuffer(gl.ARRAY_BUFFER, modelMatrixBuffer)
    let mat_array = new Float32Array(16*3)
    for (let i = 0; i < 3; i ++) mat_array.set(modelMatrix, 16*i)
    gl.bufferData(gl.ARRAY_BUFFER, mat_array, gl.STATIC_DRAW)
    
    for (let i = 0; i < 4; ++i) {
      gl.enableVertexAttribArray(a_modelMatrix + i)
      gl.vertexAttribPointer(a_modelMatrix + i, 4, gl.FLOAT, false, 64, i * 16)
    }
    
    gl.drawArrays(gl.LINE_LOOP, 0, 3)
    
    function makeShader (type, src) {
      const shader = gl.createShader(type)
      gl.shaderSource(shader, src)
      gl.compileShader(shader)
      if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        return shader
      }
      console.log(gl.getShaderInfoLog(shader))
    }
    
    function makeProgram (vShader, fShader) {
      const program = gl.createProgram()
      gl.attachShader(program, vShader)
      gl.attachShader(program, fShader)
      gl.linkProgram(program)
      if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
        return program
      }
      console.log(gl.getProgramInfoLog(shader))
    }
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"&gt;&lt;/script&gt;

    如果您使用WebGL 1.0,我建议使用Uniform 变量而不是矩阵属性。制服是一个全局着色器变量:

    attribute vec4 a_pos;
    uniform mat4 u_modelMatrix;
    
    void main () {
        gl_Position = u_modelMatrix * a_pos;
    } 
    
    const u_modelMatrix = gl.getUniformLocation(program, 'u_modelMatrix')
    
    // [...]
    
    gl.uniformMatrix4fv(u_modelMatrix, false, modelMatrix)
    

    console.clear()
    
    const canvas = document.createElement('canvas')
    const gl = canvas.getContext('webgl')
    
    document.body.appendChild(canvas)
    canvas.width = 300
    canvas.height = 300
    
    gl.viewport(0, 0, 300, 300)
    
    const vertexShaderSrc = `
      attribute vec4 a_pos;
      uniform mat4 u_modelMatrix;
    
      void main () {
        gl_Position = u_modelMatrix * a_pos;
      }
    `
    
    const fragmentShaderSrc = `
      precision highp float;
    
      void main () {
        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
      }
    `
    
    const vShader = makeShader(gl.VERTEX_SHADER, vertexShaderSrc)
    const fShader = makeShader(gl.FRAGMENT_SHADER, fragmentShaderSrc)
    const program = makeProgram(vShader, fShader)
    gl.useProgram(program)
    
    
    const modelMatrix = mat4.create()
    const scale = vec3.create()
    vec3.set(scale, 2, 2, 2)
    mat4.scale(modelMatrix, modelMatrix, scale)
    
    const a_pos = gl.getAttribLocation(program, 'a_pos')
    const u_modelMatrix = gl.getUniformLocation(program, 'u_modelMatrix')
    
    const posBuffer = gl.createBuffer()
    const modelMatrixBuffer = gl.createBuffer()
    
    gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer)
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -0.3, 0.3, 0.3, 0.3, 0.0, 0.0 ]), gl.STATIC_DRAW)
    gl.vertexAttribPointer(a_pos, 2, gl.FLOAT, false, 0, 0)
    gl.enableVertexAttribArray(a_pos)
    
    gl.uniformMatrix4fv(u_modelMatrix, false, modelMatrix)
    
    gl.drawArrays(gl.LINE_LOOP, 0, 3)
    
    function makeShader (type, src) {
      const shader = gl.createShader(type)
      gl.shaderSource(shader, src)
      gl.compileShader(shader)
      if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        return shader
      }
      console.log(gl.getShaderInfoLog(shader))
    }
    
    function makeProgram (vShader, fShader) {
      const program = gl.createProgram()
      gl.attachShader(program, vShader)
      gl.attachShader(program, fShader)
      gl.linkProgram(program)
      if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
        return program
      }
      console.log(gl.getProgramInfoLog(shader))
    }
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"&gt;&lt;/script&gt;

    但是,如果您创建 WebGL 2.0 上下文:

    const gl = canvas.getContext('webgl')

    const gl = canvas.getContext('webgl2')
    

    还有一个顶点数组对象:

    const vao = gl.createVertexArray();
    gl.bindVertexArray(vao);
    

    您可以使用Instancing。 matix 属性是实例属性:

    gl.bindBuffer(gl.ARRAY_BUFFER, modelMatrixBuffer)
    gl.bufferData(gl.ARRAY_BUFFER, modelMatrix, gl.STATIC_DRAW)
    
    for (let i = 0; i < 4; ++i) {
      gl.enableVertexAttribArray(a_modelMatrix + i)
      gl.vertexAttribPointer(a_modelMatrix + i, 4, gl.FLOAT, false, 64, i * 16)
      gl.vertexAttribDivisor(a_modelMatrix + i, 1)
    }
    

    gl.drawArrays(gl.LINE_LOOP, 0, 3)

    gl.drawArraysInstanced(gl.LINE_LOOP, 0, 3, 1)
    

    console.clear()
    
    const canvas = document.createElement('canvas')
    const gl = canvas.getContext('webgl2')
    
    document.body.appendChild(canvas)
    canvas.width = 300
    canvas.height = 300
    
    gl.viewport(0, 0, 300, 300)
    
    const vertexShaderSrc = `
      attribute mat4 a_modelMatrix;
      attribute vec4 a_pos;
    
      void main () {
        gl_Position = a_modelMatrix * a_pos;
      }
    `
    
    const fragmentShaderSrc = `
      precision highp float;
    
      void main () {
        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
      }
    `
    
    const vShader = makeShader(gl.VERTEX_SHADER, vertexShaderSrc)
    const fShader = makeShader(gl.FRAGMENT_SHADER, fragmentShaderSrc)
    const program = makeProgram(vShader, fShader)
    gl.useProgram(program)
    
    
    const modelMatrix = mat4.create()
    const scale = vec3.create()
    vec3.set(scale, 2, 2, 2)
    mat4.scale(modelMatrix, modelMatrix, scale)
    
    const vao = gl.createVertexArray();
    gl.bindVertexArray(vao);
    
    const a_pos = gl.getAttribLocation(program, 'a_pos')
    const a_modelMatrix = gl.getAttribLocation(program, 'a_modelMatrix')
    
    const posBuffer = gl.createBuffer()
    const modelMatrixBuffer = gl.createBuffer()
    
    gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer)
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -0.3, 0.3, 0.3, 0.3, 0.0, 0.0 ]), gl.STATIC_DRAW)
    gl.vertexAttribPointer(a_pos, 2, gl.FLOAT, false, 0, 0)
    gl.enableVertexAttribArray(a_pos)
    
    gl.bindBuffer(gl.ARRAY_BUFFER, modelMatrixBuffer)
    gl.bufferData(gl.ARRAY_BUFFER, modelMatrix, gl.STATIC_DRAW)
    
    for (let i = 0; i < 4; ++i) {
      gl.enableVertexAttribArray(a_modelMatrix + i)
      gl.vertexAttribPointer(a_modelMatrix + i, 4, gl.FLOAT, false, 64, i * 16)
      gl.vertexAttribDivisor(a_modelMatrix + i, 1)
    }
    
    //gl.drawArrays(gl.LINE_LOOP, 0, 3)
    gl.drawArraysInstanced(gl.LINE_LOOP, 0, 3, 1)
    
    function makeShader (type, src) {
      const shader = gl.createShader(type)
      gl.shaderSource(shader, src)
      gl.compileShader(shader)
      if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        return shader
      }
      console.log(gl.getShaderInfoLog(shader))
    }
    
    function makeProgram (vShader, fShader) {
      const program = gl.createProgram()
      gl.attachShader(program, vShader)
      gl.attachShader(program, fShader)
      gl.linkProgram(program)
      if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
        return program
      }
      console.log(gl.getProgramInfoLog(shader))
    }
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"&gt;&lt;/script&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多