OpenGL渲染与自己的Phong照明实现

时间:2010-03-28 22:08:28

标签: c++ reflection opengl raytracing

我使用以(0,0,0)为中心并直接观察球体原始的相机实现了Phong照明方案。以下是场景文件的相关内容,用于使用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产生的颜色比我图像中的颜色深得多。
  4. 这是我看到的最突出的三个差异。以下是我对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;
    }
    

    以下是相关的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 :(得分:3)

作为第一步,我会检查你的交叉面曲面法线是否正常化,在计算漫反射和镜面反射术语点积时尤为重要。

出于调试目的,您可以逐个检查照明术语的输出(例如场景环境输出,光环境 - 漫反射 - 镜面反射输出,光衰减系数等)0,方程式中的其他项。一些简单的术语可能会产生相同的输出,您可以使用这种方法将搜索范围缩小到更少的代码行。它甚至可能与您实现中的其他对象/方法有关。

另外,请记住,OpenGL的Phong着色不严格遵循Phong着色模型,因为法线是按顶点计算的,然后在三角形内插,它们不是在表面上的每个点计算的。您的球体模型似乎足够细分,因此这不应该是一个实际问题。

据我所知,除非你使用sRGB色彩空间作为渲染目标,否则OpenGL不会执行伽玛校正。我希望正确的软件实现能够产生非常类似的硬件OpenGL实现结果。快乐的调试:)

答案 1 :(得分:0)

就我而言,我对伽马值差异的初步猜测是正确的。调用我的渲染算法的主程序通过执行image->TosRGB()调用来校正图像的每个像素的RGB值,从而执行伽马校正。在评论出来之后,我获得了OpenGL生成的图像。