13
Разработка интерактивных систем на OpenFrameworks Случайные движения и шум Перлина. Графика: вывод частей изображения УрГУ / ИММ весна 2011 лекции и объявления: вопросы отправляйте на адрес www.uralvision.blogspot.com [email protected]

Случайные движения и шум Перлина. Графика: вывод частей изображения

Embed Size (px)

Citation preview

Page 1: Случайные движения и шум Перлина. Графика: вывод частей изображения

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

Случайные движения и шум Перлина.Графика: вывод частей изображения

УрГУ / ИММ весна 2011лекции и объявления: вопросы отправляйте на адрес www.uralvision.blogspot.com [email protected]

Page 2: Случайные движения и шум Перлина. Графика: вывод частей изображения

Случайные движения

Пусть мы рисуем кружок на экране в центре (x,y).Чтобы его "оживить", хорошо бы его рисовать не в (x,y), а в (x+x1, y+y1), где x1 и y1 - некоторые малые добавки, "шум".

Как получить такие x1, y1?

Вариант 1. Использовать генератор случайных чиселx1 = ofRandom(-10,10);y1 = ofRandom(-10, 10);

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

Page 3: Случайные движения и шум Перлина. Графика: вывод частей изображения

Случайные движенияВариант 2. Сгладить генератор случайных чиселА именно, генерировать скачки редко и плавно двигаться между ними.

float jumpTime = 0; //время последнего прыжка, //от начала работы приложенияfloat x1=0; float y1=0; //текущее состояние шумаfloat x1Target=0; float y1Target=0; //целевое состояние, //к которому плавно двигаться

void testApp::update() { float time = ofGetElapsedTimef (); //берем текущее время if ( time > jumpTime + 0.5 ) { //если предыдущий скачок был давнее 0.5 сек тому назад jumpTime = time; //запоминаем время x1Target = ofRandom( -10, 10 ); //новые координаты, куда идти шуму y1Target = ofRandom( -10, 10 ); } x1 = 0.95 * x1 + 0.05 * x1Target; //плавное движение к (x1Target, y1Target) y1 = 0.95 * y1 + 0.05 * y1Target;

}

Этот вариант более интересный, но все равно движение недостаточно гладкое.

Page 4: Случайные движения и шум Перлина. Графика: вывод частей изображения

Шум ПерлинаШум Перлина был создан Кеном Перлином (англ.) в 1983 году и впоследствии был назван в честь своего создателя.

