
После некоторой отладки я обнаружил, что проблема в том, что WebGL по умолчанию устанавливает premultipliedAlpha: true, что означает, что он ожидает что значения RGB каждого пикселя в текстурах уже умножены на значение альфа, и поэтому они должны быть меньше или равны значению альфа. Однако на практике это часто не совсем так, возможно, из-за сжатия текстур. (Мое изображение в качестве примера вырезано из реальной текстуры, где я впервые заметил эту проблему.) Когда некоторые значения RGB превышают значение альфа, пиксели по-прежнему хорошо отображаются на холсте, но при преобразовании в изображение они будут выглядеть совершенно по-другому. Приведенный ниже фрагмент кода дополнительно демонстрирует эту проблему с чистым цветным фоном со значениями RGBA (1,0, 0,99, 0,99, 0,99).
Я мог бы обойти эту проблему, установив для premultipliedAlpha значение false:
Код: Выделить всё
var ctx3d = cvs3d.getContext('experimental-webgl', {premultipliedAlpha: false});
Примечание. В приведенном ниже фрагменте кода код рендеринга изображения адаптирован из https://stackoverflow.com/a/12396488.
Код: Выделить всё
var img, tex, vloc, tloc, vertexBuff, texBuff;
var cvs3d = document.getElementById('cvs');
var ctx3d = cvs3d.getContext('experimental-webgl');
var uLoc;
// create shaders
var vertexShaderSrc =
"attribute vec2 aVertex;" +
"attribute vec2 aUV;" +
"varying vec2 vTex;" +
"uniform vec2 pos;" +
"void main(void) {" +
" gl_Position = vec4(aVertex + pos, 0.0, 1.0);" +
" vTex = aUV;" +
"}";
var fragmentShaderSrc =
"precision highp float;" +
"varying vec2 vTex;" +
"uniform sampler2D sampler0;" +
"void main(void){" +
" gl_FragColor = texture2D(sampler0, vTex);" +
"}";
var vertShaderObj = ctx3d.createShader(ctx3d.VERTEX_SHADER);
var fragShaderObj = ctx3d.createShader(ctx3d.FRAGMENT_SHADER);
ctx3d.shaderSource(vertShaderObj, vertexShaderSrc);
ctx3d.shaderSource(fragShaderObj, fragmentShaderSrc);
ctx3d.compileShader(vertShaderObj);
ctx3d.compileShader(fragShaderObj);
var progObj = ctx3d.createProgram();
ctx3d.attachShader(progObj, vertShaderObj);
ctx3d.attachShader(progObj, fragShaderObj);
ctx3d.linkProgram(progObj);
ctx3d.useProgram(progObj);
ctx3d.viewport(0, 0, 100, 100);
vertexBuff = ctx3d.createBuffer();
ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, vertexBuff);
ctx3d.bufferData(ctx3d.ARRAY_BUFFER, new Float32Array([-1, 1, -1, -1, 1, -1, 1, 1]), ctx3d.STATIC_DRAW);
texBuff = ctx3d.createBuffer();
ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, texBuff);
ctx3d.bufferData(ctx3d.ARRAY_BUFFER, new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]), ctx3d.STATIC_DRAW);
vloc = ctx3d.getAttribLocation(progObj, "aVertex");
tloc = ctx3d.getAttribLocation(progObj, "aUV");
uLoc = ctx3d.getUniformLocation(progObj, "pos");
img = new Image();
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABa0lEQVR4nO3Pv0sCcRjH8U8ZCnnGGcWZnnDE0VShYEgIrvoHODTU0tQ/IPg/1NrQ3Jg1tGQNYYFxSOSJlcPpddpFX8sf511XQg5tZRiFtfbeHvg+L54v8Ncom43+y/7Q3tpa8axcTp2KhYxstM/rnRdlICATjxtGp6M1rsps7dksyUb7/EitbKqmcfnc7Wo/ASN10yRep5NvAGBG7TwzaucXGfdSsdVIH6mVzewjSX57gXXYYnPbaS4QWphb9ft3HqpV6M3m+4MmZUmLinooSHKSaHqpD+gdcvv7OTdF+e4kCURRAADZUgEACACVaLooSPKuqKipL4H1RGI9Fo3GOI+H+1CPISq3EKQb1LT2EwAVANk6OFm+fzLuPgEAEJidDXAsy9EOBx0JhyMxxjoBwAWAJZpOCZKMvHKL+SH6dTt/Ee8DvspFj7nYcSfLuyb54Mx00Md5fa3rWqjvC4M0RTk8K/P+jd/u/9fTG7CvknfIF2DvAAAAAElFTkSuQmCC';
img.onload = function() {
ctx3d.clearColor(0, 0, 0, 0);
ctx3d.clear(ctx3d.COLOR_BUFFER_BIT);
tex = ctx3d.createTexture();
ctx3d.bindTexture(ctx3d.TEXTURE_2D, tex);
ctx3d.texParameteri(ctx3d.TEXTURE_2D, ctx3d.TEXTURE_MIN_FILTER, ctx3d.NEAREST);
ctx3d.texParameteri(ctx3d.TEXTURE_2D, ctx3d.TEXTURE_MAG_FILTER, ctx3d.NEAREST);
ctx3d.texImage2D(ctx3d.TEXTURE_2D, 0, ctx3d.RGBA, ctx3d.RGBA, ctx3d.UNSIGNED_BYTE, this);
ctx3d.enableVertexAttribArray(vloc);
ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, vertexBuff);
ctx3d.vertexAttribPointer(vloc, 2, ctx3d.FLOAT, false, 0, 0);
ctx3d.enableVertexAttribArray(tloc);
ctx3d.bindBuffer(ctx3d.ARRAY_BUFFER, texBuff);
ctx3d.bindTexture(ctx3d.TEXTURE_2D, tex);
ctx3d.vertexAttribPointer(tloc, 2, ctx3d.FLOAT, false, 0, 0);
ctx3d.drawArrays(ctx3d.TRIANGLE_FAN, 0, 4);
cvs3d.toBlob(blob => {
document.getElementById('img').src = URL.createObjectURL(blob);
})
};
var cvs1 = document.getElementById('cvs1');
var ctx1 = cvs1.getContext('experimental-webgl');
ctx1.clearColor(1.0, 0.99, 0.99, 0.99);
ctx1.clear(ctx1.COLOR_BUFFER_BIT);
cvs1.toBlob(blob => {
document.getElementById('img1').src = URL.createObjectURL(blob);
})Код: Выделить всё
html {
background: repeating-conic-gradient(#888 0% 25%, #777 0% 50%) 50% / 20px 20px;
}Код: Выделить всё
Подробнее здесь: https://stackoverflow.com/questions/798 ... the-canvas