| |
XMR1 Member
Anmeldedatum: 28.04.2010 Beiträge: 1209 Wohnort: Bayern
|
Verfasst am: 06.05.2012, 15:08 Titel: [Problem]RenderTarget2D zum Cachen verwenden |
|
Hallo,
ich versuche mich gerade daran, RenderTargets zum cachen von Controls zu verwenden.
Ich schreibe das ganze für WP7 und somit mit dem Reach Profil.
Im Prinzip habe ich meine Controls (Button/Graph/..), die einmal in das RenderTarget gerendert werden sollen und anschließend wird das RenderTarget auf den Bildschirm gerendert.
Besonders bei Graphen führt das zu Verbesserung der Performance und ich kann dadurch auch recht einfach komplexere Animationen auf alle möglichen Controls anwenden.
Bei jeder Veränderung des Controls wird das RenderTarget neu gefüllt und dann wieder ganz normal gezeichnet.
Mein Problem ist, dass es zu kurzem blinken des Bildschirms kommt, wenn sich ein Control ändert.
Ich habe auch schon ein kleines Testprojekt erstellt.
Im Prinzip würde ich gerne so rendern:
| Code: | GraphicsDevice.Clear(Color.CornflowerBlue);
// irgendwas zeichen
Controls.Render(); // zeichnet die Controls
// noch mehr zeichnen |
Das Rendering der Controls sieht so aus:
| Code: |
void Render()
{
if (IsDirty)
{
device.SetRenderTarget(Cache);
// fill rendertarget
IsDirty = false;
device.SetRenderTarget(null);
}
// eigentliches zeichnen
batch.Begin();
batch.Draw(Cache, Pos, Color.White);
batch.End();
}
|
Im Idealfall wird das RenderTarget genau 1x erstellt und es muss nur der Cache gezeichnet werden.
Das Problem ist, dass der ganzen Bildschirm jedes mal kurz lila flackert, wenn ich den Cache erneuere.
Das kann ich umgehen, indem ich oben nach
| Code: | | device.SetRenderTarget(null); |
noch ein
| Code: | | device.Clear(Color.CornflowerBlue); |
einfüge. Dann flackert nicht mehr der ganze Bildschirm sondern nur noch alle anderen Controls, die zuvor gerendert wurden.
Verwende ich die RenderTargets etwa gänzlich falsch?
Die einzige Lösung die mir einfällt, wäre, das ganze in 2 Pässen zu machen: Erst alle Controls Cachen/updaten, und dann in einem weiteren Pass auf den Bildschirm zeichnen.
(Ich habe auch schon versucht den BackBuffer zu umgehen und statt diesem ein eigenes RenderTarget zu verwenden, das führt aber zu den gleichen Problemen..) _________________ Webseite | marc.stanglmayr.de
Blog | blog.mastasoftware.net
studentpartners.de |
|
| Nach oben |
|

|
Astror Enales XNA.mag - Team
Anmeldedatum: 20.08.2007 Beiträge: 790
|
Verfasst am: 07.05.2012, 10:47 Titel: |
|
Hm, das klingt sehr merkwürdig. Das einzige was mir spontan bei deinem Code eingefallen ist, clear doch mal vor dem Rendering im Target den screen mit transparenz:
| Code: | device.SetRenderTarget(Cache);
GraphicsDevice.Clear(Color.Transparent);
// fill rendertarget
IsDirty = false;
device.SetRenderTarget(null); |
Hierbei beachten, das alpha blending eingeschaltet ist, sonst hast du einen schwarzen Hintergrund!
Hab hier leider grad kein Xna, nur OpenGL zum testen... _________________ Blog: http://blog.ac-games.de
Working on: Delta Engine | ANX.Framework | AC.AL |
|
| Nach oben |
|

|
XMR1 Member
Anmeldedatum: 28.04.2010 Beiträge: 1209 Wohnort: Bayern
|
Verfasst am: 07.05.2012, 20:34 Titel: |
|
Das clearen hab ich schon gemacht, das hab ich durch den Kommentar ersetzt.
Was ich letzlich erreichen will ist:
| Code: |
GraphicsDevice.SetRenderTarget(Target);
GraphicsDevice.Clear(Color.CornflowerBlue); // jetzt ist Target blau
GraphicsDevice.SetRenderTarget(null);
// jetzt könnte ich es zeichnen (und es wäre auch blau)
GraphicsDevice.SetRenderTarget(Target); // das hier ist das "Problem"
GraphicsDevice.SetRenderTarget(null);
// jetzt will ich es zeichnen, aber dadurch, dass ich es erneut als RenderTarget auf dem GraphicsDevice gesetzt habe ist es wieder Lila geworden.
|
Ich habe den Parameter RenderTargetUsage.PreserveContents gefunden, der genau das tut - das RenderTarget wird nicht explizit gecleared.
Trotzdem danke für die Hilfe. _________________ Webseite | marc.stanglmayr.de
Blog | blog.mastasoftware.net
studentpartners.de |
|
| Nach oben |
|

|
giniedp Member
Anmeldedatum: 29.06.2011 Beiträge: 308 Wohnort: Kiel
|
|
| Nach oben |
|

