微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 WebGL2

如何解决在 WebGL2

我正在尝试将 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,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)
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.0 ]),gl.STATIC_DRAW)
gl.vertexAttribPointer(a_pos,0)
gl.enabLevertexAttribArray(a_pos)

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

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

gl.drawArrays(gl.LINE_LOOP,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))
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script>

解决方法

您必须为每个顶点坐标指定 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,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)
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.0 ]),gl.STATIC_DRAW)
gl.vertexAttribPointer(a_pos,gl.FLOAT,false,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,gl.STATIC_DRAW)

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

gl.drawArrays(gl.LINE_LOOP,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))
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script>


如果您使用 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,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,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,'a_pos')
const u_modelMatrix = gl.getUniformLocation(program,'u_modelMatrix')

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

gl.bindBuffer(gl.ARRAY_BUFFER,0)
gl.enableVertexAttribArray(a_pos)

gl.uniformMatrix4fv(u_modelMatrix,modelMatrix)

gl.drawArrays(gl.LINE_LOOP,gl.LINK_STATUS)) {
    return program
  }
  console.log(gl.getProgramInfoLog(shader))
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script>


但是,如果您创建一个 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,i * 16)
  gl.vertexAttribDivisor(a_modelMatrix + i,1)
}

gl.drawArrays(gl.LINE_LOOP,3)

gl.drawArraysInstanced(gl.LINE_LOOP,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,scale)

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

const a_pos = gl.getAttribLocation(program,1)
}

//gl.drawArrays(gl.LINE_LOOP,3)
gl.drawArraysInstanced(gl.LINE_LOOP,1)

function makeShader (type,gl.LINK_STATUS)) {
    return program
  }
  console.log(gl.getProgramInfoLog(shader))
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。