您的位置:首页 > 其它

VR系列——Oculus Rift 开发者指南:三、Oculus Rift的渲染(三)

2017-05-18 20:29 316 查看

交换纹理集初始化

本节介绍了渲染的初始化,包括创建交换纹理集。

最初,确定渲染FOV和分配所需的ovrSwapTextureSet。下面的代码演示了如何计算所需的纹理大小:

// 配置立体设置。
Sizei recommenedTex0Size = ovr_GetFovTextureSize(session, ovrEye_Left, session->DefaultEyeFov[0], 1.0f);
Sizei recommenedTex1Size = ovr_GetFovTextureSize(session, ovrEye_Right, session->DefaultEyeFov[1], 1.0f);
Sizei bufferSize;
bufferSize.w = recommenedTex0Size.w + recommenedTex1Size.w;
bufferSize.h = max ( recommenedTex0Size.h, recommenedTex1Size.h );


渲染纹理大小是根据FOV和在眼睛中心展示所需的像素密度确定的。虽然FOV和像素密度两个值可以修改以提高性能,这个例子推荐使用FOV(从session->DefaultEyeFov 获取)。ovr_GetFovTextureSize 的功能是计算基于这些参数每只眼睛所需要的纹理大小。

Oculus 公司API允许应用程序使用任何一个共享的纹理或2个单独的纹理进行眼部渲染。为简单起见,本例子使用一个单一的共享纹理,使其足够大去适应两只眼睛的渲染。一旦纹理的大小是已知的,应用程序可以调用ovr_CreateSwapTextureSetGL 或ovr_CreateSwapTextureSetD3D11 ,以指定API方法去分配纹理集。下面是如何在OPenGL下创建和访问一个纹理集:

ovrSwapTextureSet * pTextureSet = 0;

if (ovr_CreateSwapTextureSetGL(session, GL_SRGB8_ALPHA8, bufferSize.w, bufferSize.h, &pTextureSet) == ovrSuccess)
{
// 访问样本纹理:
ovrGLTexture* tex = (ovrGLTexture*)&pTextureSet->Textures[i];
glBindTexture(GL_TEXTURE_2D, tex->OGL.TexId);
...
}


从这个例子可以看出,ovrSwapTextureSet 包含了ovrTexture对象数组,不管是D3D纹理句柄还是OpenGL纹理ID,都可以包装用来渲染绘制。这里有一个相似的例子关于使用Direct3D进行纹理集的创建和访问:

ovrSwapTextureSet * pTextureSet = 0;
ID3D11RenderTargetView * pTexRtv[3];

D3D11_TEXTURE2D_DESC dsDesc;
dsDesc.Width = bufferSize.w;
dsDesc.Height = bufferSize.h;
dsDesc.MipLevels = 1;
dsDesc.ArraySize = 1;
dsDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
dsDesc.SampleDesc.Count = 1;
dsDesc.SampleDesc.Quality = 0;
dsDesc.Usage = D3D11_USAGE_DEFAULT;
dsDesc.CPUAccessFlags = 0;
dsDesc.MiscFlags = 0;
dsDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;

if (ovr_CreateSwapTextureSetD3D11(session, DIRECTX.Device, &dsDesc, 0, &pTextureSet) ==  ovrSuccess)
{
for (int i = 0; i < pTextureSet->TextureCount; ++i)
{
ovrD3D11Texture* tex = (ovrD3D11Texture*)&pTextureSet >Textures[i];
DIRECTX.Device->CreateRenderTargetView(tex->D3D11.pTexture, NULL, &pTexRtv[i]);
}
}


在这种情况下,可以使用新创建的渲染目标视图来进行眼睛纹理
dc90
渲染。在帧渲染部分描述了更为详细的视图设置。

Oculus分层组件服务提供了sRGB的校正渲染,使视觉效果更为逼真,更好的MSAA和节能的纹理采样,这对VR应用来说非常重要。如上图所示,应用程序将创建sRGB 交换纹理集。适当的处理sRGB渲染是一个复杂的课题,这一部分只提供了一个概述,更广泛的信息不属于本文档的范围。

