Вы находитесь на странице: 1из 39

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

на OpenFrameworks

Двумерная графика

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

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


perevalovds@gmail.com
УрГУ / ИММ весна 2011
Настройка экрана

в main.cpp:

ofSetupOpenGL(&window, 1024,768, OF_WINDOW);

1024, 768 - размеры экрана, OF_WINDOW - вывод в окно.

Чтобы вывести на полный экран в 1280x1024:

ofSetupOpenGL(&window, 1280,768, OF_FULLSCREEN);


Настройка экрана
Переключение между полноэкранным режимом в ходе работы
программы (в update()) :
ofSetFullscreen(bool fullscreen)

Пример: по нажатию '1'/'2' - вкл/выкл полноэкранный режим:

void testApp::keyPressed(int key)


{
if ( key == '1' ) {
ofSetFullscreen( true );
}
if ( key == '2' ) {
ofSetFullscreen( false );
}
}
Настройка фона

ofBackground(int r, int g, int b)

устанавливает цвет фона (по умолчанию 128, 128, 128).


Примечание: надо ставить в setup(), если включен
ofSetBackgroundAuto.

ofSetBackgroundAuto(bool bAuto)
- включает/выключает режим очистки картинки
в каждом кадре, перед вызовом draw() (по умолчанию true).
Рисование фигур
Линия ofLine(float x1, float y1, float x2, float y2)

Прямоугольник ofRect(float x1, float y1, float w, float h)

Круг ofCircle(float x, float y, float radius)

Треугольник ofTriangle(float x1, float y1, float x2, float y2,


float x3, float y3)

Эллипс ofEllipse

Многоугольник ofBeginShape(), ofVertex(), ofEndShape()

Гладкая кривая ofCurve


Рисование фигур
Настройки:

Цвет рисования ofSetColor(int red, int greeb, int blue), где числа от 0 до 255.
ofSetColor(int red, int green, int blue, int alpha )
/*alpha - прозрачность, см. далее*/
ofSetColor(int hexColor) - 16-чная задание цвета,

Толщина линий
ofSetLineWidth(float lineWidth)
толщина линий в пикселах

Заливать/не заливать фигуры


ofFill() - заливать
ofNoFill() - не заливать
Вывод текста
- Простой вывод текста, без настроек шрифта и размера:

ofDrawBitmapString("Some text", 50, 50 ); //параметры: текст и координаты

- Для вывода нормальным шрифтом и размером - использовать ofTrueTypeFont:

1) скопировать в bin/data шрифт,


например, verdana.ttf (есть в папке openframeworks)
2) объявить: ofTrueTypeFont myFont;
3) в setup(): myFont.loadFont("verdana.ttf", 32 /*размер*/);
4) в draw(): myFont.drawString("Good", 50, 50);

- Вывод в текстовое окно консоли:


cout << "Text" << endl;
Пример

Это то, что называется "генерируемое искусство"


(generative art) и "творческое программирование" (creative
coding)
Пример
Объявление переменных
float px; //начало линии
float py;
float qx; //отступ
float qy;
float col; //цвет

setup()
ofBackground( 255, 255, 255 );
ofSetBackgroundAuto( false );
px = 320;
py = 240;
qx = 0;
qy = 0;
col = 0;
Пример
update()
px += ofRandom( -1, 1 ); //ofRandom(a,b) - случайная велечина в [a,b]
py += ofRandom( -1, 1 );
qx += ofRandom( -0.3, 0.3 );
qy += ofRandom( -0.3, 0.3 );

if ( px < 0 ) px += 640;
if ( px >= 640 ) px -= 640;
if ( py < 0 ) py += 480;
if ( py >= 480 ) py -= 480;

if ( qx < -30 ) qx += 15;


if ( qx > 30 ) qx -= 15;
if ( qy < -30 ) qy += 15;
if ( qy > 30 ) qy -= 15;

col += 0.02;
if ( col >= 256 ) col = col - 256;
Пример
draw()
int r = col;
int g = int(col * 2) % 256;
int b = 255 - col;
ofSetColor( r, g, b );
ofLine( px, py, px + qx, py + qy );
Рисование изображений
Коллаж
Коллаж (от фр. collage — наклеивание) — технический приём в изобразительном искусстве,
заключающийся в наклеивании на подложку предметов и материалов, отличающихся от основы по
цвету и фактуре. Коллажем также называется произведение, целиком выполненное в этой технике.
(Википедия)

А здесь мы будем под коллажом понимать размещение различных картинок на экране.

Для коллажа нужно:


- загрузить набор
картинок,
осуществить их
- вращение,
- перенос,
- изменение размера,
- прозрачность.

http://www.chinesecontemporary.com/hong_hao_5.htm
Загрузка и рисование изображения
объявление картинки
ofImage image;

в setup()
image.loadImage( "texture.jpg" ); //загрузка с диска
//файл должен лежать в bin/data

