なんだか雲行きの怪しい雑記帖

ぐだぐだ日記とメモと,あと不定期更新

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

【HSP】【hgimg4】Effekseerプラグインでhgimg4でも映えるエフェクトを!

この記事は

HSPのAdventCalendar、略さず言うと Hot Soup Processor Advent Calendar 20175日目の記事です。
去年も12/05に記事を書きましたが、今年も無事(?)12/05に記事を書くことができました。
特に意味はないけど ナントナク(*‘ω‘ *)ウレシイ

前置き

今回はエフェクト再生ランタイム「Effekseer」のスゴイ機能をhgimg4でも使えるようにプラグイン作ったので、hgimg4の超入門も兼ねて改めて使い方や使うとこういうことが出来ます! というのの紹介(有体にいうと宣伝)になります。

なお、話の中身自体は私の前の記事「【HSP】【DXLib】【Effekseer】HSPからエフェクト再生ランタイム「Effekseer」を使えるプラグインを作った話」と重複するところが少なからずあります、ご了承ください。

この記事の内容

今回の記事では下記の内容に触れていきます。

・hgimg4+Effekseerによるエフェクト描画(基本編)
・hgimg4+Effekseerによるエフェクト描画(応用編)
・エフェクトを使ったサンプル


基本編ではhgimg4+Effekseerでとりあえずエフェクトが出せるようになるまでを取り上げます。

応用編では、hgimg4+Effekseerで歪みエフェクトも出せるようにするまでを扱います。

最後に、どうせなのでエフェクト使った動くサンプルを作ってみたのでそれの紹介になります。
エフェクトありなしとで比較もあるので、エフェクトを入れると画面がどう変わるのか感じてもらえればと思います。

サンプルコードとサンプルデータ、hgimg4対応Effekseerプラグイン

本題の前に、本記事中で使われたサンプルコードとサンプルデータのDLなどは次から。
解凍するとそのままスクリプトを実行できます。

サンプルコード一式のダウンロード(GoogleDrive)

20171201:hgimg4対応Effekseerプラグインのダウンロード(GoogleDrive)

hgimg4+Effekseerによるエフェクト描画(基本編)

基本編ではhgimg4+Effekseerで「エフェクトを画面に出すまで」について触れていきます、具体的な内容は下記。

・Effekseerプラグインの初期化
・エフェクトのロード
・エフェクトの再生
・エフェクトの描画
・エフェクトの位置・回転・スケール設定


前準備編

では早速Effekseerプラグインの初期化から…の前に、hgimg4を触った事がない人も居ると思うので、まずhgimg4を使うところから説明していきます。

hgimg4はhgimg3の後継となる3Dグラフィクスの描画ランタイムで、本格的な3Dモデル表示とアニメーション、高度なエフェクト、物理エンジン、2Dスプライトの統合管理などパワフルな機能を持っています。(本家サイトより)
また、bulletなどの物理エンジンも組み込まれており、(OBAQなどと比べて)ライセンス的に問題が少ないため、特にゲームでの使用が視野に入るランタイムになっています。

…というのは口上で、実際はそれなりに使い方に癖があったり手が届かない機能があったりしますが、その辺は置いておいて先ずはとてもシンプルな例をば。

hgimg4で単色の箱をだすまで

hgimg4で赤い箱をだすサンプル。
// hgimg4ランタイムを使う
#include "hgimg4.as"

// タイトル
title "red box"

// hgimg4ランタイムのリセット
gpreset

// 画面クリアの設定:毎回黒でクリア
setcls CLSMODE_SOLID, 0x00000000

// 箱モデルを生成:id_model変数に箱モデルのIDが入る
gpbox id_model, 1, 0xffff0000

// ループ
repeat

// 箱モデルの回転:箱モデルのIDに対して角度加算
addang id_model, 0.0, deg2rad(3), deg2rad(0.5)

// 描画
redraw 0

// カメラの設定
setpos GPOBJ_CAMERA, 0, 0, 10

// シーンの描画
gpdraw

redraw 1
await 16
loop

そして重要なことですが、スクリプトを保存して実行する前に、以下のディレクトリを保存したスクリプトと同じディレクトリにコピーして下さい。

HSPをインストールしたディレクトリ/sample/hgimg4/res

sampleからコピーしてくるので疑問に思った方居るかもしれませんが、驚くべきことにこれは本当に必要な操作です

hgimg4.txtにこう書かれています。