有几个步骤来确保应用程序实时渲染达到正确的sRGB阴影和使用不同的方式来实现这一目标。例如,当一些应用程序使用GPU着色器的数学做了更多的定制控制时,大多数的GPU为指定的sRGB输入输出面提供硬件加速改善正确的gamma阴影。对于Oculus公司 SDK,当应用程序通过sRGB空间交换纹理集,分层组件将依赖GPU采样器做sRGB线性转换。

所有的颜色纹理送入GPU着色器应该适当的标记sRGB正确格式,如:DXGI_FORMAT_BC1_UNORM_SRGB。这也是为应用程序推荐的,为Oculus 分层组件提供4层纹理这样的静态纹理,如果不这样处理,会导致纹理看起来比预期的要亮。

对于D3D11, ovr_CreateSwapTextureSetD3D11提供的纹理格式,会读取纹理的内容时所使用的失真合成器中被使用。其结果是,应用程序将要在sRGB空间中请求交换纹理集格式(例如DXGI_FORMAT_R8G8B8A8_UNORM_SRGB)。

如果你的应用程序配置为渲染成线性格式纹理(如DXGI_FORMAT_R8G8B8A8_UNORM),并使用HLSL代码去处理线性到Gamma变换,或者不关心任何的gamma校正,则

请求一个sRGB格式(如DXGI_FORMAT_R8G8B8A8_UNORM_SRGB)交换纹理集。

使用ovrSwapTextureSetD3D11_Typeless标志。

创建一个线性格式的RenderTargetView (如DXGI_FORMAT_R8G8B8A8_UNORM)。

注:一般忽略深度缓冲格式ovrSwapTextureSetD3D11_Typeless标志(DXGI_FORMAT_D32),因为它们总是转换成无类型的。

对于OpenGL,阅读纹理内容时,失真分层组件将使用格式化参数ofovr_CreateSwapTextureSetGL 。其结果是,应用程序应该请求交换纹理集格式优选sRGB空间(例如GL_SRGB8_ALPHA8)。此外,该应用程序在渲染到这些纹理之前,应该调用glEnable(GL_FRAMEBUFFER_SRGB)。

虽然不推荐,但如果把你的应用程序配置为线性格式的纹理(如GL_RGBA),且GLSL执行线性到gamma转换或不关心gamma校正,则

请求sRGB格式(例如GL_SRGB8_ALPHA8)交换纹理集

当渲染交换纹理时,不要调用glEnable(GL_FRAMEBUFFER_SRGB)

下面提供的代码示例,将演示如何使用D3D11提供的ovrSwapTextureSetD3D11_Typeless 标志:

D3D11_TEXTURE2D_DESC dsDesc;
dsDesc.Width = sizeW;
dsDesc.Height = sizeH;
dsDesc.MipLevels = 1;
dsDesc.ArraySize = 1;
dsDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
dsDesc.SampleDesc.Count = 1; // 不允许多重采样
dsDesc.SampleDesc.Quality = 0;
dsDesc.Usage = D3D11_USAGE_DEFAULT;
dsDesc.CPUAccessFlags = 0;
dsDesc.MiscFlags = 0;
dsDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;

ovrResult result = ovr_CreateSwapTextureSetD3D11(session, DIRECTX.Device, &dsDesc,
ovrSwapTextureSetD3D11_Typeless, &TextureSet);
if(!OVR_SUCCESS(result))
return;

for (int i = 0; i < TextureSet->TextureCount; ++i)
{
ovrD3D11Texture* tex = (ovrD3D11Texture*)&TextureSet->Textures[i];
D3D11_RENDER_TARGET_VIEW_DESC rtvd = {};
rtvd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
rtvd.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
DIRECTX.Device->CreateRenderTargetView(tex->D3D11.pTexture, &rtvd, &TexRtv[i]);
}


