Problem mit Phong beim Raytracing



  • Hallo C/C++ Community,

    ich schreibe einfach mal hier rein, da sich das wohl am besten für mein Problem anbietet. Ich programmiere unter C mit (OpenGL benutze ich dabei eigentlich nur zum Pixel färben des Bildschirms) ein Raytracing-Programm und benutze dafür den Phong Algorithmus mit Halfway-Vektor zum Erzeugen der Farben.

    Allerdings beobachte ich dort das Phänomen, dass beim Entfernen meiner Kugeln von der Lichtquelle das Specular-Light immer stärker (und damit quasi größer) wird. Dies sieht für mich irgendwie nach einem falschen Vektor(-berechnung) aus, doch ich habe einfach nichts finden können und schon so ziemlich alle Vektoren mal normalisiert und mal nicht...

    Ob mir da wohl jemand helfen kann? Ich füge einfach mal betreffenden Code bei:

    struct color localLight(float g[3], float n[3], float ka, float kd, float ks, float ns, float eye[3]) {
        int i;
        float tmp, tmp2;
        float tmp3[3], l[3], v[3], h[3], r[3];
        struct color ambient = addCol(clearCol, clearCol);
        struct color diffuse = addCol(clearCol, clearCol);
        struct color specular = addCol(clearCol, clearCol);
        struct color result = addCol(clearCol, clearCol);
        struct color id, is;
    
        // Ambient light
        ambient.red     = ka * 0.25;
        ambient.green   = ka * 0.25;
        ambient.blue    = ka * 0.25;
    
        // Diffuse intensity
        is.red = 1;
        is.green = 1;
        is.blue = 1;
    
        // Diffuse intensity
        id = light1.color;
    
        // Diffuse light
        vectorDifference3f(l, light1.origin, g);
        getUnitVector3f(n, n);
        getUnitVector3f(l, l);
        tmp = dotProduct3f(n, l);
    
        diffuse.red     = kd * id.red * tmp;
        diffuse.green   = kd * id.green * tmp;
        diffuse.blue    = kd * id.blue * tmp;
    
        // Specular light
        scalarProduct3f(tmp3, n, 2*dotProduct3f(n, l));
        vectorDifference3f(r, tmp3, l); 
        getUnitVector3f(r, r); 
    
        vectorDifference3f(v, eye, g);
        getUnitVector3f(v, v);
    
        vectorAddition3f(h, l, v);  // Halfway Variante
        getUnitVector3f(h, h);      // Halfway Variante
        tmp2 = dotProduct3f(n, h);  // Halfway Variante
    
        if (tmp>0 && tmp2>0) tmp2 = pow(tmp2, ns);
        else tmp2 = 0;
    
        specular.red     = ks * is.red * tmp2;
        specular.green   = ks * is.green * tmp2;
        specular.blue    = ks * is.blue * tmp2;
    
        result = addCol(ambient, diffuse);
        result = addCol(result, specular);
    
        return result;
    }
    

    g ist der Schnittpunkt mit dem Objekt, der übergeben wird
    n ist die Normale des Objekts an dieser Stelle (berechnet mit vectorDifference3f(n, g, sphere.origin);)
    eye die Camera-Position
    ka, kd und ks die Koeffizienten für ambient, diffuse und specular Licht. Dort werden übrigens natürlich nur floats 0≤k≤1 übergeben; und ns = 10
    getUnitVector3f(a, b) berechnet mir a = Einheitsvektor(b) - und ja, korrekt
    addCol addiert zwei Farben (Farben sind einfach struct mit 3 floats)
    scalarProduct3f(a, b, c) speichert das Skalarprodukt von Vektor b mit Skalar c in a
    dotProduct3f(a, b) gibt Punktprodukt zurück von a und b
    VectorAddition3f(a, b, c) speichert Addition von b und c in a (analog VectorDifference3f)

    Ach ja: Ich habe eine Lichtquelle (light1, enthält float[3] origin als Ursprung und eine color) sowie eine Kugel sphere mit float radius und float[3] origin als Ursprung.

    Hm, vielleicht sieht ja jemand irgendwas...

    ciao,
    Christian



  • Es ist traditionell nicht so einfach, in fremdem Code einen logischen Fehler zun finden, aber hier scheint mir etwas komisch zu sein (bitte nicht hauen, falls es nicht massgebend sein sollte):

    scalarProduct3f(tmp3, n, 2*dotProduct3f(n, l));
        vectorDifference3f(r, tmp3, l);
    

    Dies entspricht in meinem Code (ebenfalls specular lighting im Raytracer) einem Aufruf vector<>::reflect(v, l) , also v - 2 * dot(v, n) * n ; deiner Beschreibung nach ergibt vectorDifference3f(r, tmp3, l) aber 2 * dot(v, n) * n - v , ein kleiner, aber dennoch bemerkenswerter Unterschied. Der korrekte Aufruf wäre also: vectorDifference3f(r, l, tmp3);

    Aber ich kann mich auch irren, es war ein langer Tag und ich hatte die Schweinegrippe 🤡

    MfG


  • Mod

    /rant/ schrieb:

    Aber ich kann mich auch irren, es war ein langer Tag und ich hatte die Schweinegrippe 🤡

    gute besserung und steck uns hier nicht an 🙂

    @topic
    wenn es entfernungsabhaengig anders wird, dann vergisst du wohl die vectoren die du mit verschiedenen positionen ausrechnest zu normalisieren.

    schau dir nochmal ein tutorial (oder was auch immer deine quelle war) an, da sollte oefter mal ein normalize sein.



  • Okay, sorry bin gerade erst zurückgekommen, deswegen bisher net geantwortet.
    Also es lag daran, dass meine Funktion für Einheitsvektoren bei Aufruf getUnitVector3f(array, array); mit array als ein und derselben Variable für Quell- und Zielarray direkt jeden Index des Ziels nacheinander geschrieben hat ohne erst alles zwischenzuspeichern und dann in die Variable zu schreiben. Trotzdem danke für's antworten, war ein dummer Fehler... aber braucht einfach wieder lange um so etwas zu finden. Naja, so lernt man's wenigstens auf die "harten Tour" 😉

    ciao


Anmelden zum Antworten