tarotaroのエンジニア生活

技術ネタとか日々の仕事の話とか

UE4のWindowsにおけるマルチタッチについて

この記事は、Unreal Engine4(UE4) Advent Calendar 2015 その1の17日目の記事です。
前回の記事は、@tempkinder さんによる「CutomDepthを拡張して色も出力してみる」でした。

UE4で実装したモバイル端末において、マルチタッチは、ThirdPersonのテンプレートのThirdPersonCharacterのBPを見てもらえるとわかると思うのですが、InputTouchでタッチを
Press、Release,Move,Finger(指のインデックス)の情報をそれぞれ取れるようになっている
のが確認できると思います。
Touch










これをマルチタッチ対応のWindows機で実行してもらってDebugして驚愕の事実に
気づくと思うのですが、実は、Touch1以外の指に反応しないことがわかります。
このことについて、僕はハマったので、AnswerHubを検索してみると、

Windows 7/8 touch/ multi-touch supportと言う記事が見つかりました
読んでみると、Fingerの指の識別について、Windowsでは実装されてないとのこと。
iOSとかAndroidでは、実行してうまく指の認識をしてるのになんでWindowsでは
認識しないんだろうなーと思ってソースを読んでみようかなぁと思いながら、
4.9のUnrealBuildToolのコンパイルオプション的なところを調べていると、ちょっときになる記述を見つけました

 
	if ((InBuildTarget.TargetType == TargetRules.TargetType.Program) && (GetCPPTargetPlatform(InBuildTarget.Platform) == CPPTargetPlatform.Win32))
			{
				// Check if the target has requested XP support.
				if (String.Equals(InBuildTarget.Rules.PreferredSubPlatform, "WindowsXP", StringComparison.InvariantCultureIgnoreCase))
				{
					SupportWindowsXP = true;
				}
			}

			if (WindowsPlatform.bUseWindowsSDK10 && WindowsPlatform.Compiler == WindowsCompiler.VisualStudio2015)
			{
				if (SupportWindowsXP)
				{
					throw new NotSupportedException("Windows XP support is not possible when targeting the Windows 10 SDK");
				}
				// Windows 8 or higher required
				InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("_WIN32_WINNT=0x0602");
				InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WINVER=0x0602");
			}
			else
			{
				if (SupportWindowsXP)
				{
					// Windows XP SP3 or higher required
					InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("_WIN32_WINNT=0x0502");
					InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WINVER=0x0502");
				}
				else
				{
					// Windows Vista or higher required
					InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("_WIN32_WINNT=0x0600");
					InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WINVER=0x0600");
				}
			} 
4.9は、VisualStudio2013でコンパイルされるはずなので、一番下の
 InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("_WIN32_WINNT=0x0600");
InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WINVER=0x0600");
を通るのですが、VisualStudioのWindowsのタッチの定義、実はWINVER=0x06001からになってます。
このあたりは互換性の問題でこうなってるのか、VisualStudio2013でしかコンパイル対応してないからなのか、その辺はわかりませんが、こういう理由でTouchが対応してない状況でコンパイルされています。
(ちなみに、4.10では、VisualStudio2015対応になってますが 、このあたりまだ対応してないようでした。)で、対応するために、 
InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WINVER=0x0601");
と書き換えてUnrealBuildToolをビルドし直して、UnrealEngine自体をビルドし直します。では、実際のプログラムに入っていきましょう。

実際のソースは、githubを見てもらうとして要点だけ説明します。コントーロールの操作なので、今回は、PlayerControllerを継承して実装します。BeginPlayで、アプリケーションハンドラを得て、アプリケーションに独自のメッセージハンドラを設定するようにします。このメッセージハンドラというのは、UE4用に定義されたWindowsのメッセージハンドラです。具体的に言うとWindowProcの部分のことと言っても間違いではないです。この部分の詳しいことは後で説明します。
 
void AMultiTouchPlayerController::BeginPlay(){
	TSharedPtr GenericApplication = FSlateApplication::Get().GetPlatformApplication();
	FWindowsApplication* WindowsApplication = (FWindowsApplication*)GenericApplication.Get();
	WindowsApplication->AddMessageHandler(myMessageHandler);
	myMessageHandler.TouchController = this;
	myMessageHandler.InitVariable();
}

メッセージハンドラは、IWindowsMessageHandlerを継承して、定義します。
 