・リソースフォルダについて
HGIMG4では、起動時に実行するスクリプトと同じフォルダにある
「res」フォルダから必要なリソースを読み込みます。
リソースファイルは、「sample/hgimg4/res」のフォルダに含まれています。
以下のファイルは、起動のために必要ですので、実行ファイル作成時なども必ず入れておいてください。

res/font.gpb
res/shaders フォルダ(中のファイルも含む)


hgimg4以外にこう言った動作するのに外部ファイルを必要とするランタイムが存在しないため違和感を覚える人が多そうなので何故なのか補足しておきますと…

凡そ現代の3D描画においては「画面に表示する際のポリゴンの色を計算する処理(シェーダ)」は自前で書く必要があります。
このシェーダはOpenGLならGLSL、DirectXならHLSLという言語で書かれたプログラムなのですが、このプログラムがresディレクトリに含まれています。(res/shaders)
また、hgimg4では文字列の描画のためにフォントのテクスチャデータも必要になっています。(res/font.gpb)
逆に言うとresディレクトリ内にあるファイルのうち、上記以外のファイルは必要ないので、hgimg4で何かしら作って配布する際はそれ以外のファイルは消しておいた方がライセンス的に無難です。

hgimg4でのシェーダカスタマイズについては基本編ではかなり深入りしてしまう内容となるため触れません。
応用編では触れるので興味がある人はお楽しみに。


さて、実行してみると下記のような結果になります。
hgefk_red_box.png

そして、単に箱を出すだけのサンプルでも、標準命令と同じところもあれば標準命令とはかけ離れている部分もあることに気付きます。

gpboxとは? setclsとは?

そういったものについての詳細な説明はF2ヘルプに任せるとして…。
ここではともかくhgimg4を使って描画の土台が作れたということにして、本記事の本題のEffekseerプラグインの説明に移ります。

hgimg4+Effekseerプラグイン事始め

早速ですが、先ずはEffekseerプラグインを使って画面にエフェクトを出すまでの流れを概観しましょう。

1. hgimg4の初期化をする(gpreset)
2. Effekseerプラグインを初期化する
3. エフェクトファイル「.efk」から「efkLoad」によってエフェクトをロードし、ロードしたエフェクトに対応するID(エフェクトID)を得る
4. 「efkPlay」にエフェクトIDを指定すると、実際に画面に描画されるエフェクトのインスタンスが作られる。「efkPlay」の戻り値として作られたエフェクトインスタンスのIDが得られる
5. 3で得られたエフェクトインスタンスのIDを使って、エフェクトインスタンスの位置やスケール、回転角度などが適宜設定する
6. 1フレームに1回、描画前に「efkUpdate」を実行する
7. 描画前にカメラの設定をEffekseerプラグイン側にもしておく
8. 「efkBeginDraw」、「efkKickDraw」、「efkEndDraw」を順番に呼び出すと描画される


こんな感じです。

以下、この流れに沿ってそれぞれどんなスクリプトを書けばよいのかをざっとコードで説明していきます。

Effekseerプラグインのinclude

// Effekseerプラグインを使う
#define EFFEKSEER_IS_GL (1)
#include "effekseer.hsp"

「#define EFFEKSEER_IS_GL (1)」が必須です、effekseer.hspを1ファイルにしたかったのでこうなりました。
hgimg4と一緒に使う場合は、hgimg4.asより前にincludeする必要があります。(現状)

Effekseerプラグイン初期化

// エフェクトエンジンの初期化
efkInit

呼ぶだけです。
gpresetより後のタイミングで実行してください。
DirectX9版と比べて、D3Dデバイスなどの引数が必要ないので非常にシンプルになってたりします

エフェクトファイルを読み込む

// efkファイルを読み込んでエフェクトIDを得る
efkLoad "test.efk"
effect_id = stat

efkファイルはEffekseerのツールから出力できます。

エフェクトを再生する(エフェクトIDからエフェクトインスタンスを作る)

// エフェクトIDを使ってエフェクトインスタンスを作る
efkPlay effect_id
effect_handle = stat// エフェクトインスタンスのID(ハンドル)

efkPlayを呼んだ回数だけエフェクトインスタンスを生成できます。
ので、沢山呼べば沢山エフェクトを画面上に出すこともできます。

エフェクトのフレーム更新

// エフェクトの更新
efkUpdate

1フレームに1回呼びます。

描画のためのカメラ設定

