高级渲染配置

SDK默认生成的配置值是对渲染质量最佳的。

它也提供了灵活性。例如,你能做一些改变当建立渲染目标纹理时。

这节讨论你能做的改变当在渲染质量和性能之间做选择时。

图形API拷贝或硬件渲染粒度

SDK是被这样设计的,假定你要尽可能小心的使用你的视频内存和你能精确创建你需要的对的渲染目标大小。

然而,真正的视频卡和真实的图形APIs有一些尺寸现在(有一个最大值;也有一些最小值)。他们可能也有一些粒度限制,例如,只能创建渲染目标它们是一大批在32像素尺寸或有一个限度在可能方面比率。作为一个应用开发者,你能利用特别的约束去避免使用太多的图像内存。

除了上面说的之外,真实渲染目标表面的大小在内存中可以不是必须相同的和被渲染的部分。后者可能稍微小一点。然而,因为它作为一个视口被指定,它没有任何粒度约束。当你绑定渲染目标作为一个纹理,因为它的所有面被使用,所以UV坐标必须是正确的在不同的渲染大小和表面大小之间。API会为你做这些,但是你需要告诉它相关的信息。

下面的代码展示了两阶段方法去设置目标分辨率。代码首先调用ovr_GetFovTextureSize来计算渲染目标的理想大小。然后,调用图形库去建立一个期望分辨率的渲染目标。通常,由于平台和硬件的特异性,创建的纹理大小可能不同于请求的大小。

 // Get recommended left and right eye render target sizes.
    Sizei recommenedTex0Size = ovr_GetFovTextureSize(session, ovrEye_Left,
                                  session->DefaultEyeFov[0], pixelsPerDisplayPixel);
    Sizei recommenedTex1Size = ovr_GetFovTextureSize(session, ovrEye_Right, 
                                  session->DefaultEyeFov[1], pixelsPerDisplayPixel);

    // Determine dimensions to fit into a single render target.
    Sizei renderTargetSize;
    renderTargetSize.w = recommenedTex0Size.w + recommenedTex1Size.w;
    renderTargetSize.h = max ( recommenedTex0Size.h, recommenedTex1Size.h );

    // Create texture.
    pRendertargetTexture = pRender->CreateTexture(renderTargetSize.w, renderTargetSize.h);

    // The actual RT size may be different due to HW limits.
    renderTargetSize.w = pRendertargetTexture->GetWidth();
    renderTargetSize.h = pRendertargetTexture->GetHeight();

    // Initialize eye rendering information.
    // The viewport sizes are re-computed in case RenderTargetSize changed due to HW limitations.
    ovrFovPort eyeFov[2] = { session->DefaultEyeFov[0], session->DefaultEyeFov[1] };

    EyeRenderViewport[0].Pos  = Vector2i(0,0);
    EyeRenderViewport[0].Size = Sizei(renderTargetSize.w / 2, renderTargetSize.h);
    EyeRenderViewport[1].Pos  = Vector2i((renderTargetSize.w + 1) / 2, 0);
    EyeRenderViewport[1].Size = EyeRenderViewport[0].Size;
传递给ovr_SubmitFrame的数据作为层描述的一部分。


你可以自由的选择渲染目标大小和左右眼视口作为你喜欢的,提供你指定的这些值当调用ovr_SubmitFrameusing时给ovrTexture.然而,使用ovr_GetFovTextureSize会确保你分配最佳大小给特殊的HMD在使用中。接下来描述怎样修改默认配置来权衡质量和性能。你应该也注意到API支持使用不同的渲染目标为每个眼如果这是你的引擎需要的。OculusWorldDemo允许你紧抓在使用一个单一渲染目标独立于每个眼,通过操纵设置菜单和选择共享渲染目标选项。

强制一个对称视野

API会为每个眼睛返回一个FOV它是不对称的,也就是左边到中心点的距离和右边的不同。

