WebGL 2.0错误:glDrawArrays:试图访问属性0中超出范围的顶点



我一直在学习WebGL技术。不幸的是,我遇到了一些错误。我想为直升机绘制2D两个形状。我在下面写了代码。我想做的就是在一个叫做身体的形状上做一个螺旋桨。

请注意,我试图创建一个新的缓冲区并绑定它,但仍然失败了。我认为步幅还没有被理解,但我想学习如何解决它,即使它很简单。

// Vertex shader
var _vertexShader = `
attribute vec4 _position;
void main() {
gl_Position = _position;
}
`
// Fragment shader
var _fragmentShader = `
precision mediump float;
void main() {
gl_FragColor = vec4(0.6, 0.8, 0.3, 1);
}
`
// Create shader
function createShader(gl, type, source) {
var shader = gl.createShader(type)
gl.shaderSource(shader, source)
gl.compileShader(shader)
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS)
if (success) {
return shader
} else {
console.log(gl.getShaderInfoLog(shader))
gl.deleteShader(shader)
// return false
}
}
// Linking shader by program
function createProgram(gl, vertexShader, fragmentShader) {
var program = gl.createProgram()
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
gl.linkProgram(program)
var success = gl.getProgramParameter(program, gl.LINK_STATUS)
if (success) {
return program
} else {
console.log(gl.getProgramInfoLog(program))
gl.deleteProgram(program)
// return false
}
}
function main() {
// Get a WebGL context.
var canvas = document.getElementById('canvas')
var gl = canvas.getContext('webgl2')
if (!gl) {
alert('Not support.')
return false
}
// Get the strings for our GLSL shaders.
var vertexShader = createShader(gl, gl.VERTEX_SHADER, _vertexShader)
var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, _fragmentShader)
// Link the two shaders into a program.
var program = createProgram(gl, vertexShader, fragmentShader)
// Look up where the vertex data need to go.
var positionLoc = gl.getAttribLocation(program, '_position')
// Create a buffer and put the three 2d clip space points in it.
var body_positionBuf = gl.createBuffer()
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = body_positionBuf).
gl.bindBuffer(gl.ARRAY_BUFFER, body_positionBuf)
var body_positions = new Float32Array(
[
// Body triangle (Right)
-0.25,  0,
0.25,  0,
0, 0.5,
// Body triangle (Left) 
-0.15, 0,
0.15, 0,
0.15, -0.25,
// Body square
-0.15, 0,
-0.15, -0.25,
0.15, -0.25,
]   
)
var roter_positions = new Float32Array([
0.15, 0.1,
0.15, -0.1,
-0.15, 0.1,
-0.15, -0.1,
-0.15, 0.1,
0.15, 0.1,
])
gl.bufferData(gl.ARRAY_BUFFER, body_positions, gl.STATIC_DRAW)
// Code above this line is initialization code.
// Code below this line is rendering code.
// webglUtils.resizeCanvasToDisplaySize(gl.canvas)
// Tell WebGL how to convert from clip space to pixels.
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height)
// Clear the canvas.
gl.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT)

// Tell it to use our program (pair of shaders).
gl.useProgram(program)
// Turn on the attribute.
gl.enableVertexAttribArray(positionLoc)
// Bind the position buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, body_positionBuf)
// Tell the attribute how to get data out of body_positionBuf (ARRAY_BUFFER).
var size = 2
var type = gl.FLOAT
var normalize = false
var stride = 0
var offset = 0 
gl.vertexAttribPointer(positionLoc, size, type, normalize, stride, offset)
// Draw.
var drawType = gl.TRIANGLES
var count = body_positions.length / 2
gl.drawArrays(drawType, offset, count)
}
main()
<canvas id="canvas" width="500" height="250"></canvas>

我该怎么办?我不知道。。请帮帮我,谢谢。

body_positions中指定的所有顶点的第一个坐标覆盖在roter_positions中指定的顶点
更改顶点坐标:

var roter_positions = new Float32Array([
0.15, 0.6,
0.15, 0.4,
-0.15, 0.6,
-0.15, 0.4,
-0.15, 0.6,
0.15, 0.6,
])

注意,我建议使用模型矩阵来单独定义每个对象的位置和方向。但先解决你的问题,然后采取下一步行动。

如果你想使用2个缓冲区,那么你必须创建2个缓冲对象,并且你必须定义这两个对象的数据存储:

