对一个老问题的新回应,但我遇到了这个问题,并认为我会提供一个答案,以防其他人在遇到这个问题时遇到它。这是我的包装器和函数的精简版本的解决方案。
我有一个游戏,其中渲染器有几个层,其中一个是几何层。渲染时,它遍历所有层,调用它们的 Draw 函数。每个层都有自己的 RenderTarget 包装器实例。当图层绘制时,它“激活”其渲染目标,将缓冲区清除为 alpha,绘制场景,然后“停用”其渲染目标。在所有图层都绘制到它们的渲染目标之后,所有这些渲染目标然后组合到后缓冲区以生成最终图像。
GeometryLayer::Draw
* 激活此层使用的渲染目标
* 设置所需
的渲染状态 * 清除缓冲区
* 绘制几何体
* 停用此层使用的渲染目标
void GeometryLayer::Draw( const math::mat4& viewProjection )
{
m_pRenderTarget->Activate();
pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,TRUE);
pDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
pDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
pDevice->Clear(0,0,D3DCLEAR_TARGET,m_clearColor,1.0,0);
pDevice->BeginScene();
pDevice->Clear(0,0,D3DCLEAR_ZBUFFER,0,1.0,0);
for(auto it = m->visibleGeometry.begin(); it != m->visibleGeometry.end(); ++it)
it->second->Draw(viewProjection);
pDevice->EndScene();
m_pRenderTarget->Deactivate();
}
我的 RenderTarget 包装器包含一个 IDirect3DTexture9* (m_pTexture),它与 D3DXCreateTexture 一起使用以生成要绘制到的纹理。它还包含一个由纹理给出的 IDirect3DSurface9* (m_pSurface)。它还包含另一个 IDirect3DSurface9* (m_pMSAASurface)。
在我的 RenderTarget 的初始化中,有一个启用多重采样的选项。如果关闭此选项,则 m_pMSAASurface 将初始化为 nullptr。如果启用此选项,则会使用 IDirect3DDevice9::CreateRenderTarget 函数为您创建 m_pMSAASurface,并将我当前的多重采样设置指定为第 4 和第 5 个参数。
RenderTarget::Init
* 创建纹理
* 从纹理中获取表面(添加到表面的引用计数)
* 如果是 MSAA,则创建启用 msaa 的表面
void RenderTarget::Init(const int width,const int height,const bool enableMSAA)
{
m_bEnableMSAA = enableMSAA;
D3DXCreateTexture(pDevice,
width,
height,
1,
D3DUSAGE_RENDERTARGET,
D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&m_pTexture;
);
m_pTexture->GetSurfaceLevel(0,&m_pSurface);
if(enableMSAA)
{
Renderer::GetInstance()->GetDevice()->CreateRenderTarget(
width,
height,
D3DFMT_A8R8G8B8,
d3dpp.MultiSampleType,
d3dpp.MultiSampleQuality,
false,
&m_pMSAAsurface,
NULL
);
}
}
如果此 MSAA 设置关闭,则 RenderTarget::Activate 将 m_pSurface 设置为渲染目标。如果启用此 MSAA 设置,则 RenderTarget::Activate 将 m_pMSAASurface 设置为渲染目标并启用多重采样渲染状态。
RenderTarget::Activate
* 存储当前渲染目标(添加到该表面的引用计数)
* 如果不是 MSAA,则将表面设置为新的渲染目标
* 如果 MSAA,将 msaa 表面设置为新的渲染目标,启用 msaa 渲染状态
void RenderTarget::Activate()
{
pDevice->GetRenderTarget(0,&m_pOldSurface);
if(!m_bEnableMSAA)
{
pDevice->SetRenderTarget(0,m_pSurface);
}
else
{
pDevice->SetRenderTarget(0,m_pMSAAsurface);
pDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS,true);
}
}
如果此 MSAA 设置关闭,则 RenderTarget::Deactivate 只会恢复原始渲染目标。如果启用此 MSAA 设置,RenderTarget::Deactivate 也会恢复原始渲染目标,但也会将 m_pMSAASurface 复制到 m_pSurface。
RenderTarget::Deactivate
* 如果是 MSAA,则禁用 MSAA 渲染状态
* 恢复前一个渲染目标
* 丢弃前一个渲染目标上的引用计数
void RenderTarget::Deactivate()
{
if(m_bEnableMSAA)
{
pDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS,false);
pDevice->StretchRect(m_pMSAAsurface,NULL,m_pSurface,NULL,D3DTEXF_NONE);
}
pDevice->SetRenderTarget(0,m_pOldSurface);
m_pOldSurface->Release();
m->pOldSurface = nullptr;
}
当渲染器稍后向几何层询问其 RenderTarget 纹理以便将其与其他层组合时,该纹理具有从 m_pMSAASurface 复制的图像。假设您使用的是促进 Alpha 通道的格式,则此纹理可以与其他纹理混合,就像我正在处理多个图层的渲染目标一样。