除了sRGB,这些概念也适用于反射纹理的创建。欲了解更多信息,请参照分别为D3D11和OpenGL提供的ovr_CreateMirrorTextureD3D11 和ovr_CreateMirrorTextureGL函数文档。

原文如下

Swap Texture Set Initialization

This section describes rendering initialization, including creation of swap texture sets.

Initially, you determine the rendering FOV and allocate the required ovrSwapTextureSet. The following code shows how the required texture size can be computed:

// 配置立体设置。
Sizei recommenedTex0Size = ovr_GetFovTextureSize(session, ovrEye_Left, session->DefaultEyeFov[0], 1.0f);
Sizei recommenedTex1Size = ovr_GetFovTextureSize(session, ovrEye_Right, session->DefaultEyeFov[1], 1.0f);
Sizei bufferSize;
bufferSize.w = recommenedTex0Size.w + recommenedTex1Size.w;
bufferSize.h = max ( recommenedTex0Size.h, recommenedTex1Size.h );


Render texture size is determined based on the FOV and the desired pixel density at the center of the eye. Although both the FOV and pixel density values can be modified to improve performance, this example uses the recommended FOV (obtained from session->DefaultEyeFov). The function ovr_GetFovTextureSize computes the desired texture size for each eye based on these parameters.

The Oculus API allows the application to use either one shared texture or two separate textures for eye rendering. This example uses a single shared texture for simplicity, making it large enough to fit both eye renderings. Once texture size is known, the application can call ovr_CreateSwapTextureSetGL or ovr_CreateSwapTextureSetD3D11 to allocate the texture sets in an API-specific way. Here’s how a texture set can be created and accessed under OpenGL:

ovrSwapTextureSet * pTextureSet = 0;

if (ovr_CreateSwapTextureSetGL(session, GL_SRGB8_ALPHA8, bufferSize.w, bufferSize.h, &pTextureSet) == ovrSuccess)
{
// 访问样本纹理:
ovrGLTexture* tex = (ovrGLTexture*)&pTextureSet->Textures[i];
glBindTexture(GL_TEXTURE_2D, tex->OGL.TexId);
...
}


As can be seen from this example, ovrSwapTextureSet contains an array of ovrTexture objects, each wrapping either a D3D texture handle or OpenGL texture ID that can be used for rendering. Here’s a similar example of texture set creation and access using Direct3D:

ovrSwapTextureSet * pTextureSet = 0;
ID3D11RenderTargetView * pTexRtv[3];

D3D11_TEXTURE2D_DESC dsDesc;
dsDesc.Width = bufferSize.w;
dsDesc.Height = bufferSize.h;
dsDesc.MipLevels = 1;
dsDesc.ArraySize = 1;
dsDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
dsDesc.SampleDesc.Count = 1;
dsDesc.SampleDesc.Quality = 0;
dsDesc.Usage = D3D11_USAGE_DEFAULT;
dsDesc.CPUAccessFlags = 0;
dsDesc.MiscFlags = 0;
dsDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;

if (ovr_CreateSwapTextureSetD3D11(session, DIRECTX.Device, &dsDesc, 0, &pTextureSet) ==  ovrSuccess)
{
for (int i = 0; i < pTextureSet->TextureCount; ++i)
{
ovrD3D11Texture* tex = (ovrD3D11Texture*)&pTextureSet >Textures[i];
DIRECTX.Device->CreateRenderTargetView(tex->D3D11.pTexture, NULL, &pTexRtv[i]);
}
}


In this case, you can use the newly created render target views to perform eye texture rendering. The Frame Rendering section describes viewport setup in more detail.

The Oculus compositor provides sRGB-correct rendering, which results in more photorealistic visuals, better MSAA, and energy-conserving texture sampling, which are very important for VR applications. As shown above, applications are expected to create sRGB swap texture sets. Proper treatment of sRGB rendering is a complex subject and, although this section provides an overview, extensive information is outside the scope of this document.

