Frage

Ich bin ein Software-Rasterizer machen, und ich habe in ein bisschen ein snag laufen. Ich kann nicht scheinen, perspektivisch korrekte Textur-Mapping, um Arbeit zu bekommen

ist mein Algorithmus zuerst sortieren die Koordinaten auf Grundstück von y. Dies gibt eine Höchst-, Tiefst- und Mittelpunkt. Ich gehe dann über die Abtastlinien des Delta mit:

// ordering by y is put here

order[0] = &a_Triangle.p[v_order[0]];
order[1] = &a_Triangle.p[v_order[1]];
order[2] = &a_Triangle.p[v_order[2]];

float height1, height2, height3;

height1 = (float)((int)(order[2]->y + 1) - (int)(order[0]->y));
height2 = (float)((int)(order[1]->y + 1) - (int)(order[0]->y));
height3 = (float)((int)(order[2]->y + 1) - (int)(order[1]->y));

// x 

float x_start, x_end;
float x[3];
float x_delta[3];

x_delta[0] = (order[2]->x - order[0]->x) / height1;
x_delta[1] = (order[1]->x - order[0]->x) / height2;
x_delta[2] = (order[2]->x - order[1]->x) / height3;

x[0] = order[0]->x;
x[1] = order[0]->x;
x[2] = order[1]->x;

Und dann machen wir von order[0]->y zu order[2]->y, die x_start und x_end durch eine Delta erhöht. Wenn der obere Teil Rendering sind die Deltas x_delta[0] und x_delta[1]. Wenn der untere Teil Rendering sind die Deltas x_delta[0] und x_delta[2]. Dann linear wir zwischen x_start und x_end auf unserer Scanlinie interpolieren. UV-Koordinaten werden in der gleichen Art und Weise interpoliert, durch y geordnete, bei Beginn und Ende ausgehend, auf die Deltas jeden Schritt angewendet werden.

Das funktioniert gut, außer, wenn ich versuche Perspektive richtiges UV-Mapping zu tun. Der Grundalgorithmus ist UV/z 1/z und für jeden Scheitelpunkt zu nehmen und zwischen ihnen interpoliert werden. Für jedes Pixel wird die UV UV_current * z_current koordinieren. Dies ist jedoch das Ergebnis:

alt text

Der inversed Teil zeigt Ihnen, wo die Deltas umgedreht werden. Wie Sie sehen können, sind die beiden Dreiecke scheinen beide gehen zu verschiedenen Punkten in den Horizont zu sein.

Hier ist, was ich verwende, um die Z an einem Punkt im Raum zu berechnen:

float GetZToPoint(Vec3 a_Point)
{
    Vec3 projected = m_Rotation * (a_Point - m_Position);

    // #define FOV_ANGLE 60.f
    // static const float FOCAL_LENGTH = 1 / tanf(_RadToDeg(FOV_ANGLE) / 2);
    // static const float DEPTH = HALFHEIGHT * FOCAL_LENGTH; 
    float zcamera = DEPTH / projected.z;

    return zcamera;
}

Bin ich richtig, ist es ein z-Puffer Problem?

War es hilfreich?

Lösung

ZBuffer hat nichts damit zu tun.

ZBuffer ist nur dann sinnvoll, wenn Dreiecke überlappen, und Sie wollen sicherstellen, dass sie korrekt gezeichnet werden (zum Beispiel korrekt in der Z bestellt werden). Die ZBuffer wird, für jedes Pixel des Dreiecks bestimmen, ob ein zuvor platzierten Pixel näher an der Kamera ist, und wenn ja, nicht das Pixel des Dreiecks ziehen.

Da Sie zwei Dreiecke zeichnen, die sich nicht überlappen, ist dies nicht das Problem sein kann.

Ich habe einen Software-Rasterizer in festen Punkt gemacht einmal (für ein Mobiltelefon), aber ich habe nicht die Quellen auf meinem Laptop. Also lassen Sie mich heute Abend überprüfen, wie ich es tat. Im Wesentlichen, was Sie haben, ist, bekommen nicht schlecht! Eine Sache, wie dies durch einen sehr kleinen Fehler verursacht werden könnte

