OpenGL render vs. own Phong Illumination Implementation

Posted by Myx on Stack Overflow See other posts from Stack Overflow or by Myx
Published on 2010-03-28T22:08:27Z Indexed on 2010/03/28 22:13 UTC
Read the original article Hit count: 323

Filed under:
|
|
|

Hello:

I have implemented a Phong Illumination Scheme using a camera that's centered at (0,0,0) and looking directly at the sphere primitive. The following are the relevant contents of the scene file that is used to view the scene using OpenGL as well as to render the scene using my own implementation:

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

The resulting image produced by OpenGL.

Here

The image that my rendering application produces.

As you can see, there are various differences between the two:

  1. The specular highlight on my image is smaller than the one in OpenGL.
  2. The diffuse surface seems to not diffuse in the correct way, resulting in the yellow region to be unneccessarily large in my image, whereas in OpenGL there's a nice dark green region closer to the bottom of the sphere
  3. The color produced by OpenGL is much darker than the one in my image.

Those are the most prominent three differences that I see. The following is my implementation of the Phong illumination:

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;
}

Here are the related LightIntensity(...) and LightDirection(...) functions:

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;
}

I would greatly appreciate any suggestions as to any implementation errors that are apparent. I am wondering if the differences could be occurring simply because of the gamma values used for display by OpenGL and the default gamma value for my display. I also know that OpenGL (or at least tha parts that I was provided) can't cast shadows on objects. Not that this is relevant for the point in question, but it just leads me to wonder if it's simply display and capability differences between OpenGL and what I am trying to do.

Thank you for your help.

© Stack Overflow or respective owner

Related posts about c++

Related posts about raytracing