UnrealEngineをWebSocketのClientにする
わ、前回更新から1年以上経ってしまった....
はじめに
UnrealEngineと書いたのは、UE4・UE5どちらでも大丈夫だと思うため。
というわけで、Go製のWebServerに対してUnrealEngineからWebSocketを経由で通信するサンプルを作りました。
これの解説を行います。(今回はUE5でいきます)
完成イメージ
プラグインにGameInstanceSubsystemを継承したSubsystemを作成し、その中でWebSocketをServerへつなげて、Serverからメッセージを受け取ります。
それをEventDispatcherにしたので、以下の画像のように使うことができます。

解説
WebServer
github.com/gorilla/websocketのcommand exampleを参考に書きました。
ここの解説は上記のリンクに譲ろうと思います。
UnrealEngine
まず初めに、.Build.csファイルの依存モジュールにWebSocketsを追加します。
PublicDependencyModuleNames.AddRange( new string[] { "Core", // ... add other public dependencies that you statically link with here ... "WebSockets", // 例えばこんな感じ } );
続いてSubsystemを作成します。
とりあえずは常時存在してほしいので、GameInstanceSubsystemを継承したクラスで作成します。
headerの完成形はこちら
UnrealWebSock_Sample/WebsocketSampleSubsystem.h at master · crssnky/UnrealWebSock_Sample · GitHub
一部解説していきます。
9行目:IWebSocketを前方宣言します。
11行目:このプラグイン専用のLogカテゴリを宣言します。
12行目:メッセージを受信した際に発火するイベントを宣言します。
22,33行目:UGameInstanceSubsystemのInit, Deinit関数をOverrideします。
25,26行目:最後に受け取ったメッセージを取得する関数を宣言します。
29,30行目:BlueprintからBindできる、メッセージを受信した際に発火するイベントオブジェクトを宣言します。
33~36行目:ソケットオブジェクトのためのイベント関数を宣言します。
38行目:ソケットオブジェクトを宣言します。
39行目:最後に受け取ったメッセージを保持する。
sourceの完成形はこちら
UnrealWebSock_Sample/WebsocketSampleSubsystem.cpp at master · crssnky/UnrealWebSock_Sample · GitHub
void UWebsocketSampleSubsystem::Initialize(FSubsystemCollectionBase& Collection)
Socketオブジェクトを作成し、各種イベントに関数をバインドしていきます。
オブジェクト作成には、WebServerのURIやサブプロトコルwsを入れます。
(本来ならばサブプロトコルはちゃんとするべきですが、テスト用でサーバー側に処理がなく、以下のようなエラー文を経由するため、何かしらを入れておく必要があります)
UE_LOG(LogWinHttp, Warning, TEXT("Attempted to create a WinHttp WebSocket with an empty protocols list"));
設定が終わったら、最後に接続します。
void UWebsocketSampleSubsystem::Deinitialize()
GameInstanceが消える前に、Socketを切断してメモリ領域を開放します。
FString UWebsocketSampleSubsystem::CurrentMessage() const
最後に受け取ったメッセージを取得する関数です。
void UWebsocketSampleSubsystem::OnSocketConnected() const
Socketが接続したときに呼ばれる関数です。
とりあえず確認用に、ログを吐きます。
void UWebsocketSampleSubsystem::OnSocketConnectioinError(const FString& err) const
Socketの接続に失敗したときに呼ばれる関数です。
とりあえず確認用に、Warningレベルで理由を出力します。
void UWebsocketSampleSubsystem::OnSocketClosed(const int statusCode, const FString& reason, const bool wasClean) const
Socketが切断したときに呼ばれる関数です。 とりあえず確認用に、ログを吐きます。
void UWebsocketSampleSubsystem::OnSocketMessageReceived(const FString& msg)
Socketがメッセージを受信したときに呼ばれる関数です。
受け取ったメッセージを保持し、そのメッセージをイベント発行します。
おわりに
本当に、簡単にWebsocketを繋げてメッセージを受信することができました。
ミニマムで言えば、Initialize・Deinitialize・OnSocketMessageReceivedのみを実装するだけで良いので、本当に簡単です。
何かしらのWebサービスと繋げることも難しくありません。何かの可視化ツールとしても使ってみるのはいかがでしょうか?
Rust製pastelコマンドにimas色機能を追加する
はじめに
Rust製pastelコマンドとは以下のやつです。

(gifはリポジトリから拝借)
pastel is a command-line tool to generate, analyze, convert and manipulate colors. It supports many different color formats and color spaces like RGB (sRGB), HSL, CIELAB, CIELCh as well as ANSI 8-bit and 24-bit representations.
つまり、CLI上で色に関することをいろいろできるということですね。
その"いろいろ"を実現するために、様々なサブコマンドがあります。
そこにimasを追加して、アイドルやユニットのイメージカラーを取得できるようにしてみました。
pastel 0.8.1
A command-line tool to generate, analyze, convert and manipulate colors
USAGE:
pastel [OPTIONS] <SUBCOMMAND>
OPTIONS:
-m, --color-mode <mode> Specify the terminal color mode: 24bit, 8bit, off, *auto*
-f, --force-color Alias for --mode=24bit
--color-picker <color-picker>
Use a specific tool to pick the colors [possible values: gpick, xcolor,
grabc, colorpicker, chameleon, kcolorchooser]
-h, --help Prints help information
-V, --version Prints version information
SUBCOMMANDS:
color Display information about the given color
list Show a list of available color names
random Generate a list of random colors
distinct Generate a set of visually distinct colors
sort-by Sort colors by the given property
pick Interactively pick a color from the screen (pipette)
format Convert a color to the given format
paint Print colored text using ANSI escape sequences
gradient Generate an interpolating sequence of colors
mix Mix two colors in the given colorspace
colorblind Simulate a color under a certain colorblindness profile
set Set a color property to a specific value
saturate Increase color saturation by a specified amount
desaturate Decrease color saturation by a specified amount
lighten Lighten color by a specified amount
darken Darken color by a specified amount
rotate Rotate the hue channel by the specified angle
complement Get the complementary color (hue rotated by 180°)
gray Create a gray tone from a given lightness
to-gray Completely desaturate a color (preserving luminance)
textcolor Get a readable text color for the given background color
imas Get a Im@s idol's image color from im@sparql. <--- こんな感じ!!!
help Prints this message or the help of the given subcommand(s)
↑ サブコマンドに追加
そして、出来上がったものがこちら

こんな感じになります。
それでは解説していきます。
Rustからim@sparqlを叩く
im@sparqlへのクエリは以下になります。
REFIX imas: <https://sparql.crssnky.xyz/imasrdf/URIs/imas-schema.ttl#>
PREFIX imasrdf: <https://sparql.crssnky.xyz/imasrdf/RDFs/detail/>
SELECT distinct ?c
WHERE {
imasrdf:{} imas:Color ?c
}
今回は軽めの実装にするため、im@sparql内のリソース名を入力してもらうようにします。ですのでimasrdf:{}の{}には、アイドルやユニットのリソース名(Kisaragi_Chihayaやnoctchillなど)が入ります。
デシリアライズの詳しい内容は過去の記事へ。だいたい一緒です。
imas.rsファイルをcommandsフォルダに作成して処理を作ります(コード)。
HTTP GETするURLは以下のように作ります。form_urlencodedを利用すれば、クエリストリングを良い感じにしてエンコードまでしてくれます。
また、ureq::get().call()であれば同期処理でコールします。今回のようなものは、コールバック書かなくて良いのでラクですね。
let encoded_query = form_urlencoded::Serializer::new(String::new())
.append_pair("output", "json")
.append_pair("force-accept", "text/plain")
.append_pair("query", &query)
.finish();
let sparql_url = format!(
"https://sparql.crssnky.xyz/spql/imas/query?{}",
encoded_query
);
let res = ureq::get(&sparql_url).call();
if res.ok() {
・・・
}
im@sparqlのレスポンスを解釈する
受け取ったJSONを構造体に変換し、カラーコードを抜き出してColor構造体に変えているだけです。u8::from_str_radixを使えば、Hex文字列から数値に変換してくれます。
let json_str = res.into_string().unwrap();
let res_json: Response = serde_json::from_str(&json_str).unwrap();
let json = res_json.results.bindings;
if json.len() > 0 {
for data in json {
let color_string = &*(data.c.value);
if color_string.len() >= 6 {
let red: u8 = u8::from_str_radix(&color_string[0..2], 16).unwrap();
let green: u8 = u8::from_str_radix(&color_string[2..4], 16).unwrap();
let blue: u8 = u8::from_str_radix(&color_string[4..6], 16).unwrap();
let color = Color::from_rgb(red, green, blue);
out.show_color(&config, &color)?;
}
}
}
imasコマンドを追加する
まずは、mod.rsファイルです(コード)。
上部のmod郡にimasを追加します。また、imas:ImasCommandを使うよう指定します。
mod imas;
use imas::ImasCommand;
あとは、imasというサブコマンドを実行したときに、imas:ImasCommandが使われるようimpl Commandのpub fn from_string()に指定します。
"colorcheck" => Command::Generic(Box::new(ColorCheckCommand)),
"imas" => Command::Generic(Box::new(ImasCommand)), // これ
_ => unreachable!("Unknown subcommand"),
次にcli.rsファイルです(コード。
サブコマンドがたくさん並んでいますので、そこにimasコマンドの引数やヘルプを書いておきます。
.subcommand(
SubCommand::with_name("imas")
.about("Get a Im@s idol's image color from im@sparql.")
.long_about("Get a Im@s idol's image color from im@sparql.\n\n\
Example:\n \
pastel imas Kisaragi_Chihaya")
.arg(color_arg.clone()),
)
おわりに
以上が解説です。これを応用すれば、色に関する様々なアプリケーションを作成できると思います。
特に元から実装されている可視化部分がよく出来ています。imasコマンドも色を取ってきて、Color構造体に入れるだけで良い感じに可視化されるため、色を取得する部分だけでもカスタムすると面白いと思います。
HoloLens2で北朝鮮のミサイル実験を可視化 with UE4
デモ
ブログ用 pic.twitter.com/dZtI6MWv6u
— croMisaP (@croMisa) 2021年5月3日
発表資料
(16:9のスライドは埋め込みだと崩れちゃうか~) speakerdeck.com
はじめに
Tokyo HoloLens ミートアップ vol.26ではありがとうございました。
発表ではめちゃくちゃ駆け足になってしまったため、詳細に解説していきます。
内容としては、UE4を利用してHoloLens2で北朝鮮のミサイル実験を可視化した話です。
記事がめちゃ長くなりそうだったので、各要素ごとで記事にしています。
(弾道ミサイルのことはよく分からなくても記事が読めるように...)
HoloLens2とは
みなさんご存知のMicrosoftが提供するMixedRealityデバイスです。
ゴーグル型のこのデバイスを着けることで、複合現実を利用することができます。
PC等に接続せずスタンドアロンで動作し、デバイスに外向きに取り付けられたカメラで周囲の形状や装着者の手の動きを認識します。
それこそが"複合現実"です。
データ
地球儀
UEGeoCoordinates Plugin
MRTK For Unreal UX Tools
まとめ
HoloLens2、UnityもいいけどUE4もよろしくね!
UE4向けMRTK UX ToolsとUMGでらくらくUI作り
はじめに
https://crssnky.hatenablog.jp/entry/2021/BMD
↑の子記事となっています。記事の背景を知る場合はこちらから参照ください。
MRTK UX Toolsとは
Mixed Reality Tool Kitはみなさんご存知かと思いますが、それのUE4版の主なツールキットです。
UE4ではUX Toolsの他に、Graphics ToolsというMR向けマテリアルキットがあります。
UMGとは
誤解を恐れずに言えば、GUIとBlueprintで記述可能なUIシステムです。
ゲーム内はもちろん、UE4 Editorの拡張機能を作る場合にも使えます。
デモ

こういうハンドメニューだったり、

UMGのListViewだって置けちゃいます。
今回は、この2つのUIを例に解説します。
ハンドメニュー
https://github.com/microsoft/MixedReality-UXTools-Unreal/blob/public/0.12.x/Docs/HandMenu.md
公式ドキュメントとやっていることは変わらない。

見た目とコンポーネントはこのようになっています。
SceneComponentはRootをUxtUIElementにします。
ここに、UIの部品を入れていくわけですが、単純なSceneComponentによるPivotを一個挟むことを個人的にはオススメします。
というのも、位置を調整できるようにしないと、デフォの位置では下記画像のように手に埋まってしまう可能性があります。

X軸方向にズラしましょう。僕は8くらい移動させています。
UxtBackPlateはUIの背景用のコンポーネントです。ただのStaticMeshComponentではなく、UX Toolsのカスタム?品です。
下記画像を見てください。有る無しでは、UIのまとまり感がぜんぜん違うと思います。

各種ボタンについては、ChildActorComponentで他のBlueprintファイルを埋め込む形を取っています。
それらの解説は次の章へ
各種ボタン
https://github.com/microsoft/MixedReality-UXTools-Unreal/blob/public/0.12.x/Docs/PressableButton.md
ボタンに関しても、公式ドキュメントと変わらない。

UxtPressableButtonを継承したBlueprintで作ります。
そうすれば、各種プロパティをいじるだけで良い感じのボタンになるでしょう。
いじるのは以下のプロパティです。BlueprintのDetailsにあります。

ボタンのサイズやアイコン、ラベルを好きに変えていきましょう。

ボタンにはたくさんのイベントが用意されています。困りませんね。
ListView
https://github.com/microsoft/MixedReality-UXTools-Unreal/blob/public/0.12.x/Docs/WidgetComponent.md
UMGであるListView(Widget)を入れる方法の公式ドキュメントはこちら↑
え?BlueprintだけでListViewを作る方法がわからないって?だったら下記のForumを参考にすると良いですよ。僕はこれに何度も救われています(いつまで経っても覚えていない)
ListViewのUMGファイルを作ったあとということで進めていきます。

見た目とコンポーネントはこのようになっています。
UxtFollowは、HoloLens2の向きにUIを追従させるためのActorComponentであり、SceneComponentではないのですが、なぜかSceneComponentの場所に入っています。なんでやねん。

ちゃんと、Non-scene componentって書いてある↑
UxtWidgetは、UMGに触れられるように、手の当たり判定とUMGをつなぐためのコンポーネントです。
これと、Widgetコンポーネントを配置することで、触れられるUMGを表示して操作することができます。WidgetコンポーネントはちゃんとScreenSpaceではなく、WorldSpaceに配置するように設定してくださいね。
ちなみに、ListViewのスクロールは右のスクロールバーで行います。スマフォでよくあるListView全体をぐいーってスライドしてもスクロールしませんからね!(僕はその罠に嵌りました)
UxtBackPlateは前述の通り背景用です。これが無ければ本当に背景がありません。
CloseButonは、このBlueprintを閉じるためのボタンです。UMG側に用意するとWidgetだけ閉じられてしまうので、Blueprint自体をDestroyできるようにBlueprint側で用意します。
(今思えば、Widget側でイベント発行してBlueprintで受信すれば良かったか?)

おわりに
以上、簡単なボタンを持つUIやUMGを埋め込んだUIを作る方法でした。正直、UMGが使えてしまうのであればなんでもできちゃうので、HoloLens2のUIに関してはできないことが無いと思います。
とはいえ、UX Toolsの標準的な見た目のみを使っているため、見た目に凝ったUIに関しては制約があるかもです....
UE4のUEGeoCoordinates PluginでGeocentricしてみる
はじめに
https://crssnky.hatenablog.jp/entry/2021/BMD
↑の子記事となっています。記事の背景を知る場合はこちらから参照ください。
UEGeoCoordinates Pluginとは
EpicGamesが作っているUE4の公式プラグインです。
最初に言うと、このプラグインはUE4.26向けにプレビュー版として公開されており、次期バージョンのUE4.27では"GeoReference Plugin"として標準搭載されています。
もちろん、今回お話する内容はUE4.26向けのプレビュー版です。4.27ではたぶん違います。ソース見たら違ったし...
UEGeoCoordinates Pluginは、おそらく"Project Anywhere"のために作られたと予想します。現実の座標(緯度経度など)を表すためのクラスや倍精度浮動小数点を使った座標クラスなど、シミュレーション用途で必要そうなものが揃っているので。
このプラグインの使い方や現実での座標の考え方は、プラグインのリポジトリにPDFがあるのでそれを見ると分かります。座標の考え方や座標参照系など、馴染みが薄いものが分かりやすい英語と図で解説されているのでここで書く必要は無いでしょう。
Geocentricしてみる①
Geocentric coordinate systemとは、いわゆる地心座標系です。
地球の中心を(0,0,0)とし、北極点をZ軸方向、本初子午線をX軸方向、東経90度方向をY軸方向とする座標系です。単位はmで、3D界隈の人にはとっつきやすいものかと思います。
(Y軸が上方向でしょ。など、軸に関しては言いたいこともあるかもですが...)
これをね、そのままUE4に適用しちゃえば良いって話ですよ。
BP関数はこちら↓

Geographical coordinate systemは、いわゆる地理座標系です。ですので、この関数の入力は緯度, 経度, 高度(Lat, Lon, Alt)です。
プラグインのSubsystemからGeographic to Geocentric関数を呼び出すだけで変換できます。ただ、出力は倍精度浮動小数点を使った座標クラスであり、単精度浮動小数点数を使うVector3では使えません。自作の関数で、泣く泣く精度を下げています。
Geocentricしてみる②
Blueprint内で緯度経度からXYZに変換する方法は分かりました。しかし、Level内に原点を設定する必要があります。

GeoreferecingActorをLevelに置きましょう。これ自体の座標は関係ありませんが、Origin Projected Coordinatesや各種CRS(座標参照系)を指定してあげる必要があります。

Origin Projected Coordinatesは原点にしたいLevel内の座標を指定します。何も考えず、(0,0,0)でも問題ないです。
CRS(座標参照系)は、プラグインのPDFの通り、https://epsg.io/ で探しましょう。"CRS Tokyo"などでGoogleで調べても良いかもしれません。
入れたい緯度経度が日本周辺だったため、上記画像の値は東京となっています。
GeoreferencingSubsystemはこのActorの設定値を読み取り、適切な変換を行います。
おわりに
変換すれば、以下のように良い感じで緯度経度をUE4のワールド座標に変換することができます。
(これは発射点と着地点の間に最高点を入れて補間してるけどね)
ブログ用 pic.twitter.com/qViln0sUM2
— croMisaP (@croMisa) July 10, 2021
UE4でHoloLens2でも使える、昼夜を表す地球儀を作ろう
はじめに
https://crssnky.hatenablog.jp/entry/2021/BMD
↑の子記事となっています。記事の背景を知る場合はこちらから参照ください。
また、昼夜を表せられる地球儀をサクッと作りたい方向けです。
そんなに精密なものではありません。
デモ
ブログ用 pic.twitter.com/ewRHfa7gwF
— croMisaP (@croMisa) July 10, 2021
このような感じで、昼夜のテクスチャを向きで切り替える地球儀です。
テクスチャ
地球の画像と言えば、やはりNASAのBlueMarbleでしょう。
この中から、昼の地球と夜の地球を選びます。
夜の地球は一枚しかない(Earth’s City Lights)ので良いのですが、昼の地球(Blue Marble Next Generation)はいろいろな季節のものがあります。お好きなものを選びましょう。
モデル
球体であればなんでもいいです。
僕はBlenderで65280頂点の球体を作りました。それくらいでもHoloLens2は余裕みたいです。
マテリアル
UE4のお時間です。全容はこちら↓

おそらくこれはBestWayじゃないだろうけども、許してね。
まず下段ここ
ここですが、ラフネスを求めています。
海の部分だけ強く反射してほしい気分だったので、なんか良い感じに求めています。
(理論は無く、本当に"良い感じで"求めました)
そうすると、以下のような感じになります。


次は上段ここ
ここは、外から入力された光の向き(Vec4)と、ローカル座標の内積を取得しています。
マテリアルに当たる光をDirectionalLightにすることで、昼夜の判定を模擬します。
光と内積については、以下ブログの"セルシェーダーと内積"の章を見ると分かりやすいです。
UE4 誰でもわかるセルシェーダー入門 - Let's Enjoy Unreal Engine
最後はここ
内積による昼夜の判定から、ifノードで表示するテクスチャを選択しています。
Emissiveにも入れることでDirectionalLightしか無い宇宙空間でも、光の当たらない方を見せることができます。
Blueprint
コンポーネントはこんな感じです↓

SceneComponent系は、StaticMeshComponentだけです。作った球体メッシュに作ったマテリアルを貼ってあげましょう。
ActorComponent系は、HoloLens2による入力を受けるためのコンポーネントです。主にTransformを変えるためのものです。説明は割愛。
マテリアルで取得するための光の向きはBlueprintで入れます。
このようなBP関数を作り、ConstructionScriptはもちろん、Tickなどで定期更新してあげましょう。常にTickを呼ぶのはアレなので、僕はHoloLens2がGrabしているだけTickするようにしています。
おわりに
以上です。簡単!環境によっては、画像をDLする時間やマテリアルをビルドする時間の方が手を動かす時間より長いかもしれませんね。
説明は割愛しましたが、HoloLens2のMRTKのコンポーネントを入れることで、自分の手で動かしたり回したりできます。まさに地球儀です。
ここになにか情報を重畳してあげることで、MRでリッチな自分だけの地球儀を作れるようになると思います。
cereal-UE4でJSONデータを読み込む
はじめに
https://crssnky.hatenablog.jp/entry/2021/BMD
↑の子記事となっています。記事の背景を知る場合はこちらから参照ください。
データ
実は、北朝鮮のミサイル実験のJSONデータはこのリポジトリにまとまっています。
このリポジトリは、元々Webアプリケーションとしてミサイル実験の可視化を行うプロダクト(ReadMe参照)のものですが、そこに使われているものがよくまとまっており、定期的に更新もされているため非常に使いやすいです。
本プロジェクトでは、
を読み取ります。
ライブラリ
読み取りに使うのは、cerealというC++のJSONライブラリです。UE4で扱うため、cereal-UE4も追加で入れます。
使い方は、伊藤兎さんのcereal-UE4に関する記事を読むと分かりやすいです。
GitHub - USCiLab/cereal: A C++11 library for serialization
元データは以下のような形のため、C++で非常に解釈しづらいです。
{ "er-scud": {"name": "スカッドER", "type": "MRBM"}, // keyに名前が入っている "hwasong-12": {"name": "火星12号", "type": "IRBM"}, .... }
ですので、自前で良い感じに整形してから(前処理として)、C++で読み込んでいます。
{ "root": { "missiles": [ { "key": "er-scud", // 名前をvalue側に移した "name": "スカッドER", "type": "MRBM" }, { "key": "hwasong-12", "name": "火星12号", "type": "IRBM" }, .... }
これならば、以下のC++で読めますね。
USTRUCT(BlueprintType) struct FMissile { GENERATED_BODY() UPROPERTY(BlueprintReadWrite, Category = "MissileTest") FString key; UPROPERTY(BlueprintReadWrite, Category = "MissileTest") FString name; UPROPERTY(BlueprintReadWrite, Category = "MissileTest") FString type; }; template<typename T> void serialize(T& a, FMissile& in) { a( make_nvp("name", in.name), make_nvp("key", in.key), make_nvp("type", in.type) ); }
おわりに
UE4でJSONを解釈するための、個人的BestWayでした。伊藤兎さんの記事にある通り、標準機能はBestではないためこちらを利用することをおすすめします。