【问题标题】:Rendering some contents at lower resolution以较低的分辨率渲染一些内容
【发布时间】:2019-02-11 15:38:38
【问题描述】:

我正在使用昂贵的海洋着色器 (https://threejs.org/examples/webgl_shaders_ocean.html),它会破坏旧移动设备的用户体验(帧速率从 60fps 下降到 20fps)。如果在渲染器上设置较低的像素比(2 而不是 3),我可以获得双倍的 FPS(大约 40fps)。我还以编程方式将画布大小减小到 50%,然后通过 CSS 将其增大以填充屏幕但分辨率较低。

这两个操作是我现在可以做的最好的事情来提高性能。但是成本很高,因为我不仅在海洋中,而且在场景中涉及的所有其他模型中都失去了很多分辨率。

我正在寻找一种方法以低分辨率渲染昂贵的部分(如此着色器材质),以在渲染后恢复它,我的意思是:在海洋网格平面上定义 onBeforeRender 以便我可以将分辨率降低到 1 /3,例如。然后,在渲染完网格之后,我可以使用 onAfterRender 来恢复原来的像素比例。我可以毫无问题地降低 onBeforeRender 的分辨率,但是当我在 AfterRender 上恢复原始的高质量分辨率时,屏幕变黑了。这些是我对https://threejs.org/examples/js/objects/Water.js的更改

scope.onBeforeRender = function ( renderer, scene, camera ) {       
    (original onBeforeRender code)

    renderer.setPixelRatio( 0.5 );
    renderer.render( scene, mirrorCamera, renderTarget, false );
};


scope.onAfterRender = function ( renderer, scene, camera ) {
    renderer.setPixelRatio( 2 );
};

我想知道这个策略是否正确。我至少在正确的道路上吗?这是一个基本的 JSFiddle 来说明这个问题。有一个名为“overrideFunctions()”的方法,它重新定义了 Water.js onBeforeRender() 以在渲染海洋之前降低像素比率。然后,我们定义“onAfterRenderer()”来恢复原始质量,以便模型可以在高分辨率上渲染。

https://jsfiddle.net/spacorum/y5398gLm

注释了三行。如果取消注释第 168 行,全局质量将降低到仅 0.25dpi。这没关系,但是如果您随后取消注释第 174 行,模型就会消失,天空呈现黑色......并且画布太小了。在渲染海洋之前,我也尝试过您的建议 renderer.clear() ,但现在没有任何区别。这么近。。


编辑 3:这是我最接近的展示我需要的东西。海洋的孤立、低分辨率版本,包括反射。如果我能设法以正常分辨率显示其余部分,那就可以做到: https://jsfiddle.net/spacorum/f63z2ceg/


编辑 4: 只是尝试使用不同的技术:主场景和背景场景。我最近已经尝试过类似的东西,但我被卡住了。在这个测试中,我设法显示了一个低分辨率版本的大海,将其背景场景渲染到 WebGLRenderTarget(仅使用窗口大小的 1/10)。它似乎有所改善,但我不确定计算是否相同,我只是以较低的分辨率显示它。无论如何,按照这种方式,我无法让球体看到海内(我想这很正常,因为它们在不同的场景中,对吧?)。 renderer.clearDepth 能以某种方式帮助这里吗? https://jsfiddle.net/spacorum/wbtcx9re/


EDIT 5:我的最新方法,混合 EDIT3 和 EDIT4。有两个场景,海洋/太阳添加到背景/次要场景和球体添加到主要场景。在不执行任何 renderer.clear() 并将 renderer.autoClear 设置为 false 的情况下,我可以渲染两个场景,并且球体“进入”添加到辅助场景的海洋,到目前为止一切都很好。 (当然还没有反射,但我可以解决这个问题,将球体的副本添加到次要场景)。然后,我可以在渲染次要场景之前降低分辨率(第 166 行)。但是如果我稍后恢复它以使球体以原始分辨率渲染(取消注释第 173 行),第一个场景消失并呈现白色。我不明白为什么两次更改分辨率会导致这种情况,我可能忘记更新后面的东西,但我看不到它:/ https://jsfiddle.net/spacorum/o91se8fz/

【问题讨论】:

    标签: performance mobile three.js render resolution


    【解决方案1】:

    海洋渲染缓慢的部分原因是环境立方体贴图的每帧重建。如果你没有靠近水的物体不断变化,你可能只需要偶尔更新一次环境贴图,或者当你切换天空之类的时候更新一次。

    编辑:只需重新阅读您的问题..您可能走在正确的道路上。您将需要自己控制帧缓冲区清除。设置renderer.autoClear = false,并在渲染缩小的海洋之前调用renderer.clear()。否则,三在渲染海洋后自动清除缓冲区。 @spacorum

    如果您不需要每帧完整的 envmap 重建,我的初始答案也可能仍然适用,并允许您以全分辨率渲染水。

    【讨论】:

    • 我已经阅读过这个(仅在相机更改时更新/渲染)但这个演示使用 FirstPersonControls 和 MobileControls(鼠标/陀螺仪)所以我猜相机无论如何都会更新每一帧。我可能错了..我会按照您的建议尝试清除渲染器,这看起来很有希望!如果我能以这种方式“低渲染”最难的部分,理论上我可以提高帧率。感谢您的回答。
    • 是的,我提到的是关于海洋着色器的编写方式。它每帧重新渲染环境立方体贴图。您可以将其修改为仅在您告诉它时重新渲染立方体贴图,这使得正常的每帧操作更便宜。
    • 我要试试这个,只渲染每两到三帧,看看它是如何工作的。顺便说一句,我添加了一个 JSFiddle,我在其中覆盖了海洋网格平面的 onBeforeRender()。我可以降低像素比,但我不可能在不渲染全黑的情况下增加它 onAfterRender()。
    • 啊对..它可能导致画布调整大小从而擦除内容。另一种方法是将海洋渲染到屏幕外渲染目标,然后将该目标用作主场景渲染的 .background。
    • 我已经按照您的建议将海洋/太阳渲染到 WebGLTarget(后来作为场景背景)。我在 EDIT3、EDIT4 和 EDIT5 中添加了这种方法和其他两种方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-07
    • 1970-01-01
    • 2020-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多