НФР_4

advertisement
10.Моделирование рисования древесным углем
Одной из характерных особенностей для изображений в этой технике является заметно
увеличенная контрастность изображения. Простейшим способом моделирования этого для
изображений в оттенках серого цвета является преобразование интенсивности
изображения по следующей формуле:
В этой формуле в качестве степени p используется величина, большая единицы.
Типичным значением степени является 3.5.
Данное преобразование применяется к значению освещенности, полученной по формуле
Фонга. В результате получается изображение с усиленным контрастом.
Полученная таким образом освещенность используется для индексирования в
специальную текстуру, называемую Contrast Enhancement Texture. На следующем рисунке
приводится пример такой текстуры.
Рис 3. Пример Contrast Enhancement Texture.
Наложением этой текстуры удается не только еще больше усилить контрастность, но и
придать получившемуся изображению зернистость, характерную для рисунков углем по
бумаге.
Однако, если t-координата для наложения СЕТ-текстуры задается явно как
модифицированная освещенность, то какую величину следует взять в качестве первой
текстурной координаты s ?
Если в качестве s для обращения к СЕТ взять одну из стандартных текстурных координат,
связанных с изображаемым объектом, то это может привести к появлению заметных
артефактов.
Наиболее удобным было бы взять в качестве данной текстурной координаты случайное
значение.
В качестве источника такого случайного значения удобно использовать дополнительную
текстуру, значения цветовых компонент для которой были получены при помощи
генератора псевдослучайных чисел.
Тогда, использовав обычные текстурные координаты для обращения к такой текстуре, на
выходе мы получим фактически случайное значение цвета, одну из компонент которого
можно использовать в качестве текстурной координаты s для обращения к СЕТ.
Еще одним характерным элементом рисунков углем является так называемое
"размывание" (smuding), когда художник (обычно просто рукой) слегка размазывает уголь
по бумаге для получения плавных полутонов.
Достаточно простым способом моделирования размывания является просто смешение
(blending) текстурированного (при помощи СЕТ) изображения с нетекстурированным
изображением с усиленной контрастностью.
Заключительным шагом является наложения рисунка на бумагу, которая задается при
помощи отдельной текстуры, и также вносит свой вклад в получающееся изображения.
Данный алгоритм довольно легко реализуется при помощи шейдеров. При этом
вершинный шейдер отвечает за вычисления освещенности в вершинах и преобразование
ее для увеличения контраста.
Задачей фрагментного шейдера является наложение СЕТ, смешение текстурированной
модели с нетекстурированной и наложения бумаги на получившееся значение.
Ниже приводятся листинги вершинного и фрагментного шейдеров на GLSL.
//
// Charcoal vertex shader
//
uniform vec3 lightPos;
uniform vec3 eyePos;
varying vec3 color;
void main(void)
{
const vec3 ambient
= vec3 ( 0.0 );
const vec3 diffuse
= vec3 ( 1.0, 1.0, 1.0 );
const vec3 luminance = vec3 ( 0.3, 0.59, 0.11 );
vec3 p = vec3 ( gl_ModelViewMatrix * gl_Vertex );
vec3 l = normalize ( lightPos - p );
vec3 n = normalize ( gl_NormalMatrix * gl_Normal );
// compute illumination
color = ambient + diffuse * max ( dot ( n, l ), 0.0 );
// apply CEO
color = vec3 ( pow ( clamp ( dot ( color, luminance ), 0.0, 1.0 ), 3.5 ) );
gl_Position
= gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord [0] = gl_MultiTexCoord0;
}
//
// Charcoal fragment shader
//
varying vec3
color;
uniform sampler2D
uniform sampler2D
uniform sampler2D
randomTex;
cetTex;
paperTex;
void main (void)
{
vec4 random
vec3 contrast
vec3 smudge
vec3 paper
=
=
=
=
texture2D ( randomTex, gl_TexCoord [0].xy );
texture2D ( cetTex, vec2 ( random.x, 1.0 - color.x ) ).rgb;
0.5 * (contrast + color);
texture2D ( paperTex, gl_FragCoord.xy / 512.0 ).rgb;
gl_FragColor.rgb = contrast + vec3 ( 1.0 ) - paper;
gl_FragColor.a
= 1.0;
}
На следующем рисунке приводится изображение, построенное с использованием этих
шейдеров.
Рис 4. Изображение в технике рисования углем по бумаге.
Для получения Contrast Enhancement Texture использовался простой скрипт на языке
Python, приводимый на следующем листинге.
#
# Script to create contrast enhancement texture
#
import PIL, Image, random, math, ImageEnhance
# basic parameters: bitmap size and contrast power
size
= 512
contrastExp = 15
noiseDensity = 3.0
im
= Image.new ( "RGB", (size, size) )
# fill it with white
for i in range (size):
for j in range (size):
im.putpixel ( (i,j), ( 255, 255, 255 ) )
numBlackPixels = int( noiseDensity * float(size) * float(size) )
for i in range ( numBlackPixels) :
x = random.random ()
y = random.random ()
# apply contrast enhansment
y = math.pow ( y, contrastExp )
px = int(x*(size-1))
py = size - 1 - int(y*(size-1))
if py < 0:
py = 0
if py >= size:
py = size - 1
im.putpixel ( (px, py), (0, 0, 0))
sh = ImageEnhance.Sharpness ( im )
im2 = sh.enhance ( 0.2 )
im2.show ()
im2.save ( "cet.bmp", "bmp" )
Следующий скрипт используется для построения текстуры, состоящей из случайных
значений.
#
# Script to random texture
#
import PIL, Image, random
# basic parameters: bitmap size
size = 256
im
= Image.new ( "RGB", (size, size) )
for i in range (size):
for j in range (size):
r = int ( 255.0 * random.random () )
g = int ( 255.0 * random.random () )
b = int ( 255.0 * random.random () )
im.putpixel ( (i,j), ( r, g, b ) )
im.show ()
im.save ( "random.bmp", "bmp" )
10.1.Листинг программы для моделирования эффекта рисования углем
#include
"libExt.h"
#include
#include
#include
<glut.h>
<stdio.h>
<stdlib.h>
#include
#include
#include
#include
#include
"libTexture.h"
"TypeDefs.h"
"Vector3D.h"
"Vector2D.h"
"GlslProgram.h"
Vector3D
Vector3D
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
Vector3D
float
int
int
bool
eye
( -0.5, -0.5, 1.5 );
light ( 5, 0, 4 );
decalMap;
stoneMap;
teapotMap;
randomMap;
cetMap;
paperMap;
rot ( 0, 0, 0 );
angle
= 0;
mouseOldX = 0;
mouseOldY = 0;
useFilter = true;
// camera position
// light position
// decal (diffuse) texture
GlslProgram program;
void
startOrtho
{
glMatrixMode
matrix
glPushMatrix
glLoadIdentity
()
// select the projection
();
();
// store the projection matrix
// reset the projection matrix
// set up an ortho screen
glOrtho
glMatrixMode
glPushMatrix
glLoadIdentity
( GL_PROJECTION );
( 0, 512, 0, 512, -1, 1 );
( GL_MODELVIEW );
();
();
// select the modelview matrix
// store the modelview matrix
// reset the modelview matrix
}
void
endOrtho
{
glMatrixMode
matrix
glPopMatrix
matrix
glMatrixMode
glPopMatrix
matrix
}
void init ()
{
glClearColor
glEnable
glEnable
glDepthFunc
()
( GL_PROJECTION );
// select the projection
();
// restore the old projection
( GL_MODELVIEW );
();
// select the modelview matrix
// restore the old projection
(
(
(
(
1.0, 1.0, 1.0, 1.0 );
GL_DEPTH_TEST );
GL_TEXTURE_2D );
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_TEXTURE1_ARB );
glDisable
( GL_TEXTURE_2D );
glActiveTextureARB ( GL_TEXTURE2_ARB );
glDisable
( GL_TEXTURE_2D );
glActiveTextureARB ( GL_TEXTURE0_ARB );
glBindTexture
( GL_TEXTURE_2D, paperMap );
glEnable
( GL_TEXTURE_2D );
glDepthMask
glColor4f
( GL_FALSE );
( 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, randomMap );
glActiveTextureARB ( GL_TEXTURE2_ARB );
glBindTexture
( GL_TEXTURE_2D, cetMap );
glEnable
( GL_TEXTURE_2D );
glTexParameteri
glTexParameteri
( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE );
( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE );
glActiveTextureARB ( GL_TEXTURE3_ARB );
glBindTexture
( GL_TEXTURE_2D, paperMap );
glActiveTextureARB ( GL_TEXTURE0_ARB );
if ( useFilter )
program.bind ();
glMatrixMode ( GL_MODELVIEW );
glPushMatrix ();
glRotatef
glRotatef
glRotatef
( rot.x, 1, 0, 0 );
( rot.y, 0, 1, 0 );
( 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' )
exit ( 0 );
// quit requested
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 charcoal effect" );
glutDisplayFunc
glutReshapeFunc
glutKeyboardFunc
glutMouseFunc
glutMotionFunc
glutIdleFunc
(
(
(
(
(
(
display
reshape
key
mouse
motion
animate
// register handlers
);
);
);
);
);
);
init
();
initExtensions ();
if ( !GlslProgram :: isSupported () )
{
printf ( "GLSL not supported.\n" );
return 1;
}
if ( !program.loadShaders ( "charcoal.vsh", "charcoal.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" );
randomMap = createTexture2D ( true, "random.bmp" );
cetMap
= createTexture2D ( true, "cet.bmp"
);
paperMap = createTexture2D ( true, "paper.dds" );
program.bind ();
program.setTexture
program.setTexture
program.setTexture
program.setTexture
program.unbind ();
(
(
(
(
"mainTex",
"randomTex",
"cetTex",
"paperTex",
0
1
2
3
);
);
);
);
printf ( "Render scene with charcoal effect\n" );
printf ( "Press F key to turn charcoal mode on/off\n" );
glutMainLoop ();
return 0;
}
Related documents
Download