这是因为人们,就和Rift一样,有一个宽的FOV当看向外边时。当你看向里边时,你的鼻子会阻挡。我们也是向下看比向上看好。同样的原因,Rift的视图也不是对称的。它是通过镜头控制的,多种多样的塑料品的位,和屏幕边缘。精确的细节依赖你的脸形状,你的IPD,和你把Rift放在你脸的精确位置;所有这些建立在配置工具中和存储在用户的简况中。这些意味着几乎没有人有所有他们的FOV的四个边设置相同的角度,所以截面椎体产生会是偏离中心的。另外,大部分人的眼睛不会有相同的视野。它们会是接近的,但是极少是完全相同的。

作为一个例子,我们第一代的DK1头戴,作者的左眼有下面的FOV:

。53.6度向上

。58.9度向下

。50.3度向里(朝向鼻子)

。58.7度向外(远离鼻子)

在代码和文档中,这设计半角因为传统上一个FOV代表一个总边-边角度。在这个例子中,总水平FOV是50.3+58.7=109.0度,总垂直FOV是53.6+58.9=112.5度。

推荐的和最大视野能被从HMD访问就像下面展示:

ovrFovPort defaultLeftFOV = session->DefaultEyeFov[ovrEye_Left];

ovrFovPort maxLeftFOV = session->MaxEyeFov[ovrEye_Left];
DefaultEyeFov涉及到推荐的FOV值基于当前用户的profile设置。MaxEyeFov设计到最大FOV头戴能显示的最大角度不管profile设置。

默认值用额外的GPU加载提供一个好的用户体验。如果你的应用没有消耗大量的GPU资源,你可以使用最大FOV设置去减小依赖profile设置的精确度。你可以提供一个滑动条在应用控制面板中让用户能选择修改FOV设置在默认和最大值之间。但是,如果你的应用是使用GPU很严重,你可以减小FOV默认值就像改进性能通过减小视野中描述的。

上下左右的FOV角度是最方便的形式去设置选择或入口边界在你的图形引擎中。FOV的值也被用来去决定投影矩阵的使用在左右眼场景渲染期间。我们提供一个API使用函数ovrMatrix4f_Projection为这个意图:

ovrFovPort fov;

// Determine fov.
...

ovrMatrix4f projMatrix = ovrMatrix4f_Projection(fov, znear, zfar, 0);
这是普遍的FOV的顶和底边不同于左和右边当观看一个PC监视器时。一般的调用显示器的面比率,很少的显示器是正方形的。然而,一些图形引擎不支持偏离中心的截面椎体。为了兼容这些引擎,你需要修改FOV值通过ovrHmdDesc结构。大体上,这是好的扩展边比收缩它们。这会有一点紧张在图形引擎上,但是会给用户完全沉浸式的体验,甚至它们不能看到一些被渲染的像素。

一些图形引擎要求你表明对称的水平和垂直视野,一些需要一个较少的直接的方法就像一个水平FOV和一个面比率。一些对象频繁的变换FOV,可以强调两眼被设置为相同。下面的代码例子处理这个约束例子:

ovrFovPort fovLeft = session->DefaultEyeFov[ovrEye_Left];
ovrFovPort fovRight = session->DefaultEyeFov[ovrEye_Right];

ovrFovPort fovMax = FovPort::Max(fovLeft, fovRight);
float combinedTanHalfFovHorizontal = max ( fovMax.LeftTan, fovMax.RightTan );
float combinedTanHalfFovVertical = max ( fovMax.UpTan, fovMax.DownTan );

ovrFovPort fovBoth;
fovBoth.LeftTan = fovBoth.RightTan = combinedTanHalfFovHorizontal;
fovBoth.UpTan = fovBoth.DownTan = combinedTanHalfFovVertical;


// Create render target.
Sizei recommenedTex0Size = ovr_GetFovTextureSize(session, ovrEye_Left, 
                                                    fovBoth, pixelsPerDisplayPixel);
Sizei recommenedTex1Size = ovr_GetFovTextureSize(session, ovrEye_Right, 
                                                    fovBoth, pixelsPerDisplayPixel);

