почему это gl.clear (gl.COLOR_BUFFER_BIT) и requestAnimationFrame очистят все примитивы, которые я нарисовал раньше - PullRequest
0 голосов
/ 31 января 2019

Привет, ребята. Я прижимаюсь к WebGL и пытаюсь сделать из нее игру Тетрис.

У меня есть пара вопросов, которые я хотел бы задать:

  1. Для этогоВ игре я хотел сначала нарисовать сетку в качестве фона.Однако я заметил, что после того, как я нарисовал линию, если я использую gl.clear(gl.COLOR_BUFFER_BIT ); после, она очистит все линии, которые я нарисовал раньше.Я понимаю, что gl.clear(gl.COLOR_BUFFER_BIT ); - это очистка цветового буфера (и вы, вероятно, спросите, почему я хотел бы это сделать. Просто потерпите меня).Затем я попытался использовать gl.uniform4f( uColor, 0, 0, 0, 1); для повторной отправки цвета фрагментному шейдеру, но это не помогло.

Фрагмент похож на этот

window.onload = function(){
    getGLContext();
    initShaders();
    drawLines( 0, 0, 400,400 );
    gl.clear(gl.COLOR_BUFFER_BIT );
    gl.uniform4f( uColor, 0, 0, 0, 1);
}

Для игры мне нужна сетка в качестве фона, и мне нужно requestAnimationFrame для игрового цикла, и я буду рендерить Тетромино внутри цикла.Поэтому после рисования линии я использовал это draw(), чтобы нарисовать другие тетромино.Однако это удаляет линию, которую я нарисовал раньше.И когда я закомментирую gl.clear(gl.COLOR_BUFFER_BIT ); внутри draw(), он удалит строку вместе с цветом фона.

function draw() { gl.clear(gl.COLOR_BUFFER_BIT ); gl.drawArrays(gl.TRIANGLES, 0, index*6); requestAnimationFrame(draw); }

Вот демо: https://codepen.io/zhenghaohe/pen/LqxpjB

Надеюсь, вы сможете ответить на эти два вопроса.Спасибо!

1 Ответ

0 голосов
/ 31 января 2019

Как правило, так работает WebGL.

WebGL просто рисует в прямоугольнике пикселей.Нет памяти о примитивах.Там нет структуры.Есть только код и получающийся холст, представляющий собой прямоугольник пикселей.

Большинство программ / страниц WebGL очищают весь холст каждый кадр и перерисовывают 100% того, что они хотят показывать каждый раз, когда рисуют.Для тетриса общий код может быть чем-то вроде

function render()  {
  clear the canvas
  draw the grid
  draw all the stable pieces
  draw the current piece
  draw the next piece
  draw the effects
  draw the score
}

Любое знание примитивов или другой структуры полностью зависит от вашего кода.

Если вы хотите, чтобы линии сетки были статическими, либо установите статический фон с помощью CSS, либо используйте другой холст

Использование фона:

const gl = document.querySelector('#c').getContext('webgl');

function render(time) {
  time *= 0.001;

  gl.clearColor(0, 0, 0, 0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  drawBlocks(gl, time);
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);

// --- below this line not important to the answer

function drawBlocks(gl, time) {
  gl.enable(gl.SCISSOR_TEST);
  
  const numBlocks = 5;
  for (let i = 0; i < numBlocks; ++i) {
    const u = i / numBlocks;
    gl.clearColor(i / 5, i / 2 % 1, i / 3 % 1, 1);
    const x = 150 + Math.sin(time + u * Math.PI * 2) * 130;
    const y = 75 + Math.cos(time + u * Math.PI * 2) * 55;
    gl.scissor(x, y, 20, 20);
    gl.clear(gl.COLOR_BUFFER_BIT);
  }
  
  gl.disable(gl.SCISSOR_TEST);
}
#c {
  background-image: url(https://i.imgur.com/ZCfccZh.png);
}
<canvas id="c"></canvas>

Использование 2 полотен

// this is the context for the back canvas. It could also be webgl
// using a 2D context just to make the sample simpler
const ctx = document.querySelector('#back').getContext('2d');
drawGrid(ctx);

// this is the context for the front canvas
const gl = document.querySelector('#front').getContext('webgl');

function render(time) {
  time *= 0.001;

  gl.clearColor(0, 0, 0, 0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  drawBlocks(gl, time);
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);

// --- below this line not important to the answer

function drawBlocks(gl, time) {
  gl.enable(gl.SCISSOR_TEST);
  
  const numBlocks = 5;
  for (let i = 0; i < numBlocks; ++i) {
    const u = i / numBlocks;
    gl.clearColor(i / 5, i / 2 % 1, i / 3 % 1, 1);
    const x = 150 + Math.sin(time + u * Math.PI * 2) * 130;
    const y = 75 + Math.cos(time + u * Math.PI * 2) * 55;
    gl.scissor(x, y, 20, 20);
    gl.clear(gl.COLOR_BUFFER_BIT);
  }
  
  gl.disable(gl.SCISSOR_TEST);
}

function drawGrid(ctx) {
  // draw grid
  ctx.translate(-10.5, -5.5);
  ctx.beginPath();
  for (let i = 0; i < 330; i += 20) {
    ctx.moveTo(0, i);
    ctx.lineTo(330, i);
    ctx.moveTo(i, 0);
    ctx.lineTo(i, 300);
  }
  ctx.strokeStyle = "blue";
  ctx.stroke();
}
#container {
  position: relative; /* required so we can position child elements */
}
#front {
  position: absolute;
  left: 0;
  top: 0;
}
<div id="container">
  <canvas id="back"></canvas>
  <canvas id="front"></canvas>
</div>

Что касается того, почему он очищается, даже если вы не вызывали clear, это потому, что спецификация говорит, что он должен делать

См .: Почему WebGL «очищает» отрисовку переднего буфера?

...