Resize WebGL context in iOS

2019-09-08 15:41发布

iOS WebGL has a bug, which can be reproduced with following HTML:

<html>
<head>
    <title>Resize WebGL</title>
    <meta name="viewport" content="width=device-width, user-scalable=no">
</head>
<body>

<input type="button" id="resizeButton" value="resize"><br>
<canvas id="chart" style="width:100px; height:100px; border:1px solid #000;">
    <script>
        var canvas = document.getElementById('chart');
        var gl = null;

        function resetGL() {
            var devicePixelRatio = 2; // Warning: overrides window.devicePixelRatio
            var w = Math.floor(canvas.clientWidth * devicePixelRatio);
            var h = Math.floor(canvas.clientHeight * devicePixelRatio);
            if (canvas.width != w || canvas.height != h) {
                console.log("resetGL: Setting canvas.width=" + w + " canvas.height=" + h);
                canvas.width = w;
                canvas.height = h;
            }
            if (!gl || gl.isContextLost()) {
                gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
                console.log("Allocated WebGL context: " + gl);
            }
        }

        function redraw() {
            requestAnimationFrame(function () {
                resetGL();
                gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
                gl.clearColor(1, 1, 0.8, 1);
                gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            });
        }

        var bToggle = false;
        function resize() {
            bToggle = !bToggle;
            var s = bToggle ? '50px' : '100px';
            console.log("");
            console.log("Button: Setting canvas.style.width=" + s + " canvas.style.height=" + s);
            canvas.style.width = s;
            canvas.style.height = s;
            redraw();
        }
        var button = document.getElementById('resizeButton');
        button.addEventListener("click", resize);
        redraw();
    </script>
</canvas>
<br>
Press "resize", and iOS stomps on this text!
</body>
</html>

I have uploaded this HTML to http://adam1234.s3-website-us-east-1.amazonaws.com/bug.html so you can run it easily.

For people who don't have an iOS device, I have uploaded screenshots of my iPad before and after pressing the button, which show the bug in iOS.

This code works on desktop browsers and Android, but in iOS the resized WebGL window goes outside the Canvas and stomps on stuff outside the canvas. This is a bug in iOS. The bug goes away if devicePixelRatio is set to 1, but I want to use the higher resolution of retina screens.

How can I resize a high resolution WebGL canvas in iOS?

1条回答
戒情不戒烟
2楼-- · 2019-09-08 16:06

I found a work-around. The app should put the WebGL <canvas> element inside a <div>, and recreate the <canvas> element whenever the <div> size changes. Also, the <canvas> should have no border to avoid another iOS bug in placing the GL window inside the canvas with thick border in retina displays. If you want a border, then just put the border on the <div> element.

查看更多
登录 后发表回答