Doc:JA/2.6/Manual/Game Engine/Python API/VideoTexture
The VideoTexture module
VideoTexture
モジュールを使うと、ゲームの実行中にテクスチャを操作できます。テクスチャに使えるソースはいくつかあります、ビデオファイル、イメージファイル、ビデオキャプチャ、メモリバッファ、カメラレンダー、またはこれらの混合です。ビデオファイルとイメージファイルは、ファイル名の代わりにURLを指定することでインターネットからロードできます。さらに、それらのイメージをGPUに送る前にフィルタを適用し、blue screen、color band、gray、normal mapなどの映像効果をかけることもできます。VideoTexture
はイメージやビデオをロードするのにFFmpegを使用しており、FFmpegがサポートしているフォーマットはVideoTexture
でもすべてサポートされています。以下はサポートしているフォーマットの一部です。
- AVI
- Ogg
- Xvid
- Theora
- dv1394 camera
- video4linux capture card (this includes many webcams)
- videoForWindows capture card (this includes many webcams)
- JPG
動作の仕組み
原理は簡単です。まず、すでに存在しているテクスチャをオブジェクトと名前によって指定し、次に動的コンテントを持ったテクスチャを作成して、二つのテクスチャをGPU内で入れ替えます。ゲームエンジンはテクスチャが交換されたことには気づかず、通常通りにオブジェクトを表示します。それでいて、あなたがテクスチャをコントロールできるようになっているわけです。使用を終えると、新しいテクスチャは削除され、古いテクスチャが復帰します。
このページでは簡単な例を使ってVideoTexture
モジュールを解説します。
ゲームの準備
VideoTexture
モジュールを使う前に、適切なテクスチャをもったオブジェクトがなくてはいけません。
たとえば、ゲームの中に、本物の番組を流しているテレビを配置したいとします。テレビのオブジェクトを作成し、画面の部分には別個のテクスチャをUVマッピングで適用します。たとえば“tv.png
”というテクスチャだとしましょう。このテクスチャの内容はここでは重要ではありませんが、おそらく電源が切れている画面のような、暗いグレーにすると良いでしょう。テレビの電源を入れなければならないとき、ビデオキャプチャカードからの映像を使った動的テクスチャが作成されるようにします。それをtv.png
と入れ替えれば、テレビは本物同様になります。
VideoTexture
が入れ替えられるテクスチャの作り方は二通りあります。
- 単純なUVテクスチャ。
- テクスチャチャンネルを持ったBlenderマテリアル。
VideoTexture
はテクスチャのレベルで動作するので、ゲームエンジンがもっている凝ったテクスチャ機能も使えます。GLSL、multi-texture、custom shadersなど。
例
たとえば、ゲーム内のあるオブジェクトが、一つまたはそれ以上の面に対してマテリアル/イメージを適用されており、そこにビデオを表示したいとします。
最初のステップはTexture
オブジェクトの作成です。これは一度だけ実行されるスクリプトで行うことにしましょう。ゲームがスタートした時点では、ビデオはテクスチャを更新しない限り表示されないかもしれません。これについてはあとで触れます。通常、スクリプトはビデオを表示させるオブジェクトに付加します。そうするとオブジェクトの参照を簡単に取得できます。
import VideoTexture
contr = GameLogic.getCurrentController()
obj = contr.owner
if not hasattr(GameLogic, 'video'):
“video
”属性をチェックするのは、テクスチャの作成を一度だけにするためです。
マテリアルの取得
matID = VideoTexture.materialID(obj, 'IMvideo.png')
VideoTexture.materialID()
は便利な関数で、これによりvideo.png
をテクスチャとして使っているマテリアルを取得します。この方法はBlenderマテリアルでもUVテクスチャでも使えます。UVテクスチャの場合は、そのテクスチャが適用されている面に付随する内部的なマテリアルを呼び出します。Blenderマテリアルの場合は、そのテクスチャを第一テクスチャとして使っているマテリアルを呼び出します。
“IM
”の接頭辞は、探しているのがテクスチャであると示すためのものです。マテリアルの場合は“MA
”を先頭につけます。たとえば、このオブジェクト上でVideoMat
という名前のマテリアルを探す場合、コードは以下のようになります。
matID = VideoTexture.materialID(obj, 'MAVideoMat')
テクスチャの作成
VideoTexture.Texture
クラスは、動的テクスチャをGPUにロードするTexture
オブジェクトを作成します。コンストラクタは必須の引数1つと、オプションの引数3つをとります。
gameObj
- ゲームオブジェクト。
materialID
VideoTexture.materialID()
で返されるのと同じマテリアルインデックス。0にすると最初のマテリアルになります。
textureID
- 複数のテクスチャが存在すす場合のテクスチャインデックス。0にすると最初のチャンネルになります。
- UVテクスチャの場合はこの値は常に0にします。
textureObj
- 再使用したいテクスチャを持つ
Texture
オブジェクト。 - この引数を使う場合、そのテクスチャ上にはいかなるソースも作成するべきではありません。また、テクスチャを更新する必要もありません。得られるテクスチャはマテリアルにもテクスチャにも使用できます。
GameLogic.video = VideoTexture.Texture(obj, matID)
テクスチャを永続的にする
以前にオブジェクトに対してGameLogic
“video
”属性を割り当てましたが、その理由は、Texture
はゲームの実行中に永続的でなければならないからです。ローカル変数はスクリプトの終わりで消去され、同時にGPUテクスチャも消去されます。GameLogic
モジュールオブジェクトは永続的にしたいオブジェクトを保存するのに便利なのです。
ソースを作成する
Texture
オブジェクトを得ることができましたが、テクスチャのソースがないので、これだけでは何もできません。VideoTexture
で使用可能な種類の中から、ソースオブジェクトを作成する必要があります。
VideoFFmpeg
- 動画。
- ビデオファイル、ビデオキャプチャ、ビデオストリーミング
ImageFFmpeg
- 静止画
- イメージファイル、ウェブ上のイメージ
ImageBuff
- メモリ上のイメージ
- CGI、グラフィックアプリケーション
ImageViewport
- ビューポートの全体または一部(つまりアクティブカメラによるレンダリングイメージ)
ImageRender
- アクティブでないカメラによるレンダリングイメージ
ImageMix
- 上記のうちの二つ、またはそれ以上の混合
この例ではソースとしてシンプルなビデオファイルを使います。VideoFFmpeg
コンストラクタはファイル名を引数に取ります。ファイルの場所についての混乱を避けるため、GameLogic.expandPath()
を使ってファイルのフルパスを取得します。ここでビデオファイルは.blendファイルと同じディレクトリにあるとします。
movie = GameLogic.expandPath('//trailer_400p.ogg')
GameLogic.video.source = VideoTexture.VideoFFmpeg(movie)
ビデオソースオブジェクトを作ったら、それをTexture
オブジェクトのsource
属性に割り当てることで、ソースのセットアップと永続化を行います。ソースオブジェクトそのものも永続的になります。
Texture
のソースはいつでも変更できます。たとえばゲームの進行中に二つの映像を切り替えたい場合、以下のようにします。
GameLogic.mySources[0] = VideoTexture.VideoFFmpeg('movie1.avi')
GameLogic.mySources[1] = VideoTexture.VideoFFmpeg('movie2.avi')
そして実行中に再割り当てします。
GameLogic.video.source = GameLogic.mySources[movieSel]
ソースのセットアップ
VideoFFmpeg
ソースはムービーの再生をコントロールする属性がいくつかあります。
range
- [start,stop] (floats).
- ビデオの再生範囲。始めからの秒数で指定します。デフォルトではビデオ全体です。
repeat
- (integer).
- リピート回数。-1で無制限にリピートします。
framerate
- (float).
- 相対的なフレームレート。1.0より小さくすると遅くなり、大きくすると速くなります。
scale
- (bool).
- Trueにすると高速なニアレストネイバーアルゴリズムで拡大します。
- テクスチャに使うビデオの幅と高さは2の乗数でなければいけません。そうでない場合、指定した方法でスケーリングされます。デフォルトでは正確ですが遅い
gluScaleImage()
関数を使います。一番良いのは最初からビデオを適切な大きさにしておくことです。そうすれば実行時にはスケーリングの必要がなくなります。
flip
- (bool).
- Trueにするとイメージは上下に反転されます。
- FFmpegからのイメージは常に上限判定している状態なので、この属性はデフォルトでTrueになっています。
filter
- ビデオをGPUに送る前にフィルタを適用します。
VideoTexture
フィルタオブジェクトのうちのひとつを指定します。デフォルトではイメージは何も変更されずにGPUに送られます。ビデオにアルファチャンネルが存在している場合は、それは自動的にロードされてGPUに送られます。
ここではscale
属性をTrueにしましょう。なぜならgluScaleImage()
は本当に遅くて、リアルタイムビデオには向いていないからです。ビデオの縦横がもともと2の乗数になっている場合は、この設定は何の影響もありません。
GameLogic.video.source.scale = True
Play the video
これでビデオを再生する準備ができました。
GameLogic.video.source.play()
ビデオの再生はバックグラウンドプロセスではありません。テクスチャを更新して初めて再生されます。よって、毎フレーム実行されるスクリプトでTexture
オブジェクトのcode>refresh()メソッドを呼び出す必要があります。
if hasattr(GameLogic, 'video'):
GameLogic.video.refresh(True)
ビデオソースが停止している場合は、refresh()
は何の効果もありません。refresh()
の引数は、テクスチャを再計算する必要があるかどうかを指定するフラグです。ビデオ再生の場合は、あきらかにTrueでしょう。
ビデオのステータスをチェックする
ビデオソースクラス(VideoFFMpegなど)はstatus
という属性を持っています。ビデオが再生中の場合、この値は2です。停止している場合は3です。よっで今回の例では、
if GameLogic.video.source.status == 3:
#ビデオは止まっている
高度なワークフロー
Texture.refresh()
メソッドでTrueを指定すると、一度GPUに送られたイメージは次のフレームでは無効化され、ソースから新しくロードされます。このやり方では、Pythonでイメージが使用できなくなるという副作用があります。よってソースのrefresh()
メソッドを手動で呼び出すという方法もあります。
高度なワークフローの例は以下のようになります。
- Pythonでイメージバッファを使う (テクスチャには影響しない):
GameLogic.video.refresh(False)
image = GameLogic.video.source.image
# imageはRGBAピクセルのバイナリ列
# ... imageを使う
# 次のフレームのため無効にする
GameLogic.video.source.refresh()
- Pythonで使うため、GPUにはダウンロードせずにイメージをソースからロードする:
# テクスチャのほうのrefreshを呼んでいないことに注意 # テクスチャオブジェクトを使わずにソースオブジェクトだけを作成することもできます
image = GameLogic.video.source.image
# ... imageを使う
GameLogic.video.source.refresh()
- もしメッシュに適用されているマテリアルが二つ以上あり、特定のマテリアルのテクスチャを修正したい場合、マテリアルのIDを取得します。
matID=VideoTexture.materialID(gameobj,"MAmat.001")
GLSLマテリアルは2チャンネル以上のテクスチャを持つことができます。テクスチャはテクスチャスロットの順番に応じて特定されます。ここでは2としましょう。
tex=VideoTexture.Texture(gameobj, matID, 2)
デモのダウンロード
デモファイルをダウンロードできます。
高度なデモ
このデモは、同じテクスチャ上で二つのビデオを交互に使うデモンストレーションです。このデモを使うにはelephant dreamの予告編(teaser)のビデオファイルが必要です。他のファイルで置き換えることもできます。
このデモはImageMix
ソースを使ったデモンストレーションです。ImageMix
は他のTexture
ソースを必要とします。たとえばVideoFFmpeg
、ImageFFmpeg
、ImageRender
など。これらのソースをsetSource()
でセットして、setWeight()
でそれぞれの相対的な重みを設定します。重みは0から255で、すべてのソースの重みの合計が255にならなければいけません。ImageMix
はすべてのソースを重みに応じて合成します。元になる複数のソースは、すべて同じサイズ(一番近い2の乗数にスケーリングされた後で)でなけれはいけません。そうでない場合、コンソールでPythonのエラーが出ます。