|
XMR1 Member
Anmeldedatum: 28.04.2010 Beiträge: 1209 Wohnort: Bayern
|
Verfasst am: 07.05.2012, 22:03 Titel: |
|
Na toll, das ist fürs Phone.
Denke ich dann völlig falsch, oder wieso erscheint mir mein gewünschtes Verhalten anders nicht möglich?
Ich will letzlich so zeichnen können:
| Code: |
// jede dieser Komponenten ist losgelöst von der anderen und sie können in unterschiedlichster Reihenfolge gezeichnet werden
// z.B. FPS Counter, Debug Output und Game Gui
componentA.Draw();
componentB.Draw();
componentC.Draw();
|
Die Draw Methode jeder Komponente sollte so aussehen:
| Code: |
void Draw()
{
if (IsDirty)
{
UpdateCache(); // in meinem Fall: renderTarget füllen
IsDirty = false;
}
DrawCached(); // renderTarget als Textur auf den Bildschirm zeichnen
} |
Ich will also immer das gecachte zeichnen, außer der Cache ist ungültig, dann will ich ihn vorher aktualisieren.
Mein Problem ist, dass (wegen dem oben gezeigten Standardverhalten von RenderTargets) dieses immer Lila gefüllt wird, wenn man es aufs GraphicDevice setzt.
Folglich kommt es beim aktualisieren immer zu (unerwünschtem) flackern!
Irgendwer eine Idee wie man das richtig machen könnte? _________________ Webseite | marc.stanglmayr.de
Blog | blog.mastasoftware.net
studentpartners.de |
|
| Nach oben |
|

|
Astror Enales XNA.mag - Team
Anmeldedatum: 20.08.2007 Beiträge: 790
|
Verfasst am: 07.05.2012, 22:26 Titel: |
|
Wenn ich das jetzt richtig verstanden habe, willst du bei jeder Komponente checken, ob diese Dirty ist und dann diese neu in das Target rendern. Das erscheint mir keine gute Lösung zu sein. Lieber solltest du direkt checken ob ein Control Dirty ist und dann in diesem Falle alle Controls neu in den Cache zeichnen. Wenn sich nämlich z.b. 10 Controls pro Tick ändern, dann hast du 10 RenderTarget switches und 10 Render-Durchläufe des Spritebatch. Das erscheint mir nicht ratsam. _________________ Blog: http://blog.ac-games.de
Working on: Delta Engine | ANX.Framework | AC.AL |
|
| Nach oben |
|

|
giniedp Member
Anmeldedatum: 29.06.2011 Beiträge: 308 Wohnort: Kiel
|
Verfasst am: 07.05.2012, 22:52 Titel: |
|
Hast Du wirklich so viele "teure" Komponenten die es wert sind diese Optimierung zu betreiben? Falls ja, dann ist das vermutlich nicht mit den Rendertargets zu lösen, wie Astor schon sagte. Eine andere Idee die mir in de Sinn kommt ist folgende:
Du musst Dir merken welcher Bereich vom Bildschirm "dirty" ist und dann nur diesen Bereich rendern. Beim Rendern gehst Du durch alle Componenten. Vor dem Zeichnen sagst Du aber dem Graphicsdevice welcher Ausschnitt vom Bildschirm tatsächlich gerendert werden soll. Ich glaub dafür musst Du das scissor rectangle setzen. Wenn ich mich recht entsinne, macht das auch die SpriteBatch. |
|
| Nach oben |
|

|
XMR1 Member
Anmeldedatum: 28.04.2010 Beiträge: 1209 Wohnort: Bayern
|
Verfasst am: 07.05.2012, 22:53 Titel: |
|
Edit: giniedp's Ansatz erscheint auch nicht schlecht.
Allerdings würde sich das nur für die Graphen lohnen.
Den Vorteil den ich in den RenderTargets sehe ist, dass ich (wie unten beschrieben) leicht Animationen auf sämtliche UI Controls anwenden kann.
----- Edit: Ende -----
Ja, das hab ich im letzten Post falsch ausgedrückt.
Jede Komponente hat ein beliebiges Set zu zeichnen, u.a. Controls.
Jedes Control hat natürlich seinen eigenen Cache (nicht die ganze Komponente).
Dabei kommt es u.U. - wie Astror Enales gesagt hat - dazu, dass man eventuell 10 Controls gleichzeitig neu rendern muss.
Das sollte aber eher selten sein, da so Sachen wie Opacity/Verschiebung/Rotation alle auf das gecachte RenderTarget angewandt werden können.
So muss sich ein Label z.B. nur neu Zeichnen, wenn sich der Text ändert.
Bei kleinen Buttons und Labels macht es an sich weniger Sinn mit RenderTargets zu cachen, aber es wird auch Graphen geben, bei denen man ohne RenderTargets halt jedes mal erneut LinienSets rendern müsste.
Daher die Idee, diese in RenderTarget zu packen und das dann zu rendern.
Ich hab das halt gleich in die Base Klasse "UiControl" gepackt, damit alle UI Controls vom Caching profitieren können.
Und ich kann somit einheitliche Effekte leicht überziehen (ich packe das RenderTarget, das jetzt jedes Control besitzt um sich selbst zu repräsentieren und kann es ganz leicht rotieren/skalieren/ausfaden/etc. Das ist mit einem LinienSet/Text/zusammengesetzten Control natürlich schwieriger).
Das ganze war für das Hauptmenü gedacht und nicht das Spiel selber, sogesehen mach ich mir nicht die großen Performanceprobleme, aber ich will halt dieses flackern wegkriegen, weil das deutlich nervt.
Und die einzige Möglichkeit wie ich das geschafft habe ist, indem ich einmal für alle Controls den Cache erneuere (wenn nötig) und in einem zweiten Durchlauf erst auf den Bildschirm zeichne, aber das erscheint mir halt nicht also "richtige" Lösung. _________________ Webseite | marc.stanglmayr.de
Blog | blog.mastasoftware.net
studentpartners.de |
|
| Nach oben |
|

|
|
|
|