...


// Initialize rendering info.
ovrFovPort eyeFov[2];
eyeFov[0]                       = fovBoth;
eyeFov[1]                       = fovBoth;

...


// Compute the parameters to feed to the rendering engine.
// In this case we are assuming it wants a horizontal FOV and an aspect ratio.
float horizontalFullFovInRadians = 2.0f * atanf ( combinedTanHalfFovHorizontal );
float aspectRatio = combinedTanHalfFovHorizontal / combinedTanHalfFovVertical;

GraphicsEngineSetFovAndAspect ( horizontalFullFovInRadians, aspectRatio );
...
注意:你需要决定FOV在创建渲染对象之前,因为FOV影响一个给定质量的推荐渲染目标的大小。

通过减少像素密度改进性能

DK1有一个1280*800像素的分辨率,在两眼之间分离。然而因为宽的Rift的FOV和远景投射工作方式,媒介渲染目标的尺寸需求匹配现在的分辨率在足够高的显示器的中心。

例如,为了达到一个1:1像素映射在屏幕中心为作者的FOV设置一个DK1需求一个很大的渲染目标在2000*1056像素大小。

虽然现在的图形卡能渲染这个分辨率在需求的60HZ,未来的HMDs可能有足够高的分辨率。为了虚拟现实,低于60HZ提供了一个糟糕的用户体验;它一直是一个好方式来减小分辨率来维持帧率。这和一个用户有一个高分辨率2560*1600监视器一样。很少的3D应用能运行在全屏本地分辨率,所以很多应用允许用户选择一个低分辨率监视器放大一级去填充屏幕。

你能使用相同的策略在HMD上。那就是,运行它在一个低视频分辨率和让硬件为你放大一级。然而,这会产生两个过滤的步骤:一个是失真处理和一个视频放大。不幸的是,双过滤产生非常大的人工影响。它通常更影响留下视频模式在本地分辨率,除了媒介渲染目标的限制大小。这给一个相似的增长在性能上,除了更多细节。

一个解决方式是允许用户去调整分辨率通过一个分辨率选择器。然而渲染目标的真实分辨率依赖用户的配置,而不是一个标准硬件设置这意味着“本地分辨率”是不同对不同的人。另外的,呈现分辨率高比物理硬件分辨率能使用户混乱。他们不会理解选择1280*800是一个足够好的下降在质量上,虽然这个分辨率通过硬件指出。

一个好的选项是修改像素PerDisplayPixel值传递给ovr_GetFovTextureSize函数。这也能基于一个滚动条展现在应用渲染设置上。这判定相关的渲染目标像素的大小就和他们映射像素到显示器表面的中心。例如。0.5的一个值会减小渲染目标的大小从2000*1056到1000*528像素,可能允许中间范围PC图形卡维持60HZ。

float pixelsPerDisplayPixel = GetPixelsPerDisplayFromApplicationSettings();

Sizei recommenedTexSize = ovr_GetFovTextureSize(session, ovrEye_Left,  fovLeft, 
                                                   pixelsPerDisplayPixel);
虽然你能设置参数值大于1.0来产生一个高分辨率媒介渲染目标,Oculus没有观察到任何有用增加在质量上和它有一个高性能代价。

OculusWorldDemo允许你去尝试改变渲染目标像素密度。导航到设置菜单和选择像素密度。按上和下箭头键去调整像素密度在眼投射的中心。1.0的值设置渲染目标像素目标来显示表面1:1的点在显示器上。0.5的值设置渲染目标像素的密度为一半在显示器表面。另外的,你能选择Dynamic Res Scaling它会导致像素密度自动调整在0-1之间。


通过减少FOV改善性能

为了减少像素数在媒体渲染目标上,你能增加性能通过减少FOV-像素是被拉伸的。

