3 Stimmen

Texturierung mit GLSL (in PyOpenGL und Pygame)

Nachdem ich frustriert war, dass die Fixed-Function-Pipeline in Python langsam ist, habe ich angefangen, mich mit Shadern zu beschäftigen, um die Parallaxen-Hintergründe meines Spiels zu zeichnen. Allerdings kann ich keine einfache Möglichkeit finden, zu texturieren, welche Eckpunkte gezeichnet werden.

Ich habe derzeit ein PyOpenGL Vertex Buffer Object mit einem Array von Scheitelpunkten, von denen jeder wie folgt ist: [x, y, z, texX, texY, texID]

Ich übergebe diese an die Shader mit getAttribLocation/glEnableVertexAttribArray. Ich bin nicht sicher, ob es funktioniert, da die Shader derzeit nicht kompilieren, aber die Dinge haben ok mit farbigen Vertices gearbeitet, bevor ich meine wahrscheinlich schreckliche Textur-Code hinzugefügt.

Was ich will, ist ein texturiertes Modell mit einem Shader zu zeichnen, mit mehreren Texturen, aber das Modell ist ein flacher Hintergrund. Es ist ein großes (1600x800 oder so) Bild, das in 256x256 Texturen und Quad-Poly aufgeteilt ist. (Nebenfrage: Ist es besser, mehr kleine Polygone zu haben, so dass weniger Teile des Polygons außerhalb des Bildschirms sind, oder große Polygone, so dass es weniger Textur-Bindung gibt?)

Weil es mehrere, verwandte Texturen ist, möchte ich es alle in den Shader zu tun, ohne die Textur für jeden Chunk auf der CPU zu binden, so dass ich dachte, dass das Senden von Texturdaten mit Vertex-Daten am besten wäre, aber ich kann es nicht bekommen, zu arbeiten.

Könnte jemand bitte geben Sie mir ein einfaches Beispiel für die Vertex und Fragment-Shader interagieren, um mehrere polys mit verschiedenen Texturen zu machen?

EDIT: Shader, Vbo und andere Dinge hier: http://pastebin.com/3LaYiyvh Shader werden jetzt kompiliert, aber Dreiecke sind unsichtbar.

EDITEDIT: Ich habe es geschafft! Bin mir nicht sicher, wie ich es geknackt habe, aber hier ist das Programm: http://pastebin.com/k87sfiEf Ich glaube, es ist so etwas wie, so lange Sie alle Texturen am Anfang binden, kann der Shader zwischen ihnen wechseln. Aber ich bin mir nicht sicher. Auch der Hinweis, es ist eine schlechte Idee, einen großen Hintergrund in kleinere Stücke zu teilen, um zu zeichnen, weil der Austausch von Texturen beim Zeichnen. Große Texturen mit verschwendetem Platz sind in Ordnung, Atlanten sind besser!

2voto

datenwolf Punkte 154484

Nachdem ich frustriert war, dass die Fixed-Function-Pipeline in Python so langsam ist, habe ich angefangen, mich mit Shadern zu beschäftigen, um die Parallaxen-Hintergründe meines Spiels zu zeichnen.

Wenn eine feste Funktion für Sie langsam ist, wird sie durch die Verwendung von Shadern nicht schneller.

Wahrscheinlich machen Sie einfach etwas grundlegend falsch, z. B. den Sofortmodus, oder Sie haben überhaupt keine HW-Beschleunigung (mangels ordnungsgemäß installierter Treiber oder Ähnlichem).

1voto

SigTerm Punkte 25410

Könnte jemand bitte geben Sie mir ein einfaches Beispiel für die Vertex und Fragment-Shader interagieren, um mehrere polys mit verschiedenen Texturen zu machen?

Googeln Sie nach GLSL-Tutorials. Beispiele wurden bereits geschrieben, und es gibt keinen Grund, sie noch einmal für Sie zu schreiben. Oder laden Sie das NVidia OpenGL SDK herunter und untersuchen Sie es. OpenGL.org empfiehlt auch Bücher. Das "Orange Book" behandelt Shader.

die in 256x256 aufgeteilt ist

Traditionell wird empfohlen, das Gegenteil zu tun - nehmen Sie alle Texturen, die Sie können, und kombinieren Sie sie in einem einzigen "Atlas"-Textur, die vorzugsweise etwas wie 16384x16384 ist - zu minimieren Zustand wechseln.

Was ich will, ist ein texturiertes Modell mit einem Shader zu zeichnen, mit mehreren Texturen, aber das Modell ist ein flacher Hintergrund. Es ist ein großes (1600x800 oder so) Bild

1600x800 passen vollständig in die Textur auf so ziemlich jeder Hardware seit Riva TNT 2 pro. Wenn du dich um "verschwendeten" Texturspeicher sorgst, dann unterstützen viele Karten Non-Power-of-2-Texturen. Allerdings haben Non-Power-of-2-Texturen normalerweise Einschränkungen, und auf einige Hardware (bestimmte Ati-Karten + Treiber), die eine solche Textur verwenden, führen zu einem Sturzflug der FPS. D.h. von 200..400 auf 40. Das ist es nicht wert. Auf Hardware mit sogar 256MB VRam sind ungenutzte 40 Prozent der Textur eine Mikrooptimierung. Und dann wiederum könnte man Textur-Atlanten verwenden und den "verschwendeten" Platz mit etwas Nützlichem füllen, wenn man mit der Vram-Nutzung geizt. Denken Sie auch daran, dass Sie nie wissen, wie effizient Fahrer verwendet den Videospeicher.

