Автор: Владимир Дьячков «Nikola Tesla»

Опубликовано: 05.03.2008

Изменено: 05.03.2008

Постоянная ссылка

Комментарии [0]

Реализация процессора эффектов постобработки. Часть 1 - Разработка фреймворка


Начало большой статьи по реализации популярных пост-эффектов в современных 3D приложениях. В первой части описывается разработка фреймворка на OpenGL и разбирается синтаксис файла пост-эффекта.



Страницы: 1 2 3
Содержание

Предисловие
Введение
Разработка фреймворка для реализации пост-эффектов
      Описание проблемы и предлагаемое решение
      Архитектура фреймворка
      Синтаксис файла пост-эффекта
      Реализация фреймворка с использованием библиотеки OpenGL
Список источников

Предисловие

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

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

Читать такую большую статью - труд, старвнимый, пожалуй, с написанием самой статьи, поэтому, прежде чем приступать к ее чтению, позвольте вас хоть как-то на это простимулировать. Во второй части статьи вы можете найти бинарник (10 Мб) приложения демонстрирующего несколько различных пост-эффектов. Все эффекты выполняются в одном приложении, но не фиксирваны в его коде. Каждый пост-эффект описывается в специальном конфигурационном файле. Для полноценного функционирования демки необходимо железо уровня не ниже GeForce 6600.

Введение

В этой статье я попытаюсь осветить проблему интегрирования пост-эффектов в приложения использующие трехмерную графику, а также создать несколько популярных пост-эффектов на основе предлагаемого решения – фреймворка для реализации пост-эффектов. В первой части статьи будет рассмотрена архитектура такого фреймворка и способ описания пост-эффектов на основе специальных конфигурационных файлов. Также будут рассмотрены некоторые аспекты реализации постобработки средствами C++ и OpenGL. Во второй части статьи речь пойдет о реализации некоторых пост-эффектов на основе разработанного фреймворка. Как можно будет заметить, последний существенно упрощает создание и внедрение пост-эффекта в приложение. Жесткая фиксация пост-эффекта в коде графического движка по сравнению с описанием пост-эффекта в текстовом файле, или в специальном редакторе, создает дополнительные трудности, не обладает достаточной гибкостью и сильно зависит от программиста. Использование специальных файлов для конфигурации пост-эффектов позволяет забыть обо всех тонкостях работы с 3D API и сосредоточиться непосредственно на создании пост-эффекта, в результате чего создание нового эффекта с нуля занимает всего несколько минут.

Статья будет интересна как начинающим, так и людям, профессионально занимающимся 3D программированием. От читателя требуется знание принципов ООП и языка C++, а также знание хотя бы одного 3D API. Если вы еще не знакомы с OpenGL или Direct3D, то прежде чем читать эту статью, вам лучше обратиться к соответствующей литературе по этим 3D API, например [OGL] или [Lun]. Если вы уже знакомы с библиотекой OpenGL 1.2, но не знакомы с расширениями OpenGL, то вам следует ознакомиться с использованием расширений, например по книге [Bor05]. Также необходимо знание одного из высокоуровневых языков программирования шейдеров, желательно GLSL. Начинать знакомство с GLSL лучше с чтения "Оранжевой книги" [Rost05], а HLSL с чтения [Lun]. По языку Cg тоже имеется информация, например на сайте nVidia [NVCg] или в книге [CG].

Разработка фреймворка для реализации пост-эффектов

Описание проблемы и предлагаемое решение

Современные тенденции развития игрового бизнеса зачастую подразумевают разбиение процесса разработки игры на несколько параллельных этапов. Каждый, кто занят в проекте, занимается своим делом и отвечает за определенный пункт, как и при любом техпроцессе, идет четкое разделение труда. С точки зрения такого разделения нам необходимо знать, кому следует доверить задание пост-эффектов. Думаю очевидно, что за этот пункт должны отвечать дизайнеры пост-эффектов или дизайнеры уровней, но никак не программисты. Именно дизайнеры в нужный момент вправе задавать и создавать различные пост-эффекты, а также настраивать их параметры.

