D3D9中的抗锯齿/多重采样

时间:2009-07-11 17:40:41

标签: directx direct3d antialiasing multisampling

我正在D3D9中编写一个3D建模应用程序,我希望尽可能广泛地兼容。这意味着使用很少的硬件相关功能,即多重采样。然而,虽然实时渲染不需要完美无瑕,但我确实需要提供漂亮的屏幕捕获,没有多重采样,看起来很混乱和差。

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

首先,这里是我如何创建screencapture的示例。我知道只保存已经渲染的帧的后备缓冲区更简单,但是我需要能够保存与实际渲染窗口不同的维度图像 - 这就是我这样做的原因。为简洁起见,省略了错误检查,恢复状态代码和释放资源。 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()的调用,这是我希望我可以用D3DMULTISAMPLE_4_SAMPLES替换pp.MultiSampleType的地方,但这不起作用。

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

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

任何智慧或指示都会非常感激......

谢谢!

3 个答案:

答案 0 :(得分:3)

通过渲染到更大的缓冲区并缩小或组合抖动缓冲区来进行超级采样可能是您最好的选择。组合多个抖动缓冲区应该为给定数量的样本提供最佳质量(优于常规网格,只需在分辨率的倍数下缩放相同数量的样本并缩小),但具有多个渲染过程的额外开销。它的优点是不受渲染目标的最大支持大小的限制,并允许您选择几乎任意级别的AA(尽管如果组合许多抖动缓冲区,您将不得不注意精度问题)。 / p>

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

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

答案 1 :(得分:1)

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

不可否认,如果卡片不能创建4倍于后台缓冲区大小的纹理,你仍会遇到问题......

编辑:还有另一种想到的方式。

如果您使用微小的抖动对视图矩阵重复n次,您将能够生成任意数量的图像,然后您可以将它们一起添加到一起以形成非常高度抗锯齿的图像。奖金是,它可以在任何可以渲染图像的机器上工作。显然,它虽然慢了。当你这样做时,256xAA确实看起来很棒!

答案 2 :(得分:0)

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

我自己也没试过。