2010-03-28 16 views
6

Implementé un esquema de iluminación de Phong usando una cámara centrada en (0,0,0) y mirando directamente a la esfera primitiva. Los siguientes son los contenidos pertinentes del archivo de escena que se utiliza para ver la escena usando OpenGL, así como para hacer que la escena usando mi propia aplicación:renderizado OpenGL versus implementación de iluminación propia de Phong

ambient 0 1 0 

dir_light 1 1 1  -3 -4 -5 

# A red sphere with 0.5 green ambiance, centered at (0,0,0) with radius 1 
material 0 0.5 0 1 0 0 1 0 0 0 0 0 0 0 0 10 1 0 
sphere 0 0 0 0 1 

Here

La imagen resultante producida por OpenGL.

Here

La imagen que produce mi aplicación de renderización.

Como se puede ver, hay varias diferencias entre los dos:

  1. El reflejo especular en mi imagen es más pequeña que la de OpenGL.
  2. La superficie difusa parece no difuminarse correctamente, lo que hace que la región amarilla sea innecesariamente grande en mi imagen, mientras que en OpenGL hay una bonita región verde oscuro más cerca de la esfera
  3. El color producido por OpenGL es mucho más oscuro que el de mi imagen.

Esas son las tres diferencias más importantes que veo. Lo que sigue es mi implementación de la iluminación de Phong:

R3Rgb Phong(R3Scene *scene, R3Ray *ray, R3Intersection *intersection) 
{ 
    R3Rgb radiance; 
    if(intersection->hit == 0) 
    { 
    radiance = scene->background; 
    return radiance; 
    } 

    R3Vector normal = intersection->normal; 
    R3Rgb Kd = intersection->node->material->kd; 
    R3Rgb Ks = intersection->node->material->ks; 

    // obtain ambient term 
    R3Rgb intensity_ambient = intersection->node->material->ka*scene->ambient; 

    // obtain emissive term 
    R3Rgb intensity_emission = intersection->node->material->emission; 

    // for each light in the scene, obtain calculate the diffuse and specular terms 
    R3Rgb intensity_diffuse(0,0,0,1); 
    R3Rgb intensity_specular(0,0,0,1); 
    for(unsigned int i = 0; i < scene->lights.size(); i++) 
    { 
    R3Light *light = scene->Light(i); 
    R3Rgb light_color = LightIntensity(scene->Light(i), intersection->position); 
    R3Vector light_vector = -LightDirection(scene->Light(i), intersection->position); 

    // calculate diffuse reflection 
    intensity_diffuse += Kd*normal.Dot(light_vector)*light_color; 

    // calculate specular reflection 
    R3Vector reflection_vector = 2.*normal.Dot(light_vector)*normal-light_vector; 
    reflection_vector.Normalize(); 
    R3Vector viewing_vector = ray->Start() - intersection->position; 
    viewing_vector.Normalize(); 
    double n = intersection->node->material->shininess; 
    intensity_specular += Ks*pow(max(0.,viewing_vector.Dot(reflection_vector)),n)*light_color; 

    } 

    radiance = intensity_emission+intensity_ambient+intensity_diffuse+intensity_specular; 
    return radiance; 
} 

Aquí están los LightIntensity relacionado (...) y LightDirection (...) funciones:

R3Vector LightDirection(R3Light *light, R3Point position) 
{ 
    R3Vector light_direction; 
    switch(light->type) 
    { 
    case R3_DIRECTIONAL_LIGHT: 
     light_direction = light->direction; 
     break; 

    case R3_POINT_LIGHT: 
     light_direction = position-light->position; 
     break; 

    case R3_SPOT_LIGHT: 
     light_direction = position-light->position; 
     break; 
    } 
    light_direction.Normalize(); 
    return light_direction; 
} 

R3Rgb LightIntensity(R3Light *light, R3Point position) 
{ 
    R3Rgb light_intensity; 
    double distance; 
    double denominator; 
    if(light->type != R3_DIRECTIONAL_LIGHT) 
    { 
    distance = (position-light->position).Length(); 
    denominator = light->constant_attenuation + 
         light->linear_attenuation*distance + 
         light->quadratic_attenuation*distance*distance; 
    } 

    switch(light->type) 
    { 
    case R3_DIRECTIONAL_LIGHT: 
     light_intensity = light->color; 
     break; 

    case R3_POINT_LIGHT: 
     light_intensity = light->color/denominator; 
     break; 

    case R3_SPOT_LIGHT: 
     R3Vector from_light_to_point = position - light->position; 
     light_intensity = light->color*(
         pow(light->direction.Dot(from_light_to_point), 
          light->angle_attenuation)); 
     break; 
    } 
    return light_intensity; 
} 

Le agradecería alguna sugerencia en cuanto a cualquier error de implementación que sea evidente. Me pregunto si las diferencias podrían estar ocurriendo simplemente debido a los valores gamma utilizados para la visualización por OpenGL y el valor gamma predeterminado para mi pantalla. También sé que OpenGL (o al menos las partes que me proporcionaron) no puede proyectar sombras sobre los objetos. No es que esto sea relevante para el punto en cuestión, pero me lleva a preguntarme si se trata simplemente de diferencias de visualización y capacidad entre OpenGL y lo que estoy tratando de hacer.

Gracias por su ayuda.

Respuesta

0

En mi caso, mi conjetura inicial sobre las diferencias en los valores gamma era correcta. El programa principal que llamó a mi algoritmo de representación ejecutó la corrección gamma corrigiendo el valor RGB de cada píxel de mi imagen haciendo una llamada image->TosRGB(). Después de comentar la llamada, obtuve la imagen producida por OpenGL.

3

Como primer paso, verificaría si la superficie de intersección normal está normalizada, especialmente importante cuando se calculan los productos de punto de término difuso y especular.

Para la depuración, puede verificar las salidas de sus condiciones de iluminación (como salida ambiental de escena, luz ambiente-difusa-salida especular, factores de atenuación de la luz, etc.) una por una, 0 'de los otros términos en el ecuaciones. Es probable que algunos términos simples produzcan resultados idénticos, y puede reducir su búsqueda a menos líneas de código con este enfoque. Puede incluso estar relacionado con otros objetos/métodos en su implementación.

Además, tenga en cuenta que el sombreado Phong de OpenGL no sigue estrictamente el modelo de sombreado Phong, porque las normales se calculan por vértice y luego se interpolan dentro de los triángulos, no se calculan por punto en la superficie. Su modelo de esfera parece estar lo suficientemente teselado, por lo que este no debería ser un problema práctico.

OpenGL no realiza la corrección de gamma a menos que utilice el espacio de color sRGB como objetivo de renderizado, hasta donde yo sé. Esperaría una implementación de software correcta para producir resultados muy similares de una implementación de OpenGL de hardware. Depuración feliz :)

Cuestiones relacionadas