【问题标题】:why is that gl.clear(gl.COLOR_BUFFER_BIT) and requestAnimationFrame will clear all the primitives I drew before为什么 gl.clear(gl.COLOR_BUFFER_BIT) 和 requestAnimationFrame 会清除我之前画的所有图元
【发布时间】:2019-01-31 10:55:05
【问题描述】:

大家好,我一直在学习 WebGL,并试图用它制作俄罗斯方块游戏。

我有几个问题想问:

  1. 对于这个游戏,我想首先绘制网格作为背景。但是我注意到,在我画线之后,如果我在之后使用gl.clear(gl.COLOR_BUFFER_BIT );,它会清除我之前画的所有线。我知道gl.clear(gl.COLOR_BUFFER_BIT ); 是关于清除颜色缓冲区(您可能会问我为什么要这样做。请耐心等待。)。然后我尝试使用gl.uniform4f( uColor, 0, 0, 0, 1); 再次将颜色发送到片段着色器,但没有帮助。

sn-p是这样的

window.onload = function(){
    getGLContext();
    initShaders();
    drawLines( 0, 0, 400,400 );
    gl.clear(gl.COLOR_BUFFER_BIT );
    gl.uniform4f( uColor, 0, 0, 0, 1);
}
  1. 对于游戏,我需要网格作为背景,我需要 requestAnimationFrame 用于游戏循环,并将在循环内渲染 Tetrominos。因此,在画完线之后,我用这个draw() 来画其他的 Tetrominos。但是它删除了我之前画的线。当我在draw() 中注释掉gl.clear(gl.COLOR_BUFFER_BIT ); 时,它会删除该行以及背景颜色。

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

这里是演示:https://codepen.io/zhenghaohe/pen/LqxpjB

希望您能回答这两个问题。谢谢!

【问题讨论】:

  • 为什么画完就清零了?您通常在绘制每一帧之前清除,而不是在绘制完之后。
  • 如果你看一下代码你就会知道我想先设置网格所以我画了一条线然后我有这个循环requestAnimationFrame 来绘制每个 Tetrominos。 requestAnimationFrame 包含 gl.clear(gl.COLOR_BUFFER_BIT ) 否则我看不到每幅画的背景颜色。这就是为什么我说画完线后我打电话给`gl.clear(gl.COLOR_BUFFER_BIT )

标签: graphics webgl webgl2


【解决方案1】:

这通常是 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);
}
&lt;canvas id="c"&gt;&lt;/canvas&gt;

使用 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 它也会清除,那是因为规范说它应该这样做

见:Why WebGL 'clear' draw to front buffer?

【讨论】:

  • 感谢您的回复!我想你是对的。但我真的很想知道这两个问题的答案: 1. 为什么gl.clear(gl.COLOR_BUFFER_BIT ); 删除了我之前绘制的原始元素 2. 为什么即使没有将gl.clear(gl.COLOR_BUFFER_BIT ); 放入render 循环中,这些东西都是从循环将替换之前在进入循环之前绘制的线?我认为它只会在线条之上绘制更多内容。
  • WebGL 只是一个用于绘制像素矩形的 API。它不记得之前画了什么。
  • 1.颜色缓冲区是绘制输出的地方。当您将COLOR_BUFFER_BIT 传递给glClear() 时,您是在告诉它,“清除输出”。 2. 如果您希望 WebGL 将新绘图与旧绘图混合,您必须调用 glEnable(GL_BLEND); 或者不要将它们绘制到相同的像素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-22
  • 2014-11-22
  • 1970-01-01
  • 2023-04-04
相关资源
最近更新 更多