class  GARDEN_API FMyWindowsMessageHandler :
	public IWindowsMessageHandler
{

public:
	void InitVariable();
	virtual bool ProcessMessage(HWND hwnd, uint32 msg, WPARAM wParam, LPARAM lParam, int32& OutResult) override;
	AMultiTouchPlayerController *TouchController;
	bool isTouchInit;
};

 ProcessMessageと言うのがWin32のアプリを作ったことがある方なら知ってるであろうWinProc関数です。ProcessMessageの中身の詳しいところは、githubのソースを読んでもらうとして、概要を説明するとTouchのメッセージをHookして、処理してUE4側に投げるようにします。

 あとは、注意点だけ書いておきます。Touchなどのメッセージ定義などは、WindowsAPIのWinuser.hに定義されていますが、これをincludeしようとすると、DWORDなどのWindows特有の定義などでエラーになってしまいます。
これを回避するために、"AllowWindowsPlatformTypes.h"と"HideWindowsPlatformTypes.h"のincludeで括ります。こうすることで、Windows特有の定義のエラーを回避することができます。
あと、 FSlateApplicationとかは、Slateに入っているので、*.Build.csに、"Slate"を追加しておきます。
 以上マルチタッチについて駆け足でしたが書いてみました。
読んでいただきありがとうございます。
最後にMultTouchを使ったサンプル動画を貼って終わりにしときます。


明日は  @rarihomaさんの「UE4+FMOD」です。FMODは前回のぷちコンの時@rarihomaさんが使っていて便利というのを聞いて調べようと思っていたところなのでありがたいです。


 

Q-display 4K50(QDPY001)を買ってみた

画質できには、そんなに悪くないように感じられた、
とりあえず、Sony製のBDV-M1Bで4KでBlue-rayを出力してみた結果
この通り。
IMG_0104 

IMG_0105 


IMG_0107
IMG_0109
IMG_0111
















IMG_0112


































































ちょうどFireTVが来てたので、それの出力の 1080pで出した結果がこんな感じ
安物ではあるけれども、HDMI1がARCになってて、音声出力のリターンが
できるみたいだけど、東芝のTVでは、ARC付きのHDMI以外の端子の音声出力も
ARCでリターンしてたんだけど、UPQの奴は、HDMI1のやつしかリターン
しないみたいなので、アンプとかには、光端子ケーブルで出力するしかないみたいね。

PCの出力は試してないけど、そのうちレビューが上がるだろうねぇ。 

Dynamic Material(Texture)を試す

今回はDynamic Material(Texture)を紹介します、UE4はBlueprintでいろいろできますが、
テクスチャ自体を生成して、それを貼り付けたいというのをやろうとすると、
Blueprintだけではできなかったりします。
そこで、C++を使ってテクスチャを生成してしまおうという手法です
詳しくの解説については、
Procedual Material をみてもらうとして、
サンプルプロジェクトとかソースとかがなかったので
それだけ用意しました、

簡単に解説すると
09のコピー














実行まえは、上のように、テクスチャが黒いのに、実行すると

24のコピー 














テクスチャ自体を書き換えて、赤色にできるという感じです、
これだけだと、Material Treeでもできるやろという感じなのですが、
たとえば、Displacement mapのテクスチャ自体を書き換えて、波のアニメーションを作ったりとかが
できるということなんです。 

で、サンプルプロジェクトは以下になります

download (82MB)

UE4で連続コンボを実装する


24
ステートの遷移グラフ


39
アニメーションBPの連続攻撃部分全部




07
攻撃のモーションのNotifyイベント


20

2番めの連続攻撃に行くか行かないかのステート条件




27
連続攻撃の2番めの攻撃のステート条件

53
キャラクタBP、ThirdParsonをちょっと改変しただけ



14

最初の攻撃の時の条件の式

29

4番目の攻撃のIdle状態に戻る条件
 


26

 キャラクタのAnimaionGraph

 




Xperia Z Ultra 買いました

IMG_0355



















 Xperia Z Ultra 買いました、使用感的には、仕事で、いろいろ今までいろんなAndroid端末