За примером далеко ходить не надо. Представим, что на некотором игровом уровне есть некая зона, например зона с повышенной радиоактивностью (привет Сталкеру =), и нужно показать, что при входе в эту зону картинка на экране искажается, имитируя спазмы у персонажа, например потемнение в глазах, двоится изображение и т.п. В этом случае проще в редакторе уровня предусмотреть возможность задания дизайнером как размеров и положения такой зоны, так и действующий в ней пост-эффект. Тут же можно будет задать одним из параметров степень проявления этого эффекта в зависимости от расстояния до эпицентра радиации. Рядом можно предусмотреть редактор пост-эффектов, в котором описывается весь процесс "фильтрации" изображения, сколько и каких проходов надо выполнить для получения желаемого результата. Таким образом, мы добиваемся того, что задание пост-эффекта почти ничем не отличается от задания материала для модели в сцене. Необходимая гибкость будет обеспечена за счет того, что пост-эффекты станут еще одним типом контента игры, наподобие fx файлов Microsoft DirectX. Остается самое интересное - написать фреймворк, в котором будут работать заданные дизайнером пост-эффекты.

Итак, для начала определимся, что же такое фреймворк и что он из себя представляет. Фреймворк - довольно широкое понятие, и если верить wikipedia.org он обозначает "простую концептуальную структуру, используемую для решения сложной проблемной задачи". Или, что более подходит в нашем случае: Software Framework - каркас программной системы (или подсистемы). Он может включать вспомогательные программы, библиотеки кода, язык сценариев и другое ПО, облегчающее разработку и объединение разных компонентов большого программного проекта. Теперь определимся, что же будет представлять собой фреймворк для реализации пост-эффектов. Очевидно, это будет набор C++ классов для реализации постобработки, а также парсер текстовых файлов, однозначно определяющих сам пост-эффект. Конечно, для полноценного фреймворка сюда нужно добавить, пожалуй, редактор пост-эффектов. Редактор нужен для того, чтобы дизайнер эффекта не копался в текстовом файле, а имел возможность мгновенно наблюдать воочию то, что у него получается. Но написание специализированного редактора пост-эффектов выходит за рамки данной статьи.

Следует отметить, что подобные фреймворки для реализации пост-эффектов давно не являются чем-то революционным. Если посмотреть в ресурсных файлах не очень старых игр, например XPand Rally Extreme, сделанной на движке Chrome Engine, то можно найти файлы, отвечающие за постпроцессинг. В Chrome Engine эти файлы имеют расширение .ppfx. Из названия видно сходство с .fx файлами, но очевидно это их собственный формат, не имеющий к DirectX никакого отношения.

Конечно, для создания эффектов и настройки их параметров проще использовать специально предназначенные для этого решения, например, такие как Render Monkey или FX Composer. Но нам в нашем приложении надо каким-то образом "переваривать" созданный где-либо эффект, и применять его к исходному изображению. Вот для этого и нужен настоящий фреймворк, он получает на вход файл пост-эффекта и "преобразует" его в набор взаимосвязанных 3D API объектов внутри приложения, или, иначе говоря, формирует сам пост-эффект. Затем созданный пост-эффект используется для обработки исходного изображения.

Архитектура фреймворка

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

Судя из названия пост-эффект должен применяться к уже отрендеренной сцене. Следовательно, перед постобработкой следует непосредственно сама обработка, или непосредственно рендеринг трехмерной сены. Сначала вся 3D сцена, или ее часть, над которой необходимо выполнить постобработку, выводится в буфер в видеопамяти с последующим использованием полученного изображения как текстуры для постобработки, иначе говоря, производится рендеринг 3D сцены в текстуру Render To Texture (RTT).

Без аппаратной поддержки RTT, в OpenGL таким буфером может быть обычный задний буфер, располагающийся в видеопамяти ускорителя, с последующим копированием изображения в текстуру. При имеющейся аппаратной поддержке RTT это может быть либо PBuffer с привязкой к текстуре, либо же Frame Buffer Object (FBO, объект буфера кадра, расширение GL_EXT_framebuffer_object). Использование FBO дает серьезные преимущества по сравнению с остальными методами. Плюс ко всему, при использовании FBO возможен вывод одновременно в несколько цветовых буферов, так называемый Multiply Render Targets (MRT, расширение GL_ARB_draw_buffers). Более подробно узнать про использование FBO можно на официальном сайте OpenGL [OGLEXT], сайтах изготовителей видеокарт, а также из статей [FBO], [GD06a] и [S3DFBO]. Если версия OpenGL не поддерживает расширение Frame Buffer Object, то от идеи реализации на ней пост-эффектов отказываться не стоит, несложные эффекты она потянет, но, например, рендеринг в несколько целей - нет. Поддержка FBO (расширение GL_EXT_framebuffer_object) имеется на видеокартах NVIDIA, начиная с FX5200 и на ATI, начиная с Radeon 9500. Главное чтобы были установлены свежие драйвера, так как в некоторых случаях наличие и возможности этого расширения напрямую зависят от версии драйвера.

