OpenGL render против собственной реализации освещения Phong
я реализовал схему освещения Фонга, используя камеру, которая центрирована на (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
полученное изображение, произведенное OpenGL.
изображение, которое создает мое приложение рендеринга.
как вы можете видеть, существуют различные различия между ними:
- зеркальная подсветка на моем изображении меньше, чем в OpenGL.
- диффузная поверхность, похоже, не диффузна правильным образом, в результате чего желтая область будет излишне большой на моем изображении, тогда как в OpenGL есть хорошая темно-зеленая область ближе к нижней части сферы
- цвет произведенный 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 ответов
в качестве первого шага я бы проверил, нормализована ли ваша нормальная поверхность пересечения, особенно важная при расчете диффузных и зеркальных точечных продуктов.
для целей отладки, вы можете проверить выходы ваших терминов освещения (как выход сцены окружающий, светлый окружающ-диффузно-отражательный выход, светлые факторы амортизации, ЕТК) по-одному, 0'инг другие термины в уравнениях. Некоторые простые термины, вероятно, произведут идентичный выход, и вы можете сузить при таком подходе поиск сводится к меньшему количеству строк кода. Это может даже оказаться связанным с другими объектами / методами в вашей реализации.
кроме того, Пожалуйста, имейте в виду, что Фонг-затенение OpenGL не следует модели Фонг-затенения строго, потому что нормали вычисляются на вершину, а затем интерполируются внутри треугольников, они не вычисляются на точку на поверхности. Модель сферы представляется достаточно тесселяция, так что это не должно быть практическим проблема.
OpenGL не выполняет гамма-коррекцию, если вы используете цветовое пространство sRGB в качестве цели рендеринга, насколько я знаю. Я ожидал бы, что правильная реализация программного обеспечения даст очень похожие результаты аппаратной реализации OpenGL. Счастливая отладка:)
в моем случае мое первоначальное предположение о различиях в значениях гаммы было правильным. Основная программа, которая вызвала мой алгоритм рендеринга, выполнила гамма-коррекцию, исправив RGB-значение каждого пикселя моего изображения, выполнив image->TosRGB()
звонок. После комментирования вызова я получил изображение, созданное OpenGL.