var body_positionBuf = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, body_positionBuf)
gl.bufferData(gl.ARRAY_BUFFER, body_positions, gl.STATIC_DRAW)
var roter_positionBuf = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, roter_positionBuf)
gl.bufferData(gl.ARRAY_BUFFER, roter_positions, gl.STATIC_DRAW)  

最后,可以通过两个分离的绘制调用在两个分离缓冲区中绘制网格。在每次绘制调用之前,您必须定义通用顶点属性数据的数组:

gl.bindBuffer(gl.ARRAY_BUFFER, body_positionBuf)
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0)       
gl.drawArrays(gl.TRIANGLES, 0, body_positions.length / 2)
gl.bindBuffer(gl.ARRAY_BUFFER, roter_positionBuf)
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0)       
gl.drawArrays(gl.TRIANGLES, 0, roter_positions.length / 2)

参见示例,eher我将更改应用于您的原始代码:

// Vertex shader
var _vertexShader = `
attribute vec4 _position;
void main() {
gl_Position = _position;
}
`
// Fragment shader
var _fragmentShader = `
precision mediump float;
void main() {
gl_FragColor = vec4(0.6, 0.8, 0.3, 1);
}
`
// Create shader
function createShader(gl, type, source) {
var shader = gl.createShader(type)
gl.shaderSource(shader, source)
gl.compileShader(shader)
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS)
if (success) {
return shader
} else {
console.log(gl.getShaderInfoLog(shader))
gl.deleteShader(shader)
// return false
}
}
// Linking shader by program
function createProgram(gl, vertexShader, fragmentShader) {
var program = gl.createProgram()
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
gl.linkProgram(program)
var success = gl.getProgramParameter(program, gl.LINK_STATUS)
if (success) {
return program
} else {
console.log(gl.getProgramInfoLog(program))
gl.deleteProgram(program)
// return false
}
}
function main() {
// Get a WebGL context.
var canvas = document.getElementById('canvas')
var gl = canvas.getContext('webgl2')
if (!gl) {
alert('Not support.')
return false
}
// Get the strings for our GLSL shaders.
var vertexShader = createShader(gl, gl.VERTEX_SHADER, _vertexShader)
var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, _fragmentShader)
// Link the two shaders into a program.
var program = createProgram(gl, vertexShader, fragmentShader)
// Look up where the vertex data need to go.
var positionLoc = gl.getAttribLocation(program, '_position')
// Create a buffer and put the three 2d clip space points in it.

var body_positions = new Float32Array(
[
// Body triangle (Right)
-0.25,  0,
0.25,  0,
0, 0.5,
// Body triangle (Left) 
-0.15, 0,
0.15, 0,
0.15, -0.25,
// Body square
-0.15, 0,
-0.15, -0.25,
0.15, -0.25,
]   
)
var roter_positions = new Float32Array([
0.15, 0.6,
0.15, 0.4,
-0.15, 0.6,
-0.15, 0.4,
-0.15, 0.6,
0.15, 0.6,
])
var body_positionBuf = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, body_positionBuf)
gl.bufferData(gl.ARRAY_BUFFER, body_positions, gl.STATIC_DRAW)
var roter_positionBuf = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, roter_positionBuf)
gl.bufferData(gl.ARRAY_BUFFER, roter_positions, gl.STATIC_DRAW)

// webglUtils.resizeCanvasToDisplaySize(gl.canvas)
// Tell WebGL how to convert from clip space to pixels.
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height)
// Clear the canvas.
gl.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT)

// Tell it to use our program (pair of shaders).
gl.useProgram(program)
// Turn on the attribute.
gl.enableVertexAttribArray(positionLoc)
// Bind the position buffer.

gl.bindBuffer(gl.ARRAY_BUFFER, body_positionBuf)
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0)       
gl.drawArrays(gl.TRIANGLES, 0, body_positions.length / 2)
gl.bindBuffer(gl.ARRAY_BUFFER, roter_positionBuf)
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0)       
gl.drawArrays(gl.TRIANGLES, 0, roter_positions.length / 2)
}
main();
<canvas id="canvas" width="500" height="250"></canvas>


当然,您可以将2个数组添加到1个缓冲区中。您必须创建一个带有数据存储的缓冲区,该缓冲区对于两个数组都足够大。通过gl.bufferData:将数据添加到缓冲区

