WWW.DOCX.LIB-I.RU
БЕСПЛАТНАЯ  ИНТЕРНЕТ  БИБЛИОТЕКА - Интернет материалы
 

«8.4 Обзор методов имитации акварели Моделирование акварели средствами компьютерной графики - одна из интереснейших подзадач NPR. В настоящее время существует несколько ...»

8.4 Обзор методов имитации акварели

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

Размытие изображения и затемнение краев

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

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

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

Метод визуализации поверхностей с эффектами акварели

Очень любопытный подход, использующий создание освещенной сцены путем наложения нескольких полупрозрачных слоев краски. Каждый слой создается с помощью линейной интегральной свертки шума Перлина (Perlin noise), затем с помощью обратной вычитательной модели освещения (inverted substractive lighting model) вычисляется распределение толщины слоев. [9]

Метод имитации акварели с помощью клеточных автоматов

Этот метод описан в [21]. Рассмотрим его подробнее.

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

Клеточный автомат представляет собой набор клеток, заданных регулярной сеткой, каждая клетка находится в каждый момент времени в определенном состоянии. С течением времени состояние каждой клетки меняется в зависимости от ее собственного состояния и состояния соседних клеток. Пожалуй, самый известный пример использования клеточных автоматов - игра Жизнь.

Перенос пигмента и модель диффузии

Чтобы смоделировать перенос пигмента с кисти на бумагу, а также распределение пигмента на бумаге, используется двумерный клеточный автомат на конечной сетке, представляющей поверхность бумаги. Он представляет собой массив клеток, каждая из которых способна содержать определенное количество воды и пигмента (растворенного в воде). Это похоже на лоток для приготовления льда, где краска наливается в один из контейнеров и, если контейнер полон, растекается в соседние.

Итак, мы имеем следующее представление:

Каждая клетка Pij имеет 2 индекса i и j

Содержимое клеток описывается двумя переменными Wij и Iij, количеством воды и пигмента соответственно.

Каждая клетка имеет 4-х соседей

Функция перехода состояний Sij = (Wij, Iij)

Sij(t + t) = f (Sij(t), Sk(t) | k натуральное)

Моделирование бумаги

Чтобы смоделировать волокнистую структуру бумаги, добавим условие, что каждая клетка может вмещать ограниченное количество воды и пигмента. Добавим к состоянию каждой клетки 2 дополнительные переменные Bij и Cij - константы, выбранные пропорционально толщине бумаги. Bij описывает высоту "дна" клетки, а Cij - максимальный объем клетки. Волокна бумаги могут моделироваться различными способами. Можно использовать псевдослучайные процессы, или использовать библиотеки предопределенных волокон.

Моделирование кисти

Кисть состоит из отдельных щетинок.





На каждой щетинке может помещаться некоторое количество краски, и по мере рисования краска стекает на кончик кисточки, перемещается на бумагу и кисточка сохнет. Дополнительный эффект дает неравномерное распределение краски на щетинках кисти. Необычный, но эффективный способ представления кисти - как второго клеточного автомата, с теми же состояниями Bij и Cij. Во время рисования краска стекает к кончику кисти, что может быть смоделировано изменением высоты дна для каждой клетки таким образом: Bij = Bij + x. В этом выражении х - расстояние от клетки Pij до кончика кисти, а - константа, пропорциональная наклону кисти.

Моделирование процесса рисования

Процесс рисования начинается с переноса частиц воды и краски с кисти на бумагу. Клетки получают определенное количество воды и краски, далее за распределение его по бумаге отвечает функция переноса. Это происходит за 4 шага. Для каждого временного шага:

Перенос и диффузия частиц воды. Если клетка Pij полна воды, вода перельется в соседние клетки. В то же время часть воды может перелиться из соседних клеток в Pij.

Перенос частиц краски. С краской аналогично.

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

Испарение воды. На каждом шаге часть воды испаряется, и краска сохнет. Если вся вода испарилась, частицы краски остаются в клетке Pij как сухая краска.

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

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

Метод, в основе которого - моделирование физических процессов течения воды и рассеивания пигмента.

Этот метод показал в настоящее время наиболее привлекательный и реалистичный результат. [1], [16]

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

9.Моделирование техники акварели

Одним из довольно простых методов моделирования техники акварели (watercolor rendering) является разбиение процесса построения изображения на отдельные слои. Для каждого такого слоя вычисляется его толщина (определяющая степень его влияния) и все они последовательно наносятся на бумагу.

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

Толщина этого слоя определяется по следующей формуле:

Следующий слой отвечает на неосвещенные части и его толщина задается следующей формулой:

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

Довольно простым способом композиции всех этих слоев является следующий:

Для рендеринга моделей, состоящих из большого числа небольших граней, вычисление параметров слоев проще всего реализовать в вершинном шейдере.

Ниже приводится реализация такого шейдера на GLSL.

//

// Watercolor vertex shader//

uniform vec3 lightPos;

uniform vec3 eyePos;

varying vec3 diffuseThickness;

varying vec3 unlitThickness;

void main(void)

{

const vec3 one = vec3 ( 1.0 );

const vec3 ambient = vec3 ( 0.4, 0.4, 0.4 );

const vec3 diffuse = vec3 ( 0.0, 0.0, 1.0 );

const float specPower = 50.0;

vec3 p = vec3 ( gl_ModelViewMatrix * gl_Vertex );

vec3 l = normalize ( lightPos - p );

vec3 v = normalize ( vec3 ( eyePos ) - p );

vec3 h = normalize ( l + v );

vec3 n = normalize ( gl_NormalMatrix * gl_Normal );

// compute layers thicknesses

diffuseThickness = (1.0 - pow ( max ( dot ( n, h ), 0.0 ), specPower ) ) * (one - diffuse);

unlitThickness = (1.0 - max ( dot ( n, l ), 0.0 ) ) * (one - ambient);

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

gl_TexCoord [0] = gl_MultiTexCoord0;

}

Задачей фрагментного шейдера является получение значения из шумовой текстуры и смешение его с проинтерполированными параметрами слоев.

Соответствующая реализация приводится ниже.

//

// Watercolor fragment shader

//

varying vec3 diffuseThickness;

varying vec3 unlitThickness;

uniform sampler2D noiseMap;

void main (void)

{

vec3 color = diffuseThickness;

vec3 noise = texture2D ( noiseMap, gl_TexCoord [0].xy * vec2 ( 0.7, 2.0 ) ).xyz;

color = vec3 ( 1.0 ) - color * unlitThickness * noise.x;

gl_FragColor = vec4 ( color, 1.0 );

}

Рис 1. Чайник, изображенный в стиле акварели.

Можно слегка модифицировать описанный алгоритм, "смягчая" резкие края объектов. Для этого достаточно домножить толщину диффузного слоя на max((n,v),0). Данный множитель, обращаясь в нуль на контурных линиях объекта, производит требуемое смягчение.

При этом толщина диффузного слоя вычисляется по следующей формуле:

Изображение, полученное при использовании смягчения краев, приводится на рис 2.

Рис 2. Изображение чайника, выполненное в стиле акварели со смягчением краев.

Ниже приводятся соответствующие вершинный и фрагментный шейдеры.

//

// Watercolor vertex shader with edge softening

//

uniform vec3 lightPos;

uniform vec3 eyePos;

varying vec3 diffuseThickness;

varying vec3 unlitThickness;

void main(void)

{

const vec3 one = vec3 ( 1.0 );

const vec3 ambient = vec3 ( 0.4, 0.4, 0.4 );

const vec3 diffuse = vec3 ( 0.0, 0.0, 1.0 );

const float specPower = 50.0;

vec3 p = vec3 ( gl_ModelViewMatrix * gl_Vertex );

vec3 l = normalize ( lightPos - p );

vec3 v = normalize ( vec3 ( eyePos ) - p );

vec3 h = normalize ( l + v );

vec3 n = normalize ( gl_NormalMatrix * gl_Normal );

// compute layers thicknesses

diffuseThickness = (1.0 - pow ( max ( dot ( n, h ), 0.0 ), specPower ) ) *

(one - diffuse) * max ( dot ( n, v ), 0.0 );

unlitThickness = (1.0 - max ( dot ( n, l ), 0.0 ) ) * (one - ambient);

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

gl_TexCoord [0] = gl_MultiTexCoord0;

}

//

// Watercolor fragment shader with edge softening

//

varying vec3 diffuseThickness;

varying vec3 unlitThickness;

uniform sampler2D noiseMap;

void main (void)

{

vec3 color = diffuseThickness;

vec3 noise = texture2D ( noiseMap, gl_TexCoord [0].xy * vec2 ( 0.7, 2.0 ) ).xyz;

color = vec3 ( 1.0 ) - color * unlitThickness * noise.x;

gl_FragColor = vec4 ( color, 1.0 );

}

9.1 Листинг программы для моделирования эффекта акварели

#include "libExt.h"

#include <glut.h>

#include <stdio.h>

#include <stdlib.h>

#include "libTexture.h"

#include "TypeDefs.h"

#include "Vector3D.h"

#include "Vector2D.h"

#include "GlslProgram.h"

Vector3D eye ( -0.5, -0.5, 1.5 ); // camera position

Vector3D light ( 5, 0, 4 ); // light position

unsigneddecalMap; // decal (diffuse) texture

