Using RenderTarget as a texture after drawing on a texture

Page update date :
Page creation date :

Verification environment

Windows
  • Windows 10
  • Windows 11
Visual Studio
  • Visual Studio 2022
MonoGame
  • 3.8.1

About Render Targets

Normally, when you draw, the drawing content is displayed on the screen, but you can use a render target to write the drawing to a texture. The contents written in the texture can be used as a texture as it is. For example, if you write the contents of the TV to a texture and then paste the texture to the TV screen, you can move a different image in the TV. Of course, it can also be used as a still image, and you can create a texture dynamically without preparing an image file for the texture in advance.

Preparing Images

You don't need an image file to use the render target, but I'll prepare an image file to make it easier to understand as a sample.

It will be used as a normal content file, so please register it in MGCB. Texture Leave the name as .

field

Game1 Let's write it in the class. The existing code will not be changed in particular, so I will only describe the added amount without describing it.

/// <summary>描画するテクスチャー画像。</summary>
private Texture2D _texture;

/// <summary>描画対象となるレンダーターゲット。</summary>
private RenderTarget2D _renderTarget;

_texture The fields are for loading the prepared images and are not particularly relevant to the content of this tip.

RenderTarget2D Fields defined in the class become render targets. Since it is necessary to GraphicsDevice instantiate , it cannot be created at this stage, so it is only defined.

Game1 constructor

public Game1()
{
  _graphics = new GraphicsDeviceManager(this);
  Content.RootDirectory = "Content";
  IsMouseVisible = true;

  // ゲームの解像度の設定
  _graphics.PreferredBackBufferWidth = 1280;
  _graphics.PreferredBackBufferHeight = 720;
}

There is nothing special to do here. For the time being, I have specified the resolution of the game so that it can be compared with the render target.

LoadContent

protected override void LoadContent()
{
  _spriteBatch = new SpriteBatch(GraphicsDevice);

  // TODO: this.Content を使用してゲーム コンテンツをここに読み込みます

  // コンテンツからテクスチャーを読み込みます
  _texture = Content.Load<Texture2D>("Texture");

  _renderTarget = new RenderTarget2D(GraphicsDevice, 540, 360);
}

First, read the use Texture2D Content.Load for drawing with .

GraphicsDevice If there is RenderTarget2D , you can generate it anywhere, but in the example we will create it in LoadContent the method. The render target is a real texture, so it has a size. The GraphicsDevice constructor also specifies the size along with .

Draw

If you use a render target, the code here is the main one.

protected override void Draw(GameTime gameTime)
{
  // TODO: ここに描画コードを追加します

  // 描画先対象をレンダーターゲットに設定
  GraphicsDevice.SetRenderTarget(_renderTarget);

  // テクスチャーの情報をクリアし単色で塗りつぶします
  GraphicsDevice.Clear(Color.LightYellow);

  // スプライトバッチを使用してスプライトを書き込みます
  // レンダーターゲットの外に影響ないことを確認するためにわざと領域をはみ出るように描画しています
  _spriteBatch.Begin();
  for (int i = 0; i < 4; i++)
  {
    _spriteBatch.Draw(_texture, new Vector2((i / 2) * 200 - 50, (i % 2) * 200 - 50), Color.White);
  }
  _spriteBatch.End();

  // レンダーターゲットを解除します。これ以降の描画処理はメインウインドウに対して行われます
  GraphicsDevice.SetRenderTarget(null);

  // メインウィンドウの描画情報をクリアし単色で塗りつぶします
  GraphicsDevice.Clear(Color.CornflowerBlue);

  // メインウィンドウに対してレンダーターゲットをテクスチャーとして描画します
  _spriteBatch.Begin();
  _spriteBatch.Draw(_renderTarget, new Vector2(100, 100), Color.White);
  _spriteBatch.End();

  base.Draw(gameTime);
}

Since drawing is basically GraphicsDevice performed on , even if the drawing process is performed as it is, it will be drawn against the main window. GraphicsDevice.SetRenderTarget By specifying a RenderTarget2D method, you can switch the drawing destination to a texture.

After switching, the drawing process is performed in the same way as when drawing in the main window. GraphicsDevice.Clear clears the drawing information and drawsSpriteBatch the sprite. In order to check whether you are really drawing against the texture, I deliberately specified the drawing position so that the sprite protrudes this time.

When you have finished drawing to the render target, GraphicsDevice.SetRenderTarget specify the null method. This allows you to return the drawing target to the main window.

RenderTarget2D can be used as a texture as it is, so SpriteBatch.Draw I specify the _renderTarget method to draw it as a sprite.

execution

Once you've written the code, try running it. If it looks like the figure, it is OK.

The fill color for the render target and the fill color for the main window are separated, so you can see where the texture was created as the render target. I drew the sprite so that it protrudes against the render target, but I think you can see that it is properly clipped and not drawn towards the main window.

That's all the code that achieves the render target. There is nothing particularly difficult. I think the only thing I care about is managing the switching of drawing destinations and RenderTarget2D managing .

Try moving it

The result of the previous execution looks like the image is simply cropped and drawn, so Next, I would like to move the sprite to make sure that it is properly drawn in the render target.

Update Since we want to update the rotation every time, we will prepare the rotation angle in the field.

/// <summary>テクスチャーを回転させる角度。</summary>
private float _rotate;

Update In the method, increase the _rotate number of .

protected override void Update(GameTime gameTime)
{
  if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
    Exit();

  // TODO: ここに更新ロジックを追加します

  // テクスチャーの回転角度を更新します
  _rotate += 0.01f;

  base.Update(gameTime);
}

Draw The method sets the sprite to _rotate rotate. You only need to know that it is rotating, so the other values are set appropriately.

protected override void Draw(GameTime gameTime)
{
  // 中略

  // スプライトバッチを使用してスプライトを書き込みます
  // レンダーターゲットの外に影響ないことを確認するためにわざと領域をはみ出るように描画しています
  _spriteBatch.Begin();
  for (int i = 0; i < 4; i++)
  {
    _spriteBatch.Draw(_texture, new Vector2((i / 2) * 200 + 32, (i % 2) * 200 + 32),
      null, Color.White, _rotate * i, new Vector2(64, 64), 1, SpriteEffects.None, 0);
  }
  _spriteBatch.End();

  // 中略

  // メインウィンドウに対してレンダーターゲットをテクスチャーとして描画します
  _spriteBatch.Begin();
  _spriteBatch.Draw(_renderTarget, new Vector2(400, 400), null, Color.White,
    _rotate, new Vector2(_renderTarget.Width / 2, _renderTarget.Height / 2), 1, SpriteEffects.None, 0);
  _spriteBatch.End();

  base.Draw(gameTime);
}

When you run it, it should draw while rotating as shown in the figure.