Что сказал @pleup.Canvas 2d значения всегда записываются в холст предварительно умноженным.Это означает, что в тот момент, когда вы позвонили putImageData
, ваши данные были умножены на альфа, и данные были потеряны.
const ctx = document.createElement("canvas").getContext("2d");
const imgData = ctx.createImageData(2, 2);
const data = imgData.data;
data[ 0] = 255; data[ 3] = 255;
data[ 4] = 255; data[ 7] = 192;
data[ 8] = 255; data[11] = 64;
data[12] = 255; data[15] = 0;
ctx.putImageData(imgData, 0, 0);
const newImgData = ctx.getImageData(0, 0, 2, 2);
const newData = newImgData.data;
console.log(newData[ 0], newData[ 3]);
console.log(newData[ 4], newData[ 7]);
console.log(newData[ 8], newData[11]);
console.log(newData[12], newData[15]);
Использование 255 для цвета частично скрывает проблему, поскольку то, что находится на 2d-холсте после вызова putImageData
, равно
red = 255 alpha = 255
red = 192 alpha = 192
red = 64 alpha = 64
red = 0 alpha = 0
без умножения (при загрузке вWebGL) вы получаете 255 секунд назад для всех значений, кроме 0
red alpha result
red = 255 alpha = 255 = 255 * 255 / 255 = 255
red = 192 alpha = 192 = 192 * 255 / 192 = 255
red = 64 alpha = 64 = 64 * 255 / 64 = 255
red = 0 alpha = 0 = 0 * 0 = 0
Если значение цвета было скажем 20 и разные альфа
red = 20 * 10 / 255 = 1 alpha = 10
red = 20 * 7 / 255 = 1 alpha = 7
red = 20 * 4 / 255 = 0 alpha = 4
red = 20 * 0 / 255 = 0 alpha = 0
А затем без умножения получается
1 * 255 / 10 = 26 not even close to what we put in
1 * 255 / 7 = 36 not even close to what we put in
0 * 255 / 4 = 0
0 * 0 = 0
Просто указываю, как это с потерями.
const ctx = document.createElement("canvas").getContext("2d");
const imgData = ctx.createImageData(2, 2);
const data = imgData.data;
data[ 0] = 20; data[ 3] = 10;
data[ 4] = 20; data[ 7] = 7;
data[ 8] = 20; data[11] = 4;
data[12] = 20; data[15] = 0;
ctx.putImageData(imgData, 0, 0);
const newImgData = ctx.getImageData(0, 0, 2, 2);
const newData = newImgData.data;
console.log(newData[ 0], newData[ 3]);
console.log(newData[ 4], newData[ 7]);
console.log(newData[ 8], newData[11]);
console.log(newData[12], newData[15]);
Если вы действительно хотите вручную поместить данные в текстуру в WebGL, вам просто нужно использовать typedArray
const width = 2;
const height = 2;
const data = new Uint8Array(width * height * 4);
data[ 0] = 255; data[ 3] = 255;
data[ 4] = 255; data[ 7] = 192;
data[ 8] = 255; data[11] = 64;
data[12] = 255; data[15] = 0;
const level = 0;
const internalFormat = gl.RGBA;
const border = 0;
const format = gl.RGBA;
const type = gl.UNSIGNED_BYTE;
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, border,
format, type, data);
Если вы хотите прочитать эти данныевместо того, чтобы проходить через 2D холст, просто позвоните gl.readPixels
const newData = new Uint8Array(width * height * 4);
gl.readPixels(0, 0, width, height, format, type);
const gl = document.querySelector("canvas").getContext("webgl", {
premultipliedAlpha: false,
});
const VERTEX_SHADER = `
attribute vec4 a_Position;
attribute vec2 a_TexCoord;
varying vec2 v_TexCoord;
void main() {
gl_Position = a_Position;
v_TexCoord = a_TexCoord;
}
`;
const FRAGMENT_SHADER = `
precision mediump float;
uniform sampler2D u_Sampler;
varying vec2 v_TexCoord;
void main() {
gl_FragColor = texture2D(u_Sampler, v_TexCoord);
}
`;
const vshader = gl.createShader(gl.VERTEX_SHADER);
const fshader = gl.createShader(gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.shaderSource(vshader, VERTEX_SHADER);
gl.shaderSource(fshader, FRAGMENT_SHADER);
gl.compileShader(vshader);
gl.compileShader(fshader);
gl.attachShader(program, vshader);
gl.attachShader(program, fshader);
gl.linkProgram(program);
gl.useProgram(program);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
const farr = new Float32Array([
-1, 1, 0, 1,
-1, -1, 0, 0,
1, 1, 1, 1,
1, -1, 1, 0
]);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, farr, gl.STATIC_DRAW);
const a_Position = gl.getAttribLocation(program, "a_Position");
const a_TexCoord = gl.getAttribLocation(program, "a_TexCoord");
const fsize = farr.BYTES_PER_ELEMENT;
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 4 * fsize, 0);
gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, 4 * fsize, 2 * fsize);
gl.enableVertexAttribArray(a_Position);
gl.enableVertexAttribArray(a_TexCoord);
const pixels = new Uint8Array(2 * 2 * 4);
pixels.fill(255);
pixels[0 * 4 + 3] = 0;
pixels[1 * 4 + 3] = 1;
pixels[2 * 4 + 3] = 128;
const texture = gl.createTexture();
const u_Sampler = gl.getUniformLocation(program, "u_Sampler");
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
canvas { background: red; }
<canvas></canvas>