OpenGL рендер против собственной реализации подсветки Phong - PullRequest
6 голосов
/ 29 марта 2010

Я реализовал схему подсветки фонга, используя камеру с центром в (0,0,0) и смотрящий прямо на примитив сферы. Ниже приведено соответствующее содержимое файла сцены, который используется для просмотра сцены с использованием OpenGL, а также для рендеринга сцены с использованием моей собственной реализации:

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

Результирующее изображение, созданное OpenGL.

Here

Изображение, которое создает мое приложение рендеринга.

Как видите, между этими двумя понятиями существуют различные различия:

  1. Зеркальное выделение на моем изображении меньше, чем в OpenGL.
  2. Кажется, что диффузная поверхность не распространяется правильно, в результате чего желтая область на моем изображении будет слишком большой, тогда как в OpenGL есть хорошая темно-зеленая область ближе к нижней части сферы
  3. Цвет, созданный OpenGL, намного темнее, чем на моем изображении.

Это наиболее заметные три различия, которые я вижу. Следующее - моя реализация освещения Фонга:

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

Вот связанные функции LightIntensity (...) и LightDirection (...):

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

Буду очень признателен за любые предложения относительно любых ошибок реализации, которые очевидны. Мне интересно, могут ли различия возникать просто из-за значений гаммы, используемых для отображения OpenGL, и значения гаммы по умолчанию для моего дисплея. Я также знаю, что OpenGL (или, по крайней мере, части, которые мне предоставили) не может отбрасывать тени на объекты. Не то, чтобы это относилось к рассматриваемому вопросу, но просто заставляет меня задуматься, не является ли это просто отображением и различиями возможностей между OpenGL и тем, что я пытаюсь сделать.

Спасибо за вашу помощь.

Ответы [ 2 ]

3 голосов
/ 29 марта 2010

В качестве первого шага я бы проверил, нормализуется ли нормали поверхности вашего пересечения, особенно это важно при расчете диффузных и зеркальных точечных произведений.

В целях отладки вы можете проверять выходные данные ваших условий освещения (такие как выход окружающей среды сцены, выходной световой рассеянный-зеркальный выход, коэффициенты ослабления света и т. Д.) Один за другим, 0 'другие члены в уравнениях , Некоторые простые термины могут давать одинаковый результат, и вы можете сузить поиск до меньшего количества строк кода с помощью этого подхода. Может даже оказаться, что он связан с другими объектами / методами в вашей реализации.

Кроме того, имейте в виду, что затенение Фонга в OpenGL не строго следует модели затенения Фонга, поскольку нормали вычисляются для каждой вершины, а затем интерполируются внутри треугольников, а не для точки на поверхности. Ваша сферическая модель, по-видимому, достаточно рассортирована, поэтому это не должно быть практической проблемой.

OpenGL не выполняет гамма-коррекцию, если вы не используете цветовое пространство sRGB в качестве цели рендеринга, насколько я знаю. Я ожидаю, что правильная программная реализация даст очень похожие результаты аппаратной реализации OpenGL. Удачной отладки:)

0 голосов
/ 01 апреля 2010

В моем случае мое первоначальное предположение о различиях в значениях гаммы было верным.Основная программа, которая называла мой алгоритм рендеринга, выполняла гамма-коррекцию, исправляя значение RGB каждого изображения моего изображения с помощью вызова image->TosRGB().Закомментировав звонок, я получил изображение, созданное OpenGL.

...