触ってきましたが、それと比べると、出来がものすごくいいです。iPhoneと比べるとAndroidって
動きのアニメーションがなぁっという人がいますが、はっきりいって、iPhoneよりも滑らかです
あと、Xperia Zのほうで電源関係のバグがありますが、これは、Sim Free 版のZ UltraのLTE版 ですが、
電源関係のバグはないです。 画面は発色がものすごくよいです。カメラについては、基本Xperia Zとかとほぼ同じなのでそんなに画質は変わりはないですが、厚さもiPad miniよりも薄いです。
薄さの感じ的には、iPad miniも板を持ってる感じがしたんですが、
Z Ultraはもっと板を持ってる感覚が強いです。
画面下の黒ふちの部分がちょっと長いかなと感じます。
IMG_0358
 


















上の画像は、iPad miniとの大きさの比較ですね。ちなみに、某店でマグネットの変換
アダプタ買ったんですがいまいちですね、端子がすぐはずれてしまいます。
買わない方がいいと思います。 

Androidアプリの速度の最適化

今回は、アプリを作ったときに反応速度が気になるときの最適化というか、速度がかわる方法を2つほどかきたいと思います。特にDBまわりとスレッドまわりです。
まず、DBまわり。
ネットワークを通してえた情報などをオフラインでも使えるように、DBに蓄えたりすることがあると思います。大量のデータをDBHelperでsqlを使ってInsertするときに 次のように一回ずつDBをオープンして、クローズしたりしてませんか?

public void insert(Data data) {
        SQLiteDatabase db = getWritableDatabase();        
        String insertSql;
         Date date = new Date();
        long time=date.getTime();
        insertSql = String.format(
                    "insert into log_table(insert_date,title,guid,category,description,public_date,vender_name,vender_code) "
                            +"values (?,?,?,?,?,?,?,?);");
        Object arg[]={ String.valueOf(time),data.title,data.guid,data.category,data.description,
                   data.public_date,data.vender_name,data.vender_code};
            db.execSQL(insertSql, arg);
        db.close();
 }

渡すデータをArrayListにして、DBに書き込む方法を最適化してみましょう。

    public void inserts(ArrayList<Data> data) {
        SQLiteDatabase db = getWritableDatabase();
        String insertSql;
        Date date = new Date();
        long time=date.getTime();
        db.beginTransaction();
        try{
        insertSql = String.format(
                "insert into     log_table(insert_date,title,guid,category,description,public_date,vender_name,
   vender_code) "
                        +"values (?,?,?,?,?,?,?,?);");

            SQLiteStatement stmt = db.compileStatement(insertSql);
            for(int ncount=0;ncount<newsdata.size();ncount++){
                if(results.get(ncount))continue;
                String related_link = "";
                String related_title="";
                Data nwdata = data.get(ncount);
                stmt.bindString(1,String.valueOf(time));
                stmt.bindString(2,nwdata.title);
                stmt.bindString(3,nwdata.guid);
                stmt.bindString(4,nwdata.category);
                stmt.bindString(5,nwdata.description);
                stmt.bindString(6,nwdata.public_date);
                stmt.bindString(7,nwdata.vender_name);
                stmt.bindString(8,nwdata.vender_code);
                stmt.executeInsert();
            }
            db.setTransactionSuccessful();
        }finally {
            db.endTransaction();
        }
        db.close();
    }

この方法を使うことで、実際アプリが5倍ほど早くなりました。
DB保存が遅いなと感じてる方はぜひ試してみましょう。

つぎに、スレッドです。
Asyncや、Threadを使うときにいつもPriorityをいじらずに使っているかたが、多いのではないでしょうか。PriorityをMIN_PRIORITYにするだけで、Galaxy系は2倍近く速度があがることが確認できました、
HTCの端末だと1.5倍ぐらいでした。Priorityを低くすると優先度が下がると思われますが、なぜか速度はあがります。いまのところ特にUI Threadが遅くなるとかもないようなので、設定するといいと思います。
Threadの場合は普通にsetPriorityで。
Asyncの場合は、doInBackgroundのなかで、
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
をすればいいです。

ぜひともお試しあれ。 
 

個人制作のアプリを公開しました

個人で作ったアプリがリリースされましたので、ここで紹介しておきます。YoutubeSoundCloudのクライアントで、リスト表示し連続再生ができるアプリです。プレイリストなどを検索する機能もついているので、他の人が作ったリストや、自分が作ったリストを一気に聞くことができます。
アプリはこちらです。
https://play.google.com/store/apps/details?id=com.freeworks.android.musicflow
よろしくお願いします。