Как правило, так работает 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 «очищает» отрисовку переднего буфера?