После того как мы получили текстуру с исходным изображением, можно выполнить постобработку. Осуществляется она выводом прямоугольника (Screen Quad) в текущий фреймбуфер с применением этой текстуры и соответствующего пост-эффекту шейдера.

Далее все зависит от конкретного эффекта. Если эффект несложный, например необходимо перевести изображение в монохром и добавить эффект старой кинопленки, то можно осуществлять вывод этого изображения сразу в задний буфер. Если эффект более сложный, например bloom, и требует нескольких проходов по изображению/ям, то будут необходимы дополнительные буферы для ввода - рендер-таргеты (render-targets). Таким образом, количество и форматы рендер-таргетов зависят от конкретного эффекта, и задаются они на этапе выполнения. Описать формат и размер рендер-таргета можно при задании пост-эффекта в текстовом файле.

Итак, определимся с необходимыми классами. Во-первых, желательно абстрагироваться от конкретного 3D API и завернуть все обращения к функциям 3D API в отдельные классы-обертки. Благодаря этому система станет удобнее и гибче, можно использовать один и тот же код загрузки, настройки и применения пост-эффекта независимо от выбранного 3D API. Во-вторых, надо определиться с тем, какие объекты будут присутствовать в процессе постобработки.

Нам понадобятся следующие основные абстрактные классы-обертки, реализации которых будут уникальны для каждого 3D API. В скобках указаны имена соответствующих классов.

  • текстура (Texture) - представляет собой текстурный объект, может быть двумерной или кубической текстурой, доступны функции привязки bind() и задания параметров;
  • шейдер (ShaderProgram) - представляет собой шейдерный объект, доступны функции установки значений uniform переменных, функция привязки, компиляции и пр.;
  • фреймбуфер (FrameBuffer) - или рендер-таргет - объект для вывода изображения, к нему могут быть привязаны текстуры. В OpenGL реализуется на основе расширений PBuffer и FBO;
  • рендерер (View) - основной класс для настройки состояния конвейера рендеринга, создания окна, установки видеорежима, а также создания объектов текстур, шейдеров, фреймбуферов и пр. Этот класс также управляет установками текущих матриц преобразований, очисткой содержимого буферов, сменой переднего и заднего буфера и т.п. За изменением состояния рендерера следит специальный менеджер RendererState, любое обращение к 3D API, которое изменяет состояние рендерера, должно происходить через этот менеджер. Это необходимо как для уменьшения кол-ва обращений к драйверу, так и для отслеживания состояния рендерера. Присутствует также абстрактный класс RendererConfig, который получает и хранит информацию о возможностях видеокарты: количестве текстурных модулей, максимальном размере текстур, количестве MRT и т.п. RendererState и RendererConfig имеют свои реализации для OpenGL API;
  • проход фильтрации (PostprocFilterPass) - содержит все необходимые в процессе постобработки объекты, такие как текстуры, фреймбуфер и шейдер для обработки, обеспечивает взаимосвязь между ними, а также устанавливает и настраивает эти объекты перед постобработкой. Результатом применения прохода фильтрации к входному изображению/ям, располагающимся во входных текстурах, является картинка во фреймбуфере, которую в последствии можно использовать как входную текстуру для последующей обработки в другом проходе фильтрации;
  • фильтр (PostprocFilter) - это совокупность поочередно применяемых проходов фильтрации, с возможностью регулировать их последовательность. Или иными словами - это и есть сам пост-эффект, а точнее его представление в программе;
  • компилятор или загрузчик пост-эффектов (PostprocCompiler) - модуль, отвечающий за загрузку файлов пост-эффектов. На вход получает имя загружаемого файла, а на выходе - указатель на готовый экземпляр класса PostprocFilter. Состояние последнего однозначно определяется набором проходов фильтрации описанным в файле.