в draw()
ofSetColor( 255, 255, 255 ); //зачем это нужно - см. ниже
//"Прозрачность всего изображения"
image.draw ( 100.0, 50.0 ); //вывод на экран
//левый верхний угол будет в (100, 50)

Это изображение можно скачать с


http://uralvision.blogspot.com/2010/03/4.html
Исходное изображение было взято с
http://ayesha5.files.wordpress.com/2008/06/sun-flower2.jpg
Поворот изображения
в draw()

ofPushMatrix(); //запомнить матрицу преобразования


ofRotate( 10.0 ); //поворот в градусах левого верх. угла
image.draw( 0.0, 0.0 ); //рисуем
ofPopMatrix(); //восстановить матрицу
Вращение около своего центра
в draw()
//Рисуем повернутым, и чтоб центр был в ( 200.0, 100.0 )
ofPushMatrix();
ofTranslate( 200.0, 100.0 ); //центр картинки
ofRotate( 20.0 ); //поворот
//рисование со сдвигом:
image.draw( -image.width / 2, -image.height / 2
); ofPopMatrix();
Прозрачность
Прозрачность для пикселов
Чтобы сделать хороший коллаж из нескольких картинок,
нужно убрать черный фон. Это делается путем
использования прозрачности для пикселов изображения.
Применение прозрачности для
пикселов изображения
Если к каналам Red, Green, Blue добавить канал Alpha, то
можно задавать прозрачность пикселов.

Alpha = 0 - пиксел прозрачен и невидим,


Alpha = 255 - пиксел полностью непрозрачен.
То есть можно просто вырезать фон.
Схема смешивания цветов при
прозрачности
Обычно данные о прозрачности хранятся в виде параметра "alpha". Это
"непрозрачность".

Если значение alpha фрагмента в [0, 1] (то есть alpha = Alpha / 255.0)
то старый цвет C0 смешивается с цветом фрагмента C1 по формуле

R = (1-alpha) * R0 + alpha * R1
G = (1-alpha) * G0 + alpha * G1
B = (1-alpha) * B0 + alpha * B1

Если alpha = 0 - новый цвет равен просто старому C0.


Если alpha = 1 - новый цвет равен цвету фрагмента C1.
При промежуточных значениях - происходит смешивание цветов.

Если несколько объектов накладываются - процедура выполняется


последовательно, от дальнего к ближнему.
Схема смешивания цветов при
прозрачности
Красный квадрат накладываем на черный, белый и синий
цвет.
Накладываем три раза, с alpha: 0.3, 0.6, 1.0.
Способы получения изображений с
вырезанным фоном
1. из векторного редактора
2. "умным" выделением краев в Photoshop или Gimp
3. вручную - плохое качество (алиасинг-рваные края)!
Форматы картинок, хранящие
прозрачность
1. Форматы, позволяющие хранить прозрачность
png-24 - наилучший по качеству / размеру / скорости
распаковки
bmp-32, tiff, tga.
2. Форматы, которые хранят прозрачность 1-битовую
(рваные края):
gif, png-8.

3. Не хранит прозрачность в принципе:


jpg.
Пример: вращающиеся подсолнухи
//Объявление переменных
ofImage image; //картинка
float angle = 0.0; //угол вращения

//Инициализация
void testApp::setup(){
image.loadImage( "texture.png" ); //png - с прозрачностью
angle = 0.0;
}

//Обновление состояния
void testApp::update(){
angle += 0.1; //поворот
}
Пример: вращающиеся подсолнухи
//Рисование
void testApp::draw(){
//включить режим прозрачности
ofEnableAlphaBlending();

//2-й вариант, с точным указанием функции для прозрачности:


//glEnable(GL_BLEND);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

for (int i=0; i<5; i++) {


ofPushMatrix();
ofTranslate( 300.0 + i * 100.0, 300.0 ); //перенос
ofRotate( angle ); //вращение
ofScale( 1.0 + 0.2 * i, 1.0 + 0.2 * i ); //увеличение размера
image.draw( -image.width / 2, -image.height / 2 );
ofPopMatrix();
}
ofDisableAlphaBlending(); //выключение режима прозрачности
//glDisable(GL_BLEND);
}
Прозрачность всего изображения
Также для коллажей часто используют прозрачность для всего
изображения (слоя).

На картинке показан коллаж, где некоторые подсолнухи наложены с


прозрачностью. А у двух подсолнухов к тому же сделана полная
прозрачность (т.е. невидимы) соответственно Red, Blue и Green, Blue
каналы.
Прозрачность всего изображения
- это реализуется путем установки цвета
ofSetColor( r, g, b, a),
перед рисованием изображения.
Дело в том, что изображения рисуются с попиксельным умножением на
компоненты текущего цвета, что условно можно записать так:

R = r / 255.0 *R0
G = g / 255.0 *G0
B = b / 255.0 * B0
A = a / 255.0 * A0

Поэтому-то, чтобы вывести изображение без изменений, используется


ofSetColor(255, 255, 255) перед рисованием изображения.

Внимание: если стоял черный цвет, то изображение будет невидимым.


