Ich habe eine benutzerdefinierte Sprite-Routine (openGL 2.0), die ein einfaches Sprite-Blatt verwendet (meine Texturen sind horizontal nebeneinander angeordnet).
Hier ist zum Beispiel ein Test-Sprite-Blatt mit zwei einfachen Texturen:
Beim Erstellen meines openGL-Sprite-Objekts muss ich nun die Gesamtzahl der Frames in seinem Atlas angeben und beim Zeichnen angeben, welchen Frame ich zeichnen möchte.
Es wird dann herausgefunden, woher die Textur stammt:
Teilen Sie die erforderliche Bildnummer durch die Gesamtzahl der Bilder (um die linke Koordinate zu erhalten).
Tauchen Sie dann 1 um die Gesamtzahl der Frames und addieren Sie das Ergebnis zur oben berechneten linken Koordinate.
Das scheint zu funktionieren, aber manchmal bekomme ich Probleme. Sagen wir zum Beispiel, ich möchte das X unten zeichnen und ich bekomme ...........
Ich habe davon gehört, zwischen jede Textur eine "Polsterung" von 1 Pixel zu setzen, aber könnte jemand genau erklären, wie das funktioniert? Ich meine, wenn ich das mache, wird es sicherlich die Berechnungen für das Erhalten der Textur abwerfen.
Wenn ich die Polsterung einfach in die aufgenommene Textur einbeziehe (damit das Sprite mit einem leeren Rand gezeichnet wird), führt dies sicherlich zu Problemen bei der Kollisionserkennung? (dh Sprites scheinen zu kollidieren, wenn Begrenzungsrahmen verwendet werden, wenn die transparenten Teile kollidieren).
Würde mich freuen, wenn jemand erklären könnte.
quelle
GL_NEAREST
oderGL_LINEAR
zum Rendern der Textur?Antworten:
Das Problem bei der Verwendung von Texturatlanten und benachbarten Texeln, die auslaufen, hängt mit der Funktionsweise der linearen Texturfilterung zusammen.
Für jeden Punkt in der Textur, der nicht genau in der Mitte eines Texels abgetastet wird, werden bei der linearen Abtastung 4 benachbarte Texel abgetastet und der Wert an der von Ihnen angeforderten Stelle als gewichteter Durchschnitt (basierend auf dem Abstand vom Abtastpunkt) aller 4 berechnet Proben.
Hier ist eine schöne Visualisierung des Problems:
Da Sie so etwas wie
GL_CLAMP_TO_EDGE
in einem Texturatlas nicht verwenden können , müssen Sie um den Rand jeder Textur Randtexel erstellen. Diese Randtexel verhindern, dass benachbarte Samples aus völlig unterschiedlichen Texturen im Atlas das Bild durch die oben erläuterte gewichtete Interpolation verändern.Beachten Sie, dass Sie bei Verwendung der anisotropen Filterung möglicherweise die Breite des Rahmens erhöhen müssen. Dies liegt daran, dass anisotrope Filterung die Größe der Probenumgebung bei extremen Winkeln erhöht.
Um zu veranschaulichen, was ich mit einem Rand um den Rand jeder Textur meine, betrachten Sie die verschiedenen in OpenGL verfügbaren Umbruchmodi. Achten Sie besonders darauf
CLAMP TO EDGE
.Obwohl es einen Modus namens "Clamp to Border" gibt, ist dies eigentlich nicht das, woran wir interessiert sind. In diesem Modus können Sie eine einzelne Farbe definieren, die als Rand um Ihre Textur für alle Texturkoordinaten verwendet werden soll, die außerhalb der normalisierten [0.0 -1,0] Bereich.
Was wir wollen, ist das Verhalten zu replizieren
CLAMP_TO_EDGE
, bei dem jede Texturkoordinate außerhalb des richtigen Bereichs für die (Unter-) Textur den Wert des letzten Texelzentrums in der Richtung erhält, in der es außerhalb der Grenzen lag. Da Sie fast die vollständige Kontrolle darüber haben Die Texturkoordinaten in einem Atlas-System. Das einzige Szenario, in dem sich (effektive) Texturkoordinaten auf einen Ort außerhalb Ihrer Textur beziehen, ist der gewichtete Durchschnittsschritt der Texturfilterung.Wir wissen, dass
GL_LINEAR
die 4 nächsten Nachbarn wie im obigen Diagramm dargestellt abgetastet werden, daher benötigen wir nur einen 1-Texel-Rand. Wenn Sie eine anisotrope Filterung verwenden, benötigen Sie möglicherweise einen breiteren Texelrand, da dies unter bestimmten Bedingungen die Größe der Probenumgebung erhöht.Hier ist ein Beispiel für eine Textur, die den Rand deutlicher darstellt. Für Ihre Zwecke können Sie den Rand jedoch 1 Texel oder 2 Texel breit machen.
(HINWEIS: Der Rand, auf den ich mich beziehe, ist nicht das Schwarz an allen vier Bildrändern, sondern der Bereich, in dem sich das Schachbrettmuster nicht mehr regelmäßig wiederholt.)
Falls Sie sich gefragt haben, hier ist, warum ich immer wieder anisotrope Filterung anspreche. Es ändert die Form der Probenumgebung basierend auf dem Winkel und kann dazu führen, dass mehr als 4 Texel zum Filtern verwendet werden:
http://www.arcsynthesis.org/gltut/Texturing/ParallelogramDiag.svg
Je größer der von Ihnen verwendete Anisotropiegrad ist, desto wahrscheinlicher ist es, dass Sie sich mit Beispielvierteln befassen müssen, die mehr als 4 Texel enthalten. Ein 2-Texel-Rand sollte für die meisten anisotropen Filtersituationen ausreichend sein.
Last but not least wird hier ein gepackter Texturatlas erstellt, der das
GL_CLAMP_TO_EDGE
Verhalten bei Vorhandensein einesGL_LINEAR
Texturfilters repliziert :( Subtrahiere 1 von X und Y in den schwarzen Koordinaten, ich habe das Bild vor dem Posten nicht Korrektur gelesen. )
Aufgrund der Randspeicherung erfordert das Speichern von 4 256x256-Texturen in diesem Atlas eine Textur mit den Abmessungen 516x516. Die Ränder sind farbcodiert, je nachdem, wie Sie sie während der Atlaserstellung mit Texeldaten füllen würden:
In diesem gepackten Beispiel verwendet jede Textur im Atlas effektiv einen Bereich von 258 x 258 des Atlas. Sie generieren jedoch Texturkoordinaten, die dem sichtbaren Bereich von 256 x 256 zugeordnet sind. Die angrenzenden Texel werden immer nur verwendet, wenn die Texturfilterung an den Rändern der Texturen im Atlas durchgeführt wird und die Art und Weise, wie sie entworfen wurden, das
GL_CLAMP_TO_EDGE
Verhalten nachahmt .Falls Sie sich gefragt haben, können Sie andere Arten von Umbruchmodi mit einem ähnlichen Ansatz implementieren. Dies
GL_REPEAT
kann durch Austauschen der Texel für den linken / rechten und oberen / unteren Rand im Texturatlas und ein wenig cleverer Texturkoordinatenmathematik in a implementiert werden Shader. Das ist etwas komplizierter, also mach dir vorerst keine Sorgen. Da Sie nur mit Sprite-Sheets zu tun haben, beschränken Sie sich aufGL_CLAMP_TO_EDGE
:)quelle