// Effekseer側のカメラの設定
efkSetPersProj deg2rad(45)/*fovy*/, 1.5/*aspect*/, 0.5/*near*/, 768.0/*far*/
efkSetLookAtCamera 0, 0, 10/*カメラ位置*/, 0, 0, 0/*注視点*/, 0, 1, 0/*カメラ上ベクトル*/

ここではhgimg4が設定しているデフォルトの値などを使っていますが、
実際は自分でhgimg4側に設定したものと同じものを設定する必要があります。

エフェクトの描画

// エフェクトの描画
efkBeginDraw
efkKickDraw
efkEndDraw

3個の命令ですが、この順番で呼び出す必要があります。

実際にエフェクトをだす

さて、hgimg4の簡単な使い方から、Effekseerプラグインの使い方まで説明が終わりました。
特にEffekseerプラグインの方は使い方の説明に終始しており実際に動くスクリプトが出てこなかったので、退屈に感じた人も居るかと思います。

ということで、ここでは実際に動くサンプルを示します。
// Effekseerプラグインを使う
#define EFFEKSEER_IS_GL (1)
#include "effekseer.hsp"

// hgimg4ランタイムを使う
#include "hgimg4.as"

// タイトル
title "simple effect"

// hgimg4ランタイムのリセット
gpreset

// エフェクトエンジンの初期化
efkInit

// 画面クリアの設定:毎回黒でクリア
setcls CLSMODE_SOLID, 0x00000000

// 箱モデルを生成:id_model変数に箱モデルのIDが入る
gpbox id_model, 1, 0xffff0000

// efkファイルを読み込んでエフェクトIDを得る
efkLoad "test.efk"
effect_id = stat

// エフェクトIDを使ってエフェクトインスタンスを作る
efkPlay effect_id
effect_handle = stat// エフェクトインスタンスのID(ハンドル)

// ループ
repeat

// 箱モデルの回転:箱モデルのIDに対して角度加算
addang id_model, 0.0, deg2rad(3), deg2rad(0.5)

// エフェクトの更新
efkUpdate

// 描画
redraw 0

// カメラの設定
setpos GPOBJ_CAMERA, 0, 0, 10

// Effekseer側のカメラの設定
efkSetPersProj deg2rad(45)/*fovy*/, 1.5/*aspect*/, 0.5/*near*/, 768.0/*far*/
efkSetLookAtCamera 0, 0, 10/*カメラ位置*/, 0, 0, 0/*注視点*/, 0, 1, 0/*カメラ上ベクトル*/

// シーンの描画
gpdraw

// エフェクトの描画
efkBeginDraw
efkKickDraw
efkEndDraw

redraw 1
await 16
loop

実際に動かしてみるとこんな感じに、赤い箱とエフェクトが同じ画面上に出ます。
hgefk_red_effect_simple.png

エフェクトの位置、スケール、回転を設定する

// エフェクトインスタンスの位置、スケール、回転
efkSetPos effect_handle, 3, 0, 0
efkSetScale effect_handle, 0.1, 0.2, 0.3
efkSetRot effect_handle, 0, deg2rad(90), 0

これらを適用した状態だと描画結果は次のようになりますん。
hgefk_simple_effect_srt.png

その他のリファレンス実装

hgimg4用のEffekseerプラグイン本体には、サンプル実装としてエフェクトビューアなどを同梱しています。
より実践的な使い方のサンプルになっていますので、もっと使い倒してたい人は参照してください。



hgimg4+Effekseerによるエフェクト描画(応用編)

応用編ではhgimg4+Effekseer用のプラグインを作った時、歪みエフェクトを何とかだせるようにしようと色々実装した内容について紹介していきます。
具体的な内容は下記。

・キャプチャ用バッファと歪みバッファ

…一個しか内容がありませんが、中身は少し複雑です。

キャプチャ用バッファとは

Effekseerには「歪み」という、画面上に出したエフェクトによってエフェクトより奥に存在するオブジェクトが屈折して見える機能が存在します。
hgefk_simple_distortion.png
:Effekseer本体に同梱されている歪みエフェクトをキャプチャしたもの

Effekseer的には、「歪み」エフェクトを描画する直前の描画バッファをテクスチャとしてとりだし、それを使って屈折表現を実装しています。
重要なのはこの”「歪み」エフェクトを描画する直前の描画バッファをテクスチャとしてとりだす”処理で、これがないと「歪み」が使えません。