依赖减少,这能导致隧道美景减少沉浸式的场景。然而,减少FOV增加性能有两个方式。最明显的是填充率。一个固定像素密度在视网膜,一个低FOV有少的像素。因为投射的属性数学,最外边FOV的边是最贵的在像素数的地位。第二个原因是这儿有少量对象可视的在每个帧中这意味着少量动画,少的状态变化和少的绘制调用。

减少FOV设置让玩家做一个非常痛苦的选择。一个虚拟现实的关键体验是沉浸式的在模拟世界中,和一个大范围的FOV。失去这些方面不是我们曾经推荐的。然而,如果你已经牺牲很多分辨率,应用一直没有运行在60HZ在用户的机器上,这是最后的一个手段选项。

我们推荐给玩家一个最大值FOV滚动条这意味着每个眼睛的FOV的四个边。

ovrFovPort defaultFovLeft = session->DefaultEyeFov[ovrEye_Left];
ovrFovPort defaultFovRight = session->DefaultEyeFov[ovrEye_Right];

float maxFovAngle = ...get value from game settings panel...;
float maxTanHalfFovAngle = tanf ( DegreeToRad ( 0.5f * maxFovAngle ) );

ovrFovPort newFovLeft  = FovPort::Min(defaultFovLeft, FovPort(maxTanHalfFovAngle));
ovrFovPort newFovRight = FovPort::Min(defaultFovRight, FovPort(maxTanHalfFovAngle));


// Create render target.
Sizei recommenedTex0Size = ovr_GetFovTextureSize(session, ovrEye_Left  newFovLeft, pixelsPerDisplayPixel);
Sizei recommenedTex1Size = ovr_GetFovTextureSize(session, ovrEye_Right, newFovRight, pixelsPerDisplayPixel);

...


// Initialize rendering info.
ovrFovPort eyeFov[2];
eyeFov[0]                       = newFovLeft;
eyeFov[1]                       = newFovRight;

...


// Determine projection matrices.
ovrMatrix4f projMatrixLeft = ovrMatrix4f_Projection(newFovLeft, znear, zfar, 0);
ovrMatrix4f projMatrixRight = ovrMatrix4f_Projection(newFovRight, znear, zfar, 0)
它可能是有趣的去尝试没有方形的FOV。例如,夹住足够的上和下范围当保留全水平FOV为一个‘Cinemascope’感觉。

OculusWorldDemo允许你去阐释减少FOV在默认之下。导航到设置菜单,选择Max FOV值。按下上和下箭头去改变最大角度在度数上。

通过单通道渲染改善性能

一个重大的立体渲染的消耗是渲染连个视图,每个眼睛一个。

一些应用,立体影像方面可能不是特别重要的和一个单通道视图可能是被接受的作为性能的回报。另一方面,一些用户可能获得眼紧张从一个立体视图和希望转换到一个单通道。然而,他们一直希望戴着HMD就像它给他们一个高FOV和头部追踪。

OculusWorldDemo允许用户抓紧单通道渲染模式通过按下F7键。

为了单通道渲染,你的代码应该用下面变换:

。设置FOV到最大对称FOV基于两个眼。

。调用ovhHmd_GetFovTextureSize和FOV去判定推荐的渲染目标大小。

。两眼的配置使用相同渲染目标和相同视口当调用ovr_SubmitFrame.

。渲染场景用共享渲染目标。

合并左右眼的FOV到一个单独媒介渲染。渲染一直是失真两次,每个眼一次,因为镜头不是精确的在用户的眼前面。然而,这一直是一个重大性能增加。

设置一个虚拟IPD为0意味着每件事似乎是巨大的和无限远的,所以用户会失去很多景深在场景中。

注意:这是重要的去缩放虚拟IPD和虚拟头部运动一起,如果虚拟IPD是设置为0,所有虚拟头部运动归于脖子运动也是被淘汰的。悲哀的,这失去很多景色归于平行。但是如果头部运动和IPD不同意,它能导致严重的失真和不舒服。谨慎尝试。


你可能感兴趣的:(高级渲染配置)