Raytracing mit OpenGL



  • Hallo,

    ich versuche einen Raytracing-Algorithmus zu schreiben. Von jedem Pixel des GUI-Fensters ausgehend soll ein Strahl direkt in Z richtung gehen und wenn auf ein Dreieck gestoßen wird soll dieser Pixel farbig dagestellt werden.

    Hier mal die wichtigsten Methoden (Point3D und Face sind eigene Strukturen, die die gewünschten Operationen bereistellen):

    const int WINDOW_WIDTH = 800;
    const int WINDOW_HEIGHT = 800;
    vector<Point3D> points; 
    vector<Face> triangles;
    
    void renderPixelColor(int x, int y, float r, float g, float b)
    {
        glColor3f(r,g,b);
        glBegin(GL_POINTS);
        glVertex2i(x, y);
        glEnd();
    }
    
    double getDeterminante(int aa, int ab, int ac, int ba, int bb, int bc, int ca, int cb, int cc)
    {
        return aa*(bb*cc-cb*bc)-ab*(ba*cc-ca*bc)-ac*(ba*cb-ca*bb);
    }
    
    int shootRayAndReturnNumberOfVisibleTriangle(Point3D startPoint)
    {
        Point3D direction = Point3D(0, 0, 1);
        int currentT = 1000000000;
        int visibleTriangle = -1;
        for (int i = 0; i < triangles.size(); i++){
    	Face triangle = triangles.at(i);
    	Point3D a = triangle.point1;
    	Point3D Eb = triangle.point2-a;
    	Point3D Ec = triangle.point3-a;
    	Point3D k = a-startPoint;
    	double detT = getDeterminante(-Eb.x, -Ec.x, k.x, -Eb.y, -Ec.y, k.y, -Eb.z, -Ec.z, k.z);
    	double detA = getDeterminante(-Eb.x, -Ec.x, direction.x, -Eb.y, -Ec.y, direction.y, -Eb.z, -Ec.z, direction.z);
    	double detB = getDeterminante(k.x, -Ec.x, direction.x, k.y, -Ec.y, direction.y, k.z, -Ec.z, direction.z);
    	double detC = getDeterminante(-Eb.x, k.x, direction.x, -Eb.y, k.y, direction.y, -Eb.z, k.z, direction.z);
    	if(detA!=0){
    	    double t=detT/detA;
    	    double r=detB/detA;
    	    double s=detC/detA;
    	    if(t>0 && r>=0 && s>=0 && r+s<=1){
    		if(t<currentT){
    		    visibleTriangle=i;
    		}
    	    }
    	}
        }
        return visibleTriangle;
    }
    
    void draw()
    {
        for(int x = 0; x<= WINDOW_WIDTH; x++){
    	for(int y = WINDOW_HEIGHT; y>= 0; y--){
    	    int visibleTriangle = shootRayAndReturnNumberOfVisibleTriangle(Point3D(x, y, 0));
    	    if(visibleTriangle!=-1){
    		renderPixelColor(x, y, 1, 0.5, 0.25);
    	    }
    	}
        }
    }
    

    So wie der Code jetzt da steht müssen noch irgendwo Fehler sein. Ich weiß das, da Dreiecke die sich teilweise hinter anderen verbergen nich korrekt gezeichnet werden (also der Teil der nicht verborgen ist).
    Ich habe aber beim besten Willen keine Idee wo sich der fehler befinden könnte. Ist bestimmt nur eine Kleinigkeit in der Berechnung.
    In der Hoffnung, dass sich hier im Forum jemand mit Raytracing auskennt bitte ich euch um Hilfe bei der Fehlersuche 🙂


  • Mod

    zwischen zeile 42 udn 43

    currentT=t;
    


  • Ich frag mich nur gerade was das mit OpenGL zu tun hat (ja, ich sehe die OpenGL Aufrufe, trotzdem...).



  • hustbaer schrieb:

    Ich frag mich nur gerade was das mit OpenGL zu tun hat (ja, ich sehe die OpenGL Aufrufe, trotzdem...).

    🤡



  • rapso schrieb:

    zwischen zeile 42 udn 43

    currentT=t;
    

    Oh, guter Hinweis, danke 🙂

    Leider noch nicht des Problems Loesung 😞

    Zum besseren verstaendnis: ich nutze die Formel die hier ab Folie 7 erklaert wird http://www.cs.ucr.edu/~vbz/cs130f13-14.pdf.

    Mehr dazu wie das mit den Matrizen funktioniert gibts hier: http://de.wikipedia.org/wiki/Cramersche_Regel

    Das Problem wird in diesem Screenshot deutlich:http://s14.directupload.net/images/131114/wrlq9hbi.png
    So hier sollte es eigentlich aussehen (Farben sind egal): http://s7.directupload.net/images/131114/vnx74uvb.png



  • Es liegt definitiv an der Berechnung von t (also der distanz zwischen dem Fenster und dem Dreieck).
    Ich habe die Methode so geaendert, dass jetzt t in abhaengigkeit von s und r errechnet wird (Zeile 18):

    int shootRayAndReturnNumberOfVisibleTriangle(Point3D startPoint)
    {
        Point3D direction = Point3D(0, 0, 1);
        int currentT = 1000000000;
        int visibleTriangle = -1;
        for (int i = 0; i < triangles.size(); i++){
    	Face triangle = triangles.at(i);
    	Point3D a = triangle.point1;
    	Point3D Eb = triangle.point2-a;
    	Point3D Ec = triangle.point3-a;
    	Point3D k = a-startPoint;
    	double detA = getDeterminante(-Eb.x, -Ec.x, direction.x, -Eb.y, -Ec.y, direction.y, -Eb.z, -Ec.z, direction.z);
    	double detR = getDeterminante(k.x, -Ec.x, direction.x, k.y, -Ec.y, direction.y, k.z, -Ec.z, direction.z);
    	double detS = getDeterminante(-Eb.x, k.x, direction.x, -Eb.y, k.y, direction.y, -Eb.z, k.z, direction.z);
    	if(detA!=0){
    	    double r=detR/detA;
    	    double s=detS/detA;
    	    double t = a.z+Eb.z*r+Ec.z*s-startPoint.z;
    	    if(t>0 && r>=0 && s>=0 && r+s<=1){
    		if(t<currentT){
    		    visibleTriangle=i;
    		    currentT=t;
    		}
    	    }
    	}
        }
        return visibleTriangle;
    }
    

    Jetzt funktioniert alles wie gewuenscht. Ich waere aber trotzdem sehr dankbar, wenn mir jemand erklaeren koennte warum es vorher nicht geklappt hat. Die Loesung jetzt scheint mir mehr eine Ausweichloesung zu sein...


  • Mod

    double getDeterminante(int aa, int ab, int ac, int ba, int bb, int bc, int ca, int cb, int cc)
    {
        return aa*(bb*cc-cb*bc)-ab*(ba*cc-ca*bc)-ac*(ba*cb-ca*bb);
    }
    
    ...	Point3D a = triangle.point1;
    	Point3D Eb = triangle.point2-a;
    	Point3D Ec = triangle.point3-a;
    	Point3D k = a-startPoint;
    	double detT = getDeterminante(-Eb.x, -Ec.x, k.x, -Eb.y, -Ec.y, k.y, -Eb.z, -Ec.z, k.z);
    	double detA = getDeterminante(-Eb.x, -Ec.x, direction.x, -Eb.y, -Ec.y, direction.y, -Eb.z, -Ec.z, direction.z);
    	double detB = getDeterminante(k.x, -Ec.x, direction.x, k.y, -Ec.y, direction.y, k.z, -Ec.z, direction.z);
    	double detC = getDeterminante(-Eb.x, k.x, direction.x, -Eb.y, k.y, direction.y, -Eb.z, k.z, direction.z);
    ...
    

    ist das absicht dass du int als parameter fuer die determinante nutzt?
    1. es kann bei der menge an multiplikationen schnell einen voerflow geben
    2. sind die eingangsdaten echt int oder vielleicht float?


Anmelden zum Antworten