unsigned stoneMap;

unsigned teapotMap;

unsigned noiseMap;

unsigned paperMap;

Vector3D rot ( 0, 0, 0 );

float angle = 0;

int mouseOldX = 0;

int mouseOldY = 0;

bool useFilter = true;

GlslProgram program;

void startOrtho ()

{

glMatrixMode ( GL_PROJECTION ); // select the projection matrix

glPushMatrix (); // store the projection matrix

glLoadIdentity (); // reset the projection matrix

// set up an ortho screen

glOrtho ( 0, 512, 0, 512, -1, 1 );

glMatrixMode ( GL_MODELVIEW ); // select the modelview matrix

glPushMatrix (); // store the modelview matrix

glLoadIdentity (); // reset the modelview matrix

}

void endOrtho ()

{

glMatrixMode ( GL_PROJECTION ); // select the projection matrix

glPopMatrix (); // restore the old projection matrix

glMatrixMode ( GL_MODELVIEW ); // select the modelview matrix

glPopMatrix (); // restore the old projection matrix

}

void init ()

{

glClearColor ( 1.0, 1.0, 1.0, 1.0 );

glEnable ( GL_DEPTH_TEST );

glEnable ( GL_TEXTURE_2D );

glDepthFunc ( GL_LEQUAL );

glHint ( GL_POLYGON_SMOOTH_HINT, GL_NICEST );

glHint ( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

}

void display ()

{

glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

startOrtho ();

glActiveTextureARB ( GL_TEXTURE0_ARB );

glBindTexture ( GL_TEXTURE_2D, paperMap );

glEnable ( GL_TEXTURE_2D );

glActiveTextureARB ( GL_TEXTURE1_ARB );

glDisable ( GL_TEXTURE_2D );

glActiveTextureARB ( GL_TEXTURE2_ARB );

glDisable ( GL_TEXTURE_2D );

glDepthMask ( GL_FALSE );

glColor4f ( 1, 1, 1, 1 );

/*

glBegin ( GL_QUADS );

glTexCoord2f ( 0, 0 );

glVertex2f ( 0, 0 );

glTexCoord2f ( 1, 0 );

glVertex2f ( 511, 0 );

glTexCoord2f ( 1, 1 );

glVertex2f ( 511, 511 );

glTexCoord2f ( 0, 1 );

glVertex2f ( 0, 511 );

glEnd ();

*/

endOrtho ();

glDepthMask ( GL_TRUE );

glActiveTextureARB ( GL_TEXTURE0_ARB );

glBindTexture ( GL_TEXTURE_2D, teapotMap );

glActiveTextureARB ( GL_TEXTURE1_ARB );

glBindTexture ( GL_TEXTURE_2D, noiseMap );

glActiveTextureARB ( GL_TEXTURE2_ARB );

glBindTexture ( GL_TEXTURE_2D, paperMap );

glActiveTextureARB ( GL_TEXTURE0_ARB );

if ( useFilter )

program.bind ();

glMatrixMode ( GL_MODELVIEW );

glPushMatrix ();

glRotatef ( rot.x, 1, 0, 0 );

glRotatef ( rot.y, 0, 1, 0 );

glRotatef ( rot.z, 0, 0, 1 );

glutSolidTeapot ( 0.4 );

glPopMatrix ();

if ( useFilter )

program.unbind ();

glutSwapBuffers ();

}

void reshape ( int w, int h )

{

glViewport ( 0, 0, (GLsizei)w, (GLsizei)h );

glMatrixMode ( GL_PROJECTION );

glLoadIdentity ();

gluPerspective ( 60.0, (GLfloat)w/(GLfloat)h, 1.0, 60.0 );

glMatrixMode ( GL_MODELVIEW );

glLoadIdentity ();

gluLookAt ( eye.x, eye.y, eye.z, // eye

0, 0, 0, // center

0, 0, 1 ); // up

}

void key ( unsigned char key, int x, int y )

{

if ( key == 27 || key == 'q' || key == 'Q' ) // quit requested

exit ( 0 );

if ( key == 'f' || key == 'F' )

useFilter = !useFilter;

}

void animate ()

{

angle = 0.001f * glutGet ( GLUT_ELAPSED_TIME );

light.x = 2*cos ( angle );

light.y = 2*sin ( angle );

light.z = 3 + 0.3 * sin ( angle / 3 );

program.bind ();

program.setUniformVector ( "eyePos", eye );

program.setUniformVector ( "lightPos", light );

program.setUniformFloat ( "time", angle );

program.unbind ();

glutPostRedisplay ();

}

void motion ( int x, int y )

{

rot.y -= ((mouseOldY - y) * 180.0f) / 200.0f;

rot.z -= ((mouseOldX - x) * 180.0f) / 200.0f;

rot.x = 0;

if ( rot.z > 360 )

rot.z -= 360;

if ( rot.z < -360 )

rot.z += 360;

if ( rot.y > 360 )

rot.y -= 360;

if ( rot.y < -360 )

rot.y += 360;

mouseOldX = x;

mouseOldY = y;

glutPostRedisplay ();

}

void mouse ( int button, int state, int x, int y )

{

if ( state == GLUT_DOWN )

{

mouseOldX = x;

mouseOldY = y;

}

}

int main ( int argc, char * argv [] )

{

// initialize glut

glutInit ( &argc, argv );

glutInitDisplayMode ( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );

glutInitWindowSize ( 512, 512 );

// create window

glutCreateWindow ( "OpenGL watercolor rendering" );

// register handlers

glutDisplayFunc ( display );

glutReshapeFunc ( reshape );

glutKeyboardFunc ( key );

glutMouseFunc ( mouse );

glutMotionFunc ( motion );

glutIdleFunc ( animate );

init ();

initExtensions ();

if ( !GlslProgram :: isSupported () )

{

printf ( "GLSL not supported.\n" );

return 1;

}

if ( !program.loadShaders ( "watercolor.vsh", "watercolor.fsh" ) )

{

printf ( "Error loading shaders:\n%s\n", program.getLog ().c_str () );

return 3;

}

decalMap = createTexture2D ( true, "../Textures/oak.bmp" );

stoneMap = createTexture2D ( true, "../Textures/block.bmp" );

teapotMap = createTexture2D ( true, "../Textures/Oxidated.jpg" );

noiseMap = createTexture2D ( true, "noise-2D.png" );

paperMap = createTexture2D ( true, "paper.dds" );

program.bind ();

program.setTexture ( "noiseMap", 1 );

program.setTexture ( "paperMap", 2 );

program.unbind ();

// printf ( "Render scene in watercolor mode\n" );

// printf ( "Press F key to turn watercolor mode on/off\n" );

glutMainLoop ();

return 0;

}




Похожие работы:

«Контрольный итоговый тест по русскому языку в 9 классе (Повторение и обобщение изученного) Вариант 11.Найдите неологизмА)А) гильдия;Б) консенсус;В) фельдфебель;Г) дочиста2. Найдите слова, относящиеся к официально-деловой речи:А) братец мешкает;Б) во исполнение решения;В) моби...»