Также понадобятся следующие вспомогательные классы:

  • менеджер ресурсов (ResourceMgr) и загрузчики таких ресурсов как текстуры, шейдеры GLSL, материалы и меши (последние 2 типа ресурсов для фреймворка избыточны, они служат лишь для функционирования демки пост-эффектов);
  • файловая система, система ввода, лог, таймер, системные переменные;
  • математическая библиотека;
  • набор классов рендерера: вершинные и индексные массивы, полигональная сетка, материал, uniform-переменные, источники освещения, пирамида видимости, камера, шрифт, биллбоард, ограничивающий параллелепипед и прочие необходимые для работы фреймворка и демки классы.

Далее будут рассмотрены реализации некоторых из этих классов для OpenGL.

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

На рисунке 1 показана возможная UML диаграмма классов архитектуры фреймворка.

Рис. 1. UML диаграмма основных классов фреймворка
Рис. 1. UML диаграмма основных классов фреймворка

Небольшие пояснения к диаграмме. Классы текстура (Texture) и шейдер (ShaderProgram) имеют одно сходство - это ресурсы приложения, и их желательно хранить унифицировано в менеджере ресурсов (ResourceMgr). Чтобы реализовать такую возможность эти классы наследуются от абстрактного класса Resource. Ниже будет представлено более подробное описание некоторых классов.

Теперь немного о том, как это работает.

После создания окна, настройки видеорежима, инициализации OpenGL рендерера и загрузки 3D сцены, выполняется загрузка и компиляция файла пост-эффекта:

	PostprocFilter * pp_filter;
	PostprocCompiler PostProcComp;
	...
	pp_filter = PostProcComp.compile("post_proc_fx_file.ppf");

При успешной загрузке файла пост-эффекта загрузчик PostProcComp создаст экземпляр класса PostprocFilter в соответствии с заданными в файле установками и возвратит указатель на пост-эффект pp_filter. Далее от нас требуется совсем немного. Сперва перед отрисовкой 3D сцены нужно вызвать метод pp_filter->begin(&camera); а после отрисовки - вызвать pp_filter->end(); где camera - объект камеры. Тогда все то, что будет отрисовываться между этими вызовами будет автоматически выводиться во входной рендер-таргет объекта pp_filter, и над этим изображением впоследствии будет выполняться постобработка. Чтобы выполнить пост-обработку нужно вызвать у пост-эффекта метод pp_filter->process(). При этом внутри этой функции автоматически происходит вся постобработка сцены. Обобщая вышесказанное, привожу следующий фрагмент кода:

...
// установка последовательности проходов заданных внутри 
// файла пост-эффекта (если требуется)
// (об этом позже)
pp_filter->setSequence("SEQ1");

// установка значений uniform переменных шейдеров (также если требуется)
pp_filter->getFilterPass(0)->getShader()->setUniform("time",timer->getTime());
PostprocFilterPass * pass = pp_filter->getFilterPass("DOWNLUMADAPT0");
if (pass)
	pass->getShader()->setUniform("dtime",FPS_counter->getFrameInterval());

// начало рендеринга 3D сцены, внутри pp_filter->begin() происходит установка
// текущим начального рендер-таргета
pp_filter->begin(&camera);

// отрисовка сцены
// рендерим скайбокс
skyBox->Render(view,&camera);
// затем проходимся по всем объектам-мешам сцены и ренерим их
for (unsigned i=0; i < meshes.size(); i++)
{
	meshes[i]->render(view,&camera);
}

// рендеринм воду...
water->render(view,camera);
// заканчили рендеринг 3D сцены
// внутри end() происходит переключение на задний буфер
pp_filter->end();
// теперь непостредственно постобработка всего того что мы 
// нарендерили в процессе постобоаботки в заднем буфере 
// мы получим обработанное изображение
pp_filter->process();
...

Все! Управляться с фреймворком действительно очень просто! При работе с пост-эффектом даже не нужно задумываться, каким образом происходит обработка. Фреймворк выступает здесь как черный ящик, в который следует положить файл пост-эффекта, вызвать в нужном месте несколько функций и получить на выходе обработанное изображение.

В итоге мы приходим к такой картине: все параметры эффектов, наличие и форматы рендер-таргетов, последовательность и число проходов, используемые шейдеры и текстуры - описываются в текстовом файле как некий сценарий или скрипт и однозначно определяют пост-эффект. Теперь настало время определиться с примерным синтаксисом такого макроязыка.

Синтаксис файла пост-эффекта