Allgemeine Tipps beim Debuggen dies ein paar Testdreiecke zu haben ist (Hang linksseitigen, Neigung der rechten Seite, 90-Grad-Winkel, etc etc) und Schritt durch sie mit dem Debugger und sehen Sie, wie Sie Ihre Logik beschäftigt sich mit den Fällen.

EDIT:

peudocode meiner Rasterizer (nur U, V und Z berücksichtigt werden ... wenn Sie auch tun gouraud wollen Sie müssen auch alles tun, für RG und B ähnlich, was Sie für U und V tun und Z:

Die Idee ist, dass ein Dreieck in zwei Teile zerlegt werden kann. Das Oberteil und das Unterteil. Die Spitze ist von y [0] bis y [1] und dem Unterteil ist von y [1] bis Y [2]. Für beiden Gruppen müssen Sie den Schritt Variablen berechnen, mit dem Sie interpoliert werden. Das folgende Beispiel zeigt Ihnen, wie das Oberteil zu tun. Bei Bedarf kann ich auch den unteren Teil liefern.

Bitte beachten Sie, dass ich bereits die benötigte Interpolation Offsets für den unteren Teil in dem unten berechnen ‚Pseudo-Code‘ Fragment

  • erste Ordnung der Koordinaten (x, y, z, u, v) in der Reihenfolge, so dass Koord [0] .y
  • nächstes Prüfen, ob 2 Sätze von Koordinaten identisch sind (nur x und y überprüfen). Wenn Sie also nicht ziehen
  • Ausnahme: hat das Dreieck eine flache Oberseite? wenn ja, wird die erste Steigung unendlich
  • sein
  • exception2: Ist das Dreieck einen flachen Boden hat (ja Dreiecken können diese auch haben; ^)), dann die letzte Steigung wird auch unendlich sein
  • berechnen 2 Pisten (links und rechts)
    leftDeltaX = (x [1] - x [0]) / (y [1] -y [0]) und rightDeltaX = (x [2] - x [0]) / (y [2] -y [0] )
  • der zweite Teil des Dreiecks berechnet abhängig von: wenn die linke Seite des Dreiecks ist nun wirklich auf dem linksseitigen (oder Bedürfnisse Swapping)

