Механизм, через который работает 3D Vision на картах NVidia, довольно прост - драйвер добавляет footer в каждый вершинный шейдер таким образом, чтобы позиция вершины в clip space различалась для правого и левого кадра (см. NVIDIA 3D Vision Automatic Best Practices Guide). Таким образом стерео автоматически работает в большинстве трёхмерных игр и даже тех, которые изначально под него не разрабатывались.
Проблемы начинаются в случаях, если при рендеринге использовались какие-то нечестные техники или в случае различных deferred подходов - картинка обычно выглядит неестественно, если не сказать хуже. 3D Vision работает на уровне геометрического пайплайна, во всех остальных случаях нужно что-то делать руками самостоятельно. Вот недавно по работе мне было поручено исправить некоторые огрехи нашего движка при работе в стерео-режиме. Как выяснилось, одна из техник использовала механизм отложенного рендеринга партиклов, при котором цвет и дополнительная информация сначала рисуются в промежуточный render target, а потом изображение из него "вклеивается" в основной кадр. Понятно, что 3D Vision проплывает в этом случае по левому борту, и необходимы поправки уже в пиксельном шейдере. Но вот загвоздка - стандартными средствами Direct3D выяснить какой из кадров - правый или левый, рисуется в данный момент - в шейдере невозможно, а без возможности их различать нет и возможности что-либо изменить.
Начав искать в Сети методы решения подобных проблем, я обнаружил, что NVidia предоставляет пример StereoIssues в NVIDIA Graphics SDK 11, в котором имеется код по созданию специальной "стереотекстуры" (файл nvstereo.h). Стереотекстура позволяет семплировать в шейдере данные, которые будут различаться для левого и правого кадра, так что, например, можно вычислить смещение для каждого кадра по формуле:
pos.x += separation * (pos.w - convergence)
Это очередной хак на уровне D3D9/10 API, и для его включения необходимо разместить fourcc 'NV3D' в последней строке staging текстуры формата RGBA32F, данные из которой впоследствии необходимо скопировать в обычную текстуру посредством UpdateSurface()/CopySubresourceRegion(). При копировании драйвер разместит данные для левого кадра в целевой текстуре, а для правого (как я понимаю) создаст shadow copy и разместит в ней данные для правого кадра, взяв их по определённому адресу (см. раздел 3D Video в GDC09 3DVision The In and Out). Если всё сделать в том порядке, который предлагается в примере, то шейдер действительно будет семплировать различные данные по одним и тем же текстурным координатам. Ну а дальше уже дело техники...
Одним из подводных камней, о который я споткнулся, является то, что недостаточно просто при старте скопировать данные в стереотекстуру и в дальнейшем пользоваться ею. Всё дело в том, что 3D Vision не включается с первым же кадром: драйвер сначала собирает некоторую информацию о первых кадрах, и только потом включается стереорежим. После его включения и нужно создавать стереотекстуру, а лучше всего проверять переключение режимов функцией NvAPI_Stereo_IsActivated() из NvAPI, и обновлять её после изменения результата. А в примере StereoIssues идут ещё дальше: т. к. пользователь может динамически изменять такие параметры 3D Vision как EyeSeparation и Convergence, то необходимо отслеживать изменения этих параметров и своевременно обновлять данные в стереотекстуре.
Тоже намучися помню с этим.
ОтветитьУдалитьКстати ты функцию NvAPI_Stereo_IsActivated вызываешь каждый кадр?
Если да, то могу посоветовать глянуть на механизм windows messenges для того чтобы не вызывать ее каждый кадр, а только по требованию. Потому что у нас например вызов этой функции приводил к жестким тормозам.( там видимо идет обращение к драйверу, который в свою очередь уходит в защищенный режим т.е. Свитчит контекст из юзер в кернел мод)
Вызываю в каждом кадре :(
ОтветитьУдалитьМы в основном работаем с дебажным билдом, final собирается отдельно скриптом, поэтому fps не особо и разницу заметить трудно. Но вообще то что ты описал было в XDDM, в WDDM всё по-другому, а т. к. 3D Vision работает только в Vista/7, то причина тормозов должна быть в чём-то другом. Вообще я считал что функция просто проверяет флажок в драйвере и всё.
Да, сделали проверку значений раз в 20 кадров - думаю, это самое простое решение.
ОтветитьУдалитьХа-ха, теперь смешно после предыдущего моего комментария это читать :-)
ОтветитьУдалить