[Godot4.3]テクスチャにセットしたイメージを更新する

コントロールとテクスチャとイメージ

Godotで画像なりのイメージを描画しようと思うと、まず画像を扱えるコントロール(Splite2D、TextureRectなど)をシーンに設置する。
次にコントロールにテクスチャを設定する。そのテクスチャ(Texture2Dとか)に画像(Image)を設定する。これで画像が表示される。

例:[ TextureRect [ Texture2D [ Image ] ] ]

イメージを更新したらテクスチャから作り直さないとダメ?

問題はテクスチャにセットしたイメージが更新された場合だ。

いろいろなサンプルなどを見ると更新毎にテクスチャを作り変えてたりします。

func update():
	texture_rect = ImageTexture.create_from_image(img)

みたいな。

画像ファイルを読み込むみたいな大きな変更ならいざ知らず、マウスでイメージに線を引いたり更新頻度が高い場合、毎回テクスチャを作成するのは気持ち悪い。
もちろんそんな必要はありませんでした。

サンプル

シーン構成

  • Node2D(node_2d.gd)
  • CanvasLayer
    • TextureRect

TextureRectにはなにも設定しなくて大丈夫です。

スクリプト

# node_2d.gd
extends Node2D

@onready var tex:TextureRect = $CanvasLayer/TextureRect

const image_width:int = 800
const image_height:int = 600

const draw_rect_width:int = 50
const draw_rect_height:int = 50

var img:Image

func _ready() -> void:
	img = Image.create(image_width, image_height, false, Image.FORMAT_RGBA8)
	img.fill(Color.WHITE)
	tex.texture = ImageTexture.create_from_image(img)

func _input(_event: InputEvent) -> void:
	if _event is InputEventMouseButton:
		if _event.pressed:
			var mouse_pos:Vector2i = get_global_mouse_position()
			mouse_pos.x -= draw_rect_width / 2
			mouse_pos.y -= draw_rect_height / 2
			
			img.fill_rect(Rect2i(mouse_pos, Vector2i(draw_rect_width, draw_rect_height)), Color.BLACK)
			tex.texture.update(img) # <-- Update!

このサンプルを実行すると左クリックした場所に黒い四角が描画されます。

ImageTextureを使え!

ImageTextureテクスチャにはちゃんとイメージの更新のためのメソッドが用意してありました。ざっくり調べたところImageTextureテクスチャだけです。

ImageTexture.update()

サンプルで使っているメソッドです。

使用には条件があります。

  1. すでにImageが設定されている
  2. 更新に指定するImageと、すでに設定されているImageの サイズフォーマットミップマップ が一致している

ことが条件です。

サンプルの様にピクセル情報(色)を変更するのに最適!

ImageTexture.set_image()

サンプルでは使用していませんが、Imageを差し替えたい場合に使用できます。

ドキュメントではメモリの再割り当てされるらしいので、当然ImageTexture.update()の方が効率がいい。

まとめ

今回はテクスチャに設定したイメージを更新しました。ただ、他の便利なテクスチャ(AtlasTextureとか)の更新はどうしたら…あきらめてテクスチャ作り直し!

おまけ

Godotはアプリ起動時に必要なアセットをGPUメモリに乗せる(これはValkanの設計?)ことで高速な実行を実現しているらしい。そのため実行中の変更(今回でいえばイメージの更新)が少しメンドくさい。

参考リンク

ImageTexture

コメント

タイトルとURLをコピーしました