Ich möchte das alles im Shader machen, ohne die Textur für jeden Chunk auf der CPU binden zu müssen,

Das können Sie nicht tun. Shader binden keine Texturen. Sie verwenden Texturen, die bereits gebunden wurden.

Ich bin nicht sicher, ob es funktioniert, da die Shader derzeit nicht kompiliert werden können,

Dann lassen Sie sie kompilieren und fragen Sie erneut. Es ist nicht möglich, Ihnen zu helfen, ohne Ihren Shader oder Ihre Fehlermeldung zu sehen. Sie wissen doch, dass Shader-Compiler erzeugt Fehlermeldungen richtig?

Nachdem ich frustriert war, weil die Pipeline mit festen Funktionen in Python langsam ist

Erwägen Sie den Wechsel zu einer kompilierten Sprache wie C oder C++. Sie können leicht 200..400 Bilder pro Sekunde mit rohen festen Funktion opengl in C/C++-Anwendung ("Dungeon Crawler") ohne Verwendung von Puffern oder Display-Listen zu bekommen - IF Sie verwenden den richtigen Algorithmus zur Entfernung verdeckter Flächen (und vsync ist deaktiviert) UND Ihre Texturen sind mip-mapped. Bekannte "fixed function" Anwendungen sind Quake 1..3, Half-Life 1, Cube und viele andere Spiele, die rasend schnell sind. Das heißt - wenn es langsam ist, ist es Ihre Schuld.

Im Gegensatz zu C/C++ hat Python einen größeren Overhead für Funktionsaufrufe - das Ausführen von Bytecode, das Extrahieren von Werten unbekannten Typs aus einer Liste/einem Tupel (die/der "alles" enthalten kann) und das anschließende Ablegen als Float in etwas wie glVertex3f, während es schließlich an einen nativen API-Aufruf weitergeleitet wird, wird langsamer sein als ein ähnlicher C/C++-Aufruf, der keine Zwischenschritte hat. Sie können dem entgegenwirken, indem Sie Anzeigelisten oder Pufferobjekte verwenden, aber für mich ist es die Mühe nicht wert. Die Verwendung einer bestimmten Sprache für eine bestimmte Aufgabe ist jedoch eine Frage der persönlichen Vorliebe.

--EDIT--

Aber wenn Shader keine Texturen binden können, wie funktioniert dann Multitexturierung?

Es gibt N Texturstufen (mindestens 2 - siehe glGet/GL_MAX_TEXTURE_COORDS/GL_MAX_TEXTURE_UNITS), Sie setzen mehrere Texturen auf einmal. Siehe glActiveTexture . Ohne Shader (feste Funktion) geben Sie die Farboperation für jede Stufe mit glTexEnv . Mit Shadern legen Sie mehrere Texturen fest und bestimmen, welcher Sampler welche Texturstufe verwendet, indem Sie glUniform1i/glUniform1v und lesen dann mit Sampler2D und ähnlichen Funktionen Daten aus ihnen im Shader. Shader kann keine Texturen wechseln. Er kann Texturen verwenden, die bereits von Ihrem Programm eingestellt wurden. Der Shader hat keine Kenntnis über Texturen außerhalb des Shaders. Technisch gesehen kennt der Shader nicht einmal eine "Textur", er hat einen "Sampler", der zum Lesen von Daten verwendet wird.

Oder Textur-Sampling? Shader müssen in der Lage sein, Texturen auszuwählen/zu verändern...

Shader schaltet oder wählt Texturen überhaupt nicht aus. Dieser Teil wird von Ihrem Programm erledigt. Für weitere Informationen lesen Sie die OpenGL-Spezifikationen und die GLSL-Spezifikationen für Ihre Version von opengl/glsl. Beide stehen auf der Website opengl.org im Menü "Dokumentation" zum Download bereit.

Wie ich schon sagte, brauchen Sie an dieser Stelle ein GLSL-Tutorial oder ein Buch. Beide sind leicht zu finden. Holen Sie sich entweder ein und halten Sie es zu lesen, bis Sie "get" es. Im Moment sieht es nicht so aus, als hättest du deine Hausaufgaben gemacht und versucht, einen einfachen Shader mit Hilfe eines Buches oder Tutorials zu erstellen. Wenn Sie kein Buch finden können, dann NVidia OpenGL SDK hatte viele Beispiele (in C/C++, aber es ist nicht so schwer, sie zu konvertieren).

1voto

Weeble Punkte 15723

Vielleicht finden Sie etwas Nützliches in meinem Minecraft Mapping Blogbeiträge . Alle Beispiele verwenden Python, Pygame und PyOpenGL. Sie machen eine Menge Dinge in einem Fragment-Shader. Sie verwenden nur triviale Geometrie: nur ein Quad.

Nach Ihrer Beschreibung klingt es so, als ob Sie mit einer großen Textur viel besser dran wären als mit mehreren kleinen. Es gibt jedoch Szenarien, in denen es wirklich Sinn macht, viele kleine Texturen zu haben und zwischen ihnen im Shader zu wählen. Array-Texturen können in dieser Situation nützlich sein, da sie nicht die gleichen Probleme mit Filtern und Klammern haben, die bei der Verwendung eines Texturatlasses auftreten können. (In der Tat verwenden die Beispiele in meinem Blog einen Texturatlas und leiden einige Probleme mit Mip-Mapping, wenn zu weit herausgezoomt. Ich habe kürzlich Array-Texturen verwendet, um dieses Problem zu lösen).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X