[OpenGL] Texture Wrap Mode für einzelne Primitives

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

[OpenGL] Texture Wrap Mode für einzelne Primitives

Beitrag von BeRsErKeR »

Hallo ich stehe gerade etwas auf dem Schlauch. Ich bin leider auch nicht der Vollblutprofi was Grafikprogrammierung angeht.

Was tue ich?

Ich zeichne mit OpenGL eine tile-based map aus einem Textureatlas (große Textur, die alle Tiles enthält). Ich verwende zwei VBO, eins für die Vertexdaten und eins für die Texturkoordinaten. Am Ende wird alles mit DrawArrays auf den Schirm gezaubert. So weit so gut.

Mein Problem:

Ich möchte nun auch Teile von Tiles anzeigen. Grundlegend die 4 Quadranten. Also z.B. nur den oberen linken Abschnitt. Das bekomme ich noch über die Texturkoordinaten hin. Nun möchte ich allerdings auch ermöglichen, dass der obere linke Teil 2 mal nebeneinander angezeigt wird. Also quasi eine Wiederholung eines Tile-Teils. Das würde prinzipiell gehen, wenn ich GL_TEXTURE_WRAP_S bzw. GL_TEXTURE_WRAP_T auf GL_REPEAT setze. Der Haken an der Sache ist, dass ich diesen Wert nur global setzen kann und nicht spezifisch für eine Anzahl von Vertices bzw. Primitives (ich nutze ja DrawArrays). Oder gibt es da eine Möglichkeit?

Was will ich erreichen?

Im Prinzip soll der Anwender nicht nur Tiles befüllen können sondern pro Tile noch weitere Dinge festlegen können:
- X-Offset bzw. Y-Offset innerhalb des Tiles (-half tile size, 0, +half tile size)
- Breite und Höhe innerhalb des Tiles (half tile size oder full tile size)
- Repeat des Tile-Teils (falls kein Voll-Tile)
- Spiegeln an X- und Y-Achse (für Voll-Tile oder Tile-Teil)
Tiles können dann auch Leerraum enthalten. Wenn z.B. Repeat aus ist und die Breite/Höhe nur eine halbes Tile beträgt.

Lösung?

Wahrscheinlich versuche ich das einfach auf dem falschen Weg zu lösen. Hab auch schon Shader probiert, aber da komme ich auch nicht wirklich weiter und ich glaube auch nicht, dass die da gut geeignet sind.

Also die Lösung müsste Teile eines Tiles (welches wiederum Teil eines Tileatlas ist) beliebig innerhalb eines Tiles platzieren, wiederholen und auch spiegeln können. Das meiste geht über Texturkoordinaten, aber halt die Einstellung für die Wiederholung nicht.

Kann mir da wer helfen?

Wäre schön wenn ich dafür nicht die Grafik selbst anpassen muss oder Tiles als EInzelgrafiken verarbeiten muss.

Die einzige Lösung, die mir einfällt, wäre alle 4 Quadranten eines Tiles separat als Primitive zu zeichnen. Das vervierfacht aber die Daten und ich würde das gern vermeiden wenn möglich. Zumal ich fürs Repeat dann selbst noch Logik einbauen muss, obwohl es dafür schon ein OpenGL-Feature gibt.
Ohne Input kein Output.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [OpenGL] Texture Wrap Mode für einzelne Primitives

Beitrag von dot »

BeRsErKeR hat geschrieben:Der Haken an der Sache ist, dass ich diesen Wert nur global setzen kann und nicht spezifisch für eine Anzahl von Vertices bzw. Primitives (ich nutze ja DrawArrays). Oder gibt es da eine Möglichkeit?
nope
BeRsErKeR hat geschrieben:Lösung?
Im Shader die Texturkoordinaten passend ausrechnen... ;)
BeRsErKeR hat geschrieben:Also die Lösung müsste Teile eines Tiles (welches wiederum Teil eines Tileatlas ist) beliebig innerhalb eines Tiles platzieren, wiederholen und auch spiegeln können. Das meiste geht über Texturkoordinaten, aber halt die Einstellung für die Wiederholung nicht.

Kann mir da wer helfen?
mod() wird dir helfen... ;)
Benutzeravatar
Sternmull
Establishment
Beiträge: 264
Registriert: 27.04.2007, 00:30
Echter Name: Til
Wohnort: Dresden

Re: [OpenGL] Texture Wrap Mode für einzelne Primitives

Beitrag von Sternmull »

Ich würde sagen das du deine Möglichkeiten schon ganz gut ausgekundschaftet hast. Und ja, der Wrap-Modus von OpenGL beeinflusst nur was passiert wenn auf einem Texel "außerhalb der Textur" zugegriffen wird. Deine Anforderung ist zwar ähnlich, kann damit aber nicht erfüllt werden.
Wenn es um eine 2D-Darstellung geht bei der keine besonderen Filter benötigt werden (also z.B. keine trilineare Filterung), dann würde ich es mit einem Pixelshader versuchen. Dem könntest du die Tilemap auch gleich direkt als Textur übergeben. Der Shader kann dann direkt auf diese Map zugreifen und entscheiden welchen Texel er jetzt wo aus deinem Textur-Atlas lesen muss. Texturfilterung musst du dann allerdings selber implementieren weil die native ja nichts von deinen Tile-Grenzen im Altlas weiß... und dann stumpf zwischen den Texeln von benachbarten Tiles interpoliert, weil sie ja davon ausgeht das alles zusammen hängt. Aber dieses Problem müsstest du ja auch jetzt schon (gelöst) haben. Wenn du deine Tiles immer komplett und mit gleichen Wrap-Modi darstellen würdest, dann könntest du es mit einem Texture-Array statt des Atlas lösen. Aber ein bilinearer Filter sollte sich mit vertretbarem Aufwand nachbauen lassen. Vielleicht willst aber auch gar keinen Filter.
Falls der Shader-Ansatz nicht in Frage kommt (z.B. weil du impotente Hardware unterstützen willst), dann bleibt eigentlich nur noch der Ausweg über Geometrie. Also wirklich ein Quad pro Tile zeichnen.
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [OpenGL] Texture Wrap Mode für einzelne Primitives

