Клонировать визуализированное изображение в окно/экран для обработки

Фон

У меня есть программа для разработки систем управления автомобилем, которая использует комбинацию языка сценариев TCL и OpenGL для дополнительной визуализации поведения автомобиля при движении по дороге.

Что я делаю, так это реализую для него поддержку OculusRift, и до сих пор мне удалось решить сенсорную часть, и, щелкнув правой кнопкой мыши окно, в котором едет машина, я могу отправить его в oculus rift. Пока это выглядит так: Youtube-Video

Визуальная часть программы уже имеет множество функций и включает в себя такие параметры, как настройка FOV, объективов типа «рыбий глаз», ориентация камеры, вид изнутри автомобиля и т. д.

Осмотрев папку с программным обеспечением, я нашел файл TCL со следующими строками:

// ... cut here

gl pushmatrix
gl loadidentity
gl translate $x $y $z
gl rotate $xrot 1 0 0
gl rotate $yrot 0 1 0
gl rotate $zrot 0 0 1
gl translate $offx $offy $offz
lassign [lrange [OGL get modelviewmatrix] 12 14] tx ty tz
gl popmatrix


dict set ::View($view) CameraMode FixedToBodyA
dict set ::View($view) xrot $xrot
dict set ::View($view) yrot $yrot
dict set ::View($view) zrot [expr $zrot + $zrot_eyeAngle]
dict set ::View($view) dist $conf(dist)
dict set ::View($view) VPtOffset_x $tx
dict set ::View($view) VPtOffset_y $ty
dict set ::View($view) VPtOffset_z $tz
dict set ::View($view) FieldOfView $conf(fov)
dict set ::View($view) AspectRatio $conf(AspectRatio)

return;
}

Я не нашел ни одной строки, которая обрабатывает сам рендеринг, но команды "gl" было достаточно, чтобы я понял, что этот файл TCL запускается непосредственно в процессе рендеринга. Поэтому я расширил вышеизложенное следующим образом:

// load a self written DLL that wraps OVR functionality (Github link bellow)

# now run tclovrGetData() from the loaded DLL to get sensor data
set data [tclovrGetData] 
// data = x y z xrot yrot zrot

gl pushmatrix
gl loadidentity
gl translate $x $y $z
gl rotate $xrot 1 0 0
...

Ссылка Github на DLL

Как вы можете видеть на видео, на мониторе все выглядит хорошо, но, как мы знаем, линзы Rift вносят искажения (которые для меня были незначительными) и некоторые хроматические аберрации.

Моя идея

Я хочу захватить это «изображение/текстуру/кадр» на экране в видео каждые 10-20 мс (я все еще новичок в терминологии) и выполнить для него некоторую цветовую фильтрацию (я хочу посмотреть, смогу ли я уменьшить Хроматическая аберрация). Затем, возможно (чтобы все было независимо), создайте новое окно с измененным изображением и отправьте его в Rift. В основном получите изображение в требуемом «формате», чтобы иметь возможность выполнять на нем вычисления.

Моя идея заключалась в том (поскольку мы привязаны к процессу рендеринга) добавить несколько дополнительных строк в вышеуказанный файл TCL, которые вызывают дополнительные функции внутри моей DLL, которые могут делать следующее:

// Begin Oculus rendering loop
//1. get frame that is currently being rendered (in this process)
//2. copy this frame to memory
//3. perform some operations (color filtering) on this frame in memory
//4. send this frame to a new window

Теперь мой вопрос:

  • Возможно ли что-то подобное?
  • Может ли кто-нибудь указать мне правильное направление? т.е. некоторые функции gl, которые я мог бы использовать?
  • Может, Direct3D тоже работает?

Я прочитал этот пост в stackoverflow, но не смог понимать :/


person Skavee    schedule 05.11.2014    source источник
comment
Разве аппаратное обеспечение дисплея не должно справляться с такими вещами за вас? Необходимость делать в программном обеспечении то, что аппаратное обеспечение должно обрабатывать, никогда не будет эффективным или разумным…   -  person Donal Fellows    schedule 05.11.2014
comment
Да, должно. Что ж, OculusRift все еще находится в стадии разработки. Я также не знаю, выполняется ли при рендеринге с использованием программного обеспечения Oculus какая-то постобработка, чтобы минимизировать это. Но, по крайней мере, я не вижу коррекции хроматических аберраций, исходящей от линз. Мой первый план состоял в том, чтобы использовать функции рендеринга Oculus. Но я действительно был ошеломлен, особенно потому, что у меня был ограниченный доступ к программному обеспечению симулятора, и поэтому я точно не знал, как получить информацию о текстуре / кадре, чтобы перенаправить их в механизм рендеринга Oculus.   -  person Skavee    schedule 06.11.2014


Ответы (1)


Возможно ли что-то подобное?

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

Может ли кто-нибудь указать мне правильное направление? т.е. некоторые функции gl, которые я мог бы использовать?

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

Более быстрое решение

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

В зависимости от доступных функций OpenGL, которые вы можете использовать, существуют методы для выполнения всей обработки изображения на графическом процессоре. Самым простым может быть использование шейдера:

  1. Рендеринг сцены в фреймбуфер
  2. Нарисуйте текстурированный квадрат, где текстура из (1), во фрагментном шейдере проделайте все необходимые операции.

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

person BDL    schedule 05.11.2014
comment
Спасибо за ответ. Если я правильно прочитал это, мне в основном нужно привязать пункт назначения FB к нашему собственному FB, выполните обработку, а затем привяжите наш FB обратно к экранному буферу (0). Одна вещь все еще немного неясна. Я предполагаю, что может быть только один целевой FB для каждого процесса, и поэтому glBindFramebuffer(GL_FRAMEBUFFER, fbo); свяжет правильное изображение (в окне) с нашим FB, предполагая, что я делаю этот вызов из того же процесса. - person Skavee; 05.11.2014
comment
Приложение может иметь только один задний буфер, но несколько объектов кадрового буфера. - person BDL; 05.11.2014
comment
Ладно, кажется, я начинаю понимать. По сути, если я сделаю следующее: glBindFramebuffer(GL_FRAMEBUFFER, fbo); // now do operations on fbo glBindFramebuffer(GL_FRAMEBUFFER, 0); я бы фактически выбрал fbo в качестве цели для рендеринга, затем я бы обработал то, что находится внутри fbo, и как только я нарушу границу в 3-й строке. Что в fbo будет вынесено на экран? - person Skavee; 05.11.2014
comment
да. FBO позволяют выполнять рендеринг в текстуры или буферы рендеринга. Когда вы привязываете 0 к GL_FRAMEBUFFER, задний буфер окна привязывается. - person BDL; 05.11.2014