Software Rendering: wieder Clipping, wieder Texturkoordinaten



  • Problem:
    Hab ein sehr großes Dreieck, das gegen die Far Clipping Plane geclippt wird:

    OpenGL:
    http://loop.servehttp.com/~vertexwahn/uploads/opengl_screenshot_far_clip.png

    Mein Software Renderer:
    http://loop.servehttp.com/~vertexwahn/uploads/software_screenshot_far_clip.png

    wie man sieht scheint etwas mit den Texturkoordinaten nicht zu stimmen. Die verwendete Textur kann man hier bestaunen:
    http://loop.servehttp.com/~vertexwahn/uploads/checkerboard.png

    Für kleine Dreiecke, die ich gegen die Left/Right/Top/Bottom Clipping Plane geclippt habe haben sich für mich erkennbaren optischen Fehler ergeben:
    Software:
    http://loop.servehttp.com/~vertexwahn/uploads/clipping/software_screenshot_cl.png
    OpenGL:
    http://loop.servehttp.com/~vertexwahn/uploads/clipping/opengl_screenshot_cl.png

    von dem grün markierten Pixel im folgenden Bild zu sehen
    http://loop.servehttp.com/~vertexwahn/uploads/software_screenshot_kp.png

    weiß ich das die Texturkoordinaten für u,v im Intervall [0;1/8] also [1;0.125] liegen, weil das grün markierte Pixel durch OpenGL orange dargestellt wird und die Textur nur in den genannten Bereich orange ist. Da die Farbe des grün markierten Pixels aber rot ist sind die Texturkoordinaten anscheinend falsch - jetzt fragt sich warum.

    meine Eingabedaten sehen so aus:

    # ein großes Dreieck
    # vertex data
    v 0 0 0
    n 0 1 0
    t 0 0
    c 1 1 1
    
    v 20000 0 0
    n 0 1 0
    t 1 0
    c 1 1 1
    
    v 20000 0 -20000
    n 0 1 0
    t 1 1
    c 1 1 1
    
    # trianglelist
    f 0 1 2
    

    dann kommt die Transformation mit der Projection- und Modelview-Matrix:

    vN =  m_Projection * m_Modelview * vN; 
    vN.rhw = 1.0f/vN.w;
    

    Daten:

    v1 {x=0.64733481 y=-0.92226350 z=1.6558098 w=1.8523016 u=0.00000000 v=0.00000000 rhw=0.53986889}
    v2 {x=150.55421 y=76.036270 z=181.26152 w=181.09915 u=1.0000000 v=0.00000000 rhw=0.0055218372}
    v3 {x=-179.09331 y=111.03308 z=262.93701 w=262.61148 u=1.0000000 v=1.0000000 rhw=0.0038079065}
    

    Jetzt kommt das Clipping:
    da
    v2.z > v2.w
    v3.z > v3.w
    gilt muss geclippt werden.

    Nach dem Clippen gibt es folgende Vertices:

    T0 {x=0.64733481 y=-0.92226350 z=1.6558098 w=1.8523016 u=0.00000000 v=0.00000000 rhw=0.53986889}
    T1 {x=82.727890 y=41.215893 z=99.997772 w=99.997780 u=0.54754364 v=0.00000000 rhw=0.24729055}
    T2 {x=-67.007874 y=41.218246 z=100.00328 w=100.00327 u=0.37640464 v=0.37640464 rhw=0.33809304}
    

    Anschließend erfolgt (x y z w) -> (x/w, y/w, z/w, 1) und Multiplikation mit der Viewport-Matrix um Bildschirmkoordinaten zu erhalten. Dies hat keine Auswirkungen auf den rhw-Wert.

    der Rasterisierer berechnet die Texturkoordinaten {u=0.17897670 v=0.084484227 }
    da aber 0.17897670 > 1/8 = 0.125 ist muss etwas falsch gelaufen sein - nur fragt sich was

    Fehleranalyse:
    1. Der Clipper macht etwas falsch
    2. Der Rasterisierer macht etwas falsch
    3. Samplen in die Textur ist falsch
    3. Andere Ursache (?)

    1: zum Clipper:
    Betrachten wird die Kannte v1, v2 - nun soll der Schnittpunkt mit der Far Clipping Plane berechnet werden

    Gesucht ist der Punkt s1 an dem s1.z/s1.w = 1 gilt und der gleichzeitig auf der Kante v1, v2 liegt:

    v1.z + t * (v2.z - v1.z)
    ------------------------ = 1
    v1.w + t * (v2.w - v1.w)
    

    nach t umformen:

    v1.w-v1.z
    t = -----------------------
        (v2.z-v1.z)-(v2.w-v1.w)
    

    für v1,v2 erhält man für t = 0.54754364
    die Texturkoordinaten berechnen sich nach T1 = v1.uv + t * (v2.uv - v1.uv)
    (siehe oben für Ergebnis von T1)

    die Kannte v3v1 ergibt für t = 0.62359536
    (siehe oben für Ergebnis von T2)

    Der Clipper arbeitet anscheinend korrekt... oder hat jemand einen Fehler entdeckt?

    Nach dem Clippen kommt Teilung durch w und Berechnung der Bildschirmkoordinaten:
    T0{x=431.83231 y=120.50367 z=0.00000000 ...}
    T1{x=431.83231 y=120.50367 z=0.00000000 ...}
    T2{x=431.83231 y=120.50367 z=0.00000000 ...}

    3. Der Rasterisierer macht etwas falsch
    zunächst berechne ich die baryzentrischen Koordinaten meines grün markierten Pixels (grün markiertes Pixel hat Bildschirmkoordinaten 387, 240 mit Koordinateneursprung links unten)
    alpha0=0.45060849
    alpha1=0.28155282
    alpha2=0.26783872

    Die Texturkoordinaten werden wie folgt berechnet:
    (EDIT: Dieser Code wurde verändert)

    output_fragment.textureCoordinates.uv = v1.uv * v1.rhw * alpha1 + v2.uv.y * v2.rhw * alpha2 + v3.uv.y * v3.rhw * alpha3;
    output_fragment.textureCoordinates.uv /= (v1.rhw * alpha1 + v2.rhw * alpha2 + v3.rhw * alpha3);
    

    Die berechneten Texturkoordinaten lauten: {u=0.17897670 v=0.084484227 }
    u ist größer als 1/8 -> verdammt - Texturkoordinaten falsch

    Frage:
    was mache ich falsch?

    Edit: Um rhw Werte ergänzt



  • (x y z w) -> (x/w, y/w, z/w, 1)
    [...]
    Nach dem Clippen kommt Teilung durch w und Berechnung der Bildschirmkoordinaten:
    T0{x=431.83231 y=120.50367 z=0.00000000 ...}
    T1{x=431.83231 y=120.50367 z=0.00000000 ...}
    T2{x=431.83231 y=120.50367 z=0.00000000 ...}

    Und w ist 1 ?
    Dann waere die Interpolation linear.



  • Nach der Multiplikation mit der Projection- und Modelviewmatrix berechne ich 1.0f/w und speichere es in der Variablen rhw:

    v1.position =  m_Projection * m_Modelview * v1.position; 
    v2.position =  m_Projection * m_Modelview * v2.position;
    v3.position =  m_Projection * m_Modelview * v3.position;
    
    v1.rhw = 1.0f / v1.position.w;
    v2.rhw = 1.0f / v2.position.w;
    v3.rhw = 1.0f / v3.position.w;
    

    Der Rasterisierer verwendte dann das berechne rhw:

    output_fragment.textureCoordinates.uv = v1.uv * v1.rhw * alpha1 + v2.uv.y * v2.rhw * alpha2 + v3.uv.y * v3.rhw * alpha3;
    

    rhw ist nicht gleich 1
    Entsteht beim Clippen ein neues Vertex dann berechne ich dieses einfach mit:

    T[t].rhw = V[i].rhw + t * (V[j].rhw-V[i].rhw);
    

    @hellihjb
    Du hast recht der obige Code war falsch - ich hab ihn jetzt so umgeändert wie er in meiner Implementierung ist - war ein Fehler beim "abschreiben" meinerseits



  • Vertexwahn schrieb:

    Entsteht beim Clippen ein neues Vertex dann berechne ich dieses einfach mit:

    T[t].rhw = V[i].rhw + t * (V[j].rhw-V[i].rhw);
    

    Solang noch keine perspektivische Projektion stattgefunden hat, kann man 1/w nicht linear interpolieren.



  • Das Clippen findet ja nach der perspektivischen Projektion statt - vor der perspektivischen Teilung.



  • Mit "Projektion" meinte ich die "perspektivische Teilung".
    Solang Du im 3D-Raum bist sind x,y,z,w linear, 1/w aber nicht.



  • Danke! Das wars.

    statt

    T[t-1].rhw = V[i].rhw + intersection * (V[j].rhw-V[i].rhw);
    

    mach ich jetzt

    T[t-1].rhw = 1.0f/T[t-1].position.w;
    

Log in to reply