Color
Teoría del color
• El color que vemos en los objetos es resultado de la luz reflejada por su superficie
• El negro es la ausencia de color. Un objeto negro no refleja nada
• El blanco es la combinación de todos los colores. Un objeto blanco refleja todas la luz que le llega
390nm 720 nm
• El color es una longitud de onda de luz, visible para el ojo humano
Las tres componentes del color
• El ojo humano tiene tres tipos de células receptoras de luz
– el primer tipo se excita más con fotones de longitud de onda rojiza – el segundo tipo se excita más con fotones de longitud de onda verde – el tercer tipo se excita más con fotones de longitud de onda azulada
• El cerebro mezcla la combinación de las tres y devuelve un solo color resultado
• De esta forma, cualquier color que vemos es en realidad una combinación de ondas con longitudes dentro del espectro visible
Espacio de color
• Es un espacio 3D cuyas dimensiones son las componentes R, G y B
• Variando cada eje entre 0 y 1 obtenemos el cubo de color, que incluye todos los colores visibles al ojo humano
G
Azul (0,0,1)
R
B
Rojo (1,0,0) Verde (0,1,0)
Magenta (1,0,1) Blanco (1,1,1)
Cian (0,1,1)
Amarillo (1,1,0)
Negro (0,0,0) Grises (x,x,x)
Sombreado de polígonos
• Para definir el color activo (con el que se pintan los vértices) se usa:
void glColor3f (GLfloat rojo, GLfloat verde, GLfloat azul) void glColor3ub (GLfloat rojo, GLfloat verde, GLfloat azul)
• Si todos los vértices tienen el mismo color, todo el polígono es constante
• Si cada vértice tiene un color diferente, el color del interior del polígono dependerá del modo de sombreado elegido:
– Modo plano: el color del polígono es el del último vértice
glShadeModel (GL_FLAT)
– Modo interpolado: el color del
polígono se deduce a partir del color de cada vértice
glShadeModel (GL_SMOOTH)
G
R
B
// Activa el sombreado suave glShadeModel (GL_SMOOTH);
// Dibuja el triángulo glBegin (GL_TRIANGLES);
// Vértice rojo
glColor3ub (255, 0, 0);
glVertex3f (100, 0, 0);
// Vértice verde
glColor3ub (0, 255, 0);
glVertex3f (0, 100, 0);
// Vértice azul
glColor3ub (0, 0, 255);
glVertex3f (0, 0, 100);
glEnd();
G
R
B
• Cambiando a modo de
sombreado plano, el triángulo quedaría entero de color azul
Bits de color
• Si el sistema operativo no puede mostrar 24 bits color, éste busca los colores más
adecuados --> no es preciso cambiar el código!
• Lógicamente, la calidad de la imagen será diferente
24 bits
8 bits
• Si el número de bits color es pequeño, podemos indicarle a OpenGL que use tramas para aproximar el color real:
glEnable (GL_DITHER);
8 bits con dithering
Modo indexado de color
• OpenGL también permite trabajar directamente con la paleta de color, en lugar de usar las componentes RGB
• Para establecer el color activo se usa:
void glIndexi (GLint indice);
• Ventajas del modo indexado:
– es más rápido (sólo se utiliza un valor por pixel) – permite animaciones de paleta
– permite usar el color para indicar otra magnitud
• Desventajas
– no permite efectos de iluminación
Ejemplo: navegador 3D en color
void PanelVista_Paint(TObject *Sender) {
switch (ModoColor) {
case 2: // modo sólido
glPolygonMode(GL_FRONT,GL_FILL);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
break;
case 1: // modo alámbrico
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
}
// Transformación de vista glPushMatrix();
gluLookAt (...);
// dibujamos los objetos RenderWorld();
glPopMatrix();
}
Iluminación
Luz ambiente
• Es la luz que no viene de ninguna dirección particular
• Aunque provenga de una fuente, después de múltiples rebotes por la escena ha perdido la direccionalidad
• Los objetos iluminados por esta luz la reciben de igual manera en todas sus superficies y en todas direcciones
Materiales
• En el mundo real, los objetos tienen color por sí mismos
• El color del material se define según las longitudes de onda que refleje
• Bajo una luz blanca, los objetos aparecen con sus colores naturales
(1.0, 1.0, 1.0)
(0.5, 0.2, 1.0)
(0.5, 0.2, 1.0)
• En general, la luz emitida es el resultado de la luz que llega, escalada por los coeficientes del material
(lr, lg, lc)
(mr, mg, mb)
(lr*mr, lg*mg, lb*mb)
Luz ambiente con OpenGL
• Para indicar a OpenGL que ha de realizar los cálculos de iluminación:
glEnable (GL_LIGHTING)
• Para seleccionar el modelo de iluminación ambiente activo:
void glLightModelfv (GL_LIGHT_MODEL_AMBIENT, GLfloat params[4])
• Para establecer el material activo:
void glMaterialfv (Glenum cara, Glenum nombre, GLfloat params[4])
GL_AMBIENT
GL_DIFFUSE
GL_SPECULAR GL_BACK
GL_FRONT_AND_BACK
GL_FRONT
// Activar los cálculos de iluminación glEnable (GL_LIGHTING);
// Seleccionar la luz ambiente
GLfloat LuzAmbiente[4] = {1.0, 1.0, 0.0, 1.0};
glLightModelfv (GL_LIGHT_MODEL_AMBIENT, LuzAmbiente);
// Seleccionar el material
GLfloat MaterialAmbiente[4] = {1.0, 0.5, 0.5, 1.0};
glMaterialfv (GL_FRONT, GL_AMBIENT, MaterialAmbiente);
// Dibujar el objeto glBegin (..)
...
...
glEnd(); (1, 1, 0)
(1, 0.5, 0.5)
(1, 0.5, 0)
Ejemplo con luz ambiente
Otra forma de definir el material
• Si un objeto tiene diferentes materiales, sería muy tedioso declarar muchos vectores RGBA y llamar a glMaterialfv en cada polígono
• Otra opción más cómoda es usar:
void glColorMaterial (Glenum cara, Glenum nombre)
• Ahora, las llamadas a glColor en realidad sirven para definir el material
GLfloat mrojo[4]= {1,0,0,1};
GLfloat mverde[4]={0,1,0,1};
glBegin (..)
glMaterialfv(GL_FRONT, GL_AMBIENT, mrojo);
...
glMaterialfv(GL_FRONT, GL_AMBIENT, mverde);
...
glEnd();
glColorMaterial(GL_FRONT, GL_AMBIENT);
glBegin (..)
glColor3f(1,0,0);
...
glColor3f(0,1,0);
...
glEnd();
Luz difusa
• La fuente tiene una localización y una dirección particular
• Una vez toca la superficie del objeto, se refleja en todas direcciones
Luz
incidente Ni
Luz especular
• También es direccional, pero el reflejo se produce en una
dirección concreta
• Produce un punto brillante en la superficie que ilumina --> reflejo especular
Luz
incidente Ni
Reflexión difusa
Reflexión especular ideal
Fuentes de luz con OpenGL
• Soporta hasta 8 fuentes de luz independientes
• La iluminación del polígono dependerá de los ángulos A y B
A B
• Estos ángulos se usan en conjunción con la iluminación y las
propiedades de los materiales para obtener el color de cada vértice
• A partir del color de los vértices, se interpola el interior de los polígonos
Vectores normales
• Para obtener los ángulos hay que conocer la normal a la superficie
• Para especificar la normal activa:
void glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz) void glNormal3fv (GLfloat n[3])
N=<nx, ny, nz>
• Las normales deben tener longitud 1
• Si queremos que OpenGL normalize los vectores automáticamente:
glEnable (GL_NORMALIZE)
• Las normales pueden calcularse de varias maneras
– promediando entre las normales de los polígonos adyacentes – a partir de la expresión analítica de la superficie
Luz difusa con OpenGL
• Para trabajar con luz difusa hay que crear una fuente de luz
• Para indicar el color de la fuente de luz:
void glLightfv (Glenum luz, Glenum nombre, GLfloat color[4])
GL_DIFFUSE
GL_AMBIENT GL_LIGHT7
GL_LIGHT0
GL_LIGHT1
• Para indicar la posición de la fuente de luz:
void glLightfv (Glenum luz, GL_POSITION, GLfloat pos[4])
• Para activar la fuente de luz:
glEnable (Glenum luz)
GLfloat LuzAmbiente[4] = {0.2, 0.2, 0.2, 1.0};
GLfloat LuzDifusa[4] = {1.0, 1.0, 0.0, 1.0};
GLfloat PosLuz[4] = {-50, 50., 100, 1.0};
GLfloat Material[4] = {1.0, 0.5, 0.5, 1.0};
glEnable (GL_LIGHTING);
// Seleccionar el material
glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, Material);
// Fuente de luz
glLightfv (GL_LIGHT0, GL_AMBIENT, LuzAmbiente);
glLightfv (GL_LIGHT0, GL_DIFFUSE, LuzDifusa);
glLightfv (GL_LIGHT0, GL_POSITION, PosLuz);
glEnable (GL_LIGHT0);
glBegin (..) // Dibujar el objeto glNormal3f(...);
glVertex3f(...);
...
glNormal3f(...);
Ejemplo con una fuente de luz difusa
Luz especular con OpenGL
• Se usa para simular superficies metálicas
• Para indicar el color de la fuente de luz:
void glLightfv (Glenum luz, GL_SPECULAR, GLfloat color[4])
• Para indicar el exponente de reflexión especular:
void glLightf (Glenum luz, GL_SHININESS, GLfloat coef)
donde 0<coef<128
coef=128 coef=32 coef=2
GLfloat LuzAmbiente[4] = {0.2, 0.2, 0.2, 1.0};
GLfloat LuzEspecular[4] = {1.0, 1.0, 0.0, 1.0};
GLfloat PosLuz[4] = {-50, 50., 100, 1.0};
GLfloat Material[4] = {1.0, 0.5, 0.5, 1.0};
glEnable (GL_LIGHTING);
// Seleccionar el material
glMaterialfv (GL_FRONT, GL_SPECULAR, Material);
glMaterialf (GL_FRONT, GL_SHININESS, 32);
// Fuente de luz
glLightfv (GL_LIGHT0, GL_AMBIENT, LuzAmbiente);
glLightfv (GL_LIGHT0, GL_POSITION, PosLuz);
glEnable (GL_LIGHT0);
glBegin (..) // Dibujar el objeto glNormal3f(...);
glVertex3f(...);
...
glNormal3f(...);
Ejemplo con una fuente de luz especular
Combinando los tres tipos
• La luz en cada vértice se calcula con la siguiente ecuación:
( )
∑ + +
+
=
luces
n e
e d
d a
a a
A
k I k I k I k
I
I cos θ cos α
N
Luz ambiente global Luz ambiente Luz difusa Luz especular
+
Objetos emisores de luz
• Además de la luz que refleja un objeto, éste puede emitir luz propia
• Para indicar el color de luz emitida por un objeto:
void glMaterialfv (Glenum cara, GL_EMISSION, GLfloat color[4])
( )
∑ + +
+ +
=
luces
n e
e d
d a
a a
A
e
I k I k I k I k
I
I cos θ cos α
Luz emitida
• Este término no afecta al resto de objetos
• En ese caso, habría que crear una fuente de luz en la misma posición del objeto
Posición de una fuente
• Si la fuente de luz está muy lejana -> fuente de luz direccional
– los rayos de luz son todos paralelos
– el ángulo con la normal es constante en todo el interior de un polígono
• Para indicar si la fuente es direccional o posicional:
GLfloat pos[4] = {a, b, c, w};
void glLightfv (Glenum luz, GL_POSITION, GLfloat pos[4])
N N
Si w!=0, la posición de la fuente es
(a,b,c,w) (coord. Homogéneas)
N
N N
Si w=0, la dirección de la luz viene dada por el vector <a,b,c>
Atenuación de una fuente
• En la realidad, la intensidad de una fuente decrece con la distancia d
• OpenGL usa un factor de atenuación dado por la ecuación:
2
1
d k d
k f k
q l
c
at
= + +
glLightf (GLenum luz, GL_CONSTANT_ATTENUATION, GLfloat kc) glLightf (GLenum luz, GL_LINEAR_ATTENUATION, GLfloat kl) glLightf (GLenum luz, GL_QUADRATIC_ATTENUATION, GLfloat kq)
• El factor de atenuación no afecta a:
– el valor de emisión de los objetos – la luz ambiente global
– las fuentes direccionales
Focos de luz
• Con un foco de luz, decidimos en qué dirección se radia la luz
• Para indicar la dirección
void glLightfv (Glenum luz, GL_SPOT_DIRECTION, GLfloat dir[3])
• Para indicar el ángulo de apertura del cono
void glLightfv (Glenum luz, GL_SPOT_CUTOFF, GLfloat grados)
• Para indicar la atenuación de la luz al alejarnos de la dirección central
void glLightfv (Glenum luz, GL_SPOT_EXPONENT, GLfloat exp)
GL_SPOT_CUTOFF
GL_SPO
T_DIRE
CTION
Moviendo las luces
• Las fuentes de luces también son transformadas por la matriz de modelado
GLfloat Pos[4]={0,0,75,1}, Dir[3]={0,0,-1};
// limpio pantalla y dibujo la esfera azul glPushMatrix();
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glLightfv(GL_LIGHT0,GL_POSITION,Pos);
glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,Dir);
glTranslatef(Pos[0],Pos[1],Pos[2]);
glColor3ub(255,0,0);
auxSolidCone(4.0f,6.0f);
glDisable(GL_LIGHTING);
glColor3ub(255,255,0);
auxSolidSphere(3.0f);
glEnable(GL_LIGHTING);
glPopMatrix();
Ejemplo: navegador 3D con iluminación
void PanelVista_Paint(TObject *Sender) {
switch (ModoColor) {
case 3: // modo iluminación glEnable (GL_LIGHTING);
glLightfv (GL_LIGHT0, GL_AMBIENT_AND_DIFFUSE, Luz);
glLightfv (GL_LIGHT0, GL_POSITION, LuzPos);
glEnable (GL_LIGHT0);
glEnable (GL_COLOR_MATERIAL);
glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
}
glPushMatrix();
glLightfv (GL_LIGHT1, GL_DIFFUSE, FocoLuz);
glLightfv (GL_LIGHT1, GL_POSITION, FocoPos);
glLightfv (GL_LIGHT1, GL_SPOT_DIRECTION, FocoDir);
glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.00001);
glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 20);
glEnable (GL_LIGHT1);
gluLookAt (...);
RenderWorld();
glPopMatrix();
}