Perlin noise (Шум Перлина, — математический алгоритм по генерированию процедурной текстуры псевдо-случайным методом. Используется в компьютерной графике для увеличения реализма или графической сложности поверхности геометрических объектов. Также может использоваться для генерации эффектов дыма, тумана и т.д.

(Более быстрая реализация, с многомерным вариантом - симплекс шум, также изобретена К. Перлином в 2001 г.)

Здесь шум - не случайный, а псевдослучайный. То есть вызовов функций типа Random нет.И при каждом старте при желании можно легко воспроизвести одинаковый шум.

Page 5: Случайные движения и шум Перлина. Графика: вывод частей изображения

Шум ПерлинаВ одномерном случяе шум Перлина - это функция f( t ).она выглядит как гладкий график некоторой случайной функции.Она определена для всех t и меняется плавно.

В openFrameworks она задается функцией float ofNoise( float t )ее результат - число в [-1, 1]. ofNoise - это просто фиксированная функция, просто с труднопредсказуемым поведением.

Можно сделать чтоб t зависело от времени, тогда ofNoise( t ) будет шумом. Но нам нужно две функции, для обеих координат.А ofNoise( t ) всегда будет возвращать одно и то же число. Как быть?

Page 6: Случайные движения и шум Перлина. Графика: вывод частей изображения

Шум ПерлинаВозвращаемся к задаче колебания кружка на экране.

Вариант 3. Использовать шум Перлина

float tX, tY; //начальные сдвиги для шума

void testApp::setup(){ tX = ofRandom( 0, 1000 ); //задаем сдвиги случайным образом tY = ofRandom( 0, 1000 );}

void testApp:: update(){ float time = ofGetElapsedTimef();

float velocity = 0.5; //скорость шума float x1 = 10 * ofNoise( tX + time * velocity ); //"гладкий" шум [-10,10] float y1 = 10 * ofNoise( tY + time * velocity );}

void testApp::draw(){ ofCircle( 100 + x1, 200 + y1, 20 ); //рисуем кружок}

Page 7: Случайные движения и шум Перлина. Графика: вывод частей изображения

Шум ПерлинаПример Мотыльки летают около своих центров по такому алгоритму.http://vimeo.com/27772326

Page 8: Случайные движения и шум Перлина. Графика: вывод частей изображения

Вывод изображения по кускамПусть есть изображение ofImage, а мы хотим вывести на экран его часть. Как это сделать?

Вариант 1. Просто скопировать нужную часть в новое изображение, используя image.pixels() и image1.setFromPixels(...).

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

Вариант 2.2. Вывести это средствами OpenGL.Так как изображение представляется в виде текстуры OpenGL, это будет работать очень быстро.Его и рассмотрим далее.

Page 9: Случайные движения и шум Перлина. Графика: вывод частей изображения

Вывод изображения по кускамПример - Rubber Mirrorhttp://www.youtube.com/watch?v=tk-g-sYb7-I

Тут изображение с камеры рисуется на заднем плане целиком. Кроме того, вырезаются небольшие квадратные кусочки, в которых есть человек. Эти квадратики также рисуются. При этом, координаты квадратиков меняются по силе Гука и силе тяжести. Поэтому кажется, что они резиновые.

Page 10: Случайные движения и шум Перлина. Графика: вывод частей изображения

Вывод изображения по кускамofTexture & texture = image.getTextureReference(); //берем текстуру изображения

texture.bind(); //делаем связывание - теперь OpenGL будет знать, //что при рисовании текстуры данные брать из texture

//как обычно для изображений, это цвет будет умножаться на выводимую картинку, поэтому надо поставить белый цвет, чтобы картинка выводилась без изменения цветовofSetColor( 255, 255, 255 );

glBegin( GL_QUADS ); //Команды OpenGL : начинаем рисовать 4-угольникиglTexCoord2f( 50, 50 ); //1-й угол, координата в текстуреglVertex2f( 100, 100 ); //координата на экране

glTexCoord2f( 150, 50 ); //2-й уголglVertex2f( 300, 100 );glTexCoord2f( 150, 150 ); //3-й уголglVertex2f( 250, 300 );glTexCoord2f( 50, 150 ); //4-й уголglVertex2f( 150, 250 );//... Тут можно рисовать 2-й, 3-й, и далее 4-угольники, можно в цикле.glEnd(); //конец задания 4-угольниковtex.unbind(); //прекращаем связывание, начатое bindЭтот метод хорош своей понятностью. Но если выводить много 4-угольников, то он будет работать недостаточно быстро. А более быстрый способ - задать массивы 4-угольников и нарисовать их одной командой.

Page 11: Случайные движения и шум Перлина. Графика: вывод частей изображения

Вывод изображения по кускам (Быстрый метод)

Пусть n - число 4-угольников, и есть массивыvector<float> pointTexture( 4 * 2 * n ); //текстурные координаты, откуда брать картинкуvector<float> pointScreen( 4 * 2 * n ); //экранные координаты, в какое место экрана выводить

В них записаны желаемые многоугольники, в порядкеx1, y1, x2, y2, x3, y3, x4, y4 - первый многоугольник,x1, y1, x2, y2, x3, y3, x4, y4 - второй многоугольник,... n-й многоугольник.

Тогда их можно вывести на экран так:ofTexture & texture = image.getTextureReference(); texture.bind(); ofSetColor( 255, 255, 255 ); glEnableClientState(GL_VERTEX_ARRAY);glEnableClientState(GL_TEXTURE_COORD_ARRAY);glTexCoordPointer( 2, GL_FLOAT, 0, &pointTexture[0] );

glVertexPointer(2, GL_FLOAT, 0, &pointScreen[0]); //первое число 2 значит, что координаты заданы двумерные, x,y (а не трехмерные x,y,z). //Для трехмерного рисования - надо задавать pointTexture( 4 * 3 * n ), pointScreen( 4 * 3 * n ).

glDrawArrays(GL_QUADS, 0, n * 4); //сколько выводить вершин - n * 4glDisableClientState(GL_TEXTURE_COORD_ARRAY);glDisableClientState(GL_VERTEX_ARRAY);

tex.unbind();

Page 12: Случайные движения и шум Перлина. Графика: вывод частей изображения

Домашнее задание I1. Считать произвольное изображение из файла image.loadImage( "image.png" );

2. Разбить его на маленькие фрагменты и вывести на экран.При этом углы фрагментов зашумить двумерной функцией ofNoise(tX,tY) где tX = 0.1 * time + i;tY = 0.1 * time + j; и (i,j) - координаты угла фрагмента на большом изображении.

Должно получиться колышущееся изображение, отдаленно напоминающее рябь воды.

Page 13: Случайные движения и шум Перлина. Графика: вывод частей изображения

Домашнее задание IIСгенерировать в центре экрана набор точекvector<ofPoint> p;p.resize( 100 );for (int i=0; i<p.size(); i++) { p[i] = ofPoint( ofRandom( 200, 600 ), ofRandom( 200, 600 ) );}

и для каждой точки хранить ее скорость и массу.vector<ofPoint> v, mass;v.resize( 100 ); // - ее также задать случайной m.resize( 100 ); // - ее также задать случайной

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

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