使用Render Target來拍攝場景

使用Render Target來拍攝場景

Render Target這個詞是在DirectX出現的,XNA同樣的也是沿用這個詞,而用途就是說,現在我們可以設定畫面的輸出位置。通常,我們所指的輸出位置,是指螢幕的部分,現在有了Render Target,我們可以自己設定輸出的位置,像是我們可以輸出到2D貼圖。

如果你有用OpenGL來做這個部分的話,那你可能會聽過一個詞Frame Buffer Object(FBO),這兩個用途是相同的。

而現在我們要做的事情,就是用Render Target將場景畫面輸出到一張2D貼圖上面。

做了這個動作以後,現在可以直接用spritbatch將他畫出來,或是直接用前面所說的VertexBuffer來建立一個平面,在將圖片貼上去顯示。

首先,我們先要將模型先放進虛擬資料夾下(在方案總管中,有一個Content的資料夾)。模型的部分,你可以自己設計,或是到XNA Creator Club上面,有些範例有提供3D模型。

要運用Render Tartget的話,我們需要宣告一個Render Target物件。接下來,我們需要Model和View、projection Matrix。

   1:  Model mModel;
   2:   
   3:  Matrix mView, mProjection;
   4:   
   5:  RenderTarget2D mRenderTarget;

 

而在Initialize的函數中,可以直接建立View和project矩陣,如下

   1:  mView = Matrix.CreateLookAt(new Vector3(0, 40, 80), 
   2:          new Vector3(0,40,0), Vector3.Up);
   3:  mProjection = Matrix.CreatePerspectiveFieldOfView(
   4:          (float)(3*Math.PI / 4), graphics.GraphicsDevice.Viewport.Width / 
   5:          graphics.GraphicsDevice.Viewport.Height, 1.0f, 10000.0f);

 

完成以後,需要在LoadContent的函數中,載入模型,輸入以下程式碼

mModel = Content.Load<Model>("dude");

 

這樣Content Pipeline就會在編譯的時候,將檔案編譯成XNB檔案,方便在runtime中執行。

讀入完成以後,接下來,需要初始化RenderTarget,如下程式碼

   1:  mRenderTarget = new RenderTarget2D(GraphicsDevice, GraphicsDevice.Viewport.Width, 
   2:  GraphicsDevice.Viewport.Height, 1, SurfaceFormat.Color);

 

第一個參數要傳入GraphicDevice

第二個參數設定RenderTarger的寬度

第三個參數設定RenderTarget的高度

第四個參數設定為1即可

第五個參數這邊設定為Color因為我們現在拍攝的是彩色的場景,可能需要依照不同的情況,會設定不同的參數

在Draw的函數中,我們就要進行Render的部分。

首先先將結果Render到Render Target,要做這個步驟,需要將輸出的位置

GraphicsDevice.SetRenderTarget(0, mRenderTarget);

 

這由這樣就可以,將輸出的位置,輸出到mRenderTarget中,第一個參數設定為0

接下來,當你Rander過後,你需要將Reder Target設定為Back Buffer(有設定到Back Buffer後,會畫到螢幕上面)

設定方式

GraphicsDevice.SetRenderTarget(0, null);

 

現在你可以用mRenderTarget中的getTexture()來取得現在畫面中的貼圖。

你可以直接將貼圖結果,用spriteBatch將結果畫出來

   1:  spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.BackToFront,
   2:   SaveStateMode.SaveState);
   3:  spriteBatch.Draw(mRenderTarget.GetTexture(), Vector2.Zero, Color.White);
   4:  spriteBatch.End();

 

結果如下:

image

用SpriteBatch來會出結果是其中一種表現結果的方式,另一種方式是使用前面一篇所教的VertexBuffer和index的方式來畫出來。

1. 宣告下列變數:

   1:  VertexBuffer mVertexBuffer;
   2:  VertexDeclaration mDeclaration;
   3:  VertexPositionColorTexture[] mVertex;
   4:  BasicEffect mEffect;
   5:  short[] mIndex;

 

2. 在Initialize中設定頂點相關資料,這邊需要設定貼圖座標!!

   1:  mVertex = new VertexPositionColorTexture[4];
   2:  mVertex[0].Position = new Vector3(-100, 100, 0);
   3:  mVertex[0].TextureCoordinate = new Vector2(0.0f, 0.0f);
   4:  mVertex[1].Position = new Vector3(-100, -100, 0);
   5:  mVertex[1].TextureCoordinate = new Vector2(0.0f, 1.0f);
   6:  mVertex[2].Position = new Vector3(100, -100, 0);
   7:  mVertex[2].TextureCoordinate = new Vector2(1.0f, 1.0f);
   8:  mVertex[3].Position = new Vector3(100, 100, 0);
   9:  mVertex[3].TextureCoordinate = new Vector2(1.0f, 0.0f);
  10:   
  11:  mDeclaration = new VertexDeclaration(GraphicsDevice, 
  12:   VertexPositionColorTexture.VertexElements);
  13:  mVertexBuffer = new VertexBuffer(GraphicsDevice, 
  14:   VertexPositionColorTexture.SizeInBytes * 4, BufferUsage.WriteOnly);
  15:  mVertexBuffer.SetData<VertexPositionColorTexture>(mVertex);
  16:   
  17:  mIndex = new short[4] { 0, 1, 2, 3 };
  18:   
  19:  mEffect = new BasicEffect(GraphicsDevice, null);
  20:  mEffect.World = Matrix.Identity;
  21:  mEffect.View = mView;
  22:  mEffect.Projection = mProjection;

這邊詳細就不再多多說明...,有需要的話可以往前面看

在Draw的函數中,使用basic effect中來做貼Texture的動作,首先,要先開啟貼圖,然後在設定貼圖,程式碼如下:

   1:  mEffect.TextureEnabled = true;
   2:  mEffect.Texture = mRenderTarget.GetTexture();

 

這樣就可以得到下面的結果

image

有興趣的話可以下載程式碼來看看,也歡迎一起討論這個部分...

Rander Target的部分,被應用在很多地方,像是你可以用來建立Multi Viewport、Deffered Buffer或是Shadow Map等的實作的部分。

程式碼下載