Это довольно часто встречающаяся "проблема"!
Прозрачность всего изображения
//Рисование
void testApp::draw(){
float w = image.width;
float h = image.height;
ofBackground(0, 0, 0); //задаем цвет фона
ofEnableAlphaBlending(); //включение прозрачности

//текущий цвет влияет на выводимую текстуру


//а именно, текстура поканально умножается на R,G,B компоненты
//цвета и еще учитывается его прозрачность
ofSetColor( 255, 255, 255 ); //непрозрачно
image.draw( w, h );

ofSetColor( 255, 255, 255, 128 ); //полупрозрачно


image.draw( w/2, h/2 );

ofSetColor( 0, 255, 0, 128 ); //полупрозрачно, только зеленый канал


image.draw( w/2, h + h/2 );
ofDisableAlphaBlending(); //выключение прозрачности
}
Результат
Рисование в буфер
Как нарисовать путь движения
маятника
Задача: в проект с качающимся маятником добавить, чтобы рисовалось, где побывал
центр маятника. То есть как будто в маятнике в центре стоит карандаш, который
чертит на бумаге.

Как это сделать? Если запоминать траекторию в виде ломаной и каждый раз ее
выводить на экран - постепенно программа будет работать все медленней.
Лучший способ решения - рисовать траекторию маятника в некоторый буфер вне
экрана, а потом выдавать содержимое буфера на экран.

Этот буфер - как бы экран, который мы не видим. В отличие от экрана, буфер не


будет чиститься при каждом рисовании экрана.

FBO - Frame Buffer Object

В такой буфер можно рисовать как на экране, а затем использовать результат как
текстуру - т.е. выводить ее а экран или рисовать ей в других буферах.
Можно делать сложные многослойные изображения, позволяющие делать эффекты
типа "следа" от движущихся объектов. Для этого нужно рисовать один буфер в
другом с разной прозрачностью.
Как нарисовать путь движения
маятника
Тогда алгоритм рисования в
draw() будет такой:
1. в буфере рисуется
прямая, соединяющая текущее
положение маятника с
предыдущим,
2. буфер выводится на экран
3. на экране рисуется сам маятник
Работа с буфером рисования

Для работы с буфером рисования в OpenFrameworks лучше всего


использовать аддон ofxFBOTexture.

Он состоит из двух файлов - ofxFBOTexture.h и ofxFBOTexture.cpp.


http://addons.openframeworks.cc/projects/list_files/ofxfbotexture

Эти файлы нужно добавить в проект, например, так:


1. Скопировать их в src проекта
2. в VisualStudio ткнуть правой кнопкой по проекту, в меню - Add Existing
Items и добавить их оба.

Правильней копировать все аддоны в папку openframeworks/addons, но


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

...
#include "ofxFBOTexture.h"

...
ofxFBOTexture buffer; //буфер для рисования вне экрана

в setup()

//создание буфера
buffer.allocate( ofGetWidth(), ofGetHeight(),
false //без автоочистки при каждом рисовании - т.к. будем там
накапливать картинки
);

buffer.clear( 0, 0, 0, 255 ); //очистка черным цветом

//нужно заметить, что если ставить не черный цвет, то буфер может окраситься в
первый используемый вами цвет. Как устранить проблему?
Работа с буфером рисования

в draw()

buffer.begin(); //начало рисования в буфер

// процедуры рисования в буфер - оформляется так же, как на экран


... ofSetColor, ofLine, ...

buffer.end(); //конец рисования в буфер

buffer.draw( 0, 0 ); //вывод буфера на экран

// остальное рисование
...

В этом случае процедуры рисования в буфер будут оставаться от кадра к кадру


(путь: который прошел маятник), а процедуры остального рисования - показываться
только в одном кадре (сам маятник с резинкой).
Домашнее задание (*)

Нарисовать многоугольник, заполненный (текстурированный) некоторым


изображением.

Подсказка. Схема вызова функций:

ofTexture tex = image.getTextureReference();


tex.bind();
glBegin( GL_QUADS );
glTexCoord2f(...)
glVertex2f(...)
...
glEnd();
tex.unbind();
Приложение:
Запись видео работающей
программы и публикация
Захват видео с экрана
Программа CamStudio - бесплатная программа для захвата
изображений с экрана и записи в видеофайл.
http://camstudio.org

При больших размерах захватываемой области скорость захвата может весьма


низкой. Не забывайте при съемке вашего проекта установить режим Release, а не
Debug.

Лучше использовать кодек CamStudio Lossless codec, он достаточно быстрый и не


портит изображение. Но файлы получаются большого размера. Поэтому, перед
публикацией, лучше конвертировать файл с помощью программы VirtualDub в другой
кодек, например, XVID.
Публикация видеоролика
Где публиковать: Youtube, Vimeo.

Youtube - наиболее распространен, интегрирован во многие блоги;


просматривается на устройствах iOS.

Vimeo - качество видео превосходит Youtube, поэтому профессиональные


работы публикуют часто одновременно и тут, и на Youtube.

Оценить