Beitrag von BeRsErKeR »

Danke erstmal für eure Antworten.

Also mal zum Verständnis bei der Lösung mit Shader. Sagen wir mal ich will den oberen linken Quadranten eines Tiles 2 mal in x-Richtung anzeigen.

Meine Idee wäre nun die Texturkoordinaten im Vertex-Shader erstmal für den ersten Quadranten zu berechnen und an den Fragment-/Pixel-Shader weiterzureichen (oder direkt im Fragment-Shader?). Dort müsste ich dann basierend auf den Pixel-Koordinaten entsprechend zeichnen (also z.B. bei half_tile_width wieder bei der Texturkoordinate des Quadranten beginnen). Sehe ich das erstmal richtig?

Ich müsste allerdings für jedes Tile (also für jeweils 4 Vertices) die Infos an die Shader weiterreichen, welche Optionen aktiv sind (Offsets, Repeat, Mirror, etc). Das müsste ich dann in Form von Arrays übergeben, nehme ich mal an, da ich Werte ja nur "uniform" an die Shader weiterreichen kann, oder? Also es keine per-vertex-values bzw. per-pixel-values gibt.

Ich bin leider noch nicht so tief drin in der Shader-Materie. Wäre für jeden Schubser in die richtige Richtung dankbar.


@Sternmull: Filter brauche ich nicht und ja es ist reines 2D.
Ohne Input kein Output.
Benutzeravatar
xq
Establishment
Beiträge: 1581
Registriert: 07.10.2012, 14:56
Alter Benutzername: MasterQ32
Echter Name: Felix Queißner
Wohnort: Stuttgart & Region
Kontaktdaten:

Re: [OpenGL] Texture Wrap Mode für einzelne Primitives

Beitrag von xq »

Ich werf jetzt hier mal abseites von den schon angesprochenen Themen eine weiter Idee in den Raum:
Texture2DArray kombiniert mit Instancing. Du hast ein Buffer mit einem einzigen Quad und Texturkoordinaten von (0;0) bis (1;1). Im Instancing-Buffer speicherst du deine Tile-Map mit der Tile-Position (vec2) und der passenden Textur-ID (int oder float)
Damit kannst du dann schön deine Sub-Tiles ohne große Performanceeinbuse machen, wenn du jeder Instanz noch ein Source-Texturquad mitgibst.

Grüße
Felix
War mal MasterQ32, findet den Namen aber mittlerweile ziemlich albern…

Programmiert viel in ⚡️Zig⚡️ und nervt Leute damit.
Benutzeravatar
Krishty
Establishment
Beiträge: 8229
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [OpenGL] Texture Wrap Mode für einzelne Primitives

Beitrag von Krishty »

Beim mod() im Pixel-Shader sollte man die Filterung beachten: http://zfx.info/viewtopic.php?f=5&t=164 ... =15#p20600
Du darfst dir nämlich dann deine eigene foolineare Filterung zusammenbauen …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Sternmull
Establishment
Beiträge: 264
Registriert: 27.04.2007, 00:30
Echter Name: Til
Wohnort: Dresden

Re: [OpenGL] Texture Wrap Mode für einzelne Primitives

Beitrag von Sternmull »

Ok, also ohne Filterung. Das macht die Sache einfacher. Ich würde es wie gesagt nach Möglichkeit komplett im Fragment-Shader lösen. Dort die Tilemap als Textur übergeben. In der würde dann stehen wo welches Tile mit welchen Parametern (Spiegelung, Drehung, ... was weiß ich) angezeigt werden soll. Das wüde ich dann mit einem großen Quad darstellen das alles abdeckt wo die Tilemap gerendert werden soll... also wahrscheinlich Vollbild. In Texturkoordinaten für dieses Quad würde ich die "globale Map-Position" übergeben. Den Integer-Anteil würde ich verwenden um in die Tilemap zu gucken, und den nachkommateil für die Tile-Internen Koordinaten. Oder einfacher gesagt: Für Texturkoordinaten die Tile-Größe als Einheit nehmen.
Wenn du auch auf viertel-Teil-Auflösung arbeiten willst, dann würde ich allerdings diese Größe als Einheit verwenden.
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [OpenGL] Texture Wrap Mode für einzelne Primitives

Beitrag von BeRsErKeR »

@MasterQ32: Hm damit hab ich leider noch keine Erfahrung. Source-Texturequad würde aber nicht reichen, wie angesprochen.

@Sternmull: Ok das klingt vielversprechend. Die internen Koordinaten im Tile brauche ich eigentlich gar nicht mit übergeben. Jedes Tile hat einen 8-Bit Flag-Wert, der alle nötigen Informationen enthält. Daraus kann ich auch die internen Koordinaten bestimmen. Jetzt muss ich nur noch gucken wie ich das ganze performant als Textur in den Shader schubse. Danke erstmal.
Ohne Input kein Output.
Antworten