DirectX9版のEffekseerプラグインを作っていた時は、DirectX側で描画バッファを取り出す操作がサポートされていたため、この「歪み」機能にも対応していました。
ですが、OpenGLでは描画バッファを取り出したとしてもそれがテクスチャとして使える保証がありません
一応、CPUでアクセス可能なテクスチャとして取り出すことは可能なのですが、GPU描画を止めてCPU側メモリにデータを持ってくるためとても重い処理になるため、それは使えませんでした


GL版では「歪み」機能は諦めるか…と考えていたのですが、
hgimg4の描画バッファを取り出すのではなく、プラグイン側で用意したバッファにhgimg4で書いてもらえば問題解決では?
と気付きました。

それを実装したものがキャプチャ用バッファです。

キャプチャ用バッファと歪みバッファ

上記で説明したのがキャプチャ用バッファですが、実際にはプラグイン側で用意したバッファに描画をした後、更にEffkseerで使えるように歪みテクスチャとして設定する必要があります。

ということで、

・HSP側から描画してもらうバッファとしてキャプチャ用バッファ
・Effekseer側に歪みテクスチャとして使ってもらうための歪みバッファ


の2つが存在します。
ここだけ抑えた上で、以下歪みエフェクトを出すまでの流れをスクリプトと一緒にざっと説明していきます。

キャプチャ用バッファを作る

// キャプチャ用バッファを作る
efkInitCapture 720, 480// 画面用
efkInitDistortion 720, 480// 歪み用

解像度を指定して描画可能なバッファを作ります。
一つはキャプチャ用、もう一つは歪みテクスチャとしてEffekseer側に渡す用です。

キャプチャ用バッファに対して描画する

// キャプチャ用バッファをバインドする
efkBindCaptureBuffer 1

キャプチャ用バッファをバインドした後はhgimg4を使って好きな描画をすることで、キャプチャ用バッファに自動的に描画されます。
引数には1を指定するとキャプチャ用バッファをクリアします。

キャプチャ用した内容を歪みテクスチャにコピーします

// 歪みバッファをバインドする
efkBindDistortionBuffer 0

// 歪みバッファにキャプチャ用バッファの内容をコピー
efkDrawCaptureColor

これで歪みバッファにはこれまでの描画内容がコピーされた状態になります。

歪みバッファを歪みエフェクト用に使う設定をする

// 歪みバッファを歪みエフェクト用のテクスチャとして設定
efkRegisterDistortionBufferAsTextureView

歪みバッファをEffekseerの歪みテクスチャに設定する命令です。

元のキャプチャ用バッファに戻し、エフェクトを描画

// キャプチャ用バッファへの描画に戻す
efkBindCaptureBuffer 0

// エフェクトを描画する
efkBeginDraw
efkKickDraw
efkEndDraw

地味に忘れがちですが、キャプチャ用バッファを描画対象としてバインドし直す必要があります。

最終描画結果はキャプチャ用バッファにあるので、それを画面へコピー

// 画面への描画
gsel 0
redraw 0

// キャプチャ用バッファの内容をコピー
efkDrawCaptureColor

redraw 1

はい、かなり煩雑でしたが、ここまでで無事歪みを使ったエフェクトの描画ができます。
ちなみに、歪みを使う場合は上記の流れがほぼ定型文です。

無事にこれらを使って歪みエフェクトがでると、次のような感じになります。
hgefk_dist_red_box.png

ちなみに、スクリプトはこんな感じ、歪みを使ったエフェクトを出しています。
// Effekseerプラグインを使う
#define EFFEKSEER_IS_GL (1)
#include "effekseer.hsp"

// hgimg4ランタイムを使う
#include "hgimg4.as"

// タイトル
title "distortion effect"

// hgimg4ランタイムのリセット
gpreset

// エフェクトエンジンの初期化
efkInit

// 画面クリアの設定:毎回黒でクリア
setcls CLSMODE_SOLID, 0x00000000

// 箱モデルを生成:id_model変数に箱モデルのIDが入る
gpbox id_model, 1, 0xffff0000

// efkファイルを読み込んでエフェクトIDを得る
efkLoad "test_dist.efk"
effect_id = stat

// エフェクトIDを使ってエフェクトインスタンスを作る
efkPlay effect_id
effect_handle = stat// エフェクトインスタンスのID(ハンドル)

// キャプチャ用バッファを作る
efkInitCapture 720, 480// 画面用
efkInitDistortion 720, 480// 歪み用

