BLOGブログ

2019.08.28UE4UE/ Editor拡張

[UE4]Stylus & Tablet Pluginでペンタブレットの入力を取得する

執筆バージョン: Unreal Engine 4.23 Preview


こんにちは、エンジニアの小倉です。
今回は、UE4.23にて新たに追加予定のStylus & Tablet Pluginを紹介します。
※ 記事執筆時点でプラグインはBETAバージョンです。

目次

1. Stylus & Tablet Pluginプラグインとは
2. ペンタブレットの入力を取得する
3. C++コードでプラグインを利用する

1. Stylus & Tablet Pluginとは

Stylus & Tablet Pluginは、ペンタブレットの入力を取得するためのプラグインです。

ペンタブレットの入力を取得するAPIには主に以下の2つがあり、Stylus & Tablet PluginはTablet PC APIを使用しています。

  1. WinTab API : Wacom製。Wacomのペンタブなどで使用される。
  2. Tablet PC API : Windows製。SurfaceなどのタブレットPCで使用される。

APIは2つありますが、多くのペンタブレット(Wacom, HUION, XP-Pen製など)はどちらでも使用できるようになっています。
今回の記事では、Wacomのペンタブレットを用いることにします(使用するペンタブレットによって、取得できる情報が少し異なります)。

2. ペンタブレットの入力を取得する

まずStylus & Tablet Pluginプラグインを有効にします。

次に、ペンタブレットの入力結果をデバッグ表示するためのウィンドウを起動します。
[Window][Developer Tools][Stylus Input Debug]を順に選択します。

以下のようなStylus Input Debugウィンドウが表示されます。
表示されている入力は全て取得できるわけではなく、使用しているペンタブが対応している入力のみとなります。

主な入力データは以下のようになります。

  • Position : ペンの位置
  • Normal Pressure : ペンの筆圧
  • Tilt : ペンの傾き
  • Is Touching? : ペンがタブレットに触れているか
  • Is Inverted? : 逆さまのペンがタブレットに触れているか(Wacomではペンについている「消しゴム」のこと)

注意が必要な点としては、現状ペンタブレットの入力を取得できるのはUE4のメインフレーム上(起動時に最初に立ち上がるメインウィンドウ)だけのため、例えばStylus Input Debugウィンドウ上でタッチなどをしても入力は取れません。その場合は、ウィンドウをメインフレームにドッキングするなどが必要です。以下は、メインフレーム上でペンを動かしたときの入力を、Stylus Input Debugウィンドウで表示したものになります。

3. C++コードでプラグインを利用する

では実際に、これらの入力をC++側から利用する方法を紹介します。
まず、プラグインをC++で使用するために、.Build.csのPublicDependencyModuleNamesにStylusInputモジュールを追加します。

// ~省略~
PublicIncludePaths.AddRange(new string[] {
// ... add public include paths required here ...
"StylusInput/Public"
});
PublicDependencyModuleNames.AddRange(new string[] {
"Core",
"StylusInput"
// ... add other public dependencies that you statically link with here ...
});
// ~省略~

次に、ペンタブレットに入力が行われたときに実行されるFMyStylusMessageHandlerクラスを定義します。

#pragma once
#include "CoreMinimal.h"
#include "UnrealClient.h"
#include "GenericPlatformMisc.h"
#include "IStylusState.h"
class FMyStylusMessageHandler : public IStylusMessageHandler
{
public:
virtual void OnStylusStateChanged(const FStylusState& NewState, int32 StylusIndex);
TArray<FStylusState> States;
};

#include "MyStylusMessageHandler.h"
void FMyStylusMessageHandler::OnStylusStateChanged(const FStylusState& NewState, int32 StylusIndex)
{
States.Insert(NewState, 0);
if (States.Num() > STATES_NUMS)
{
States.SetNum(STATES_NUMS);
}
}

FStylusStateオブジェクトは入力が行われたときのペンの位置や筆圧を保持しており、例えばGetPosition()関数やGetPressure()関数で取得することができます。
上記コードでは、ペンタブレットに入力が行われたとき、FStylusStateオブジェクトを配列の先頭から蓄積する処理を行っています。

作成したFMyStylusMessageHandlerは、以下のようにStylusInputサブシステムに登録することで有効になります。

UStylusInputSubsystem* SubSytem = GEditor->GetEditorSubsystem<UStylusInputSubsystem>();
SubSytem->AddMessageHandler(StylusHandler);
view raw gistfile1.txt hosted with ❤ by GitHub

他には、以下のようにStylusInputサブシステムから直近の値を取得することもできます。

UStylusInputSubsystem* SubSytem = GEditor->GetEditorSubsystem<UStylusInputSubsystem>();
const FStylusState current = SubSytem->GetInputDevice(0)->GetCurrentState();
const FStylusState previous = SubSytem->GetInputDevice(0)->GetPreviousState();
view raw gistfile1.txt hosted with ❤ by GitHub

記事冒頭にある「ペンで線をひく」エディタ拡張は、FStylusStateオブジェクトから取得できる位置を繋いだ線を、FCanvasLineItemによって描画することで実現します。
FCanvas関連のエディタ拡張については、以前の記事を参考にしてください。

現状では(少なくとも私の環境では)、ペンタブレットが入力として取れる位置の最大値(おそらく「Size」項目と思われる)が取得できないなどの問題があり、ペンタブレットのハードウェア的な差異をなくすような実装はそれなりに手間がかかるように見えました。