There are several steps to ensuring a real-time rendered application achieves sRGB-correct shading and different ways to achieve it. For example, most GPUs provide hardware acceleration to improve gamma-correct shading for sRGB-specific input and output surfaces, while some applications use GPU shader math for more customized control. For the Oculus SDK, when an application passes in sRGB-space swap-texture-sets, the compositor relies on the GPU’s sampler to do the sRGB-to-linear conversion.

All color textures fed into a GPU shader should be marked appropriately with the sRGB-correct format, such as DXGI_FORMAT_BC1_UNORM_SRGB. This is also recommended for applications that provide static textures as quad-layer textures to the Oculus compositor. Failure to do so will cause the texture to look much brighter than expected.

For D3D11, the texture format provided in desc for ovr_CreateSwapTextureSetD3D11 is used by the distortion compositor for the ShaderResourceView when reading the contents of the texture. As a result, the application should request swap-texture-set formats that are in sRGB-space (e.g. DXGI_FORMAT_R8G8B8A8_UNORM_SRGB).

If your application is configured to render into a linear-format texture (e.g. DXGI_FORMAT_R8G8B8A8_UNORM) and handles the linear-to-gamma conversion using HLSL code, or does not care about any gamma-correction, then:

Request an sRGB format (e.g. DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) swap-texture-set.

Use the ovrSwapTextureSetD3D11_Typeless flag.

Create a linear-format RenderTargetView (e.g. DXGI_FORMAT_R8G8B8A8_UNORM)

Note: The ovrSwapTextureSetD3D11_Typeless flag for depth buffer formats (e.g. DXGI_FORMAT_D32) is ignored as they are always converted to be typeless.

For OpenGL, the format parameter ofovr_CreateSwapTextureSetGL is used by the distortion compositor when reading the contents of the texture. As a result, the application should request swap-texture-set formats preferably in sRGB-space (e.g. GL_SRGB8_ALPHA8). Furthermore, your application should call glEnable(GL_FRAMEBUFFER_SRGB); before rendering into these textures.

Even though it is not recommended, if your application is configured to treat the texture as a linear format (e.g. GL_RGBA) and performs linear-to-gamma conversion in GLSL or does not care about gamma-correction, then:

Request an sRGB format (e.g. GL_SRGB8_ALPHA8) swap-texture-set.

Do not call glEnable(GL_FRAMEBUFFER_SRGB); when rendering into the swap texture.

The provided code sample demonstrates how to use the provided ovrSwapTextureSetD3D11_Typeless flag in D3D11:

D3D11_TEXTURE2D_DESC dsDesc;
dsDesc.Width = sizeW;
dsDesc.Height = sizeH;
dsDesc.MipLevels = 1;
dsDesc.ArraySize = 1;
dsDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
dsDesc.SampleDesc.Count = 1; // 不允许多重采样
dsDesc.SampleDesc.Quality = 0;
dsDesc.Usage = D3D11_USAGE_DEFAULT;
dsDesc.CPUAccessFlags = 0;
dsDesc.MiscFlags = 0;
dsDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;

ovrResult result = ovr_CreateSwapTextureSetD3D11(session, DIRECTX.Device, &dsDesc,
ovrSwapTextureSetD3D11_Typeless, &TextureSet);
if(!OVR_SUCCESS(result))
return;

for (int i = 0; i < TextureSet->TextureCount; ++i)
{
ovrD3D11Texture* tex = (ovrD3D11Texture*)&TextureSet->Textures[i];
D3D11_RENDER_TARGET_VIEW_DESC rtvd = {};
rtvd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
rtvd.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
DIRECTX.Device->CreateRenderTargetView(tex->D3D11.pTexture, &rtvd, &TexRtv[i]);
}


In addition to sRGB, these concepts also apply to the mirror texture creation. For more information, refer to the function documentation provided for ovr_CreateMirrorTextureD3D11 and ovr_CreateMirrorTextureGL for D3D11 and OpenGL, respectively.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