2

我正在用 D3D9 编写一个 3d 建模应用程序,我想让它尽可能广泛兼容。这意味着使用很少的硬件相关功能,即多重采样。然而,虽然实时渲染不需要完美无缺,但我确实需要提供漂亮的屏幕截图,如果没有多重采样,看起来很混叠而且很差。

为了生成我的屏幕截图,我在内存中创建了一个临时表面,将场景渲染一次,然后将其保存到文件中。我首先想到的如何实现抗锯齿捕获是创建我的屏幕外模板表面作为多重采样,但当然 DX 不允许这样做,因为设备本身已使用 D3DMULTISAMPLE_NONE 进行了初始化。

首先,这是我如何创建屏幕截图的示例。我知道只保存已经渲染的帧的后缓冲区会更简单,但是我需要能够保存与实际渲染窗口不同尺寸的图像——这就是我这样做的原因。为简洁起见,此处省略了错误检查、恢复状态和释放资源的代码。m_d3ddev 是我的 LPDIRECT3DDEVICE9。

//Get the current pp
LPDIRECT3DSWAPCHAIN9 sc;
D3DPRESENT_PARAMETERS pp;
m_d3ddev->GetSwapChain(0, &sc);
sc->GetPresentParameters(&pp);

//Create a new surface to which we'll render
LPDIRECT3DSURFACE9 ScreenShotSurface= NULL;
LPDIRECT3DSURFACE9 newDepthStencil  = NULL;
LPDIRECT3DTEXTURE9 pRenderTexture   = NULL;
m_d3ddev->CreateDepthStencilSurface(_Width, _Height, pp.AutoDepthStencilFormat, pp.MultiSampleType, pp.MultiSampleQuality, FALSE, &newDepthStencil, NULL );
m_d3ddev->SetDepthStencilSurface( newDepthStencil );
m_d3ddev->CreateTexture(_Width, _Height, 1, D3DUSAGE_RENDERTARGET, pp.BackBufferFormat, D3DPOOL_DEFAULT, &pRenderTexture, NULL);
pRenderTexture->GetSurfaceLevel(0,&ScreenShotSurface);

//Render the scene to the new surface
m_d3ddev->SetRenderTarget(0, ScreenShotSurface);
RenderFrame();

//Save the surface to a file
D3DXSaveSurfaceToFile(_OutFile, D3DXIFF_JPG, ScreenShotSurface, NULL, NULL);

您可以看到对 CreateDepthStencilSurface() 的调用,这是我希望可以用 ie 替换 pp.MultiSampleType 的地方D3DMULTISAMPLE_4_SAMPLES,但这不起作用。

我的下一个想法是创建一个完全不同的 LPDIRECT3DDEVICE9 作为D3DDEVTYPE_REF,它始终支持D3DMULTISAMPLE_4_SAMPLES(无论视频卡如何)。但是,我的所有资源(网格、纹理)都已加载到我的 HAL 设备 m_d3ddev 中,因此我无法使用它们在 REF 设备下渲染场景。请注意,资源可以在 Direct3d9ex (Vista) 下的设备之间共享,但我正在使用 XP。由于有相当多的资源,重新加载所有内容以呈现这一帧,然后卸载它们,对于我的应用程序来说时间效率太低了。

我查看了用于在捕获后对图像进行抗锯齿的其他选项(即 3x3 模糊滤镜),但它们都产生了非常糟糕的结果,所以我真的很想尝试在 D3D 中获得一个抗锯齿场景,如果可能的话......

任何智慧或指示将不胜感激......

谢谢!

4

3 回答 3

3

通过渲染到更大的缓冲区并缩小或组合抖动缓冲区来进行超级采样可能是您最好的选择。组合多个抖动缓冲区应该为给定数量的样本提供最佳质量(比简单地以分辨率的倍数渲染等效数量的样本并按比例缩小的常规网格更好)但具有多个渲染通道的额外开销。它的优点是不受渲染目标的最大支持大小的限制,并且允许您选择几乎任意级别的 AA(尽管如果组合许多抖动缓冲区,您必须注意精度问题)。

opengl.org 上的文章“Antialiasing with Accumulation Buffer”描述了如何修改投影矩阵以进行抖动采样(OpenGL 但数学基本相同)。Alexander Keller 和 Wolfgang Heidrich 的论文“Interleaved Sampling”讨论了该技术的扩展,该技术以更多渲染通道为代价为您提供更好的采样模式。抱歉没有提供链接 - 作为新用户,我每个答案只能发布一个链接。谷歌应该会为您找到它们。

如果您想将渲染路径转到更大的缓冲区并进行下采样,但又不想受到最大允许渲染目标大小的限制,那么您可以使用此处所述的偏心投影矩阵生成平铺图像。

于 2009-07-16T01:01:59.213 回答
1

您总是可以渲染为宽度和高度两倍的纹理(即大小的 4 倍),然后对其进行超采样。

诚然,如果卡无法创建 4 倍于后台缓冲区大小的纹理,您仍然会遇到问题......

编辑:我想到了另一种方法。

如果您在视图矩阵中以微小的抖动重复帧 n 次,您将能够生成任意数量的图像,然后您可以将它们添加在一起以形成非常高度抗锯齿的图像。好处是,它可以在任何可以渲染图像的机器上工作。显然,它的速度较慢。当你这样做时,256xAA 确实看起来不错!

于 2009-07-14T08:13:33.997 回答
0

这篇文章http://msdn.microsoft.com/en-us/library/bb172266(VS.85).aspx似乎暗示您可以使用渲染状态标志 D3DRS_MULTISAMPLEANTIALIAS 来控制它。您是否可以创建启用了抗锯齿功能的设备,但使用此渲染状态标志将其关闭以进行屏幕渲染并打开屏幕外渲染?

不过,我自己还没有尝试过。

于 2009-07-15T07:19:47.607 回答