#webgl #mobile-safari #framebuffer
#webgl #mobile-safari #фреймбуфер
Вопрос:
По какой-то причине рендеринг в фреймбуфер, а затем из буфера на экран, похоже, не работает в мобильном Safari. У меня не было возможности проверить desktop Safari, но мой Firefox отлично отображает логотип Microsoft, на моем телефоне я просто вижу границу:
const dmnsn = [800, 600],
glCtx = twgl.getContext(document.createElement("canvas")),
imgLc =
"https://upload.wikimedia.org/wikipedia/commons/b/b6/Microsoft_logo_(1987).svg";
var bfInf = twgl.primitives.createXYQuadBufferInfo(glCtx),
pgInf = twgl.createProgramInfo(glCtx, ["vs", "fs"]),
imgTx = twgl.createTexture(glCtx, { src: imgLc }, tstSB),
scnBf = twgl.createFramebufferInfo(glCtx, [{ wrap: glCtx.REPEAT}],dmnsn[0],dmnsn[1]);
function plcCv() {
document.body.append(glCtx.canvas);
glCtx.canvas.width = dmnsn[0];
glCtx.canvas.height = dmnsn[1];
}
function drwTx(tx, fbi, fy) {
twgl.bindFramebufferInfo(glCtx, fbi);
twgl.drawObjectList(glCtx, [
{
programInfo: pgInf,
bufferInfo: bfInf,
uniforms: { u_texture: tx, u_flipy: fy }
}
]);
}
function tstSB() {
plcCv();
drwTx(imgTx, scnBf, true);
drwTx(scnBf.attachments[0], null, false);
}
html{
height:100%;
}
body{
margin:0;
height:100%;
display: flex;
align-items: center;
justify-content: center;
}
canvas{
border-style:solid;
}
<script id="vs" type="x-shader/x-vertex">
attribute vec4 position;
attribute vec2 texcoord;
uniform bool u_flipy;
varying vec2 v_texcoord;
void main() {
if(u_flipy) {
v_texcoord = vec2(texcoord.x, 1.0 - texcoord.y);
} else {
v_texcoord = texcoord;
}
gl_Position = position;
}
</script>
<script id="fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_texture;
void main() {
gl_FragColor=texture2D(u_texture,v_texcoord);
}
</script>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
Я знаю, что рисование SVGS является несколько экспериментальным, но, похоже, это отлично работает и в мобильном Safari.
Ответ №1:
Проверка ошибок в Safari, которые я вижу
WebGL: drawElements: текстура, привязанная к текстурному блоку 0, не поддается рендерингу. Возможно, он не имеет мощности 2 и имеет несовместимую фильтрацию текстур или не является «текстурным завершенным», или это тип с плавающей точкой / полуплавающей точкой с линейной фильтрацией и без соответствующего линейного расширения с плавающей точкой / полуплавающей точкой. Включено.
Чтобы выяснить, в какой текстуре возникла проблема, использовал webgl-lint и добавил эти строки
const ext = glCtx.getExtension('GMAN_debug_helper');
const tagObject = ext ? ext.tagObject.bind(ext) : () => {};
tagObject(imgTx, 'imgTx');
tagObject(scnBf.attachments[0], 'colorAttach');
Затем я получил эту ошибку
ошибка в drawElements(TRIANGLES, 6, UNSIGNED_SHORT, 0): текстура WebGLTexture («colorAttach») на текстурном блоке 0, на который ссылается uniform sampler2D u_texture, не поддается визуализации: ширина текстуры (800) не равна степени 2, а высота (600) не равна степени 2, но TEXTURE_WRAP_S (ПОВТОР) не является CLAMP_TO_EDGE и TEXTURE_WRAP_T (ПОВТОР) не является CLAMP_TO_EDGE. с WebGLProgram («неназванный«) в качестве текущей программы с привязкой к массиву вершин по умолчанию
Проблема в том, что twgl.getContext
возвращает WebGL2 в Chrome / Firefox, но только WebGL1 в Safari (который пока не поддерживает WebGL2)
Я добавил этот webgl-помощник для отключения WebGL2, и я получаю ту же ошибку в Chrome.
Если вы просто хотите, чтобы WebGL1 всегда, тогда не используйте twgl.getContext
.
В противном случае вы можете исправить это, изменив строку для twgl.createFramebufferInfo
, чтобы установить параметры, совместимые с WebGL1
scnBf = twgl.createFramebufferInfo(glCtx, [{ }],dmnsn[0],dmnsn[1]);
IIRC значения по умолчанию в twgl для createFramebufferInfo являются wrap: CLAMP_TO_EDGE
, minMag: LINEAR
const dmnsn = [800, 600],
glCtx = twgl.getContext(document.createElement("canvas")),
imgLc =
"https://upload.wikimedia.org/wikipedia/commons/b/b6/Microsoft_logo_(1987).svg";
var bfInf = twgl.primitives.createXYQuadBufferInfo(glCtx),
pgInf = twgl.createProgramInfo(glCtx, ["vs", "fs"]),
imgTx = twgl.createTexture(glCtx, { src: imgLc }, tstSB),
scnBf = twgl.createFramebufferInfo(glCtx, [{ }],dmnsn[0],dmnsn[1]);
function plcCv() {
document.body.append(glCtx.canvas);
glCtx.canvas.width = dmnsn[0];
glCtx.canvas.height = dmnsn[1];
}
function drwTx(tx, fbi, fy) {
twgl.bindFramebufferInfo(glCtx, fbi);
twgl.drawObjectList(glCtx, [
{
programInfo: pgInf,
bufferInfo: bfInf,
uniforms: { u_texture: tx, u_flipy: fy }
}
]);
}
function tstSB() {
plcCv();
drwTx(imgTx, scnBf, true);
drwTx(scnBf.attachments[0], null, false);
}
html{
height:100%;
}
body{
margin:0;
height:100%;
display: flex;
align-items: center;
justify-content: center;
}
canvas{
border-style:solid;
}
<script id="vs" type="x-shader/x-vertex">
attribute vec4 position;
attribute vec2 texcoord;
uniform bool u_flipy;
varying vec2 v_texcoord;
void main() {
if(u_flipy) {
v_texcoord = vec2(texcoord.x, 1.0 - texcoord.y);
} else {
v_texcoord = texcoord;
}
gl_Position = position;
}
</script>
<script id="fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_texture;
void main() {
gl_FragColor=texture2D(u_texture,v_texcoord);
}
</script>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
Комментарии:
1. Большое спасибо за ответ! Теперь я вспоминаю, что я уже знал, что
twgl.getContext
по умолчанию используется WebGL2, но я как-то забыл! Я думаю, поскольку я работал с кодом WebGL, я предположил, что контекст также должен быть WebGL, но контекст WebGL2, конечно, может работать с кодом WebGL!