6

(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によって生成された結果の画像。

ここ

私のレンダリングアプリケーションが生成する画像。

ご覧のとおり、この2つにはさまざまな違いがあります。

  1. 私の画像の鏡面ハイライトは、OpenGLのものよりも小さいです。
  2. 拡散サーフェスが正しい方法で拡散していないように見えるため、画像の黄色の領域が不必要に大きくなりますが、OpenGLでは、球の下部に近い素敵な濃い緑色の領域があります。
  3. OpenGLによって生成された色は、私の画像の色よりもはるかに暗いです。

これらは私が見る最も顕著な3つの違いです。以下は、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と私がやろうとしていることの表示と機能の違いだけなのかどうか疑問に思います。

ご協力ありがとうございました。

4

2 に答える 2

3

最初のステップとして、交差面の法線が正規化されているかどうかを確認します。特に、拡散反射および鏡面反射の内積を計算する場合に重要です。

デバッグの目的で、照明項の出力(シーン周囲出力、光周囲拡散鏡面出力、光減衰係数など)を1つずつ確認し、方程式の他の項を0にすることができます。いくつかの単純な用語は同じ出力を生成する可能性が高く、このアプローチを使用すると、検索をより少ないコード行に絞り込むことができます。実装内の他のオブジェクト/メソッドに関連していることが判明する場合もあります。

また、法線は頂点ごとに計算されてから三角形の内側で補間されるため、OpenGLのフォンシェーディングはフォンシェーディングモデルに厳密には従わないことに注意してください。これらはサーフェス上のポイントごとに計算されません。球モデルは十分にテッセレーションされているように見えるので、これは実際的な問題ではありません。

私の知る限り、レンダリングターゲットとしてsRGB色空間を使用しない限り、OpenGLはガンマ補正を実行しません。正しいソフトウェア実装では、ハードウェアOpenGL実装と非常によく似た結果が得られると思います。ハッピーデバッグ:)

于 2010-03-28T23:14:02.277 に答える
0

私の場合、ガンマ値の違いについての私の最初の推測は正しかった。レンダリングアルゴリズムを呼び出したメインプログラムは、呼び出しを行って画像の各ピクセルのRGB値を補正することにより、ガンマ補正を実行しましたimage->TosRGB()。通話をコメントアウトした後、OpenGLで作成された画像を取得しました。

于 2010-04-01T01:23:44.237 に答える