Texturfilter selber schreiben - Warum ist Textur nicht perfekt scharf?


  • Mod

    for (int x=XStart;x<=XEnd;x++)
    

    wieso <= ?
    was passiert wenn du zwei transparente polys hast die eine kante teilen, zeichnest du die kante dann zweimal?

    float f = (x - XStart) / (float)(XEnd - XStart + 1);
    

    woher kommt das +1 ?



  • Der Grund warum x/y bis <= anstatt nur < läuft ist folgender:

    Stell dir mal vor die willst auf ein karrierten Blatt Papier eine Linie, welche von Links nach rechts läuft (Perfekt Horizontal) zeichnen. Die Linie soll 3 Kästchen lang sein. Die Kästchen haben einen Index. Z.B:

    7,8,9

    Wenn deine Linie auf den Kästchen 7,8,9 liegt, dann muss dein for-x von 7,8,9 laufen, also for (x=7;x<=9;x++)

    Um die Länge der Linie in Pixeln zu berechen rechne ich also 9 - 7 + 1.

    9 - 7 wäre ja nur 2. Die Linie ist doch aber 3 Kästen lang, wenn sie von 7 bis 9 läuft.

    Ich zeichne also bei Polygonkonten die Nachbarkanten doppelt. Es kommt zum Z-Puffer-Fieght.


  • Mod

    das ist nicht ganz optimal, durch dieses cheaten kannst du nie eine linie der laenge 0 haben. objekte die ganz weit entfernt sind und zu klein zum zeichnen waeren zeichnen bei dir pro vertex mehrere pixel.

    das ist natuerlich eine persoenliche entscheidung des architekten des rasterizers (soweit ich weiss rasterisiert sogar renderman loecher, zumindestens in den uralten versionen), aber vielleicht magst du dir die DirectX rasterization rules anschauen

    edit: link kaputtzerlegt vom forum



  • Ich habe das jetzt so geändert, dass ich nur von x < xend laufe. Die Kanten von benachbarten Pixeln werden jetzt nur noch einmal gezeichnet.

    Diese Kante, welche Otze bemängelt hat ist nun weg.

    Ich habe aber noch ein anders Problem(das schon vorher bestand).

    So wie ich das hier beschrieben habe, so berechne ich doch die UV-Koordinate von der linken oberen Ecke des Pixels richtig? 😕

    Um nun die UV-Koordinaten des rechten oberen Pixels zu berechnen habe ich mir überlegt, dass +1 an diesen Stellen rechnen muss:

    for (int x=XStart;x<=XEnd;x++)
    {
       float f = (x - XStart /*Obere Rechte Ecke des Pixels*/+ 1) / (float)(XEnd - XStart + 1); //f geht von 0 bis 0.99
       Vektor tex1 = P1.TextcoordVektor / P1.position.z * (1 - f) + P2.TextcoordVektor / P2.position.z * f; //Textcoord interpoliert zwischen den Eckpunkten P1 und P2
    
       for (int y=YStart;y<YEnd;y++)
       {
          float fy = (y- YStart /*Hier kein +1 da ich bereits bei oberer Pixelkante bin*/) / (float)(YEnd - YStart + 1);
          Vektor tex = tex1 * (1 - fy) + tex2 * f; //Textcoord interpoliert zwischen den Eckpunkten tex1 und tex2 (tex1 und tex2 wurden in der x-Schleife berechnet. Sie liegen auf den Dreieckskanten)
    
         tex /= tex.z; //Dividiere durch das interpolierte 1 / z -> Siehe hier warum: http://en.wikipedia.org/wiki/Texture_mapping#Perspective_correctness
    
          //Lese Texel an der Stelle tex.x und tex.y
          Texture.GetPixel((int)tex.x, tex.y) -> Farbe für Pixel
       }
    }
    

    Diese Vorgehen hat aber einen Fehler. Die Textur hat dadurch am linken Bildschirmrand eine leichte Verzehrung. Woran könnte das liegen?


  • Mod

    ich hatte dich gefragt gehabt wozu das +1 und jetzt hast du noch eines hinzugefuegt 😛

    die berechnung macht nicht so ganz sinn, was ist denn die 'linkeste' position die du erreichen kannst? die ist 1.

    z.b. 3 pixel breite linie

    float f = (x - XStart /*Obere Rechte Ecke des Pixels*/+ 1) / (float)(XEnd - XStart + 1); //f geht von 0 bis 0.99
    
    x=0 -> (0 - 0+1)/(3-0+1) -> 1/2 -> 0.25
    x=1 -> (1 - 0+1)/(3-0+1) -> 1/2 -> 0.5
    x=2 -> (2 - 0+1)/(3-0+1) -> 1/2 -> 0.75
    

    dabei moechtest du doch am linken rand 0 haben.

    (x-XStartUngerundet)/(XEndUngerundet-XStartUngerundet);
    

    manchmal ist das einfachste das mit den besten resultaten 😃



  • Das war hier gerade ein Missverständniss. Meine Formel, um die LINKE OBERE Ecke zu berechnen geht so:

    for (int x=XStart;x<XEnd;x++)
    {
       float f = (x - XStart) / (float)(XEnd - XStart);
    

    Die Formel für obere rechte Ecke:

    for (int x=XStart;x<XEnd;x++)
    {
       float f = (x - XStart + 1) / (float)(XEnd - XStart);
    

    Zahlbeispiel für Linie, welche von x = 0 bis x = 2 geht

    Linke Ecke:

    x=0 -> (0 - 0)/(3-0) -> 0/3 -> 0
    x=1 -> (1 - 0)/(3-0) -> 1/3 -> 0.33
    x=2 -> (2 - 0)/(3-0) -> 2/3 -> 0.66
    

    Rechte Ecke:

    x=0 -> (0 - 0 + 1)/(3-0) -> 1/3 -> 0.33
    x=1 -> (1 - 0 + 1)/(3-0) -> 2/3 -> 0.66
    x=2 -> (2 - 0 + 1)/(3-0) -> 3/3 -> 1.00
    

    Ich habe das +1 vergessen zu entfernen an dieser Stelle bei meinen letzten Beitrag:

    (float)(XEnd - XStart + 1);
    

    Im Quellcode steht aber jetzt

    (float)(XEnd - XStart);
    

    So. Die Frage, was an meiner Berechnung des rechten oberen Pixels falsch sein könnte bleibt bestehen. Wenn du willst, poste ich auch ein Beispielbild, wo ich die rechte obere Pixelecke zum Texturauslesen nehme, damit du den Fehler siehst.


  • Mod

    XMAMan schrieb:

    Das war hier gerade ein Missverständniss. Meine Formel, um die LINKE OBERE Ecke zu berechnen geht so:..

    Die Formel für obere rechte Ecke:

    sorry, ich bin verwirrt. ecken von was? ich dachte wir sprachen hier ueber die textur koordinate die du uebers dreieck bzw dessen scanline interpolierst.

    ein beispielbild hilft mir jetzt vielleicht tatsaechlich 🙂



  • Ich meine die Ecke vom Pixel. Wenn ich über eine reihe von Pixeln laufe, dann muss ich ja entscheiden, an welcher Stelle vom Pixel ich die UV-Koordinate will. Will ich pro Pixel nur eine UV-Koordinate, dann reicht wohl Pixelmitte oder linke obere Pixelecke. Will ich aber das ganze Pixel(Nicht nur ein einzelnen Punkt aus dem Pixel) in den Texturspace projezieren, dann brauche ich wohl alle 4 Pixelecken (also deren UV-Koordianten)

    http://fs2.directupload.net/images/150328/7a3qprj3.jpg


  • Mod

    kannst du ein wireframe vom boden zeigen?

    ist das richtig dass du bei tex1 und tex2 von P1 interpolierst? sollte das nicht eher sowas sein wie:

    Vektor tex1 = P1.TextcoordVektor/P1.positionz*(1.f)+P2.TextCoordVector/P2Position.z;
    Vektor tex2 = P3.TextcoordVektor/P1.positionz*(1.f)+P4.TextCoordVector/P2Position.z;
    

    ?



  • Ich habe den Fehler eingrenzen können. Er liegt beim Clipping in der Vertex-Interpolate-Funktion. Wenn ich das Clipping ausschalte, dann ist der Fehler weg.

    Wenn ich ein Dreieck habe, wo P1 im Bildschirm liegt, und P2 draußen. Abstand zwischen P1 und P2 ist 10. Die Bildschirmkante liegt bei 5. Dann rufe ich LinearInterpolate mit f = 0.5 auf.

    Die UV-Koordinaten werden hier ohne perspektivische Division interpoliert.

    //f geht von 0 bis 1
    private static Vertex LinearInterpolate(Vertex v1, Vertex v2, float f)
    {
    
      return new Vertex(v1.pos * (1 - f) + v2.pos * f, v1.normale * (1 - f) + v2.normale * f, v1.tTangent * (1 - f) + v2.tTangent * f, v1.texcoordU * (1 - f) + v2.texcoordU * f, v1.texcoordV * (1 - f) + v2.texcoordV * f);
    }
    

    Das funktioniert also offentsichtlich nicht. Also probiere ich es nun so:

    //f geht von 0 bis 1
    private static Vertex LinearInterpolate(Vertex v1, Vertex v2, float f)
    {
    
       float posZ = 1 / v1.pos.z * (1 - f) + 1 / v2.pos.z * f;
       Vektor tex = v1.TextcoordVektor / v1.pos.z * (1 - f) + v2.TextcoordVektor / v2.pos.z * f;
    
       tex /= posZ;
       return new Vertex(v1.pos * (1 - f) + v2.pos * f, v1.normale * (1 - f) + v2.normale * f, v1.tTangent * (1 - f) + v2.tTangent * f, tex.x, tex.y);     
    }
    

    Das funkioniert aber auch nicht. Die Texturkoordinaten sind immer noch falsch. Woran liegt das? Wie muss ichs machen?


Anmelden zum Antworten