var body_bytes = body_positions.length * 4;
var roter_bytes = roter_positions.length * 4;
var common_positionBuf = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, common_positionBuf)
gl.bufferData(gl.ARRAY_BUFFER, body_bytes + roter_bytes, gl.STATIC_DRAW); 
gl.bufferSubData(gl.ARRAY_BUFFER, 0, body_positions);
gl.bufferSubData(gl.ARRAY_BUFFER, body_bytes, roter_positions);

网格可以通过单次绘制调用绘制:

gl.bindBuffer(gl.ARRAY_BUFFER, common_positionBuf)
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0) 
var no_of_vertices = (body_positions.length + roter_positions.length) / 2      
gl.drawArrays(gl.TRIANGLES, 0, no_of_vertices)

如果在绘制第二个网格(例如,模型矩阵统一(之前,必须更改一些程序资源,那么这也可以通过两个绘制调用来完成:

gl.drawArrays(gl.TRIANGLES, 0, body_positions.length / 2)
// change resources here ...
gl.drawArrays(gl.TRIANGLES, body_positions.length / 2, roter_positions.length / 2)

参见示例,基于问题中的原始代码:

// Vertex shader
var _vertexShader = `
attribute vec4 _position;
void main() {
gl_Position = _position;
}
`
// Fragment shader
var _fragmentShader = `
precision mediump float;
void main() {
gl_FragColor = vec4(0.6, 0.8, 0.3, 1);
}
`
// Create shader
function createShader(gl, type, source) {
var shader = gl.createShader(type)
gl.shaderSource(shader, source)
gl.compileShader(shader)
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS)
if (success) {
return shader
} else {
console.log(gl.getShaderInfoLog(shader))
gl.deleteShader(shader)
// return false
}
}
// Linking shader by program
function createProgram(gl, vertexShader, fragmentShader) {
var program = gl.createProgram()
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
gl.linkProgram(program)
var success = gl.getProgramParameter(program, gl.LINK_STATUS)
if (success) {
return program
} else {
console.log(gl.getProgramInfoLog(program))
gl.deleteProgram(program)
// return false
}
}
function main() {
// Get a WebGL context.
var canvas = document.getElementById('canvas')
var gl = canvas.getContext('webgl2')
if (!gl) {
alert('Not support.')
return false
}
// Get the strings for our GLSL shaders.
var vertexShader = createShader(gl, gl.VERTEX_SHADER, _vertexShader)
var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, _fragmentShader)
// Link the two shaders into a program.
var program = createProgram(gl, vertexShader, fragmentShader)
// Look up where the vertex data need to go.
var positionLoc = gl.getAttribLocation(program, '_position')
// Create a buffer and put the three 2d clip space points in it.

var body_positions = new Float32Array(
[
// Body triangle (Right)
-0.25,  0,
0.25,  0,
0, 0.5,
// Body triangle (Left) 
-0.15, 0,
0.15, 0,
0.15, -0.25,
// Body square
-0.15, 0,
-0.15, -0.25,
0.15, -0.25,
]   
)
var roter_positions = new Float32Array([
0.15, 0.6,
0.15, 0.4,
-0.15, 0.6,
-0.15, 0.4,
-0.15, 0.6,
0.15, 0.6,
])
var body_bytes = body_positions.length * 4;
var roter_bytes = roter_positions.length * 4;
var common_positionBuf = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, common_positionBuf)
gl.bufferData(gl.ARRAY_BUFFER, body_bytes + roter_bytes, gl.STATIC_DRAW); 
gl.bufferSubData(gl.ARRAY_BUFFER, 0, body_positions);
gl.bufferSubData(gl.ARRAY_BUFFER, body_bytes, roter_positions);
// webglUtils.resizeCanvasToDisplaySize(gl.canvas)
// Tell WebGL how to convert from clip space to pixels.
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height)
// Clear the canvas.
gl.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT)

// Tell it to use our program (pair of shaders).
gl.useProgram(program)
// Turn on the attribute.
gl.enableVertexAttribArray(positionLoc)
// Bind the position buffer.

gl.bindBuffer(gl.ARRAY_BUFFER, common_positionBuf)
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0) 
var no_of_vertices = (body_positions.length + roter_positions.length) / 2      
gl.drawArrays(gl.TRIANGLES, 0, no_of_vertices)
}
main();
<canvas id="canvas" width="500" height="250"></canvas>

最新更新