2010-03-28 13 views
6

Ich habe ein Phong Illumination-Schema mit einer Kamera implementiert, die um (0,0,0) zentriert ist und direkt auf das Sphärengrundelement schaut. Im Folgenden werden die relevanten Inhalte der Szene-Datei, die verwendet wird, um die Szene als auch mit OpenGL zu sehen, die Szene mit meiner eigenen Implementierung zu machen:OpenGL render vs. eigene Phong Illumination Implementierung

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

Das resultierende Bild von OpenGL erzeugt.

Here

Das Bild, das meine Rendering-Anwendung erzeugt.

Wie Sie sehen können, gibt es verschiedene Unterschiede zwischen den beiden:

  1. Das Glanzlicht auf meinem Bild ist kleiner als die in OpenGL.
  2. Die diffuse Oberfläche scheint nicht in der richtigen Weise zu diffundieren, was dazu führt, dass der gelbe Bereich in meinem Bild unnötig groß ist, während in OpenGL ein schöner dunkelgrüner Bereich näher am unteren Ende der Kugel liegt
  3. Die Farbe produziert durch OpenGL ist viel dunkler als das in meinem Bild.

Das sind die prominentesten drei Unterschiede, die ich sehe. Hier finden Sie meine Umsetzung der Phong-Beleuchtung:

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

Hier sind die damit verbundene Lichtintensität (...) und LightDirection (...) Funktionen:

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

Ich würde sehr Anregungen zu schätzen wissen, wie zu irgendwelchen Implementierungsfehlern, die offensichtlich sind. Ich frage mich, ob die Unterschiede einfach aufgrund der Gamma-Werte, die für die Anzeige durch OpenGL verwendet werden, und des Standard-Gammawerts für meine Anzeige auftreten können. Ich weiß auch, dass OpenGL (oder zumindest die Teile, die mir zur Verfügung gestellt wurden) keine Schatten auf Objekte werfen kann. Nicht, dass das für den fraglichen Punkt relevant wäre, aber ich frage mich nur, ob es einfach Unterschiede in der Darstellung und der Funktionalität zwischen OpenGL und dem, was ich versuche, gibt.

Vielen Dank für Ihre Hilfe.

Antwort

0

In meinem Fall war meine erste Schätzung über die Unterschiede in Gamma-Werten korrekt. Das Hauptprogramm, das meinen Rendering-Algorithmus aufgerufen hat, führte eine Gammakorrektur durch, indem es den RGB-Wert jedes Pixels meines Bildes korrigierte, indem er einen image->TosRGB() Aufruf ausführte. Nach dem Auskommentieren des Anrufs habe ich das von OpenGL erzeugte Bild erhalten.

3

Als ersten Schritt würde ich überprüfen, ob Ihre Schnittflächennormale normalisiert ist, besonders wichtig bei der Berechnung von diffusen und spiegelnden Dot-Produkten.

Zu Debugging-Zwecken können Sie die Ausgänge Ihrer Lichtbegriffe (z. B. Szenenumgebungsausgabe, Lichtumgebungs-Diffusspiegelungsausgabe, Lichtabschwächungsfaktoren usw.) eins nach dem anderen überprüfen, indem Sie die anderen Begriffe in der Gleichungen. Einige einfache Begriffe produzieren wahrscheinlich identische Ausgaben, und Sie können Ihre Suche mit diesem Ansatz auf weniger Codezeilen eingrenzen. Es kann sich sogar herausstellen, dass es sich auf andere Objekte/Methoden in Ihrer Implementierung bezieht. Bitte beachten Sie, dass die OpenGL-Phong-Schattierung dem Phong-Schattierungsmodell nicht streng folgt, da die Normalen pro Scheitelpunkt berechnet und dann innerhalb der Dreiecke interpoliert werden. Sie werden nicht pro Punkt auf der Oberfläche berechnet. Ihr Kugelmodell scheint ausreichend tesselliert zu sein, daher sollte dies kein praktisches Problem sein.

OpenGL führt keine Gammakorrektur durch, es sei denn, Sie verwenden den sRGB-Farbraum als Renderziel, soweit ich weiß. Ich würde erwarten, dass eine korrekte Software-Implementierung sehr ähnliche Ergebnisse einer Hardware-OpenGL-Implementierung liefert. Happy Debugging :)