Почему мой код сломался, когда я добавил атрибут цвета в WebGL? - PullRequest
0 голосов
/ 17 июня 2020

по какой-то причине в моем коде ничего не отображается, хотя я хотел, чтобы он рисовал 9999 (по причинам тестирования) прямоугольников.

const canvas = document.getElementById("canvas");
const vertexCode = `
precision mediump float;

attribute vec4 position;
uniform mat4 matrix;
attribute vec4 color;
varying vec4 col;

void main() {
  col = color;
  gl_Position = matrix * position;
}
`;
const fragmentCode = `
precision mediump float;

varying vec4 col;

void main() {
  gl_FragColor = vec4(1, 0, 0, 1);
}
`;
const width = canvas.width;
const height = canvas.height;
const gl = canvas.getContext("webgl");
if(!gl) {
  console.log("WebGL not supported");
}
const projectionMatrix = [
  2/width, 0, 0, 0,
  0, -2/height, 0, 0,
  0, 0, 1, 0,
  -1, 1, 0, 1
];


const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexCode);
gl.compileShader(vertexShader);

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentCode);
gl.compileShader(fragmentShader);

const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);

gl.linkProgram(program);

gl.useProgram(program);

const positionBuffer = gl.createBuffer();
const colorBuffer = gl.createBuffer();
const positionLocation = gl.getAttribLocation(program, "position");
const colorLocation = gl.getAttribLocation(program, `color`);
const projectionLocation = gl.getUniformLocation(program, `matrix`);
gl.enableVertexAttribArray(positionLocation);
const vertex = [
    0, 0, 0, 1,
    0, 0, 0, 1,
    0, 0, 0, 1,
    0, 0, 0, 1
  ]
const floatArray = new Float32Array(vertex);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionLocation, 4, gl.FLOAT, false, 0, 0);

gl.enableVertexAttribArray(colorLocation);
const color = [
  1, 0, 0, 1,
  1, 0, 0, 1,
  1, 0, 0, 1,
  1, 0, 0, 1
]
const colorArray = new Float32Array(color);
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, 0, 0);

gl.uniformMatrix4fv(projectionLocation, false, projectionMatrix);
function rect(x, y, w, h) {
  floatArray[0] = x;
  floatArray[1] = y;
  floatArray[4] = x + w;
  floatArray[5] = y;
  floatArray[8] = x;
  floatArray[9] = y + h;
  floatArray[12] = x + w;
  floatArray[13] = y + h;

  gl.bufferData(gl.ARRAY_BUFFER, colorArray, gl.DYNAMIC_DRAW);
  gl.bufferData(gl.ARRAY_BUFFER, floatArray, gl.DYNAMIC_DRAW);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

}
function fill(r, g, b, a) {
  colorArray[0] = r;
  colorArray[1] = g;
  colorArray[2] = b;
  colorArray[3] = a;
  // gl.bufferData(gl.ARRAY_BUFFER, colorArray, gl.DYNAMIC_DRAW);
}
let lastTime = 0;
let fpsText = document.getElementById("fps");
function animate(currentTime) {
  fpsText.textContent = (1000 / (currentTime - lastTime)).toFixed(1);
  lastTime = currentTime;
  for(let i=0;i<9999;i++) {
    fill(random(0, 1), random(0, 1), random(0, 1), 1);
    rect(random(0, 800), random(0, 600), 10, 10);
  }
  requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
function random(low, high) {
  return low + Math.random() * (high-low)
}

Итак, все работало нормально, когда я не включил атрибут цвета . Однако все начинает ломаться, когда я ввожу код gl.enableVertexAttribArray(colorLocation); и на холсте ничего не отображается. Вы можете помочь мне найти мою ошибку? Огромное спасибо. : D

Ответы [ 2 ]

1 голос
/ 25 июня 2020

Ответ от @gman почти рабочий, нам просто нужно его немного изменить.

Вот работает jsfiddle: click .

Мои изменения:

function rect(x, y, w, h) {
  floatArray[0] = x;
  floatArray[1] = y;
  floatArray[4] = x + w;
  floatArray[5] = y;
  floatArray[8] = x;
  floatArray[9] = y + h;
  floatArray[12] = x + w;
  floatArray[13] = y + h;

  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, floatArray, gl.DYNAMIC_DRAW);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

}
function fill(r, g, b, a) {
  for (let i = 0; i < 4; i++) {
    colorArray[0 + i*4] = r;
    colorArray[1 + i*4] = g;
    colorArray[2 + i*4] = b;
    colorArray[3 + i*4] = a;
  }
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, colorArray, gl.DYNAMIC_DRAW);
}
function animate(currentTime) {
  fpsText.textContent = (1000 / (currentTime - lastTime)).toFixed(1);
  lastTime = currentTime;
  for(let i=0;i<999;i++) {
    fill(random(0, 1), random(0, 1), random(0, 1), 1);
    rect(random(0, 800), random(0, 600), 20, 20);
  }
  setTimeout(() => requestAnimationFrame(animate), 500); // SLOW!
}
void main() {
  gl_FragColor = col;
}
  1. Я переместил сеттер colorBuffer в функцию fill.
  2. Нам нужно 4 значения цвета, а не одно (потому что мы рисование прямоугольников с 4 вершинами), поэтому я добавил функцию for l oop в fill.
  3. Я уменьшил количество прямоугольников до 999, увеличил размер до 20x20 - это просто для лучшего изображения:)
  4. Мне нужно немного замедлить работу с прямоугольниками, поэтому я добавил setTimeout, чтобы уменьшить частоту кадров. Если вам нужен максимальный FPS, просто используйте обычную requestAnimationFrame(animate) вместо моей SLOW! строки.
  5. Фрагментный шейдер должен использовать цвет из вершинного шейдера.
