Сглаживание / Мультисэмплинг в D3D9 - PullRequest
1 голос
/ 11 июля 2009

Я пишу приложение для 3D-моделирования в D3D9, которое я хотел бы сделать максимально совместимым. Это означает использование нескольких аппаратно-зависимых функций, то есть мультисэмплинг. Однако, хотя рендеринг в реальном времени не обязательно должен быть безупречным, мне нужно обеспечить привлекательные снимки экрана, которые без мультисэмплинга выглядят довольно сглаженными и плохими.

Для создания снимков экрана я создаю временную поверхность в памяти, визуализирую сцену на ней один раз, затем сохраняю ее в файл. Моей первой мыслью о том, как я могу добиться захвата сглаживания, было создание моей трафаретной поверхности вне экрана как мультисэмпла, но, конечно, 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 (), в котором я надеялся заменить pp.MultiSampleType, например, D3DMULTISAMPLE_4_SAMPLES, но это не сработало.

Моей следующей мыслью было создание совершенно другого LPDIRECT3DDEVICE9 как D3DDEVTYPE_REF, который всегда поддерживает D3DMULTISAMPLE_4_SAMPLES (независимо от видеокарты). Однако все мои ресурсы (сетки, текстуры) были загружены в m_d3ddev, мое устройство HAL, поэтому я не мог использовать их для рендеринга сцены под устройством REF. Обратите внимание, что ресурсы могут быть разделены между устройствами под Direct3d9ex (Vista), но я работаю над XP. Поскольку ресурсов довольно много, перезагрузка всего для визуализации этого одного кадра, а затем их выгрузка слишком неэффективны по времени для моего приложения.

Я рассмотрел другие варианты сглаживания изображения после захвата (например, фильтр размытия 3x3), но все они дали довольно дрянные результаты, поэтому я действительно хотел бы попытаться получить сглаженную сцену прямо из D3D, если возможно. ...

Любая мудрость или указатели будут с благодарностью оценены ...

Спасибо!

Ответы [ 3 ]

3 голосов
/ 16 июля 2009

Гиперсэмплирование с помощью рендеринга в больший буфер и уменьшения или объединения дрожащих буферов, вероятно, является вашей лучшей ставкой. Комбинирование нескольких дрожащих буферов должно дать вам наилучшее качество для заданного количества выборок (лучше, чем обычная сетка от простого рендеринга эквивалентного количества выборок при кратном разрешении и уменьшении), но имеет дополнительные издержки на несколько проходов рендеринга. Он имеет то преимущество, что не ограничивается максимальным поддерживаемым размером вашей цели рендеринга, и позволяет вам выбирать произвольный уровень АА (хотя вам придется остерегаться проблем с точностью при объединении большого количества дрожащих буферов).

В статье «Сглаживание с помощью накопительного буфера» на opengl.org описывается, как изменить матрицу проекции для дрожащей выборки (OpenGL, но математика в основном такая же). В статье Александра Келлера и Вольфганга Гейдриха «Чередованная выборка» рассказывается о расширении техники, которая дает вам лучший образец выборки за счет еще большего количества проходов рендеринга. Извините, что не предоставил ссылки - как новый пользователь я могу опубликовать только одну ссылку на ответ. Google должен найти их для вас.

Если вы хотите пойти по пути рендеринга в больший буфер и сэмплирование с понижением частоты, но не хотите ограничиваться максимально допустимым размером рендера, то вы можете сгенерировать мозаичное изображение, используя нецентральные проекционные матрицы, как описано здесь .

1 голос
/ 14 июля 2009

Вы всегда можете визуализировать текстуру, которая в два раза больше ширины и высоты (т.е. в 4 раза больше размера), а затем суперсэмплировать ее вниз.

По общему признанию, у вас все еще будут проблемы, если карта не сможет создать текстуру в 4 раза больше размера заднего буфера ...

Редактировать: Есть еще один способ, который приходит на ум.

Если вы повторяете кадр с крошечными дрожаниями в матрице вида, вы сможете создать столько изображений, сколько захотите, а затем потом сложить их вместе, чтобы сформировать изображение с очень высоким сглаживанием. Бонус в том, что он будет работать на любой машине, которая может визуализировать изображение. Это, очевидно, медленнее, хотя. Тем не менее, 256xAA действительно выглядит хорошо, когда вы делаете это!

0 голосов
/ 15 июля 2009

Эта статья http://msdn.microsoft.com/en-us/library/bb172266(VS.85).aspx, кажется, подразумевает, что вы можете использовать флаг состояния рендеринга D3DRS_MULTISAMPLEANTIALIAS для управления этим. Можете ли вы создать свое устройство с включенным сглаживанием, но выключить его для рендеринга экрана и включить для рендеринга за пределами экрана, используя этот флаг состояния рендеринга?

Хотя я и сам не пробовал.

...