Ниже приведен пример такого файла для конфигурации пост-эффекта. Комментарии обозначаются символом "!" и комментируют всю строку целиком.

!----------------------------------
!	Postproc Filter	File
!----------------------------------
mm_heat.ppf
{
   ! описание используемых входных текстур
   input_texture  tex0
   {
	file	water_n.dds
   }

   ! описание используемых рендер-таргетов
   render_target  temp0
   {
	Width			512
	Height			512
	int_format		RGBA8
	texture			0
	depth_texture		24
   }

   ! описание используемых шейдеров
   shader  heat
   {
	file		PostProc/heat.glsl
	texture		FullSampler	0
	texture		DepthSampler	1
	texture		DistortSampler	2
	var_float	time	0.0
   }

   ! начальный рендер-таргет, в этот рендер-таргет будет 
   ! отрисовываться 3D сцена для постобработки

   begin_target	temp0

   pass	p1
   {
	texture	FullSampler	temp0	0
	texture	DepthSampler	temp0	depth
	texture	DistortSampler	tex0
	target	backbuffer
	shader	heat
   }

   sequence	seq0
   {
	pass	p1
   }
}

Сразу оговорюсь насчет выбранной терминологии. Каждый такой файл будем называть постпроцесс-фильтром или просто фильтром или же пост-эффектом. Рендер-таргет или фреймбуфер с текстурой - это по сути одно и тоже. Текстура - текстура, со своими параметрами и форматом, может быть целью для вывода, единственное, в этом случае ее размер должен в точности совпадать с форматом того рендер-таргета к которому она привязана (это ограничение расширения FBO).

Как видно, файл состоит из секций, каждая секция начинается с ключевого слова, обозначающего тип секции, и имени объекта который она настраивает, а также имеет тело, заключенное в фигурные скобки. Каждая секция также имеет набор параметров и настраивает определенный объект. Возможно 5 видов секций, это секция входных текстур (input_texture), секция настройки рендер-таргетов (render_target), секция настройки шейдеров (shader), секция настройки прохода фильтрации (pass), и, наконец, секция последовательности проходов (sequence). Все секции следует задавать именно в том порядке, в каком они перечислены выше. Самих секций может быть сколько угодно.

Секция input_texture служит для того, чтобы обеспечить механизм объединения различных фильтров, т.е. создать их комбинацию и обработать уже готовое изображение, которое находится в input_texture. Также посредством этого можно указать произвольные текстуры, которые могут использоваться при постобработке. Произвольная текстура из файла задается внутри этой секции следующим образом: file file_name.dds, где file_name.dds - имя файла с изображением текстуры.

Секция render_target задает объект рендер-таргета. Эти секции очень специфичны. Какой при компиляции эффекта создастся объект - зависит от реализации OpenGL, это может быть как объект PBuffer, так и FBO. Стоит отметить, что на уровне взаимодействия с другими объектами PBuffer и FBO себя ведут совершенно одинаково, так как являются реализациями одного интерфейса - FrameBuffer. Параметры Width и Height, как можно уже догадаться, задают размеры рендер-таргета, а int_format - внутренний формат текстур рендер-таргета. Для FBO - это формат текстур цветовых буферов, для PBuffer - формат присоединяемой текстуры. Для каждой реализации OpenGL есть свой список доступных форматов текстур, поэтому если данная реализация не поддерживает какой-либо формат рендер-таргета, то можно выбрать другой подходящий формат. Параметр int_format может принимать следующие значения:

LUMINANCE8_ALPHA8, LUMINANCE_FLOAT32, LUMINANCE_FLOAT16, LUMINANCE8, ALPHA_FLOAT32, ALPHA_FLOAT16, ALPHA8, RGB_FLOAT32_NV, RGB_FLOAT16_NV, RG_FLOAT32_NV, RG_FLOAT16_NV, R_FLOAT32_NV, R_FLOAT16_NV, LUMINANCE_ALPHA_FLOAT32, LUMINANCE_ALPHA_FLOAT16, RGBA_FLOAT32, RGBA_FLOAT16, RGBA8, RGB_FLOAT32, RGB_FLOAT16, RGB8, INTENSITY_FLOAT32, INTENSITY_FLOAT16, RGBA_FLOAT32_NV, RGBA_FLOAT16_NV

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