0 голосов
/ 17 июня 2020

Когда я запускаю ваш код, я получаю явную ошибку в консоли JavaScript

[. WebGL-0x7fae86814200] ОШИБКА GL: GL_INVALID_OPERATION: glDrawArrays: попытаться получить доступ к вершинам вне допустимого диапазона в атрибуте 0

Глядя на ваш код, вам нужно связать правильный буфер перед вызовом gl.bufferData для загрузки данных

У вас было это

  gl.bufferData(gl.ARRAY_BUFFER, colorArray, gl.DYNAMIC_DRAW);
  gl.bufferData(gl.ARRAY_BUFFER, floatArray, gl.DYNAMIC_DRAW);

, но это должно быть это

  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, colorArray, gl.DYNAMIC_DRAW);
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, floatArray, gl.DYNAMIC_DRAW);

const canvas = document.getElementById("canvas");
const vertexCode = `
precision mediump float;

attribute vec4 position;
uniform mat4 matrix;
attribute vec4 color;
varying vec4 col;

void main() {
  col = color;
  gl_Position = matrix * position;
}
`;
const fragmentCode = `
precision mediump float;

varying vec4 col;

void main() {
  gl_FragColor = vec4(1, 0, 0, 1);
}
`;
const width = canvas.width;
const height = canvas.height;
const gl = canvas.getContext("webgl");
if(!gl) {
  console.log("WebGL not supported");
}
const projectionMatrix = [
  2/width, 0, 0, 0,
  0, -2/height, 0, 0,
  0, 0, 1, 0,
  -1, 1, 0, 1
];


const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexCode);
gl.compileShader(vertexShader);

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentCode);
gl.compileShader(fragmentShader);

const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);

gl.linkProgram(program);

gl.useProgram(program);

const positionBuffer = gl.createBuffer();
const colorBuffer = gl.createBuffer();
const positionLocation = gl.getAttribLocation(program, "position");
const colorLocation = gl.getAttribLocation(program, `color`);
const projectionLocation = gl.getUniformLocation(program, `matrix`);
gl.enableVertexAttribArray(positionLocation);
const vertex = [
    0, 0, 0, 1,
    0, 0, 0, 1,
    0, 0, 0, 1,
    0, 0, 0, 1
  ]
const floatArray = new Float32Array(vertex);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionLocation, 4, gl.FLOAT, false, 0, 0);

gl.enableVertexAttribArray(colorLocation);
const color = [
  1, 0, 0, 1,
  1, 0, 0, 1,
  1, 0, 0, 1,
  1, 0, 0, 1
]
const colorArray = new Float32Array(color);
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, 0, 0);

gl.uniformMatrix4fv(projectionLocation, false, projectionMatrix);
function rect(x, y, w, h) {
  floatArray[0] = x;
  floatArray[1] = y;
  floatArray[4] = x + w;
  floatArray[5] = y;
  floatArray[8] = x;
  floatArray[9] = y + h;
  floatArray[12] = x + w;
  floatArray[13] = y + h;

  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, colorArray, gl.DYNAMIC_DRAW);
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, floatArray, gl.DYNAMIC_DRAW);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

}
function fill(r, g, b, a) {
  colorArray[0] = r;
  colorArray[1] = g;
  colorArray[2] = b;
  colorArray[3] = a;
  //gl.bufferData(gl.ARRAY_BUFFER, colorArray, gl.DYNAMIC_DRAW);
}
let lastTime = 0;
let fpsText = document.getElementById("fps");
function animate(currentTime) {
  fpsText.textContent = (1000 / (currentTime - lastTime)).toFixed(1);
  lastTime = currentTime;
  for(let i=0;i<9999;i++) {
    fill(random(0, 1), random(0, 1), random(0, 1), 1);
    rect(random(0, 800), random(0, 600), 10, 10);
  }
  requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
function random(low, high) {
  return low + Math.random() * (high-low)
}
<canvas id="canvas" width="800" height="600"></canvas>
<div id="fps"></div>
...