Codefragment:

 if (leftDeltaX < rightDeltaX)
 {
      leftDeltaX2 = (x[2]-x[1]) / (y[2]-y[1])
      rightDeltaX2 = rightDeltaX
      leftDeltaU = (u[1]-u[0]) / (y[1]-y[0]) //for texture mapping
      leftDeltaU2 = (u[2]-u[1]) / (y[2]-y[1])
      leftDeltaV = (v[1]-v[0]) / (y[1]-y[0]) //for texture mapping
      leftDeltaV2 = (v[2]-v[1]) / (y[2]-y[1])
      leftDeltaZ = (z[1]-z[0]) / (y[1]-y[0]) //for texture mapping
      leftDeltaZ2 = (z[2]-z[1]) / (y[2]-y[1])
 }
 else
 {
      swap(leftDeltaX, rightDeltaX);
      leftDeltaX2 = leftDeltaX;
      rightDeltaX2 = (x[2]-x[1]) / (y[2]-y[1])
      leftDeltaU = (u[2]-u[0]) / (y[2]-y[0]) //for texture mapping
      leftDeltaU2 = leftDeltaU
      leftDeltaV = (v[2]-v[0]) / (y[2]-y[0]) //for texture mapping
      leftDeltaV2 = leftDeltaV
      leftDeltaZ = (z[2]-z[0]) / (y[2]-y[0]) //for texture mapping
      leftDeltaZ2 = leftDeltaZ
  }
  • setzen die currentLeftX und currentRightX sowohl auf x [0]
  • set currentLeftU auf leftDeltaU, currentLeftV auf leftDeltaV und currentLeftZ auf leftDeltaZ
  • CALC beginnen und Endpunkt für die ersten Y-Bereich: startY = ceil (y [0]); endy = ceil (y [1])
  • Prestep x, u, v und z für den Bruchteil von y für Subpixelgenauigkeit (Ich denke, das auch für die Hin- und Herbewegungen erforderlich) Für meine FixedPoint Algorithmen dies nötig war, um die Linien und Texturen, die Illusion in viel feiner bewegter geben zu machen Schritte dann die Auflösung des Displays)
  • berechnen, wobei x auf y sein soll [1]: halfwayX = (x [2] -x [0]) * (y [1] -y [0]) / (y [2] -y [0] ) + x [0] und gleich für U und V und Z: halfwayU = (u [2] -u [0]) * (y [1] -y [0]) / (y [2] -y [0]) + u [0 ]
  • und mit Hilfe der halfwayX berechnet den Stepper für die U und V und Z: if (halfwayX - x [1] == 0) {slopeU = 0, slopeV = 0, slopeZ = 0} else {slopeU = (halfwayU - U [1]) / (halfwayX - x [1])} // ( und gleich für v und z)
  • Clipping für die Y-Spitze (so berechnen, wo wir den Fall zu ziehen, um die Spitze des Dreiecks gehen zu starten Bildschirm ausgeschaltet ist (oder aus dem Clipping-Rechteck))
  • für y = startY; y
  • Y Vergangenheit unteren Teil des Bildschirms? Stop-Rendering!
  • ber startX und ENDX für die erste horizontale Linie leftCurX = ceil (startx); leftCurY = ceil (endy);
  • Clip um die Linie zu dem linken horizontalen Rande des Bildschirms (oder Ausschnittsbereich)
  • gezogen werden
  • einen Zeiger auf das Ziel Buff vorbereitener (tut es durch Array-Indizes jedes Mal zu langsam) unsigned int buf = destbuf + (y pitch) + startX; (Unsigned int, falls Sie tun 24bit oder 32 Bit-Rendering) Auch hier bereiten Sie Ihre ZBuffer Zeiger (wenn Sie diese verwenden)
  • für (x = startX; x
  • jetzt Perspektive Textur-Mapping (ohne Verwendung eines bilineair Interpolation Sie folgendes tun):

Codefragment:

         float tv = startV / startZ
         float tu = startU / startZ;
         tv %= texturePitch;  //make sure the texture coordinates stay on the texture if they are too wide/high
         tu %= texturePitch;  //I'm assuming square textures here. With fixed point you could have used &=
         unsigned int *textPtr = textureBuf+tu + (tv*texturePitch);   //in case of fixedpoints one could have shifted the tv. Now we have to multiply everytime. 
         int destColTm = *(textPtr);  //this is the color (if we only use texture mapping)  we'll be needing for the pixel
  • Dummy-Leitung
    • Dummy-Leitung
      • Dummy-Leitung
      • optional:. Überprüfen Sie die Z-Buffer, wenn die zuvor aufgetragen Pixel an dieser Koordinate höher oder niedriger ist dann unsere
      • plotten das Pixel
      • Startz + = slopeZ; startU + = slopeU; StarTV + = slopeV; aktualisieren // alle Interpolatoren
    • } Ende x Schleife
    • leftCurX + = leftDeltaX; rightCurX + = rightDeltaX; leftCurU + = rightDeltaU; leftCurV + = rightDeltaV; leftCurZ + = rightDeltaZ; // Update Y Interpolatoren
  • } Ende y loop

    // dies ist das Ende des ersten Teils. Wir haben jetzt die Hälfte des Dreiecks gezogen. von oben, in der Mitte Y-Koordinate. // wir jetzt im Grunde tun genau die gleiche Sache, aber jetzt für die untere Hälfte des Dreiecks (der andere Satz von Interpolatoren verwendet wird)

traurig über die ‚Dummy-Linien‘ .. sie waren notwendig, um den Abschlags-Codes synchron zu bekommen. (Dauerte eine Weile, um alles sortiert weg suchen, wie beabsichtigt)

Lassen Sie mich wissen, ob dies hilft Ihnen, das Problem zu lösen Sie konfrontiert sind!

Andere Tipps

Ich weiß nicht, dass ich mit Ihrer Frage helfen können, aber eines der besten Bücher über Software-Rendering, dass ich zu der Zeit gelesen hatte, ist online verfügbar Grafik-Programmierung Black Book von Michael Abrash.

Wenn Sie 1/z werden interpoliert, müssen Sie mehrfach UV/z von z, 1/z nicht. Angenommen, Sie haben diese:

UV = UV_current * z_current

und z_current 1/z interpoliert, sollten Sie es ändern:

UV = UV_current / z_current

Und dann wollen Sie vielleicht z_current um so etwas wie one_over_z_current umbenennen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top