16
Разработка интерактивных систем на OpenFrameworks Шейдеры УрГУ / ИММ весна 2011 лекции и объявления: www.uralvision.blogspot.com вопросы по проектам и программированию: [email protected] http://pixelnoizz.files.wordpress.com/2009/08/picture-54.png?w=510&h=259

Шейдеры в OpenFrameworks

Embed Size (px)

DESCRIPTION

Работа с фрагментными шейдерами в OpenFrameworks.

Citation preview

Разработка интерактивных систем на OpenFrameworks

Шейдеры

УрГУ / ИММ весна 2011

лекции и объявления: www.uralvision.blogspot.com

вопросы по проектам и программированию: [email protected]

http://pixelnoizz.files.wordpress.com/2009/08/picture-54.png?w=510&h=259

Что такое шейдеры

1. Шейдерами сегодня обычно называют небольшие программы, которые графическая карта применяет для изменения геометрии объектов и пикселов изображений во время рендеринга.

2. Бывают вершинные (геометрия) и фрагментные (пиксельные) шейдеры.

3. Шейдеры выполняются на видеокарте и поэтому не загружают CPU. Поэтому с их помощью можно выполнять очень интересные и сложные трансформации и эффекты.

Что такое шейдеры

Шейдеры представляют собой небольшие программы на языке GLSL.

Их можно хранить в текстовых файлах. При старте вашего приложения они будут компилироваться и записываться в видеопамять.

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

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

Необходимые компоненты:

1. Аддон ofxFBOTexture для рисования в буфер:ofxFBOTexture.h, ofxFBOTexture.cpp (см. "Рисование в буфер" в лекции по двумерной графике).

2. Аддон ofxShader для загрузки/выгрузки шейдеров:ofxShader.h, ofxShader.cpp

Их можно скачать, например, вhttp://playbat-common.googlecode.com/svn/trunk/of/

Пример 1. Сглаживание

http://www.youtube.com/watch?v=Nkr4JiU0sF0

Реализуем сглаживание путем наложения друг на друга 9 сдвинутых картинок с разным весом. Радиус сдвига будет определяться X-координатой мыши.

