Directx D3D9中的抗锯齿/多重采样

Directx D3D9中的抗锯齿/多重采样,directx,direct3d,antialiasing,multisampling,Directx,Direct3d,Antialiasing,Multisampling,我正在用D3D9编写一个3d建模应用程序,我想使其尽可能广泛地兼容。这意味着使用很少的硬件相关功能,即多采样。然而,虽然实时渲染不需要完美无瑕,但我确实需要提供好看的屏幕截图,如果没有多重采样,屏幕截图看起来非常锯齿,而且很差 为了生成屏幕截图,我在内存中创建一个临时曲面,将场景渲染一次,然后将其保存到文件中。我第一个想到如何实现抗锯齿捕获的方法是将屏幕外的模具表面创建为多采样,但DX当然不允许这样做,因为设备本身已使用D3DMULTISAMPLE\u NONE初始化 首先,这里有一个我如何创建

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

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

首先,这里有一个我如何创建截图的示例。我知道只保存已渲染帧的backbuffer会更简单,但是我需要能够保存与实际渲染窗口尺寸不同的图像-这就是我这样做的原因。为简洁起见,此处列出了错误检查、恢复状态代码和释放资源。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()的调用,我希望在这里可以将pp.MultiSampleType替换为I.e.
d3dmmultisample\u 4\u SAMPLES
,但这不起作用

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

我查看了其他用于图像捕获后消除混叠的选项(即3x3模糊过滤器),但它们都生成了非常糟糕的结果,因此我真的很想尝试在可能的情况下从D3D中获得消除混叠的场景

任何智慧或建议都将不胜感激


谢谢

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

诚然,如果卡不能创建一个4倍于后缓冲区大小的纹理,你仍然会遇到问题

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

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

本文似乎暗示您可以使用渲染状态标志D3DRS_multisamplentialias来控制这一点。是否可以在启用抗锯齿的情况下创建设备,但在屏幕渲染时将其关闭,在使用此渲染状态标志进行屏幕外渲染时将其打开


不过我自己也没有尝试过。通过渲染到更大的缓冲区并缩小比例或结合抖动的缓冲区进行超级采样可能是最好的选择。组合多个抖动缓冲区应该可以为给定数量的采样提供最佳质量(比普通网格更好,因为它只需以分辨率的倍数渲染相等数量的采样并按比例缩小),但会增加多个渲染过程的额外开销。它的优点是不受渲染目标支持的最大大小的限制,并且允许您选择几乎任意级别的AA(尽管如果组合许多抖动的缓冲区,您必须注意精度问题)

opengl.org上的文章“使用累积缓冲区进行抗锯齿”描述了如何修改抖动采样的投影矩阵(opengl,但数学基本相同)。亚历山大·凯勒(Alexander Keller)和沃尔夫冈·海德里希(Wolfgang Heidrich)的论文《交错采样》(Interleave Sampling)讨论了该技术的扩展,该技术以牺牲更多渲染过程为代价,提供了更好的采样模式。很抱歉没有提供链接-作为一个新用户,我只能发布每个答案一个链接。谷歌应该为你找到它们


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

为什么不检测多采样功能,并在可用的地方使用它呢(可能带有禁用性能的选项)?我的意思是,这并不是说你通过做你想做的事情来提高兼容性。好吧,这是我最后的选择…但我真正想做的是能够提供抗锯齿图像,而不管视频卡的性能如何。我不太关心实时渲染的质量(是的,这肯定会提高兼容性-因为参考设备总是支持多重采样,所以如果我可以使用那种类型的设备来渲染屏幕截图,那应该很酷。但是仍然存在上述问题,所以我希望有其他解决方案…)+1:超级采样是我想到的唯一一件事,它可以在没有GPU支持的情况下完成。我不确定是否要更改视图矩阵。我想你会因为透视图的更改而得到其他瑕疵。不过,看看会发生什么会很有趣。我想这取决于渲染的场景。是的……我也想到了这个,一个看起来这可能是我必须要走的路。不知何故,它没有被多样本广泛支持的内置设施似乎很奇怪,因为超过一半的样本都没有