// 裏バッファを作る:キャプチャ用バッファと同じサイズにする
buffer 1, 720, 480, screen_offscreen

// ループ
repeat

// 箱モデルの回転:箱モデルのIDに対して角度加算
addang id_model, 0.0, deg2rad(3), deg2rad(0.5)

// エフェクトの更新
efkUpdate

// カメラの設定
setpos GPOBJ_CAMERA, 0, 0, 10

// Effekseer側のカメラの設定
efkSetPersProj deg2rad(45)/*fovy*/, 1.5/*aspect*/, 0.5/*near*/, 768.0/*far*/
efkSetLookAtCamera 0, 0, 10/*カメラ位置*/, 0, 0, 0/*注視点*/, 0, 1, 0/*カメラ上ベクトル*/

// キャプチャする
gsel 1// hgimg4側にダミーとして裏バッファを描画対象としておく
redraw 0

// キャプチャ用バッファをバインドする
efkBindCaptureBuffer 1

// シーンの描画
gpdraw

// 歪みバッファをバインドする
efkBindDistortionBuffer 0

// 歪みバッファにキャプチャ用バッファの内容をコピー
efkDrawCaptureColor

// キャプチャ用バッファへの描画に戻す
efkBindCaptureBuffer 0

// 歪みバッファを歪みエフェクト用のテクスチャとして設定
efkRegisterDistortionBufferAsTextureView

// エフェクトを描画する
efkBeginDraw
efkKickDraw
efkEndDraw

redraw 1

// 画面への描画
gsel 0
redraw 0

// キャプチャ用バッファの内容をコピー
efkDrawCaptureColor

color 255, 255, 255
pos 5, 50 : mes "aaa"

redraw 1
await 16
loop

正直ここまで複雑なコードにしてまで歪みを使いたいかと言われると人それぞれだと思いますが、歪みは効果的に使うとかなりエフェクトとしては映える部類だったので、何とか使えるようにしました。

エフェクトを使ったサンプル

さて、プラグインの説明も一通り終わった…。
とは言っても、ここまで苦労してエフェクトなんて使いたくない、という人も居るような気がしました。
そこで、どうせなのでここまで説明した内容とhgimg4を使ってもう少しインタラクティブなサンプルを作りました。

エフェクトありなしと切り替えできるようにしたので、エフェクトがどれくらい重要なファクターなのか体感してもらえればと思います。

マウスに赤い箱が追従します、マウス左ボタンを押すと強めに追従します。
画面外から白い箱が飛んでくるので、赤い箱を誘導して白い箱に当てると白い箱を消せます。
…それだけです…それだけです!!

hsp3gp_20171202_145441W.gifhsp3gp_20171202_145421W.gif
左側がエフェクトあり、右側がエフェクトなし

白い箱が消える時にエフェクトがでたりします、シンプル故にエフェクトがどう貢献するのかが分かりやすいものになったかなと思います。

エフェクト単体は次のような感じです。
hgefk_destroy_effect.gif
このエフェクトに関してはサンプルデータとしてバイナリデータのefkファイルと、元のプロジェクトファイルであるefkprojも入れてあります。
好きに改変してみて、出力してみて、サンプルを実行し直してみて…と、エフェクトを差し替えてどう見た目が変わるかに試してみるのもいいでしょう。



おわりに

以上、Effekseerをhgimg4でも使えるようにプラグインを作った(というより、プラグイン的には元々対応してたDirectX9版から改変してOpenGL版も対応した)ので使い方紹介兼宣伝と、エフェクトを使ったサンプルについてでした。

実はとあるプロジェクトで使ってもらっているので、そこそこ動作テストされてるだろう…と思っています。
ある程度動作テストされているので、プラグイン自体は大体の状況で正しく動いてくれるでしょう、多分

また、この記事中では紹介できませんでしたが、キャプチャ用バッファから線形デプスを取り出す機能など、OpenGL3.1仮定での高度な機能も入っています。
かなり高度な内容になってしまうので今回は端折りましたが、需要があるならそのうちそれらも解説してみたいな、と思いつつ…。

それでは、この辺で。



この投稿は Hot Soup Prcessor Advent Calendar 20175日目の記事です。
4日目 → HSP3.5 HGIMG4 で2Dビューポート表示
6日目 → シンプルな追いかけっこから始めるゲームメカニクス
関連記事
スポンサーサイト

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://fe0km.blog.fc2.com/tb.php/125-733905a2
この記事にトラックバックする(FC2ブログユーザー)

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。