VR系列——Oculus Rift 开发者指南:四、高级渲染配置(二)

强制对称的视场

通常该API将为每一边眼睛返回一个不对称的视场(译者注:FOV(Field of View)视场:在任何特定时刻可观察到的有限范围),这意味着左边缘与右边缘到中心的距离是不一致的。

这是因为人类以及Rift在向外看的时候具有更宽的视场。当你向内看时,你的鼻子是一个阻碍。我们同样相比向上看更善于向下看。出于同样的原因,Rift的视场不是对称的。它是由透镜的形状、塑料材质的种类以及屏幕的边缘所决定的。具体取决于你的脸型,你的内瞳距(译者注:内瞳距(IPD)是两眼瞳孔之间的距离,两眼空间位置的不同,是产生立体视觉的原因),及Rift放置在你脸上精确的位置;所有这些都是配置工具中设定的并且存储在用户配置文件中。所有的这一切意味着几乎没有人能够将他们的视场目标的四个边缘设置成相同的角度,因此产生的视锥将偏离中心。此外,大多数人的两眼不会有相同的视场,它们可能很相近,但是很少能一模一样。

例如,在DK1中,笔者左眼的视场如下:

  • 53.6度向上
  • 58.9度向下
  • 50.3度向内(朝向鼻子)
  • 58.7度向外(远离鼻子)

在代码和文档中,这些被称为“半角”,因为传统上视场被表示为边缘到边缘的总角度。在这个例子中,总水平视场是50.3 + 58.7 = 109.0度,总垂直视场是53.6 + 58.9 = 112.5度。

推荐的视场和最大的视场可以在HMD中获取,如下所示:

ovrFovPort defaultLeftFOV = session->DefaultEyeFov[ovrEye_Left];
ovrFovPort maxLeftFOV = session->MaxEyeFov[ovrEye_Left];

DefaultEyeFov指基于当前用户的配置文件设置的FOV推荐值(IPD,眼距等)。 MaxEyeFov指忽略配置文件该头盔所能显示的最大FOV。

默认值能够在没有不必要的额外GPU负载下提供一个良好的用户体验。如果你的应用不会消耗大量的GPU资源,你可能会使用最大的FOV设置以减少对配置文件设置的准确性的依赖。你可以在应用程序控制面板中提供一个滑动条,使用户能够在默认值和最大值之间选择设置FOV。但是,如果你的应用对GPU的消耗量大,你可能会将FOV减少到低于默认值,如30页描述的“通过缩小视场来提高性能”。

上,下,左,右(表示为半角切线)的FOV是在你的图形引擎中设置遮挡和边界的最便捷的方式。FOV值也被用于确定左、右眼场景绘制中使用的投影矩阵。为此我们提供一个API功能函数ovrMatrix4f_Projection:

ovrFovPort fov;
// 确定fov。
...
ovrMatrix4f projMatrix = ovrMatrix4f_Projection(fov, znear, zfar, isRightHanded);

当查看一个PC显示器时,FOV的上下边与左右边常常是不一样的。这通常被称为显示器的“长宽比”,而且很少有显示器是正方形的。然而,一些图形引擎不支持偏离中心的视锥。为了与这些引擎兼容,你需要根据ovrHmdDesc结构的上报结果来对FOV值进行调整。在一般情况下,最好是扩展边缘,而不是缩小它们。这会给图形引擎施加一点压力,但会给用户身临其境的体验,即使他们不能够看到一些被渲染的像素。

一些图形引擎要求你展示对称的水平和垂直领域的视场,有一些甚至需要一个更直接的方法,如水平FOV和长宽比。也有一些会反对FOV的频繁变化,并坚持双眼视场将设置为相同的。以下是一个处理这种限制情况的示例代码:

oovrFovPort 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;

// 创建渲染目标。
Sizei recommenedTex0Size = ovr_GetFovTextureSize(session, ovrEye_Left,
fovBoth, pixelsPerDisplayPixel);
Sizei recommenedTex1Size = ovr_GetFovTextureSize(session, ovrEye_Right,
fovBoth, pixelsPerDisplayPixel);
...

