OpenGL implementa un model d’iluminació global de manera que per a calcular el color en un vèrtex les variables a utilitzar són:
- La normal en el vèrtex
- La propietat de material en el vèrtex
- La posició i el color de les llums en l’escena
D’aquesta manera, per a calcular el color d’un vèrtex sobre un objecte no es considera la presència d’altres objectes en l’escena; el color dels objectes és degut a que la seua propietat de material reacciona a la presència de les llums de l’escena.
En el model d’iluminació d’OpenGL es poden definir fins a tres contribucions diferents de llum, anomenades ambient, difusa i especular.
Normals
El codi que utilitzarem per a calcular les normals en els models és el següent:
/*--------------------------------------------------------------------------
Devuelve el punto 3D asociado a unos determinados datos.
R1: radio del primer anillo.
y1: altura del primer anillo.
N: el número total de tramos en el anillo.
n: el tramo actual.
--------------------------------------------------------------------------*/
Punto3D vertice( float R1, float y1, int N, int n) {
Punto3D p;
p.x = dameX(R1, N, n);
p.y = y1;
p.z = dameZ(R1, N, n);
return (p);
}
/*--------------------------------------------------------------------------
Devuelve la normal de un vértice sobre una superficie de revolución.
R1: radio del primer anillo.
R2: radio del segundo anillo.
y1: altura del primer anillo.
y2: altura del segundo anillo.
N: el número total de tramos en el anillo.
n: el tramo actual.
--------------------------------------------------------------------------*/
Vector3D normal( float R1, float R2, float y1, float y2, int N, int n) {
Punto3D p, q, r;
Vector3D v, w, normal;
p = vertice(R1, y1, N, n);
if (R1 == 0.0f && R2 == 0.0f ) {
normal.a = normal.c = 0.0f ;
normal.b = 1.0f ;
return (normal);
}
if (R1 == 0.0f ) {
q = vertice(R2, y2, N, (n+1)%N);
}
else {
q = vertice(R1, y1, N, (n+1)%N);
}
r = vertice(R2, y2, N, n);
v = vector(p, q);
w = vector(p, r);
normal = productoVectorial(w, v);
return (normal);
}
/*--------------------------------------------------------------------------
Dibuja una tira de cuadriláteros.
R1, R2, R3: radios de trea anillos consecutivos.
y1, y2, y3: altura de cada uno de los anillos.
N: número de pasos sobre cada anillo.
--------------------------------------------------------------------------*/
void tira( float R1, float R2, float R3, float y1, float y2, float y3, int N) {
int i;
Punto3D p;
Vector3D n;
glBegin(GL_QUAD_STRIP);
for (i = 0 ; i <= N; i++) {
n = normal(R1, R2, y1, y2, N, i);
glNormal3f(n.a, n.b, n.c);
p = vertice(R1, y1, N, i);
glVertex3f(p.x, p.y, p.z);
n = normal(R2, R3, y2, y3, N, i);
glNormal3f(n.a, n.b, n.c);
p = vertice(R2, y2, N, i);
glVertex3f(p.x, p.y, p.z);
}
glEnd();
}
/*--------------------------------------------------------------------------
Algoritmo de dibujo para una forma sólida de revolución.
H: la altura de la figura.
N: el número de anillos y divisiones en cada anillo.
f(float y): puntero a la función que nos devuelve.
el valor de radio en función de y.
-----------------------------------------------------------------------*/
void formaSolida( float H, int N, float (*f)( float y)) {
int i;
float y1, y2, y3, r1, r2, r3;
for (i = 0 ; i < N- 1 ; i++) {
y1 = i*H/(N- 1 )-(H/ 2 );
r1 = f(y1);
y2 = (i+ 1 )*H/(N- 1 )-(H/ 2 );
r2 = f(y2);
if(i+2 < N) {
y3 = (i+2)*H/(N-1)-(H/2);
r3 = f(y3);
}
else {
r3 = r2;
y3 = y2;
}
tira(r1, r2, r3, y1, y2, y3, N);
}
}
Materials
Les propietats del material les definim amb la funció:
void glMaterial{if}[v](GLenum cara, GLenum nom, TYPE parametro);
per exemple:
float materialAmbiente[] = {0.34f, 0.67f, 0.15, 1.0f};
glMaterial3fv(GL_FRONT, GL_AMBIENT, materialAmbiente);
Afegint els anteriors comandaments al codi que ja teniem, obtenim una imatge com la següent:
