Результат WebGL Canvas `toBlob()` показывает искаженные цветовые пятна, которых нет на холсте (причина: неверное значениJavascript

Форум по Javascript
Ответить
Anonymous
 Результат WebGL Canvas `toBlob()` показывает искаженные цветовые пятна, которых нет на холсте (причина: неверное значени

Сообщение Anonymous »

В приведенном ниже фрагменте кода я рисую текстуру на холсте слева, затем вызываю метод Canvas.toBlob() и отображаю результат в
Изображение

После некоторой отладки я обнаружил, что проблема в том, что WebGL по умолчанию устанавливает premultipliedAlpha: true, что означает, что он ожидает что значения RGB каждого пикселя в текстурах уже умножены на значение альфа, и поэтому они должны быть меньше или равны значению альфа. Однако на практике это часто не совсем так, возможно, из-за сжатия текстур. (Мое изображение в качестве примера вырезано из реальной текстуры, где я впервые заметил эту проблему.) Когда некоторые значения RGB превышают значение альфа, пиксели по-прежнему хорошо отображаются на холсте, но при преобразовании в изображение они будут выглядеть совершенно по-другому. Приведенный ниже фрагмент кода дополнительно демонстрирует эту проблему с чистым цветным фоном со значениями RGBA (1,0, 0,99, 0,99, 0,99).
Я мог бы обойти эту проблему, установив для premultipliedAlpha значение false:

Код: Выделить всё

var ctx3d = cvs3d.getContext('experimental-webgl', {premultipliedAlpha: false});
Однако это влияет на внешний вид всех пикселей со значением альфа строго от 0 до 1, а не только тех нескольких пикселей с недопустимыми значениями RGBA для premultipliedAlpha, поэтому в зависимости от сценария это может быть неудовлетворительным решением. Есть ли другой способ решить эту проблему?
Примечание. В приведенном ниже фрагменте кода код рендеринга изображения адаптирован из 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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»