(Идея взята из примера shaderBlurExample http://forum.openframeworks.cc/index.php?topic=2729.0)

Текст шейдераСоздаем файл фрагментного шейдера blur.frag в папке bin/data:

#extension GL_ARB_texture_rectangle : enable //настройкаuniform sampler2DRect src_tex_unit0; //внешний параметрuniform float blurAmount; //внешний параметр - радиус сглаживания

void main( void ) //эта функция будет применяться к каждому пикселу{ vec2 st = gl_TexCoord[0].st; //st - вектор входных координат пиксела vec4 color; //цвет, будем его накапливать for(float i = -4.0; i <= 4.0 ; i++) { float weight = 5.0 - abs(i); color += weight * texture2DRect(src_tex_unit0, st + vec2(blurAmount * i, 0)); //взятие цвета пиксела из текстуры src_tex_unit0, //с координатами x = st[0] + blurAmount * i, // y = st[1] } color /= 25.0; gl_FragColor = color; //установка выходному пикселу цвета color} ! Важно: компилятор автоматически не преобразует float <-> int, а выдает про это предупреждения и шейдер не запускается.

Текст шейдераСоздаем файл вершинного шейдера blur.vert в папке bin/data:

void main() { gl_TexCoord[0] = gl_MultiTexCoord0; gl_Position = ftransform();}

Это вершинный шейдер, который ничего не изменяет. Просто ofxShader для работы нужен и этот файл.

Текст приложения#include "ofxFBOTexture.h" //Рисование в буфер#include "ofxShader.h" //Шейдеры ofxFBOTexture buffer; //БуферofxShader shader; //ШейдерofVideoGrabber grabber; //Захват картинки с камеры

void testApp::setup() { ofBackground(255,255,255); grabber.initGrabber(640, 480); //запуск камеры buffer.allocate(640, 480, true); //true - автоочистка фоном на каждом шаге

//Загрузка шейдера из файлов blur.frag и blur.vert. //При старте, если будут ошибки в тексте шейдера, они выведутся на экран, //с номером строки с ошибкой. shader.loadShader("blur"); }

void testApp::update() { grabber.update(); //обновление картинки с камеры}

Текст приложенияvoid testApp::draw() { //Сначала заготавливаем картинку - рисуем ее в буфер buffer.begin(); ofSetColor(255, 255, 255); grabber.draw(0, 0); //В буфер выводим кадр с камеры buffer.end();

//Включаем шейдер shader.setShaderActive(true); //Устанавливаем параметр шейдера blurAmount float blurAmount = mouseX / 20.0; //mouseX - текущая координата мыши shader.setUniformVariable1f("blurAmount", blurAmount); //1f - то есть скаляр типа float //Рисуем, что требуется на экран, "пропуская" это через шейдер ofSetColor(255, 255, 255); buffer.draw(0, 0); //Выключаем шейдер shader.setShaderActive(false);}

Пример 2. Лупа

http://www.youtube.com/watch?v=H-mYdfaku90

Реализуем в точке мыши "лупу".

(Идея взята из примера shaderZoomExample http://forum.openframeworks.cc/index.php?topic=2729.0)

Текст шейдераСоздаем файл фрагментного шейдера zoom.frag в папке bin/data: #extension GL_ARB_texture_rectangle : enableuniform sampler2DRect src_tex_unit0;uniform vec2 circlePos; //положение лупыuniform float circleRadius; //радиус лупыuniform float zoom; //коэффициент увеличения в лупе

void main( void ){ vec2 st = gl_TexCoord[0].st; float relX = st.s - circlePos.x; float relY = st.t - circlePos.y; float dist = sqrt(relX*relX + relY*relY); if( dist <= circleRadius && dist > 0.0){ //если пиксел в лупе и не центр (т.к. делим на dist) float newRad = dist * (zoom * dist/circleRadius); float newX = circlePos.x + relX / dist * newRad; float newY = circlePos.y + relY / dist * newRad; gl_FragColor = texture2DRect(src_tex_unit0, vec2(newX, newY) ); } else { gl_FragColor = texture2DRect(src_tex_unit0, st ); } }Кроме того, создаем файл вершинного шейдера zoom.vert копированием из blur.vert

Текст приложенияВ основе - текст предыдущего примера.

в setup() shader.loadShader("zoom"); в draw() //Устанавливаем параметры шейдера shader.setUniformVariable2f("circlePos", mouseX, 480 - mouseY);

shader.setUniformVariable1f("circleRadius", 120); shader.setUniformVariable1f("zoom", 1.5);

Операции с цветом

Мы научились осуществлять комбинирование цветов пикселов и производить геометрическое преобразование изображения.

Как изменять значения цветов:Цвет - имеет тип vec4, это вектор из 4-х компонент R,G,B,Alpha,которые принимают значения от 0 до 1.

vec4 color = vec4( 1.0, 0.0, 0, 1.0 ); //создать красный цвет

color[0], color[1], color[2], color[3] - R, G, B, Alpha - компоненты.

Рассмотрим еще один пример.

Пример 3. Лупа с изменением цветов

Модифицированная лупа из предыдущего примера, в которой у цветов внутри лупы переставлены местами R,G,B компоненты.

Текст шейдераФайл zoom.frag в папке bin/data:

заменяем строку

gl_FragColor = texture2DRect(src_tex_unit0, vec2(newX, newY) );

на

vec4 color = texture2DRect(src_tex_unit0, vec2(newX, newY) ); gl_FragColor = vec4( color[1], color[2], color[0], color[3] ); //перемешивание компонент цвета

Домашнее задание

1. ВихрьСделайте так, чтобы лупа внутри себя закручивала изображение.

Подсказка: поворачивать вектор в зависимости от значения dist/circleRadius.

2. Вода 1

В шейдерном языке есть функции sin, cos, atan.Сделайте волнообразное искажение изображения на экране, от центра экрана.Как будто уронили что-то в воду в центре экрана.Т.е. это должно быть видео, а не статичная картинка.

3. Вода 2С помощью нажатий мыши имитировать падение чего-то в воду на картинке.Реализовать это, к примеру, путем моделирования в текстуре амплитуду колебаний волн.