2012-04-04 9 views
0

Ich versuche, einen Tiefenschärfe-Post-Prozess zu erstellen, habe aber keine Ahnung, wo ich anfangen soll (außer Render-Tiefen-Map, wo ich gerade bin). Alle Tutorials dafür sind entweder für XNA3.1, geben Ihnen keine Erklärung oder Teil eines Buches.C#/XNA/HLSL - Wie erstellt man Schärfentiefe?

Können Sie also einen detaillierten Schritt-für-Schritt-Prozess für die Darstellung von DOF durchführen?

Antwort

8

Hier finden Sie eine Beschreibung, wie Sie mithilfe der von XNA innerhalb des Reach-Profils bereitgestellten "Out of the Box" -Funktionen eine grundlegende Annäherung erreichen können.

Sobald Sie in C# mit dem integrierten Material fertig sind, wird es hoffentlich ein wenig deutlicher, es in HLSL zu erreichen.

Wenn Sie jemals ein Spiel für Windows Phone 7 erstellen möchten, können Sie auch beginnen (da Windows Phone 7 zu diesem Zeitpunkt keine benutzerdefinierten Shader unterstützt).

Zuerst werden wir einige Instanzebene Variable definieren die Bits und Stücke, die wir um das Aussehen produzieren müssen halten:

BasicEffect effect; 
List<Matrix> projections; 
List<RenderTarget2D> renderTargets; 
SpriteBatch spriteBatch; 

Als nächstes wird in der Loadcontent() -Methode, beginnen wir werden sie bis zu laden. Beginnend mit einem Spritebatch, dass wir die letzte Szene verwenden werden, machen:

spriteBatch = new SpriteBatch(GraphicsDevice); 

durch eine Instanz von BasicEffect Gefolgt:

effect = new BasicEffect(GraphicsDevice); 
effect.EnableDefaultLighting(); 
effect.DiffuseColor = Color.White.ToVector3(); 
effect.View = Matrix.CreateLookAt(
      Vector3.Backward * 9 + Vector3.Up * 9, 
      Vector3.Zero, 
      Vector3.Up); 
effect.World = Matrix.Identity; 

effect.Texture = Content.Load<Texture2D>("block"); 
effect.TextureEnabled = true; 
effect.EnableDefaultLighting(); 

Die Besonderheiten, wie der Basiseffekt konfiguriert ist, sind nicht wichtig hier. Nur dass wir einen Effekt haben, mit dem wir rendern können.

Als nächstes werden wir ein paar Projektionsmatrizen müssen:

projections = new List<Matrix>() { 
     Matrix.CreatePerspectiveFieldOfView(
     MathHelper.ToRadians(60f), 
     GraphicsDevice.Viewport.AspectRatio, 
     9f, 
     200f), 
    Matrix.CreatePerspectiveFieldOfView(
     MathHelper.ToRadians(60f), 
     GraphicsDevice.Viewport.AspectRatio, 
     7f, 
     10f), 
    Matrix.CreatePerspectiveFieldOfView(
     MathHelper.ToRadians(60f), 
     GraphicsDevice.Viewport.AspectRatio, 
     0.2f, 
     8f)}; 

Wenn Sie die letzten beiden Parameter jedes Vorsprungs untersuchen, werden Sie feststellen, was wir hier effektiv tun, die Welt spaltet in "Brocken" auf, wobei jeder Brocken eine andere Entfernung von der Kamera abdeckt.

z.B. alles ab 9 Einheiten, alles zwischen 7 Einheiten und 10 Einheiten von der Kamera und schließlich etwas näher als 8 Einheiten.

(Sie müssen diese Abstände zwicken auf der Szene abhängig Bitte beachten Sie die kleine Menge an Überlappung.)

Als nächstes werden wir einige Ziele machen erstellen:

var pp = GraphicsDevice.PresentationParameters; 

renderTargets = new List<RenderTarget2D>() 
{ 
    new RenderTarget2D(GraphicsDevice, 
     GraphicsDevice.Viewport.Width/8, 
     GraphicsDevice.Viewport.Height/8, 
     false, pp.BackBufferFormat, pp.DepthStencilFormat), 

     new RenderTarget2D(GraphicsDevice, 
     GraphicsDevice.Viewport.Width/4, 
     GraphicsDevice.Viewport.Height/4, 
     false, pp.BackBufferFormat, pp.DepthStencilFormat), 

    new RenderTarget2D(GraphicsDevice, 
     GraphicsDevice.Viewport.Width, 
     GraphicsDevice.Viewport.Height, 
     false, pp.BackBufferFormat, pp.DepthStencilFormat), 
}; 

Jedes Renderziel entspricht zu einem bereits erwähnten "Brocken". Um einen wirklich einfachen Blur-Effekt zu erzielen, wird jedes Render-Ziel auf eine andere Auflösung eingestellt, wobei der "weiteste" Chunk eine niedrige Auflösung und der nächste Chunk eine hohe Auflösung ist.

Springen hinüber zum Draw() -Methode können wir unsere Szene Brocken machen:

 effect.Projection = projections[0]; 
     GraphicsDevice.SetRenderTarget(renderTargets[0]); 
     GraphicsDevice.Clear(Color.Transparent); 
     // render scene here 

     effect.Projection = projections[1]; 
     GraphicsDevice.SetRenderTarget(renderTargets[1]); 
     GraphicsDevice.Clear(Color.Transparent); 
     // render scene here 

     effect.Projection = projections[2]; 
     GraphicsDevice.SetRenderTarget(renderTargets[2]); 
     GraphicsDevice.Clear(Color.Transparent); 
     // render scene here 

     GraphicsDevice.SetRenderTarget(null); 

So (sicher zu sein, nicht den Hintergrund in jedem Klumpen zu machen) jetzt haben wir unsere Szene bekommen, gebrochen Nach oben und von der Ferne verschwommen, bleibt uns nur noch, es für unser endgültiges Bild wieder zusammenzufügen.

Erster Schritt, machen den (super) Hintergrund:

GraphicsDevice.Clear(Color.CornflowerBlue); 

Next jeden Brocken machen, aus weiter zum nächsten:

spriteBatch.Begin(
     SpriteSortMode.Deferred, 
     BlendState.AlphaBlend, 
     SamplerState.AnisotropicClamp, 
     null, null); 

    spriteBatch.Draw(renderTargets[0], GraphicsDevice.Viewport.Bounds, Color.White); 
    spriteBatch.Draw(renderTargets[1], GraphicsDevice.Viewport.Bounds, Color.White); 
    spriteBatch.Draw(renderTargets[2], GraphicsDevice.Viewport.Bounds, Color.White); 

    spriteBatch.End(); 

und Viola! Wir haben ein, wenn auch etwas rauh um die sprichwörtlichen Kanten, Approximation der Tiefenschärfe.

Wenn Sie nun planen, innerhalb des Reach-Profils zu bleiben, können Sie den Unschärfeeffekt verbessern, indem Sie jeden Block mit mehreren Auflösungen rendern und die resultierenden Bilder mit etwas wie dem Additiv BlendState kombinieren.

Wenn Sie andererseits planen, benutzerdefinierte Shader im HiDef-Profil zu schreiben, sind die Konzepte in etwa gleich, nur die Ausführungsmethode ändert sich.

Zum Beispiel, um das niedrig aufgelöste Rendering für eine authentischere Gauß'sche Unschärfe zu vertauschen ... oder ... die grobkörnige Idee von Brocken zu verwischen und zu der relativ feinkörnigen Methode der Unschärfe zu gelangen, die auf einer Tiefenkarte basiert.