Параметр texture - задает связанную с рендер-таргетом текстуру. Для FBO создается и прицепляется текстура, если таких текстур несколько, то каждая последующая цепляется на свободный цветовой буфер (цветовой аттачмент). Для PBuffer можно присоединить только одну текстуру. Параметр depth говорит о надобности создавать еще и буфер глубины для этого рендер-таргета, единственный его аргумент - это количество бит точности буфера глубины, оно может быть 16, 24 32. Этот параметр не зависит от конкретной реализации рендер-таргета и справедлив как для FBO, так и для PBuffer. Параметр stencil - задает количество бит буфера трафарета. Параметр depth_texture - указание компилятору пост-эффекта создать и присоединить к FBO текстуру глубины, аргумент этого параметра - это количество бит точности текстуры глубины. Задавать этот параметр имеет смысл только при наличии расширения FBO. Еще один интересный момент при использовании FBO - это возможность расшаривать рендербуферы между несколькими фреймбуферами. Это в основном касается рендербуферов с буфером глубины, когда один и тот же буфер глубины может использоваться несколькими рендер-таргетами.

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

В секции shader, описывается имя файла шейдера file, задаются значения переменных шейдера var_float и указываются используемые текстуры, если таковые имеются:
      texture FullSampler 0

где FullSampler - имя сэмплера внутри шейдера, второй параметр - номер текстурного модуля, на который будет привязываться текстура. Переменные шейдера, это uniform переменные в контексте GLSL. Вектора задаются покомпонентно, через пробелы или символы табуляции. Также доступно задание массивов uniform переменных. Синтаксис такой:
      var_float _array nameVariable [array_size] value0 value1 ...

Далее необходимо указать начальный рендер-таргет, куда будет производиться отрисовка 3D сцены, он задается как параметр begin_target и имеет всегда пустую секцию. Здесь указывается имя начального рендер-таргета или имя входной текстуры для постобработки.

Секция pass задает проход фильтрации, т.е. операцию вывода квада с соответствующими шейдером и текстурами в определенный рендер-таргет. Параметр texture ассоциирует с именем сэмплера шейдера, текстуру. Она может быть либо одним из аттачментов какого-либо рендер-таргета, либо входной текстурой. Вот небольшой пример:
      texture FullSampler temp0 0

Первым после слова texture идет имя сэмплера в шейдере, вторым - либо имя рендер-таргета с текстурой, либо имя текстуры описываемой в секции input_texture. Следующим параметром идет номер аттачмента рендер-таргета с которого нужно взять текстуру. Если вместо номера аттачмента указать слово depth, то будет использована текстура глубины присоединенная к рендер-таргету как GL_DEPTH_ATTACHMENT_EXT.

Имя шейдера указывается параметром shader. Параметр target задает имя рендер-таргета в который будет осуществляться рендеринг квада, т.е. тот в котором будет формироваться обрабатываемое в этом проходе изображение. Если параметр target имеет значение backbuffer, то это означает, что рендеринг квада будет осуществляться прямо в задний буфер, т.е. фактически сразу на экран. Последний применяемый в пост-эффекте проход обязан выводить изображение в задний буфер.

Последовательности (sequences) - это набор применяемых проходов обработки изображения. Проходы можно чередовать внутри последовательности и применять несколько раз один и тот же проход. Благодаря этому можно добиться обработки изображения, чередуя несколько раз подряд одни и те же проходы. Этот метод называется пинг-понг, и суть его в следующем: изображение выступает здесь как аналог мячика для пинг-понга, оно рендерится попеременно несколько раз, сначала в одну текстуру, затем изображение в этой текстуре рендерится в другую текстуру затем опять в предыдущую, и так далее, туда-сюда. Этим способом удобно пользоваться, когда необходимо очень дешево размыть изображение. При этом размер второй текстуры должен быть в два или несколько раз меньше чем размер первой. Размытие осуществляется за счет билинейной фильтрации при текстурировании, что довольно дешево, по сравнению с другими методами блура, например методом Гаусса.

Обращаю ваше внимание еще на один момент, я не ставил перед собой задачу разработать устойчивую к внешним деструктивным действиям систему, поэтому если вам вздумается, не соблюдая синтаксис писать в файле пост-эффекта всякую абракадабру, то это будет на вашей совести. При желании вы сами можете добавить в класс компилятора все необходимые проверки на соблюдение синтаксиса.

Страницы: 1 2 3