«Приложение 1 Лист адаптации ребенка к дошкольному учреждению Фамилия, имя ребенка Дата рождения Дата поступления в ДОУ _ Возраст при поступлении Группа здоровья _ Данные антропометрии: рост _ вес (при поступлении) рост _ вес (через месяц) Заболевания до поступления Индивидуальные особенности _ Привычки...»

«ИЗБИРАТЕЛЬНАЯ КОМИССИЯГОРОДА УЛАН-УДЭ РЕШЕНИЕ 10 сентября 2014 года г.Улан-Удэ Об итогах рассмотрения жалобы Супони С.И. Кандидат в депутаты Улан-Удэнского городского Совета депутатов по одномандатному избирательному округу №7 Супоня Сергей Иванович обратился в Избирательную комиссию г. Улан-Удэ с жалобой дей...»

«Вопросы и задания 4 этапа дистанционного конкурса "Я и дорога".1. 31 декабря 1899 года Ева Нельсон стала первой женщиной, севшей за руль автомобиля. Причём, во время показа она сбила пятерых зрителей. Назовите город, где это произошло: Прага, Магдебург, Варшава, Нью – Йорк.2. Что или кто появились 3 августа 1926 г...»

«Bonjour. Comment a va ? 30 sec.Повторение пройденного материала: Quelles boissons tu aimes et quelles boissons tu n’aimes pas ? (Tu aimes bien le caf ? Tu aimes le th ? Tu prfres le th vert ou le th noir ? Tu aimes bien...»

«ОТЧЕТ по затратам на содержание и ремонт общего имущества дома по адресу: г.Первоуральск, п.Вересовка, ул.Заводская, дом 18 за период с 01.01.2016 по 31.12.2016 гг. Общие сведения о доме Площадь дома 2432.8 Год постройки 1993 Этажность 5 Количество подъездов 3 Количество квартир 45 Доходы дома Вид услуг (работ) Начислено Оплачено Содержание и...»

«Сведения об имущественном положении и доходах лиц, замещающих муниципальные должности в муниципальном образовании Чернский район за период с 01 января 2016 года по 31 декабря 2016 года Фамилия. Имя, отчество Должность Общая сумма дохода за 2016 год (руб.) П...»







 
2017 www.docx.lib-i.ru - «Бесплатная электронная библиотека - интернет материалы»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.