- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
更新:本文是为 Quest 1 开发人员编写的。虽然 Quest 2 建立在相同的架构上,但现在更容易为阴影贴图(以及其他需要从先前渲染过程中生成的纹理读取的简单技术)做预算.
尽管移动芯片组可以支持下面概述的大多数技术,但我们强烈建议你不要这样做。不过,这并不总是一成不变的规则,因为我有看到开发者有实现下述技术但依然达到帧速率的要求。但通过避免下文提及的 PC 渲染技术,你会避免很多麻烦.
延迟渲染(或(延迟 shader)[ https://en.wikipedia.org/wiki/Deferred_shading ]), 这种技术是将光照/渲染计算推迟到第二步进行计算。这样做的目的是为了避免多次渲染同一个像素。延迟渲染主要分为两步:在第一步中,渲染场景,但只是简单地将几何信息(位置坐标,法线向量,纹理坐标和反射系数等等)存储在中间缓冲区中;在第二步中,从中间缓冲区读取信息,应用反射模型,计算出每个像素的最终颜色。 延迟渲染对 PC 开发非常有效,因为它可以将几何图形与照明分离,你只需更新每个照明所触达的像素,即可在更少的 GPU 周期内渲染更多照明.
原因有很多,但主要原因是 resolve 成本问题。什么是 resolve 成本?在我告诉你什么是 resolve 成本之前,你首先需要了解 tiled GPU 的工作原理.
为了以更低功耗实现更高的吞吐量,移动 GPU(例如 Oculus Quest 中使用的 Snapdragon 835)通常使用 tiled 架构,其中每个渲染目标都被分解成块状网格或“tiles” (从 16x16 像素到 256x256 像素的任何位置,具体取决于硬件和像素格式)。所谓 Tile,就是将几何数据转换成小矩形区域的过程,然后提交给异步处理器,异步处理器执行渲染工作以计算每个“tile”的图像结果。一旦计算出每个图块图像,GPU 必须从片上内存中将图块复制回通用内存。这实际上非常慢,因为它需要通过总线传输数据。我们将此转移称为“resolve”,因此所需的时间称为“resolve 成本”。维基百科对[tiled rendering][ https://en.wikipedia.org/wiki/tiled_rendering ]有更详细的描述,供进一步阅读.
因为要渲染的每个 texture 都需要 resolve,并且延迟渲染需要在计算照明之前渲染大量纹理,所以你的 resolve 成本将从正向渲染的大约 1ms 增加至 3ms 以上。如你所见,你可能没有这样的时间.
除了 resolve 成本之外,延迟渲染仅在你的几何体复杂且有多光照时才有优势。无论如何,这两者都无法在移动设备上真正实现,因为 GPU 处理大量顶点和计算像素填充的能力有限.
暂时的答案是坚持使用 forward 渲染。也可能有一个好的 forward+ 实现的地方,虽然我还没有看到一个.
depth/Z pre-pass 是一种常用技术,其中所有场景几何图形都作为第一步渲染,而不填充帧缓冲区,仅生成深度缓冲区值。然后渲染第二步,检查每个像素的计算深度是否等于深度缓冲区中该像素的值。如果不是,你可以跳过对该片段进行着色。由于在 PC 上处理顶点往往比着色像素快得多,因此可以节省大量时间.
首先,如果在提交绘制调用之前对几何进行排序,通过进行 Depth Pre-Pass 而节省的片段填充时间应该最少。来回绘制会导致常规深度测试拒绝你的像素,所以你只能避免对未正确排序或两个对象在不同点彼此重叠的几何图形进行像素填充.
其次,这需要绘制调用加倍,因为你必须先提交所有内容以进行 Depth Pre-Pass,然后再才是 Forward Pass。由于绘制调用对 cpu 的占用非常大,所以你需要避免这种情况.
第三,所有顶点都需要处理两次,这通常会增加 GPU 时间,而不是避免两次填充几个像素所节省的时间。这是因为顶点处理在移动设备上比在 PC 上花费的时间相对更多,并且处理片段相对较少(因为帧缓冲区大小通常较小,片段程序往往不那么复杂).
第三,所有顶点都需要处理两次,与通过避免填充少数像素两次而节省的时间相比,你通常增加的 GPU 时间会更多。这是因为移动设备的顶点处理会在 PC 耗费更多的时间,并且处理片段的时间同样相对较少(因为 framebuffer 大小通常较小,fragment program 往往不那么复杂).
resolve 成本与图像中的字节数直接相关,而不与像素数直接相关,所以,尽管我们通常以 32 位 RGBA 像素来思考量度,但如今大多数开发者都在使用 HDR 纹理,即每像素 64 位。这会将你的 resolve 成本增加一倍,并且由于显示器仅支持每通道 8 位,所以你在 resolve HDR 纹理时会浪费大量时间。更不用说移动 GPU 是针对 32 位帧缓冲区进行优化.
后处理是一种经常用于为游戏施加多种效果的技术,如 Color Grading,Bloom 照明和运动模糊。具体的实现方式是获取游戏渲染的输出,然后对图像运行全屏通道以产生新图像,然后再将其呈现给玩家。一些后期处理效果是作为一个额外的通道执行(如颜色分级),另一些则需要多个通道.
对于移动设备,后处理的主要问题同样是解析成本。生成第二张图像将引起另一次解析,并会立即消耗大约 1 毫秒的时间。更不用说计算后处理效果所花费的时间,取决于效果,这可能会占用大量资源。所以,最好避免进行后处理.
以下是替代常见后处理效果的方案:
Color grading 与其在后处理中执行 Color Grading,不如在每个片段着色器的末尾添加一个函数调用以执行相同的数学运算。这将产生相同的视觉结果,但无需额外的解析。 Bloom 真正的 Bloom 效果非常耗时。最好的选择是“伪造”。采用包含 blob 纹理的 billboarding sprite 可以产生非常接近的效果.
我认为这是最有争议的一项技术。一系列具有完整实时阴影的应用已成功支持移动设备。但是,这样做存在大量的折衷,而我认为值得避免使用.
实时阴影的一种常用技术是级联阴影贴图,这意味着场景会以各种视口大小进行多次渲染。对于必须由 GPU 处理的几何,这会令次数增加 1 到 4 倍,这从根本上限制了场景可以支持的顶点数量。它同时增加了阴影贴图纹理的解析成本(与纹理大小有关)。在 GPU 管道的另一端,在对阴影贴图进行采样时有两个选项:硬阴影和软阴影。硬阴影可以更快地渲染,但具有不可避免的锯齿问题.
由于阴影贴图的工作方式,这个测试只能得出二进制结果。你无法对阴影贴图进行双线性采样,因为它表示深度值而非颜色值。应该避免使用软阴影,因为它们需要将多个采样放到阴影贴图中,而这当然很慢。最好的选择是烘烤所有可能的阴影,而如果需要实时阴影,请寻找另一种方法。如果照明大部分都是漫反射,则通常可以接受 blob 阴影。如果需要强光照明并且阴影表面是平面,则几何阴影的效果同样相当出色.
对于 PC,你可以在着色器中采样当前的深度纹理(Unity 将其显示为_CameraDepthTexture)。之所以可行,是因为深度纹理只是 PC 上的另一种纹理,并且由于每个绘制调用都接连发生,所以深度纹理的状态将是上一次绘制调用之后的状态。但对于基于图块渲染,当前深度不在纹理之中,而是仅存储在你的图块内存中,所以无法将其作为普通纹理进行采样.
考虑到上述情况,有一个 GLES 扩展可允许你查询深度缓冲区(和帧缓冲区)的当前状态。问题是它们非常慢,只能支持你对相同像素的值进行采样(无法查询附近的像素),并且在启用 MSAA 时它们会产生一系列的问题.
启用 MSAA 时,图块实际上具有一个足够大,能够容纳所有采样的缓冲区(即 2×MSAA 的像素为 2 倍,4×MSAA 的像素为 4 倍)。这意味着默认情况下,如果对深度缓冲区进行采样,则必须按每个采样执行片段着色器,这意味着时间密集度将比预期高 2 倍或 4 倍。存在一种“解决方案”,即调用 glDisable(FETCH_PER_SAMPLE_ARM)。但这样做的问题是,它将仅检索第一个采样的值,而不是混合采样的结果,所以在启用所述功能后,MSAA 将被禁用.
除非绝对必要,否则你应避免它们对帧时间产生的影响.
几何着色器允许你在运行时生成额外的顶点,这对于诸如动态细分等功能十分有用。但是,对于基于图块渲染的 GPU 而言,几何着色器会产生问题。生成额外顶点的步骤阻止了合并过程的进行,这意味着 GPU 不能这样做,所以它会切换为“立即”模式(完全跳过分块过程)。可以猜到,这非常缓慢。所以,最好避免使用几何着色器,并且如果有必要,选择 CPU 生成顶点.
如果你用天真的方式实现它们……对于“天真的方式”,我是指分配两个眼睛缓冲区大小的纹理,计算反射矩阵,然后将场景渲染到两个纹理中。然后,你的 mirror 几何将进行屏幕空间纹理采样,从而显示反射。这种方法存在众多明显的缺陷:
我发现的最低提升是限制了 mirror camera 的视口,并更改了相应的投影矩阵,只能在视锥中渲染 camera 平面边界框。这对上面的第二点问题有所帮助。理想情况下,你同时可以使用多视图,通过一组绘制调用来渲染左右眼,但 Unity 目前不支持这项功能,它不能解决上面的第三点问题 ,并且会令第二点问题更加恶化,因为你只能为两只眼睛使用单个视口,所以你必须使用两个 mirror 边界框的重叠。所以,理想的解决方案将首先解决第三点问题,这意味着一次绘制 mirror 场景和非 mirror 场景.
有一种解决方案可以利用修改后的着色器和模板缓冲区。场景中的每种材质都将具有两种版本的着色器,一种仅在模板缓冲区中的特定位为 0 时绘制,而另一种仅在 1 时绘制。然后,你将使用材质绘制 mirror 网格。它会在模具缓冲区中设置所述位,使用第一组着色器绘制场景,使用反射矩阵设置 camera,并且在最后使用第二组着色器绘制场景。这将产生你想要的反射,同时不会填充超出所需像素的像素,并且避免了不必要的解析。然而,它无法避免绘制一堆对象两次(任何解决方案都无法避免).
尽管这听起来很容易,但如果是使用 Unity,你将会遇到很多问题(我在 Unreal 中没有遇到过,但你可能会遇到类似的挑战)。首先,在启用 Single Pass Stereo(多视图)后,Unity 将不允许你修改 camera 的投影矩阵,所以你不能使用反射 camera(如果关心 CPU 性能,你绝对应该使用这个 camera)。其次,这没有考虑 Late-Latching(在渲染线程启动时更新 camera 矩阵,从而尽可能减少延迟)。通常来说,这是一次纯粹的胜利,但如果你使用 mirror camera,则反射 camera 的变形将不再与头部变形匹配,所以你会得到奇怪的伪影,镜面中的元素不会按照预期方式排列.
最简单的解决方案是“伪造”。如果你的镜面是静态,则只需创建所有世界几何的反射副本,然后将其放在场景中即可。你需要使用脚本来移动任何动态对象的“反射”副本,从而模仿包括玩家在内的“真实”版本位置,但这将是最快、最简单的渲染解决方案,无需复杂的矩阵数学。如果可以看到镜子后面,你将不得不使用两组具有不同模板蒙版的着色器,但如果玩家由于墙壁等原因而无法看到后面,则可以只保留一组着色器.
无论你是从零开始一个新项目,还是要从 PC 移植到移动设备,明确哪里可以沿用原有的知识经验,哪里又需要采取创新的解决方案是获得最佳游戏效果的关键。 但是,你不必遵循本文的建议。请自由探索,并寻找最适合自己的方案.
原文: https://developer.oculus.com/blog/pc-rendering-techniques-to-avoid-when-developing-for-mobile-vr/ 。
最后此篇关于移动VR开发时要避免的PC渲染技术的文章就讲到这里了,如果你想了解更多关于移动VR开发时要避免的PC渲染技术的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
在我的 OpenGL 程序中,我按顺序执行以下操作: // Drawing filled polyhedrons // Drawing points using GL_POINTS // Displa
我想传递一个包含原始页面的局部变量,这个变量只包含一个带有值的符号。 当我使用此代码时,它运行良好,可以在部分中访问 origin 变量: render :partial => "products",
为什么这个 HTML/脚本(来自“JavaScript Ninja 的 secret ”)不渲染? http://jsfiddle.net/BCL54/
我想在阅读完 View 后返回到特定的网页位置(跳转到页内 anchor )。换句话说,在 views.py 中,我想做类似的事情: context={'form':my_form} return r
我有一个包含单条折线的 PathGeometry,并以固定的间隔向该线添加一个新点(以绘制波形)。使用 Perforator 工具时,我可以看到每次向直线添加一个点时,WPF 都会将整个 PathGe
尝试了解如何消除或最小化网站上不同 JavaScript 库的渲染延迟。 例如,如果我想加载来自许多社交网络的“即时”关注按钮,它们似乎会相互阻止渲染,并且您会收到令人不快的弹出窗口。 (func
我有以 xyz 点格式表示 3D 表面(即地震断层平面)的数据。我想创建这些表面的 3D 表示。我使用 rgl 和 akima 取得了一些成功,但是它无法真正处理可能会自行折叠或在同一 x,y 点具有
我正在用 Libgdx 编写一个小游戏。 我有一个 Render[OpenGL] 线程,它不断对所有对象调用 render() 和一个更新线程不断对所有对象调用 update(double delta
我有一个 .Rmd 文件包含: ```{r, echo=FALSE, message=FALSE, results='asis'} library(xtable) print(xtable(group
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improve
请不要评判我,我只是在学习 Swift。 最近我安装了 MetalPetal 框架,并按照说明操作: https://github.com/MetalPetal/MetalPetal#example-
如果您尝试渲染 Canvas 宽度和高度之外的图像,计算机是否仍会尝试渲染它并使用资源来尝试渲染它?我只是想找出在尝试渲染图像之前检查图像是否在 Canvas 内是否更好。 最佳答案 我相信它仍然在无
我在 safari 中渲染时遇到问题。 在 firefox、chrome 和 IE 上。如下图所示: input.searchbox{-webkit-border-radius:10px;-moz-b
我正在尝试通过远程桌面在 Windows7 下运行我在 RHEL7 服务器中制作的 java 程序。 服务器中的所有java程序都无法通过远程桌面呈现。如果我在服务器位置访问服务器本身,它们看起来没问
我正处于一个新项目的设计阶段,该项目将采用数据集并将其加载到文档中,然后围绕模板呈现文档。呈现的文件可以是 CSV 数据集、PDF 营销信函、电子邮件……很多东西。数据不会是数学方程式,我只是在寻找一
有没有办法在不同的 div 下渲染 React 组件的子组件? ... ... ... ... ...
使用以下代码: import numpy as np from plotly.offline import iplot, init_notebook_mode import plotly.graph_
截至最近, meteor 的所有文档都指出 onRendered是一种在模板完成渲染时获取回调的新方法。和 rendered只是为了向后兼容。 但是,这似乎对我不起作用。 onRendered永远不会
所以在我的基本模板中,我有:{% render "EcsCrmBundle:Module:checkClock" %} 然后我创建了 ModuleController.php ... getDoctr
我正在使用 vue-mathjax 来编译我的 vue 项目中的数学方程。它正在编译第一个括号 () 之间的文本。我想防止编译括号内的字符串。在文档中我发现,对于$符号,如果我们想逃避编译,我们需要使
我是一名优秀的程序员,十分优秀!