【问题标题】:Lower WebGL Render Resolution, and Increase FPS降低 WebGL 渲染分辨率,提高 FPS
【发布时间】:2017-12-07 16:32:18
【问题描述】:

我在将 2d 精灵渲染到 GL 画布时遇到问题。当我的浏览器在分辨率较低的显示器上时,它以比在高分辨率显示器上渲染时更高的 FPS 呈现。

Mac 视网膜显示屏:2880x1800 = ~20 FPS

外接显示器:1920x1080 = ~60 FPS

WebGL 在我的 1080 分辨率显示器上以比在 Mac Retina 显示器上更快的 FPS 进行渲染。

强制 WebGL 以较低分辨率呈现的最佳做法是什么?我已经尝试寻找资源来帮助回答这个问题,但在网上找不到任何东西。

我尝试降低分辨率如下:

var ratio = 1
var width = $(window).width();
var height = $(window).height();
if (window.screen.height * window.devicePixelRatio > 1080) {
   ratio = 1080/(window.screen.height * window.devicePixelRatio);
}
width = width*ratio;
height = height*ratio;
gl.canvas.width = width;
gl.canvas.height = height;

然后像这样设置我的视口:

gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);

更新代码

var width = $(window).width();
var height = $(window).height();
if (window.screen.height * window.devicePixelRatio > 1080) {
   glTools.ratio = 1080/(window.screen.height * window.devicePixelRatio);
} else {
   glTools.ratio = 1;
}
width = Math.round(width*glTools.ratio);
height = Math.round(height*glTools.ratio);
glTools.gl.canvas.width = width;
glTools.gl.canvas.height = height;
glTools.gl.viewport(0, 0, width, height);

性能更新 虽然这个问题的答案是正确的。我只是想指出另一个罪魁祸首是我的视频游戏中的 FPS。在我的代码中使用计时器并在我的游戏中执行非硬件加速的 css 动画会阻止线程,因此会导致稍后安排渲染。 在Obsidio处可以看到游戏以60FPS的速度渲染

【问题讨论】:

    标签: javascript html webgl


    【解决方案1】:

    每个 MDN 的 WebGL best practices:

    渲染到画布可以在不同的分辨率下完成 样式表最终会强制画布出现在。如果 在性能上苦苦挣扎,您应该考虑将渲染调低 分辨率 WebGL 上下文并使用 CSS 将其画布升级到 你想要的尺寸。


    WebGL 将根据您的画布的宽度和高度属性进行渲染。如下所示的画布:<canvas width="256" height="256"> 将以 256x256 渲染。但是,您可以通过使用 CSS 设置画布样式来放大绘图:canvas {width: 512px;height: 512px;} 将以放大的 512x512 显示渲染图像。

    运行下面的sn-p,你会看到输出:

    [Canvas internal rendering] W: 256 | H: 256
    [Actual canvas size] W: 512 | H: 512
    

    const canvas = document.querySelector("canvas"),
      ctx = canvas.getContext("webgl"),
      {
        width,
        height
      } = canvas.getBoundingClientRect();
    
    console.log(`[Canvas internal rendering] W: ${ctx.drawingBufferWidth} | H: ${ctx.drawingBufferHeight}`);
    console.log(`[Actual canvas size] W: ${width} | H: ${height}`);
    canvas {
      width: 512px;
      height: 512px;
    }
    <canvas width="256" height="256">

    查看您的代码后,您的游戏似乎“放大”的原因是因为您将viewport 绑定到您的渲染大小。不要把这些结合起来。您的视口设置绝对应该反映您的纵横比,但应该与您的绘图尺寸无关。 WebGL 会将其默认为您的画布大小,但由于您想要放大,请尝试将其设置为放大后的画布大小,看看您是否仍然可以获得缩放。从我上面的示例中,代码如下所示:

    ctx.viewport(0, 0, width, height);
    

    其中widthheight 来自计算元素的大小。


    升级示例:

    这是一个演示,展示了相同形状的不同渲染分辨率。您会在第一张图片中看到锯齿,但第二张图片应该很清晰。

    const vertSource = `
    attribute vec3 a_position;
    void main(void) {
        gl_Position = vec4((a_position * 2.0) - 1.0, 1.0);
    }`;
    
    const fragSource = `
    void main(void) {
        gl_FragColor = vec4(1.0);
    }`;
    
    const verts = [
      0.1, 0.1, 0,
      0.9, 0.1, 0,
      0.5, 0.9, 0
    ];
    
    function setupCanvas(canvas) {
      const gl = canvas.getContext("webgl");
    
      const {
        width,
        height
      } = canvas.getBoundingClientRect();
    
      gl.clearColor(0.0, 0.0, 0.0, 1.0);
      gl.enable(gl.DEPTH_TEST);
      gl.viewport(0.0, 0.0, gl.drawingBufferWidth, gl.drawingBufferHeight);
    
      console.log(`[Canvas internal rendering] W: ${gl.drawingBufferWidth} | H: ${gl.drawingBufferHeight}`);
      console.log(`[Actual canvas size] W: ${width} | H: ${height}`);
    
      const b = gl.createBuffer(),
        p = gl.createProgram(),
        v = gl.createShader(gl.VERTEX_SHADER),
        f = gl.createShader(gl.FRAGMENT_SHADER);
    
      gl.bindBuffer(gl.ARRAY_BUFFER, b);
      gl.shaderSource(v, vertSource);
      gl.compileShader(v);
      gl.shaderSource(f, fragSource);
      gl.compileShader(f);
      gl.attachShader(p, v);
      gl.attachShader(p, f);
      gl.linkProgram(p);
      gl.useProgram(p);
    
      const a = gl.getAttribLocation(p, "a_position");
      gl.vertexAttribPointer(a, 3, gl.FLOAT, false, 0, 0);
      gl.enableVertexAttribArray(a);
    
      function draw() {
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.DYNAMIC_DRAW);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        gl.drawArrays(gl.TRIANGLES, 0, verts.length / 3);
      }
      draw();
    }
    
    Array.from(document.querySelectorAll("canvas"))
      .forEach(setupCanvas);
    canvas {
      width: 512px;
      height: 512px;
    }
    <canvas width="256" height="256"></canvas>
    <canvas width="512" height="512"></canvas>

    【讨论】:

    • 我很欣赏这个答案,但设置画布元素的宽度和高度实际上只是放大了我的游戏。它似乎并没有降低 WebGL 呈现的分辨率。
    • @preventSmash 然后请发布您的代码以显示您当前的渲染方式。检查您的上下文的drawingBufferWidth
    • @preventSmash 查看我的进一步编辑。缩放来自使用带有渲染缓冲区大小的gl.viewport()
    • 感谢您到目前为止指导我。看来我正在降低分辨率。虽然我的游戏现在很模糊,但似乎不是 1080 分辨率。关于如何改进的任何建议?我已经更新了我在窗口调整大小代码中所做的事情。
    • 这是否考虑了缩放分辨率,例如在更高分辨率的显示器上,例如提到的 mb pro a?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多