//初始化渲染信息
ovrFovPort eyeFov[2];
eyeFov[0] = fovBoth;
eyeFov[1] = fovBoth;
...

// 计算提供给渲染引擎的参数。
// 在这种情况下,我们假设它向要水平 FOV和长宽比。
float horizontalFullFovInRadians = 2.0f * atanf ( combinedTanHalfFovHorizontal );
float aspectRatio = combinedTanHalfFovHorizontal / combinedTanHalfFovVertical;

GraphicsEngineSetFovAndAspect ( horizontalFullFovInRadians, aspectRatio );

注意:你需要在创建渲染目标前确定FOV,因为FOV会影响对于给定质量要求的渲染目标的建议大小。


原文如下


Forcing a Symmetrical Field of View

Typically the API will return an FOV for each eye that is not symmetrical, meaning the left edge is not the same distance from the center as the right edge.

This is because humans, as well as the Rift, have a wider FOV when looking outwards. When you look inwards, your nose is in the way. We are also better at looking down than we are at looking up. For similar reasons, the Rift’s view is not symmetrical. It is controlled by the shape of the lens, various bits of plastic, and the edges of the screen. The exact details depend on the shape of your face, your IPD, and where precisely you place the Rift on your face; all of this is set up in the configuration tool and stored in the user profile. All of this means that almost nobody has all four edges of their FOV set to the same angle, so the frustum produced will be offcenter. In addition, most people will not have the same fields of view for both their eyes. They will be close, but rarely identical.

As an example, on the DK1, the author’s left eye has the following FOV:

  • 53.6 degrees up
  • 58.9 degrees down
  • 50.3 degrees inwards (towards the nose)
  • 58.7 degrees outwards (away from the nose)

In the code and documentation, these are referred to as ‘half angles’ because traditionally a FOV is expressed as the total edge-to-edge angle. In this example, the total horizontal FOV is 50.3+58.7 = 109.0 degrees, and the total vertical FOV is 53.6+58.9 = 112.5 degrees.

The recommended and maximum fields of view can be accessed from the HMD as shown below:

ovrFovPort defaultLeftFOV = session->DefaultEyeFov[ovrEye_Left];
ovrFovPort maxLeftFOV = session->MaxEyeFov[ovrEye_Left];

DefaultEyeFov refers to the recommended FOV values based on the current user’s profile settings (IPD, eye relief etc). MaxEyeFov refers to the maximum FOV that the headset can possibly display, regardless of profile settings.

The default values provide a good user experience with no unnecessary additional GPU load. If your application does not consume significant GPU resources, you might want to use the maximum FOV settings to reduce reliance on the accuracy of the profile settings. You might provide a slider in the application control panel that enables users to choose interpolated FOV settings between the default and the maximum. But, if your application is heavy on GPU usage, you might want to reduce the FOV below the default values as described in Improving Performance by Decreasing Field of View on page 30.

The FOV angles for up, down, left, and right (expressed as the tangents of the half-angles), is the most convenient form to set up culling or portal boundaries in your graphics engine. The FOV values are also used to determine the projection matrix used during left and right eye scene rendering. We provide an API utility function ovrMatrix4f_Projection for this purpose:

ovrFovPort fov;
// Determine fov.
...
ovrMatrix4f projMatrix = ovrMatrix4f_Projection(fov, znear, zfar, isRightHanded);

It is common for the top and bottom edges of the FOV to not be the same as the left and right edges when viewing a PC monitor. This is commonly called the ‘aspect ratio’ of the display, and very few displays are square. However, some graphics engines do not support off-center frustums. To be compatible with these engines, you will need to modify the FOV values reported by the ovrHmdDesc struct. In general, it is better to grow the edges than to shrink them. This will put a little more strain on the graphics engine, but will give the user the full immersive experience, even if they won’t be able to see some of the pixels being rendered.

Some graphics engines require that you express symmetrical horizontal and vertical fields of view, and some need an even less direct method such as a horizontal FOV and an aspect ratio. Some also object to having frequent changes of FOV, and may insist that both eyes be set to the same. The following is a an example of code for handling this restrictive case:

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 );
...

Note: You will need to determine FOV before creating the render targets, since FOV affects the size of the recommended render target required for a given quality.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值