Итак, новый ответ на старый вопрос, но я натолкнулся на это и подумал, что дам ответ на тот случай, если кто-нибудь еще столкнется с ним, столкнувшись с этой проблемой. Вот решение с урезанной версией моих оболочек и функциями для нее.
У меня есть игра, в которой у рендерера есть несколько слоев, один из которых - слой геометрии. При рендеринге он перебирает все слои, вызывая их функции Draw. Каждый слой имеет свой экземпляр моей оболочки RenderTarget. Когда слой рисует, он «активирует» свою цель рендеринга, очищает буфер до альфы, рисует сцену, а затем «деактивирует» свою цель рендеринга. После того, как все слои отрисованы к своим целям рендеринга, все эти мишени рендеринга затем объединяются в резервный буфер для получения окончательного изображения.
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. Если эта опция включена, m_pMSAASurface создается для вас с помощью функции IDirect3DDevice9 :: CreateRenderTarget, в которой в качестве 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 :: Деактивировать
* Если 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;
}
Когда Renderer позже запрашивает геометрический слой для его текстуры RenderTarget, чтобы объединить его с другими слоями, эта текстура скопировала изображение из m_pMSAASurface. Предполагая, что вы используете формат, облегчающий альфа-канал, эту текстуру можно смешивать с другими, как я делаю с целями рендеринга нескольких слоев.