2010-03-28 13 views
6

Ho implementato uno schema di illuminazione Phong utilizzando una fotocamera centrata su (0,0,0) e guardando direttamente la primitiva della sfera. Di seguito sono riportati i contenuti pertinenti del file di scena che viene utilizzato per visualizzare la scena utilizzando OpenGL, così da rendere la scena usando la mia propria implementazione:Rendering OpenGL rispetto alla propria illuminazione di Phong Implementazione

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

L'immagine risultante prodotta da OpenGL.

Here

L'immagine che la mia applicazione di rendering produce.

Come si può vedere, ci sono varie differenze tra i due:

  1. La luce speculare sulla mia immagine è più piccola di quella in OpenGL.
  2. La superficie diffusa sembra non diffondersi nel modo corretto, risultando nella regione gialla eccessivamente grande nella mia immagine, mentre in OpenGL c'è una bella regione verde scuro più vicina alla parte inferiore della sfera
  3. Il colore prodotto da OpenGL è molto più scuro di quello nella mia immagine.

Queste sono le tre differenze più importanti che vedo. Quello che segue è la mia realizzazione dell'illuminazione 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; 
} 

Ecco il relativo LightIntensity (...) e LightDirection (...) funzioni:

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

Io apprezzo molto come tutti i suggerimenti a eventuali errori di implementazione che sono evidenti. Mi chiedo se le differenze potrebbero verificarsi semplicemente a causa dei valori gamma usati per la visualizzazione da OpenGL e il valore gamma predefinito per il mio display. So anche che OpenGL (o almeno le parti che mi sono state fornite) non possono proiettare ombre sugli oggetti. Non che questo sia rilevante per il punto in questione, ma mi porta solo a chiedermi se si tratta semplicemente di differenze di display e funzionalità tra OpenGL e quello che sto cercando di fare.

Grazie per il vostro aiuto.

risposta

0

Nel mio caso, la mia ipotesi iniziale sulle differenze nei valori gamma era corretta. Il programma principale che ha chiamato il mio algoritmo di rendering ha eseguito la correzione della gamma correggendo il valore RGB di ogni pixel della mia immagine eseguendo una chiamata image->TosRGB(). Dopo aver commentato la chiamata, ho ottenuto l'immagine prodotta da OpenGL.

3

Come primo passo, verificherei se la normale della superficie di intersezione è normalizzata, particolarmente importante quando si calcolano prodotti punto a termine diffusi e speculari.

Per scopi di debug, è possibile controllare le uscite dei termini di illuminazione (come la produzione di scene ambient, la luce di diffusione ambientale-speculare, i fattori di attenuazione della luce, ecc.) Uno a uno, 0 gli altri termini nel equazioni. È probabile che alcuni termini semplici producano risultati identici e con questo approccio puoi restringere la ricerca a un numero inferiore di righe di codice. Potrebbe anche rivelarsi correlato ad altri oggetti/metodi nella tua implementazione.

Inoltre, tieni presente che l'ombreggiatura Phong di OpenGL non segue rigorosamente il modello di ombreggiatura Phong, poiché le normali sono calcolate per vertice e quindi interpolate all'interno dei triangoli, non vengono calcolate per punto sulla superficie. Il tuo modello di sfera sembra abbastanza tassellato, quindi questo non dovrebbe essere un problema pratico.

OpenGL non esegue la correzione gamma a meno che non si utilizzi lo spazio colore sRGB come destinazione del rendering, per quanto ne so. Mi aspetto che un'implementazione software corretta produca risultati molto simili di un'implementazione hardware OpenGL. Buon debug :)

Problemi correlati