Кадровый буфер
На текущий момент мы уже успели воспользоваться несколькими типами экранных буферов: буфером цвета, в котором хранятся значения цвета фрагментов; буфером глубины, хранящим информацию о глубине фрагментов; буфером трафарета, позволяющим отбросить часть фрагментов согласно определенному условию. Комбинация этих трех буферов зовется кадровым буфером (фреймбуфером) и хранится в определенной области памяти. OpenGL достаточно гибка, чтобы позволить нам самим создавать собственные кадровые буферы, посредством задания собственных буферов цвета и, опционально, буферов глубины и трафарета.
Содержание
- Цвета
- Основы освещения
- Материалы
- Текстурные карты
- Источники света
- Несколько источников освещения
- Библиотека Assimp
- Класс полигональной сетки Mesh
- Класс 3D-модели
- Тест глубины
- Тест трафарета
- Смешивание цветов
- Отсечение граней
- Кадровый буфер
- Кубические карты
- Продвинутая работа с данными
- Продвинутый GLSL
- Геометричечкий шейдер
- Инстансинг
- Сглаживание
- Продвинутое освещение. Модель Блинна-Фонга.
- Гамма-коррекция
- Карты теней
- Всенаправленные карты теней
- Normal Mapping
- Parallax Mapping
- HDR
- Bloom
- Отложенный рендеринг
- SSAO
- Теория
- Аналитические источники света
- IBL. Диффузная облученность.
- IBL. Зеркальная облученность.
Все операции отрисовки, что мы выполняли до сих пор, исполнялись в рамках буферов, прикрепленных к базовому кадровому буферу. Базовый буфер кадра создается и настраивается в момент создания окна приложения (за нас тяжелую работу делает GLFW). Создавая собственный кадровый буфер мы получаем дополнительное пространство куда можно направить рендер.
На первый взгляд может показаться неочевидным каково применение собственных кадровых буферов, но вывод изображения в дополнительный буфер позволяет как минимум создавать эффекты зеркал или осуществлять постобработку. Но для начала мы разберемся как устроен буфер кадра, а потом рассмотрим и реализацию некоторых интересных эффектов постобработки.
Создание кадрового буфера
Как и любой другой объект в OpenGL объект кадрового буфера (сокращенно FBO от FrameBuffer Object) используя следующий вызов:
unsigned int fbo; glGenFramebuffers(1, &fbo);
Налицо уже знакомый и десятки раз примененный нами подход к созданию и использованию объектов библиотеки OpenGL: создаем объект кадрового буфера, привязываем как текущий активный буфер кадра, выполняем необходимые операции и отвязываем кадровый буфер. Привязка осуществляется следующим образом:
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
После привязки нашего буфера кадра к точке привязки GL_FRAMEBUFFER все последующие операции чтения и записи для буфера кадра будут задействовать именно его. Также возможно привязать кадровый буфер только для чтения или только для записи осуществляя привязку к специальным точкам привязки GL_READ_FRAMEBUFFER или GL_DRAW_FRAMEBUFFER соответственно. Буфер, привязанный к GL_READ_FRAMEBUFFER, будет использован как источник для всех операций чтения типа glReadPixels. А буфер, связанный с GL_DRAW_FRAMEBUFFER, станет приемником всех операций рендера, очистки буфера и прочих операций записи. Однако, по большей части вам не придется пользоваться этими точками привязки, применяя точку привязки GL_FRAMEBUFFER.
К сожалению, пока мы не готовы использовать нам буфер кадра, поскольку он не завершен. Чтобы стать завершенным кадровый буфер должен отвечать следующим требованиям:
- Должен быть подключен как минимум один буфер (цвета, глубины или трафарета).
- Должно присутствовать хотя бы одно прикрепление цвета (color attachment).
- Все подключения также должны быть завершенными (обеспечены выделенной памятью).
- Каждый буфер должен иметь одинаковое количество семплов.
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) < // все хорошо, можно плясать джигу! >
Все последующие операции рендеринга будут осуществлять вывод в подключения кадрового буфера, привязанного в данный момент. Поскольку наш буфер кадра не является базовым, то и вывод в него не окажет никакого влияния на то, что отображается в окне вашего приложения. Именно поэтому рендер в собственный кадровый буфер назван внеэкранным рендером. Чтобы команды вывода снова возымели действие на окно вывода приложения мы должны ввернуть базовый кадровый буфер на место активного:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Именно передача 0 как идентификатора кадрового буфера указывает привязать базовый буфер как активный. После выполнения всех необходимых действий с созданным кадровым буфером не забудьте удалить его объект:
glDeleteFramebuffers(1, &fbo);
Итак, вернемся на шаг назад до проверки законченности буфера: необходимо создать и подключить как минимум одно прикрепление к нашему кадровому буферу. Прикреплением называется область в памяти, которая может выступать как буфер-приемник для кадрового буфера, упрощая можно представить его как изображение. При создании прикрепления у нас есть выбор: использовать текстуры или объекты рендербуфера.
Текстурные прикрепления
После подключении текстуры к буферу кадра результат всех последующих команд будут записаны в эту текстуру так, будто она является обычным буфером цвета, глубины или трафарета.
Преимущество использования текстурного объекта в том, что результаты операций рендера будут сохранены в формате текстуры, делая их легко доступными для обработки в шейдерах.
Процесс создания текстуры для использования в кадровом буфере примерно совпадает с таковым для обычного текстурного объекта:
unsigned int texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Главное отличие в том, что размеры текстуры задаются равными размеру экрана (хотя это и не обязательно), а вместо указателя на массив значений текстуры передается NULL. Здесь мы только выделяем память под текстуру, но не заполняем её чем-либо, поскольку заполнение произойдет само при непосредственном вызове рендера в этот буфер кадра. Также отметьте отсутствие настроек режима повторения текстуры и настройки мипмаппинга, поскольку в большинстве случаев использования внеэкранных буферов это не требуется.
Если вы хотите произвести рендер всего экрана в текстуру меньшего или большего размера, то перед непосредственно рендером необходимо дополнительно вызвать glViewport, которой передать размеры используемой текстуры. В противном случае либо в кадровый буфер попадет только фрагмент изображения экрана, либо текстура кадрового буфера окажется заполненной изображением экрана только частично.
Создав объект текстуры необходимо прикрепить его к буферу кадра:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
Функция принимает следующие параметры:
- target – тип объекта кадра, к которому подключаем текстуру (только чтение, только запись, чтение/запись).
- attachment – тип прикрепления, который мы планируем подключить. В данном случае мы подключаем прикрепление цвета. Обратите внимание на 0 на конце идентификатора прикрепления – его наличие подразумевает возможность подключения более чем одного прикрепления к буферу. Подробнее этот момент рассмотрен позже.
- textarget – тип текстуры, который вы планируете подключить.
- texture – непосредственно объект текстуры.
- level – используемый для вывода МИП-уровень.
Также существует возможность подключения и буфера глубины и трафарета одновременно при использовании всего одной текстуры. Для такой конфигурации каждое 32х битное значение текстуры состоит из 24х бит значения глубины и 8 бит информации о трафарете. Для подключения буфера глубины и трафарета как одной текстуры используется тип прикрепления GL_DEPTH_STENCIL_ATTACHMENT, а формат текстуры настраивается для хранения совмещенных значений глубины и трафарета. Пример подключения буфера глубины и трафарета в виде одной текстуры приведен ниже:
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 800, 600, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL ); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture, 0);
Прикрепления рендербуфера
Хронологически объекты рендербуфера как еще один тип прикреплений кадрового буфера были добавлены в библиотеку позже текстурных, которые были единственным вариантом для работы с внеэкранными буферами в стародавние дни. Как и текстура, объект рендербуфера представляет собой реальный буфер в памяти, т.е. массив байтов, целых чисел, пикселей или еще чего-то.
Однако, у него есть дополнительное преимущество – данные в рендербуфере хранятся в особом, понятном библиотеке формате, что делает их оптимизированными именно для внеэкранного рендера.
Объекты рендербуфера сохраняют данные рендера напрямую, без дополнительных преобразований в специфичные форматы текстурных данных, что в итоге дает заметное преимущество в скорости на процессах записи в буфер. К сожалению, в общем смысле рендербуфер предназначен только для записи. Прочитать что-то из него можно только опосредованно, через вызов glReadPixels, и то это вернет пиксельные данные используемого в текущий момент буфера кадра, а не самого рендербуфер-прикрепления.
Поскольку данные хранятся во внутреннем для библиотеки формате, рендербуферы весьма быстры при записи в них или при копировании их данных в прочие буфера. Операции переключения буферов также весьма быстры при использовании объектов рендербуфера. Так, функция glfwSwapBuffers, которую мы использовали в конце каждого цикла рендера, также можно реализовать с применением объектов рендербуфера: пишем в один буфер, затем переключаемся на другой после завершения рендера. В таких задачах рендербуфер явно на коне.
Создание объекта рендербуфера довольно схоже с созданием объекта буфера кадра:
unsigned int rbo; glGenRenderbuffers(1, &rbo);
Ожидаемо, мы должны привязать объект рендербуфера, чтобы последующие операции отрисовки направляли результаты именно в него:
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
Поскольку объекты рендербуфера в общем случае недоступны для чтения, они зачастую используются для хранения данных глубины и трафарета – по большей части нам не часто нужны конкретные значения этих буферов, но в целом мы нуждаемся в их функциях. Если точнее, то нам нужен буфер глубины и трафарета для соответствующих тестов, но делать выборки из них мы не планируем. В случаях, когда выборка из буферов не планируется, рендербуфер отличный выбор, ведь бонусом еще идет и бОльшая производительность.
Создание рендербуфера для глубины и трафарета:
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);
Создание объекта рендербуфера схоже с таковым текстурных объектов. Разница лишь в том, что рендербуфер задумывался для непосредственного хранения образа, в отличие от буфера общего назначения, каковым является текстурный объект. Здесь мы указываем внутренний формат буфера GL_DEPTH24_STENCIL8, что соответствует 24м битам на значение глубины и 8ми битам на трафарет.
Не забудем и о том, что объект нужно подключить к кадровому буферу:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
Использование рендербуфера может дать некоторую выгоду в производительности процессов с использованием внеэкранных буферов, но важно понимать, когда следует использовать их, а когда – текстуры. Общий принцип таков: если вы никогда не планируете делать выборки из буфера, то используйте для него объект рендербуфера. Если же вам хоть иногда нужно сделать выборку из буфера, как, например, цвет или глубина фрагмента, то следует обратиться к текстурным прикреплениям. В конце концов выигрыш производительности не будет огромным.
Рендер в текстуру
Итак, вооруженные знаниями о том, как (в общих чертах) работают кадровые буферы, мы приступаем к их непосредственному использованию. Попробуем вывести сцену в текстурное прикрепление буфера кадра, а затем отрисуем один полноэкранный квад с применением этой текстуры. Да, на глаз различий мы не увидим – результат будет тот же, что и без использования кадрового буфера. В чем же профит такой затеи? Подождите следующей секции и узнаете.
Для начала создадим объект буфера кадра и тут же привяжем его:
unsigned int framebuffer; glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
Далее мы создадим текстурный объект, который присоединим к прикреплению цвета кадрового буфера. Снова мы задаем размеры текстуры равные размерам окна приложения, а указатель на данные оставляем пустым:
// создание текстурного объекта unsigned int texColorBuffer; glGenTextures(1, &texColorBuffer); glBindTexture(GL_TEXTURE_2D, texColorBuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); // присоедиение текстуры к объекту текущего кадрового буфера glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);
Также мы бы хотели иметь возможность проводить тест глубины (и тест трафарета, если вам это требуется), так что не забудем и о задании прикрепления глубины (и трафарета) для нашего кадрового буфера. Поскольку мы планируем делать только выборки из буфера цвета, то можно использовать рендербуфер в качестве носителя данных глубины и трафарета.
Создание объекта рендербуфера тривиально. Стоит помнить лишь о том, что мы собираемся создать совмещенный буфер глубины и трафарета. Поэтому мы и выставляем внутренний формат объекта рендербуфера в GL_DEPTH24_STENCIL8. Для наших задач 24х бит точности глубины вполне достаточно.
unsigned int rbo; glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600); glBindRenderbuffer(GL_RENDERBUFFER, 0);
Как только мы запросили память для объекта – можно его отвязывать.
Затем мы присоединяем объект рендербуфера к совмещенной точке прикрепления глубины и трафарета буфера кадра:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
Финальным аккордом будет проверка буфера кадра на полноту с выводом отладочного сообщения, если это не так:
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) std::cout
Не забудьте в конце отвязать объект буфера кадра, чтобы случайно не начать рендер не туда, куда предполагалось.
Что ж, у нас есть объект буфера кадра, полностью подготовленный к рендеру в него, вместо буфера кадра по умолчанию. Все что осталось сделать – привязать наш буфер и все последующие команды рендера будут влиять именно на привязанный буфер кадра. Все операции с буферами глубины и трафарета также будут задействовать соответствующие прикрепления текущего привязанного буфера кадра (если вы, конечно, создали таковые). Если же вы, к примеру, забыли добавить буфер глубины к кадровому буферу, то тест глубины более работать не будет, поскольку для него попросту не будет исходных данных в буфере кадра.
Итак, перечислим шаги, необходимые для вывода сцены в текстуру:
1. Привязать наш объект буфера кадра как текущий и вывести сцену обычным образом.
2. Привязать буфер кадра по умолчанию.
3. Вывести полноэкранный квад с наложением текстуры из буфера цвета нашего объекта кадрового буфера.
Сцену будем рисовать взятую из урока о тесте глубины, но в этот раз с применением уже знакомой текстуры контейнера.
Для вывода полноэкранного квада мы создадим новый набор тривиальных шейдеров. Здесь не будет каких-либо замысловатых матричных преобразований, поскольку координаты вершин мы сразу передадим в них в виде нормализованных координат устройства (NDC). Напомню, что в таком виде их можно сразу передавать на выход фрагментного шейдера:
#version 330 core layout (location = 0) in vec2 aPos; layout (location = 1) in vec2 aTexCoords; out vec2 TexCoords; void main()
Ничего особенного, не так ли? Фрагментный шейдер будет еще проще, поскольку все что он делает – выборка из текстуры:
#version 330 core out vec4 FragColor; in vec2 TexCoords; uniform sampler2D screenTexture; void main()
На вашей совести остается код, отвечающий за создание и настройку VAO для самого квада. Итерация рендера в итоге имеет следующую структуру:
// первый проход glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // буфер трафарета не используется glEnable(GL_DEPTH_TEST); DrawScene(); // второй проход glBindFramebuffer(GL_FRAMEBUFFER, 0); // возвращаем буфер кадра по умолчанию glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); screenShader.use(); glBindVertexArray(quadVAO); glDisable(GL_DEPTH_TEST); glBindTexture(GL_TEXTURE_2D, textureColorbuffer); glDrawArrays(GL_TRIANGLES, 0, 6);
Несколько замечаний. Во-первых, поскольку созданный объект буфера кадра имеет свой набор буферов, необходимо очистить каждый из них установив соответствующие флаги для функции glClear. Во-вторых, при выводе квада мы отключаем тест глубины, поскольку он излишен при рендере простой пары треугольников. Однако тест следует включить при непосредственном рендере самой сцены.
Уф! Порядочно этапов работы, в которых несложно ошибиться. Если ваша программа не отображает ничего – попробуйте поотлаживать где это возможно, а также перечитать соответствующие части данного урока. Если же все успешно заработало, то вывод будет схож с данным результатом:
Слева виден результат идентичный изображению из урока по тесту глубины, но в этот изображение выведено на полноэкранный квад. Если переключить режим рендера в каркасный (glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) – войти в режим, glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) – вернуться в обычный режим, прим. пер.), то можно увидеть, что в буфер кадра по умолчанию отрисована всего пара треугольников.
Исходный код примера находится здесь.
Ну а какая польза от всего этого? Поскольку у нас теперь есть текстура с содержимым законченного кадра, то мы легко можем получить доступ к значению каждого пикселя и реализовать множество замысловатых эффектов во фрагментном шейдере! Собирательно такой подход называется постобработкой или постпроцессингом.
Постобработка
Имея на руках текстуру, содержащую образ всего кадра, мы можем реализовать разнообразные эффекты с помощью простых операций с текстурными данными. В данном разделе будут продемонстрированы некоторые распространенные техники постпроцессинга, а также идеи как сделать свой эффект, приложив немного фантазии.
Начнем с, пожалуй, самого простого эффекта.
Инверсия цвета
Поскольку у нас есть полный доступ к данным цвета итогового кадра, то во фрагментном шейдере несложно получить величину цвета, противоположную исходной. Для этого берется выборка цвета из текстуры и отнимается от единицы:
void main()
Инверсии цвета, несмотря на простоту реализации эффекта, способна принести довольно занимательные результаты:
Все цвета в сцене оказались проинвертированы всего одной строчкой кода в шейдере, недурно, да?
Перевод в градации серого
Еще один интересный эффект – удаление всей информации о цвете с переводом изображения в градации серого. Наивное решение очевидно, достаточно просуммировать величины яркости каждого канала цвета и усреднить, заменяя средним исходные величины:
void main() < FragColor = texture(screenTexture, TexCoords); float average = (FragColor.r + FragColor.g + FragColor.b) / 3.0; FragColor = vec4(average, average, average, 1.0); >
Результаты этого подхода вполне приемлемы, но природа человеческого глаза подразумевает бОльшую чувствительность к зеленой части спектра и меньшую – к синей. Так что более физически корректное приведение к градациям серого использует усреднение цвета с весовыми коэффициентами для отдельных каналов:
void main()
На первый взгляд разница неочевидна, но в более насыщенных сценах взвешенное приведение к градациям серого дает более качественный результат.
Применение сверточного ядра
Еще одним преимуществом пост-обработки с использованием текстурной карты является тот факт, что мы можем получить доступ к любому участку текстуры. Например, взять небольшой участок вокруг текущей текстурной координаты и сделать выборку значений вокруг текущего текселя. А комбинируя значения этих выборок несложно создать определённые спецэффекты.
Сверточное ядро (матрица свертки) – это небольшой массив величин наподобие матрицы, центральный элемент которого соотносится с текущим обрабатываемым пикселем, а его окружающие элементы – с соседними текселями текстуры. При обработке, величины ядра, окружающие центральную, умножаются на значения выборок соседних текселей, а затем все складывается вместе и записывается в текущий (центральный) тексель. По большому счету, мы просто добавляем небольшое смещение текстурных координат во всех направлениях от текущего текселя и вычисляем итоговый результат с использованием значений из ядра. Возьмем, например, следующее ядро свертки:
Данное ядро умножает величины соседних текселей на 2, а текущего текселя на -15. Другими словами, ядро умножает все соседние значения на весовой коэффициент, хранящийся в ядре, и «уравнивает» эту операцию умножением значения текущего текселя на большой отрицательный Весовой коэффициент.
Большая часть сверточных матриц, что вы отыщете в сети будут иметь сумму всех коэффициентов равную 1. Если же это не так, то изображение после обработки станет либо ярче, либо темнее оригинала.
Сверточные ядра – невероятно полезный инструмент для создания эффектов постпроцессинга, поскольку довольно просты в реализации, с ними легко экспериментировать, и множество готовых примеров уже доступно в сети.
Для поддержки сверточного ядра нам придется немного изменить код фрагментного шейдера. Сделаем предположение, что использоваться будут только ядра размерности 3х3 (большая часть известных ядер действительно имеют такую размерность):
const float offset = 1.0 / 300.0; void main() < vec2 offsets[9] = vec2[]( vec2(-offset, offset), // top-left vec2( 0.0f, offset), // top-center vec2( offset, offset), // top-right vec2(-offset, 0.0f), // center-left vec2( 0.0f, 0.0f), // center-center vec2( offset, 0.0f), // center-right vec2(-offset, -offset), // bottom-left vec2( 0.0f, -offset), // bottom-center vec2( offset, -offset) // bottom-right ); float kernel[9] = float[]( -1, -1, -1, -1, 9, -1, -1, -1, -1 ); vec3 sampleTex[9]; for(int i = 0; i < 9; i++) < sampleTex[i] = vec3(texture(screenTexture, TexCoords.st + offsets[i])); >vec3 col = vec3(0.0); for(int i = 0; i
Здесь мы сперва определяем массив из 9ти значений vec2, представляющий собой массив смещений текстурных координат относительно текущего текселя. Размер смещения определен через константу, величину которой вы вольны подобрать сами. Далее мы определяем ядро, в данном случае реализующее собой эффект повышения резкости. Затем мы заполняем массив выборок, добавляя величину соответствующего смещения текстурных координат к текущим. И, наконец, суммируем все выборки, умноженные на соответствующие весовые коэффициенты.
Эффект от применения такого ядра выглядит так:
Вполне может пригодиться в сценах, где игрок находится в наркотическом трипе.
Размытие
Ядро, реализующее эффект размытия выглядит следующим образом
Поскольку общая сумма элементов равна 16, то необходимо результат поделить на 16, чтобы избежать чрезвычайного увеличения яркости. Определение ядра:
float kernel[9] = float[]( 1.0 / 16, 2.0 / 16, 1.0 / 16, 2.0 / 16, 4.0 / 16, 2.0 / 16, 1.0 / 16, 2.0 / 16, 1.0 / 16 );
Изменение элементов массива чисел, представляющих собой само ядро привело к полному преображению картинки:
Эффект размытия обладает широкими возможностями для применения. Так, например, можно менять величину размытия с течением времени для имитации опьянения персонажа, либо задрать величину размытия в сценах, где герой забыл надеть очки. Также размытие позволяет сделать переходы цветов плавными, что окажется полезным в последующих уроках.
Думаю, уже ясно, что подготовив код к использованию ядра свертки можно просто и быстро создавать новые эффекты постобработки. В завершении, разберемся с последним из популярных сверточных эффектов.
Определение границ
Ниже представлено ядро для выявления границ:
Напоминает ядро для повышения резкости, но в данном случае выделяет все границы на изображении, одновременно затеняя остальные части. Весьма полезно, если в изображении вас интересуют только границы:
Думаю, вас не удивит тот факт, что сверточные ядра применяются в программах обработки изображений и фильтрах, таких как Adobe Photoshop. Попиксельная модификация изображений в реальном времени становится вполне доступной за счет выдающейся скорости параллельной обработки фрагментов. Именно поэтому в последнее время графические пакеты все больше используют возможности видеокарт в области обработке изображений.
P.S. Из комментариев к оригиналу: отличная интерактивная демонстрация различных сверток.
P.P.S.: У нас есть телеграм-конфа для координации переводов. Если есть желание вписаться в цикл, то милости просим!
- Программирование
- C++
- Разработка игр
V-Ray frame buffer
Обзор
Параметры
Скрытые параметры
Панель инструментов VFB
Горячие клавиши VFB
Замечания
Search Keywords: VFB, G-buffer, frame buffer, render pass
Обзор
В дополнение к окну визуализируемого кадра 3ds Max (Rendered Frame Window RFW или VFB), V-Ray позволяет вам производить визуализацию в специальный буфер кадра V-Ray, который имеет некоторые дополнительные возможности:
- Позволяет вам видеть все элементы визуализации в одном окне и очень просто переключаться между ними.
- Хранит изображение в полном 32-битном формате с плавающей точкой.
- Позволяет вам производить простую корректировку цвета визуализированного изображения.
- Позволяет вам выбрать порядок в котором просчитываются бэкиты.
Параметры
Show last VFB - Показать последний VFB - если вы уже делали визуализацию с использованием V-Ray VFB и закрыли окно, эта кнопка позволяет вам открыть его снова. Этого же можно достичь при помощи вызова метода showLastVFB() визуализатора V-Ray посредством MaxScript.
vr = renderers.current vr.showLastVFB()
Enable built-in frame buffer - Разрешить встроенный буфер кадра - разрешает использовать встроенный буфер кадра V-Ray. По техническим соображениям оригинальный буфер кадра 3ds Max остается существовать и создается. Однако когда эта опция включена, V-Ray не будет помещать ни какие данные в буфер кадра 3ds Max. Для предотвращения излишнего расхода памяти мы рекомендуем устанавливать оригинальное разрешение 3ds Max очень маленьким (напр. 100х100) и выключить 3dsmax VFB в общих параметрах визуализатора 3ds Max.
Render to memory frame buffer - Просчет в буфер кадра, размещенный в памяти - будет создаваться буфер кадра V-Ray, который будет использоваться для запоминания данных о цвете, которые вы можете видеть в процессе просчета и после него. Если вы хотите просчитать изображение действительно очень высокого разрешения, которое невозможно разместить в памяти или которое может съесть такое количество памяти, что сцена не сможет быть визуализирована корректно, вы можете выключить эту возможность и использовать только возможность Render to V-Ray raw image file (просчет в файл сырого изображения V-Ray) .
Get resolution from 3ds Max - Взять разрешение из 3ds Max - это заставит V-Ray VFB брать свое разрешение из общих параметров визуализатора 3ds Max.
Output resolution - Выходное разрешение - это разрешение, которое вы хотите использовать с буфером кадра V-Ray.
Pixel aspect - Аспект пикселя - указывает соотношение сторон (аспект) пикселя для визуализируемого изображения в V-Ray VFB.
Render to V-Ray image file - Визуализация в файл изображения V-Ray - когда опция включена, V-Ray напрямую записывает в дисковый файл сырые данные изображения, как только они просчитаны. При этом никакие данные не хранятся в оперативной памяти, поэтому эта возможность очень полезна для экономии памяти при визуализации изображений огромного разрешения. Если вы хотите видеть что визуализируется, вы можете включить опцию Generate preview . Для вывода вы можете указать либо файл с расширением .vrimg , либо с расширением .exr :
-
Если вы указали расширение .vrimg , результирующий файл может быть просмотрен через меню 3ds Max File > View image. , или преобразован в файл формата OpenEXR при помощи утилиты vrimg2exr.
Скрытые параметры
У V-Ray VFB есть несколько дополнительных параметров, которые недоступны через интерфейс, но доступны через MaxScript. Это может быть полезно в некоторых ситуациях. Ниже перечислены имена этих параметров в MaxScript.
output_renderType - позволяет вам переопределить тип визуализации, указанный в настройках 3ds Max. Возможные значения:
0 - использовать тип визуализации 3ds Max (значение по умолчанию);
1 - визуализация полного изображения;
2 - визуализация региона;
3 - визуализация региона с отсечением (crop);
4 - визуализация региона с увеличением (blow-up).
output_regxmin - координата (в пикселях) X левой границы региона для визуализации;
output_regxmax - координата (в пикселях) X правой границы региона для визуализации;
output_regymin - координата (в пикселях) Y верхней границы региона для визуализации;
output_regymax - координата (в пикселях) Y нижней границы региона для визуализации.
Панель инструментов VFB
Эта часть панели инструментов устанавливает каналы для просмотра, а также режим предварительного просмотра. Выбрать каналы для просмотра можно с помощью кнопок. Вы также можете просматривать просчитанное изображение в монохромном режиме.
Сохранение данных текущего кадра в файл. Вы можете это сделать "на лету" в процессе визуализации. Создает в виртуальном буфере кадра 3ds Max копию текущего буфера кадра V-Ray. Вы можете это сделать "на лету" в процессе визуализации. Этот инструмент заставит V-Ray просчитать бакит, ближайший к указателю мыши. Перемещайте указатель мыши над буфером кадра V-Ray во время просчета для того, что бы увидеть эти бакеты просчитаными первыми. Вы можете это сделать "на лету" в процессе визуализации. Открывает и закрепляет окно, которое будет давать вам информацию о пикселе, который вы укажете правой кнопкой мыши. Если вы нажмете правую кнопку мыши над пикселом без включения этого режима, вы будете видеть окно и информацией о пикселе только пока кнопка мыши нажата. Открывает, так называемый, диалог "levels control (управление уровнями)", который позволит вам определить коррекцию цвета различных цветовых каналов. Он также показывает гистограмму данных текущего изображения в буфере. Нажмите среднюю кнопку мыши в гистограмме и перемещайте мышь для интерактивного масштабирования гистограммы. Очищает содержимое буфера кадра. Иногда полезно, когда начинается новая визуализация, для предотвращения путаницы с предыдущим изображением.
Горячие клавиши VFB
Ниже расположен список горячих клавиш, которые вы можете использовать для манипуляций с изображением в VFB. Помните, что окно VFB должно иметь текущий фокус для работы горячих кравиш:
Мышь Описание CTRL+LeftClick, CTRL+RightClick Увеличение/уменьшение Вращение колеса мыши вверх/вниз Увеличение/уменьшение Двойной щелчек левой кнопкой Масштабирование до 100% Щелчек правой кнопкой Показывает информационное окно со свойствами указанного щелчком пиксела. Для того, что бы видеть окно с информацией постоянно, включите инструмент Перемещение с нажатой средней кнопкой перемещение вида (инструмент рука) Клавиатура Описание + / - Увеличение/уменьшение * Масштабирование до 100% Клавиши управления курсором перемещение вида
Замечания
- V-Ray VFB не показывает слои G-буфера (подобно Coverage и т.п.);
Перевод © Black Sphinx, 2008. All rights reserved.
Для чего нужны фреймбуферы?
Для чего нужны фреймбуферы в opengl? Я может не точно задаю вопрос, но я и не понимаю как его задать. Я читаю книгу по opengl es 3. Там описано какие есть функции, но для чего использовать или когда использовать я не пойму. Также есть что-то типа рендерить фреймбуфер в текстуру.
Отслеживать
56k 10 10 золотых знаков 83 83 серебряных знака 136 136 бронзовых знаков
задан 7 мар 2019 в 7:48
user302477 user302477
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Что такое фреймбуфер ( OpenGL FrameBuffer , WebGL FrameBuffer )?
Когда Вы вызываете методы отрисовки, в соответствии с текущими настройками графического конвейера заполняется несколько буферов размером с область отрисовки (буфер цвета, опционально буфер глубины, буфер трафарета). Такая группа буферов и называется фреймбуфером.
Базовый фреймбуфер создается и настраивается в момент создания окна приложения. Базовый фреймбуфер привязывается по умолчанию.
У Вас есть возможность создавать и привязывать дополнительные фреймбуферы.
Создавая собственный фреймбуфер Вы получаете дополнительное пространство куда можно направить ортрисовку.
Привязывая не базовый фреймбуфер Вы говорите таким образом конвейеру, что хотите чтобы все последующие вызовы отрисовки происходили в него.
Фреймбуфер, сам по себе это только точка привязки, к нему привязываются так называемые рендер-тектуры. Рендер текстуры уже будут хранить непосредственно цветовую информацию.
После наполнения фрейм буфера(ов) Вы привязываете базовй фреймбуфер и рисуете уже на экране, используя при отрисовке информацию из фреймбуфера(ов).
Для чего это можно и нужно использовать?
Самое очевидное - программная генерация текстур.
Deferred Shading - Отложенное освещение и затенение. Это такая техника, при которой финальный цвет фрагмента определяется при отрисовке одного прямоугольника, закрывающего всю область экрана. При этом во фрагментном шейдере берутся значения из рендер текстур и из этих значений вычисляется финальный цвет. Тут есть важный момент что в этом случае скорость выполнения второго этапа не зависит от сложности сцены, а зависит от размера кадра.
G-Buffer (Geometry Buffer) - специальное название для группы текстур при отложенном рендеринге:
Результат (много источников света):
- Depth of Field или DoF - глубина резкости, пожалуй самый простой для понимания эффект - он применяет blur помноженный на значение из текстуры глубины.
- High Dynamic Range Compression или HDR - технология расширения диапазона яркости кадра подробнее тут (тут)
- Bloom - своеобразный эффект свечения, заключается в размытии границ ярких объектов.
- Screen Space Ambient Occlusion (SSAO) , обманка с самозатенением - про я недавно писал ответ на вопрос тут.
- Screen Space Reflections (SSR) - Алгоритм который позволяет получить отражения для плоских поверхностей. При этом отразится может лишь то, что попало в кадр - подходит для горизонтальных поверхностей вроде луж на земле.
- Screen Space Subsurface Scattering (SSSS) - Подповерхностное рассеивание описывает механизм распространения света, при котором свет, проникая внутрь полупрозрачного тела через его поверхность, рассеивается внутри самого тела, многократно отражаясь от частиц тела в случайном направлении и на нерегулярные углы. В итоге свет выходит из объекта в выходной точке, отличной от точки вхождения в объект
Фреймбуфер
Кадровый буфер (англ. framebuffer ) (другие названия: буфер кадра, видеобуфер, фреймбуфер) — реальное или виртуальное электронное устройство, или область памяти для кратковременного хранения одного или нескольких кадров в цифровом виде перед его отправкой на устройство видеовывода. Буфер может быть использован для выполнения над кадром различных предварительных операций, организации стоп-кадра, устранения мерцания изображения и др. Обычно кадр хранится в виде последовательности цветовых значений каждого пиксела изображения. Цветовые значения чаще всего хранятся в следующих форматах: одноразрядный (монохромный; 1 бит), 4/8-битный (палитровый), 16-битный (High Color) и 24-битный (True Color); также может присутствовать альфа-канал. Размер памяти, необходимый для хранения одного кадра, зависит от разрешения и глубины цвета.
История
Виртуальные видеобуферы
Переключение страниц
Основная статья: Двойная буферизация
Графические ускорители
См. также
Примечания
- Alvy Ray SmithDigital Paint Systems: Historical Overview (PDF). Microsoft Tech Memo 14 (May 30 1997).
- Wayne CarlsonHardware advancements. A Critical History of Computer Graphics and Animation. The Ohio State University (2003).
- Alvy Ray SmithDigital Paint Systems: An Anecdotal and Historical Overview (PDF). IEEE Annals of the History of Computing (2001).
Ссылки
- Interview with NYIT researcher discussing the 24-bit system (англ.)
- Jim Kajiya — разработчик первого коммерческого видеобуфера (англ.)
- История видеобуферов Sun Microsystems (англ.)
- Драйвер виртуального видеобуфера для Linux (англ.)
- DirectFB — уровень абстракции для видеобуфера Linux (англ.)
Wikimedia Foundation . 2010 .
Полезное
Смотреть что такое "Фреймбуфер" в других словарях:
- SAM Coupé — Тип Домашний компьютер Выпущен 1989 … Википедия
- Linux framebuffer — Загрузка Knoppix в linux framebuffer Linux framebuffer (фреймбуфер Линукс, fbdev от англ. Linux Frame Buffer Device) это графический аппарат … Википедия
- Jazz (компьютер) — У этого термина существуют и другие значения, см. Jazz. Компьютерная платформа Jazz представляет собой проект системной платы и набора системной логики, разработанный компанией Microsoft для применения совместно с разрабатывавшейся Windows NT. В… … Википедия
- Кадровый буфер — Аппаратный видеобуфер Sun cgsix Кадровый буфер (англ. framebuffer) (другие названия: буфер кадр … Википедия
- Voodoo2 — В этой статье не хватает ссылок на источники информации. Информац … Википедия
- Отложенное освещение и затенение — Отложенное освещение и затенение, отложенный рендеринг (англ. deferred shading) программная техника (методика) в трёхмерной компьютерной графике, которая обрабатывает освещение и затенение визуальной сцены. В результате работы алгоритма… … Википедия
- Буфер кадра — Аппаратный видеобуфер Sun cgsix Кадровый буфер (англ. framebuffer) (другие названия: буфер кадра, видеобуфер, фреймбуфер) реальное или виртуальное электронное устройство, или область памяти для кратковременного хранения одного или нескольких… … Википедия
- Видеобуфер — Аппаратный видеобуфер Sun cgsix Кадровый буфер (англ. framebuffer) (другие названия: буфер кадра, видеобуфер, фреймбуфер) реальное или виртуальное электронное устройство, или область памяти для кратковременного хранения одного или нескольких… … Википедия
- SPARCstation 10 — (кодовое имя Campus 2 ) рабочая станция, производимая корпорацией Sun Microsystems с мая 1992. Она была первым настольным многопроцессорным компьютером от Sun. Позже она была заменена на SPARCstation 20. Содержание 1 Особенности 1.1 Процессоры … Википедия
- SPARCstation LX — рабочая станция семейства SPARCstation от Sun Microsystems на основе архитектуры sun4m. Содержание 1 Спецификация 1.1 Процессор 1.2 Память … Википедия
- Обратная связь: Техподдержка, Реклама на сайте
- Путешествия
Экспорт словарей на сайты, сделанные на PHP,
WordPress, MODx.
- Пометить текст и поделитьсяИскать в этом же словареИскать синонимы
- Искать во всех словарях
- Искать в переводах
- Искать в ИнтернетеИскать в этой же категории
Поделиться ссылкой на выделенное
Прямая ссылка:
… Нажмите правой клавишей мыши и выберите «Копировать ссылку»