HLSL - Viele Texturen zeichnen



  • Hi! Ich habe mich nun schon eine weile mit Shadern beschäftigt, Ob Licht, schatten oder Texturing, bisher hat alle wunderbar geklappt. Nun stehe ich aber vor dem Problem, dass ich sehr viele Texturen habe, um die 100, die ich alle mit Pixel Shadern auf den Bildschirm zaubern möchte. Das ganze kann man sich wie eine kleine 2D Engine vorstellen, die mit Shadern arbeitet. Das ganze soll mit PostProcessing laufen, da es 2D ist, und ich die Transformationsmatrix dafür nicht benötige, sondern nur den Bildschirm den Bildschirm ändern muss, ist dies optimal! Bisher habe ich immer nur 2-3 Texturen benutzt, die auch immer gleich waren, so konnte ich alles über einen aufruf realisieren. Nun frage ich mich aber, wie ich mehr mal den Shader aufrufen kann, sodass ich bei jedem aufruf eine Textur auf den Bildschirm zeichne! Ist dies überhaupt möglich, oder giebt es für soetwas andere Möglichkeiten?



  • Nun stehe ich aber vor dem Problem, dass ich sehr viele Texturen habe, um die 100, die ich alle mit Pixel Shadern auf den Bildschirm zaubern möchte. Das ganze kann man sich wie eine kleine 2D Engine vorstellen, die mit Shadern arbeitet. Das ganze soll mit PostProcessing laufen, da es 2D ist, und ich die Transformationsmatrix dafür nicht benötige, sondern nur den Bildschirm den Bildschirm ändern muss, ist dies optimal! Bisher habe ich immer nur 2-3 Texturen benutzt, die auch immer gleich waren, so konnte ich alles über einen aufruf realisieren

    Ich sehe darin leider keinerlei konkrete Information.

    Nun frage ich mich aber, wie ich mehr mal den Shader aufrufen kann, sodass ich bei jedem aufruf eine Textur auf den Bildschirm zeichne!

    Ich denke, dass Du das Konzept von "Shadern" noch nicht begriffen hast.

    Erklaere bitte nochmal in kurzen und verstaendlichen Saetzen, was Du genau erreichen willst und wie Du bisher dazu vorgehst.



  • Ereichen möchte ich, das ich mittels Shader mehrere Texturen auf den Bildschirm zeichnen kann. Das Problem dabei ist, das es ehr viele Teturen sind! Im prinziep stelle ich mir das so vor, das der Shader als Input eine Textur bekommt, und diese Zeichnet er dann auf den bildschirm. Anschließend wird der Shader nochmals ausgeführt, und bekommt als Input eine andere Textur, das geht dann immer so weiter bi alle Texturen gezeichnet sind. Soweit ich weiß kann ein Shader aber nur einmal pro zeichenvorgang ausgeführt werden, darum stelle ich mir die frage, wie ich dies nun realisieren könnte.



  • Soweit ich weiß kann ein Shader aber nur einmal pro zeichenvorgang ausgeführt werden, darum stelle ich mir die frage, wie ich dies nun realisieren könnte.

    Indem Du den Zeichenvorgang mehrmals ausfuehrst.
    Das nennt sich dann Multipass-Rendering und ist gewissermassen das Gegenteil von Shadern.
    Welche Aufgabe soll Dein Shader denn ueberhaupt erfuellen?



  • Vielleicht passts ja, weil ich momentan ein einem ähnlichen Projekt arbeite (nämlich auch 2D mit Postprocessing):

    Wir machen das so, dass wir alle statischen Tiles in der Szene, die dieselbe Textur, Effect, Blendingmode, Color, Effect-Params benutzen, in 1 Vertexbuffer sammeln und dann in einem Rutsch rendern. (Tiles können bei uns mit verschiedenen Effects gerendert werden, für Normalmapping, metallische Reflexionen, Hitzeflirren etc) Das wird für alle Tile-Typen pro Layer wiederholt.
    Wenn du den Layer in eine Textur renderst, lassen sich dann Postprocessing-Effekte einfach auf den Layer als ganzes anwenden. In unserem Fall sind das Saturation, Colorshift und Fog.

    Wir rendern außerdem alle Layer inklusive dem "Game"-Layer (auf dem sich die Spielfiguren bewegen) in eine Textur, damit wir in einem weiteren Pass Verzerr-, Spiegeleffekte etc auf die gesamte sichtbare Szene anwenden können. Theoretisch kann man im Vordergrund noch weitere Layer setzen, wenn diese vor diesen Verzerreffekten etc angezeigt werden sollen, also davon nicht beeinflusst werden.

    Das System klappt eigentlich ziemlich gut. So sieht unser Projekt momentan aus:
    http://video.msn.com/video.aspx?mkt=de-de&vid=4f540683-aabf-40e7-99d5-fc1bcfd4cb00
    Also das Postprocessing für schönes Lighting zahlt sich wirklich aus, finde ich. Das Zielsystem ist Xbox 360, also gehen wir einfach mal von einer potenten Grafikkarte aus, die das auch schafft 🙂

    Meinst du sowas?



  • Wow, das habt ihr gemacht? Ich bin beeindruckt! Genau soetwas versuche ich zu machen. Ich habe für meine kleine Engine eine GUI geschrieben, sie funktioniert auch ganz gut, nur benutze ich momentan Sprites um die GUI zu rendern, und dies bietet wie ich finde für meine Zwecke einfach nicht genug funktionalität und ist einfach unprofessionel. Danke für die Antwort, leider kann ich im Internett keine Artikel zu Multipass-Rendering finden, und die Foren suche hilft mir leider auch nicht weiter 😞



  • Ich glaube ich habe es hin bekommen, zwar zeichne ich auf zwei verschiedenen Streams, aber es funktioniert, happy 🙂

    UINT Passes;
    	Effect->SetTechnique("T1");
    
    	Effect->SetTexture("Texture1", Textur0);
    	Effect->Begin(&Passes, 0);
        Effect->BeginPass(0);
    
    	Direct3DDevice->SetStreamSource(0, VertexBuffer1, 0, sizeof(CUSTOMVERTEX));
    	Direct3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
    
    	Effect->EndPass();
    
    	Effect->SetTexture("Texture1", Textur1);
    
    	Effect->BeginPass(0);
    
    	Direct3DDevice->SetStreamSource(0, VertexBuffer2, 0, sizeof(CUSTOMVERTEX));
    	Direct3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
    
    	Effect->EndPass();
    	Effect->End();
    

    Was ich hier mache, ist das ich zwei VertexBuffer habe, und auf beiden möchte ich unterschiedliche Texturen zeichnen. Der Shader macht nichts andere, als eine Textur auf das Quad zu legen. Zuerst setze ich die Technique die ich benutzen will, mein Shader hat davon nur eine. Anschließend setze ich die erste Textur und zeichne das Quad. Danach mache ich das selbe, nur das ich eine andere Textur setze. Das ganze ist ganz bestimmt nicht die beste möglichkeit, zumal ich VertexBuffer benutze, was wie ich finde für 4 Vertices völlig überflüssig ist.

    Aber wegen den Passes, ist dies damit gemeint? Ich habe ein wenig experimentiert, und das ist bisher die einzige funktionierende möglichkeit die ich gefunden habe. Es würde mich freuen wenn ihr mir ein paar Tipps geben könntet.



  • Ja, genau, anders gehts auch nicht 🙂
    Wenn du jetzt noch eine Möglichkeit hast, mehrere Tiles, die alle die gleiche Textur etc benutzen, in einen großen Vertexbuffer zusammenzufassen, dass du nicht lauter einzelne Quads renderst und u.U. oft redundante States setzt (wie Texturen und Blending), dann kannst du performancemäßig einiges rausholen.
    Klarerweise liegts auch immer an den Artists, je mehr unterschiedliche Tiles die verwenden, desto weniger lässt sich zusammenfassen zu großen Batches 🙂 Dank dem Postprocessing kommen wir aber mit sehr wenigen Tiles aus, die sich auch sehr gut zwischen Levels wiederverwenden lassen, da wir sie dank Normalmapping rotieren können wie wir wollen, das Lighting passt immer, und unterschiedliches Color Grading sorgt auch dafür, dass es nicht zu repetitiv wird, bzw man die selben Tiles in Vordergrund und Hintergrund benutzen kann, und sie trotzdem komplett anders wirken.

    Bei uns wird übrigens das Batching für die Xbox explizit im Level Editor gemacht und dann als eigene Datei zum Level dazugespeichert. Am PC machen wirs on-the-fly beim Level-Laden im Game-Modus. Im Editor-modus rendern wir nach wie vor jedes Tile einzeln als eigenen Vertexbuffer. Wir benutzen dabei immer dasselbe Quad für alle Tiles (Unit size von -1 bis 1), und platzierens mit einer entsprechenden World Matrix, auf modernen Grafikkarten macht das bei ~100 sichtbaren Tiles performancemäßig wenig Unterschied. Also du musst dich nicht sofort ins Optimieren stürzen 🙂

    Mit klassischem "Multipass-Rendering" hat das eigentlich nicht wirklich was zu tun, das beschreibt normalerweise die Technik, dasselbe Objekt mehrmals in mehreren Passes (z.B. mit Blending) zu rendern, um aufwendigen Effekte auf dem Objekt zu zeichnen, die sich aus irgendeinem Grund (eben weil z.B. mehr als 8 unterschiedliche Texturen benötigt werden) nicht in 1 Pass gezeichnet werden können.
    Gutes Beispiel sind die ganzen älteren Quake- und Unreal-Spiele, die hatten oft so glowende Rollover-Effekte oder Detail-Maps, die sich alle nicht in 1 Pass zusammen mit der Basistextur und der Lightmap rendern ließen, weil damals nur 2 Textureinheiten möglich waren. Da wurde dann der Glow oder die Detailmap in einem 2. Pass über das bereits "normal" gerenderte Polygon drübergerendert.

    EDIT: Da gibts einen ganz netten Artikel auf Gamasutra dazu, wie das bei Braid gelöst wurde. Dort wurde viel mit sanftem Alphablending gearbeitet, um aus wenigen sich überlappenden Tiles großes homhgene Flächen zu bauen, die trotzdem extrem detailliert sind und keine offensichtlichen Wiederholungen haben.



  • Dann bin ich ja froh! Nun habe ich aber doch noch eine Frage! Im moment mache ich das zeichnen so, das ich die Texturen in Poligonen rendere, in zwei Dreiecken. Biher habe ich die Textur immer mit den DX funktionen geziechnet. Ist es schneller, wenn ich die textur aber mit einem Shader zeichne, oder ist die DX variante dafür dann doch empfehlenswerter?



  • Ich denke D3DXSprite wird auch nichts anderes machen als aus jeweils 2 Dreiecke Quads zu bauen. Wobei da vielleicht schon irgendein Batching eingebaut ist, falls man mehrere Sprites auf einmal rendern will. Ich hab mich mit den D3DX-Utils nie wirklich beschäftigt.


Anmelden zum Antworten