Я не на 100% уверен, что вы спрашиваете.Вы просите сравнить на процессоре.Вы можете прочитать содержимое текстуры, прикрепив ее к кадровому буферу и вызвав gl.readPixels
.Затем вы можете сравнить все пиксели.Примечание: не все форматы текстур могут быть присоединены к кадровому буферу, но при условии, что вы используете формат, который может.Вы уже прикрепили текстуры к буферам кадров для своего пинг-понга, так что же еще нужно?
Как я уже писал в комментарии к графическому процессору, вы можете написать шейдер для сравнения 2 текстур
#version 300 es
precision highp float;
uniform sampler2D tex1;
uniform sampler2D tex2;
out vec4 outColor;
void main() {
ivec2 size = textureSize(tex1, 0); // size of mip 0
float len = 0.0;
for (int y = 0; y < size.y; ++y) {
for (int x = 0; x < size.x; ++x) {
vec4 color1 = texelFetch(tex1, ivec2(x, y), 0);
vec4 color2 = texelFetch(tex2, ivec2(x, y), 0);
vec4 diff = color1 - color2;
len = length(diff);
if (len > 0.0) break;
}
if (len > 0.0) break;
}
outColor = mix(vec4(0), vec4(1), step(len, 0.0));
}
Теперь просто нарисуйте 1 пиксель и прочитайте его с помощью readPixels.если это 0, текстуры одинаковы.Если это не так, они разные.
Код предполагает, что текстуры имеют одинаковый размер, но, конечно, если они не одинакового размера, то мы уже знаем, что они не могут быть одинаковыми.
// make 3 canvaes as sources for textures
const canvases = ['A', 'B', 'B'].map((msg) => {
const canvas = document.createElement('canvas');
canvas.width = 128;
canvas.height = 128;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, 128, 128);
ctx.font = '80px monospace';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = 'yellow';
ctx.fillText(msg, 64, 64);
document.body.appendChild(canvas);
return canvas;
});
const gl = document.createElement('canvas').getContext('webgl2');
if (!gl) { alert('need webgl2'); }
const vs = `#version 300 es
void main() {
gl_PointSize = 1.0;
gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `#version 300 es
precision highp float;
uniform sampler2D tex1;
uniform sampler2D tex2;
out vec4 outColor;
void main() {
ivec2 size = textureSize(tex1, 0); // size of mip 0
float len = 0.0;
for (int y = 0; y < size.y; ++y) {
for (int x = 0; x < size.x; ++x) {
vec4 color1 = texelFetch(tex1, ivec2(x, y), 0);
vec4 color2 = texelFetch(tex2, ivec2(x, y), 0);
vec4 diff = color1 - color2;
len = length(diff);
if (len > 0.0) break;
}
if (len > 0.0) break;
}
outColor = mix(vec4(0), vec4(1), step(len, 0.0));
}
`;
// compile shaders, link program, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const textures = canvases.map((canvas) => {
// gl.createTexture, gl.bindTexture, gl.texImage, etc.
return twgl.createTexture(gl, {src: canvas});
});
compareTextures(0, 1);
compareTextures(1, 2);
function compareTextures(ndx1, ndx2) {
gl.useProgram(programInfo.program);
// gl.activeTexture, gl.bindTexture, gl.uniform
twgl.setUniforms(programInfo, {
tex1: textures[ndx1],
tex2: textures[ndx2],
});
// draw the bottom right pixel
gl.viewport(0, 0, 1, 1);
gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point
// read the pixel
const result = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, result);
console.log('textures', ndx1, 'and', ndx2, 'are', result[0] ? 'the same' : 'not the same');
}
canvas { padding: 5px; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
Вы также можете использовать запросы окклюзии.Плюс в том, что они могут не блокировать графический процессор, как это делает readPixels.Минус в том, что вы не можете проверить их в одном и том же событии JavaScript, поэтому они могут не соответствовать вашим потребностям
// make 3 canvaes as sources for textures
const canvases = ['A', 'B', 'B'].map((msg) => {
const canvas = document.createElement('canvas');
canvas.width = 128;
canvas.height = 128;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, 128, 128);
ctx.font = '80px monospace';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = 'yellow';
ctx.fillText(msg, 64, 64);
document.body.appendChild(canvas);
return canvas;
});
const gl = document.createElement('canvas').getContext('webgl2');
if (!gl) { alert('need webgl2'); }
const vs = `#version 300 es
void main() {
gl_PointSize = 1.0;
gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `#version 300 es
precision highp float;
uniform sampler2D tex1;
uniform sampler2D tex2;
out vec4 outColor;
void main() {
ivec2 size = textureSize(tex1, 0); // size of mip 0
float len = 0.0;
for (int y = 0; y < size.y; ++y) {
for (int x = 0; x < size.x; ++x) {
vec4 color1 = texelFetch(tex1, ivec2(x, y), 0);
vec4 color2 = texelFetch(tex2, ivec2(x, y), 0);
vec4 diff = color1 - color2;
len = length(diff);
if (len > 0.0) break;
}
if (len > 0.0) break;
}
if (len > 0.0) {
discard;
}
outColor = vec4(1);
}
`;
// compile shaders, link program, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const textures = canvases.map((canvas) => {
// gl.createTexture, gl.bindTexture, gl.texImage, etc.
return twgl.createTexture(gl, {src: canvas});
});
function wait(ms = 0) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function test() {
await compareTextures(0, 1);
await compareTextures(1, 2);
}
test();
async function compareTextures(ndx1, ndx2) {
gl.clear(gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
gl.useProgram(programInfo.program);
// gl.activeTexture, gl.bindTexture, gl.uniform
twgl.setUniforms(programInfo, {
tex1: textures[ndx1],
tex2: textures[ndx2],
});
// draw the bottom right pixel
gl.viewport(0, 0, 1, 1);
const query = gl.createQuery();
gl.beginQuery(gl.ANY_SAMPLES_PASSED, query);
gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point
gl.endQuery(gl.ANY_SAMPLES_PASSED);
gl.flush();
let ready = false;
while(!ready) {
await wait();
ready = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);
}
const same = gl.getQueryParameter(query, gl.QUERY_RESULT);
console.log('textures', ndx1, 'and', ndx2, 'are', same ? 'the same' : 'not the same');
}
canvas { padding: 5px; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>