てんちょーの技術日誌

自分がつまづいたこととかメモ

VRキーボードのためにキーボードを封印したお話

はじめに

ちょっと前にGOROmanさんがこんなことを言っていました。

じゃあ実際にやってみよう!!ってことでやりました。 

マウスを封印するお話はいくつか聞いたことがありますが、キーボードを封印するお話は聞いたことがなかったので面白いかなと。

VRキーボードを除いたのはTwitterができない可能性があったので一応保険的な意味です。(結局使わなかった

条件

キーボードと名のつくものを封印します。

例として

  • PC向けの普通のキーボード
  • スマホで使えるキーボード類
  • ATM等の数字を入力する系のキーボード

などを封印しました。基準としては、数字や文字を選択してからEnterで確定するものをキーボードと定義しました。

事前準備

使ってるマイクはこれ

http://www.yodobashi.com/ec/product/100000001001262667/index.html

ATM

Cortana

ピクチャパスワード

kiritsume.com

windows音声認識

特に書いてませんが、Siriのセットアップもしました。

だが

音声認識ツールの使い心地

Cortana

対話式なので、一気にしゃべらないといけない点を除いて多分1番精度がいい。

だができることが少ない。もったいない。後述のwindows音声認識の機能を全てCortanaで出来るようにすればもっといい。

認識精度が良すぎなので、これを作った。なお全て音声認識で記事を書いてます。

スクリプトはさすがにコピペ祭りですが。

shop-0761.hatenablog.com

windows音声認識

windowsの操作が色々できるので便利っちゃ便利。 CortanaだとEnterができないので、その度にこいつでEnterを入力していました。

一応ここまで出来る。

未来感ありますね!!  ただ非常に面倒。(何回も撮り直しをしている

コマンド一覧はこちらに。

https://support.microsoft.com/ja-jp/help/12427/windows-speech-recognition-commands

多分こいつは教育できるので精度は上がる…はずなんですが、

と、ほぼ部屋に一人の状態かつ、BGMもかけられない感じでアレです はい。

Siri

Siri自体も簡単なセットアップがあるのですが、なぜかHeySiriで起動しない…

それもあってあまり使っていない…

けど、副産物的に利用できるようになる音声入力がありました。

weekly.ascii.jp

こいつが意外と使えます。対話式ではないので、多少考えながら発話できます。

ただ、途中で変換予測が変わったりして荒ぶったりすることもありますが。

iPhoneにもAndroidのパターンロックが使えるようになって欲しい…(指紋認証できるけど、ミスると結局キー入力なのでロックを切ってた

使ってみた感想

いいところ

意外と生活できるし、メールも返信できました。

ただ時々思ったように変換してくれなくて、不必要な部分をカットしたり、ペーストしてツギハギしたりしてました。

主婦さん(@Somelu01)さんとも普通にDMしたりできました。

そして、手が疲れない!!大事!!

悪いところ

誤認識時の修正が面倒。 固有名詞が認識できない。(これは辞書がないのでしゃーないけど

打ちたい内容がダダ漏れ。 居間とかでTwitterが出来ないし、話しかけたと思われてしまう。

コードが書けない。

不思議なお話

これ、結構不思議な話で、ある程度意識的に口を閉ざしている場面が幾つかあり、なぜか無口になる時がありました。

多分なんですが、音声認識される環境に居続けると余計な発言までも認識されてしまうと思ってしまい不必要な発言を避けてしまうのかも。

これはこれで卒論が書けてしまいそうですね…

まとめ

音声認識 割りといける。Juliusも使ったことがありますが、未調整のと比べるとかなり精度がよくなってきています。

一度Cortanaを封印しないで使ってみては?

コルタナの音声認識の結果をクリップボードに貼り付けるスクリプトを書いてみた

はじめに

キーボードを封印して音声認識だけで生きています

この記事も音声認識だけで書いています

コルタナの音声認識の結果がかなり良いのでそれを利用したいと思いパワーシェルのスクリプトを書いてみました( なおキーボード封印中

今回書いたもの

スクリプト更新しました( 2017年1月4日 簡単なDebug出来るようにしました

追記 2017/01/04

以下のスクリプトをパワーシェルに貼り付ける分には動くっぽいのですが、.ps1にするとアウトっぽいので取り急ぎdropboxのリンクを貼っておきます

時間がある時に修正します…

www.dropbox.com

while(1)
{
  $psArray=[System.Diagnostics.Process]::GetProcesses()
  $str=""
  foreach ($ps in $psArray){
    if($ps.MainWindowTitle -like "*Microsoft Edge"){
      #[System.Console]::WriteLine("Microsoft Edgeを発見 Handle: " + $ps.Handles + " MainWindowTitle: " + $ps.MainWindowTitle)
      Add-Type -AssemblyName system.Windows.Forms
      $cp=[Windows.Forms.Clipboard]
      $ps.MainWindowTitle.foreach{
        if($_ -match "(.*)\s[-]\sBing"){
          #[System.Console]::WriteLine("Bing検索してるMicrosoft Edgeを発見")
          $str=$matches[1]
          if($str -match "コピー終了"){
            [System.Console]::WriteLine("終了します")
            $ps.CloseMainWindow()
            $ps.Close()
            exit
          }
          $cp::SetText($str)
          [System.Console]::WriteLine("$str")
          $ps.CloseMainWindow()
          $ps.WaitForExit(3000)
          $ps.Close()
          break
        }
      }
    }
  }
}

これをパワーシェルのスクリプトで起動します

コルタナは反応に困ったらマイクロソフトエッジのbing検索を使うので、

マイクロソフトエッジのプロセスを監視してそのメインウィンドウのタイトルから正規表現で認識結果を切り取ります

追記ここから

スクリプトを更新しました

これでコピー終了というとスクリプトを停止できます

ダブルクリックで実行できるファイルを作る

このスクリプトをメモ帳などに貼り付けて、.ps1形式で保存した後に、ショートカットを作成します

そのショートカットのプロパティからリンク先の先頭に以下のように追加します

powershell -NoProfile -ExecutionPolicy Unrestricted "ファイル名"

これで適用するとpowershellの部分が勝手にpowershellがある場所のパスに変わりますがおっけーです

実質、powershell~Unrestricted までコピーして、ファイル名の前に貼っ付ければ終わりです

そうするとダブルクリックで起動できます

後はpowerShellが起動するので、コルタナに話しかけてbing検索する際にMicrosoft Edgeが一瞬起動しますが、 勝手に閉じて、クリップボードにその結果が貼り付けられてます。

ログが一応powerShellの方に表示されます。

追記ここまで

まとめ

パワーシェルのスクリプト初めて書きました

人に読ませる文書にするにはちょっと大変だけど音声認識でとりあえずここまできました

これでとりあえず快適にツイッターができます

【UE4】OculusTouchでHapticEffectが使えないとき

PlayHapticEffectが動かない

Touchのコントローラの振動にはPlayHapticEffectを使えとあります。

developer3.oculus.com

要約すると、ここからHaptic用アセットを作って適用できるよと。

f:id:shop_0761:20161023023737p:plain

  • Haptic feedback Effect Buffer 数値指定
  • Haptic feedback Effect Curve カーブで指定
  • Haptic feedback Effect Sound Wave 音声ファイルから生成

と3つあります。

今回は適当にカーブを作りました。

f:id:shop_0761:20161023023959p:plain

でHapticEffectに入れて終わり。あとは好きなところで。

f:id:shop_0761:20161023024214p:plain

これで使えるようになります。

しかし、手を抜きたいあまり、Riftのセンサーを片手で塞ぎながら空いてる手でデバッグすると反応しませんでした。

どうやらTouchを持った時に生じる揺れ(人の手は完全に静止しないので)をTriggerにしてるようです(勘)。

なので両方持つか、ちゃんと被るか、足にでもつけるかしないと振動しません。

【UE4】簡単な音声認識をしてみた

はじめに

Unreal Engine 4 (UE4) Advent Calendar 2016 10日目です。

qiita.com

本記事の主役とも言えるほげたつさんのアセットのレビューがされている こちらの記事も合わせてお読みください(何ももらってませんよ)

pafuhana1213.hatenablog.com

今回はちょーお手軽に音声認識をしてみようと思います。

というのもmikulusを見てるとUnityは標準で音声認識が出来たり、プラグインを探すと大体英語対応のものばかりで辛い目に遭いました。

なので作りました。

現在作成中のVR内で使えるキーボードに音声認識で入力アシストするのに使っています。

イメージ

こちらテスターを募集しているのでOculusTouchがある方はぜひお願いします。@shop_0761にご連絡ください。(圧倒的テスター不足)

方針

色々遠回りしたお話は、あとに書くとして端的に実装方針を説明します。

http通信を用いて実装します。

しかもこれ、ほげたつさんがすでにプラグインを作成して公開しています!!

hogetatu.hatenablog.com

つよい。

ちなみに

らしいので先日のこちらの記事を参照してゆくゆくは移行しましょう。

hogetatu.hatenablog.com

http通信については適当にググるか、頭を空っぽにしてそういうものがあるんだなくらいでも動きます。

で、音声認識側のツールはC#で適当に作れます。

参考サイトを貼っておくので自作しても構いません。先人は偉大!

参考:

neareal.com

www.misuzilla.org

面倒な方は僕がすでに作成したものでも使ってください。実行するだけです。おわり。

www.dropbox.com

ダウンロードするだけで環境が整ってしまいました。

音声認識の精度について

精度的なお話だと、

コマンドプロンプトで UWP の音声認識APIを利用するサンプル。NuGet で UWPDesktop を追加してください。https://blogs.msdn.microsoft.com/lucian/2015/10/23/how-to-call-uwp-apis-from-a-desktop-vbc-app/ · GitHub

こちらのほうがいいかもしれません。ただなぜか手元の環境だと、

await contSpeechRecognizer.ContinuousRecognitionSession.StartAsync();

のところで The speech privacy policy was not accepted prior to attempting a speech recognition. と言われてしまい実行できず…

音声認識のプライバシーポリシーってどこで設定するんだ…となってしまったので詳しい方がいればぜひお教えいただけると嬉しいです。

このように認識は外部のツール依存なので、自作してチューニングすればよりよいものになるかと思います。

実装する

と言っても、大したことはしません。

先程のほげたつさんのプラグインにはサンプルプロジェクトWebApiDemoがあるので、それを起動します。

その中にあるWebApiDemo/WebApi/Api 内にあるBP_DemoApiBaseを開きましょう。

f:id:shop_0761:20161202234346p:plain

そして、継承元の変数を表示するために赤線のところにチェックを入れます。

すると

f:id:shop_0761:20161202234427p:plain

Domain変数が見えます。

今回はアプリのポートの都合上ここを http://127.0.0.1:50001/ に書き換えます。

f:id:shop_0761:20161202234559p:plain

あとは、さっきの音声認識のツールを実行後にUE4側で実行しましょう。

SimpleGetを押せば終了!!

f:id:shop_0761:20161202235109p:plain

音声認識の結果が得られます。

ちなみにこのStringはBP_01_SimpleGet内のResponsebodyに入ってるので後はご自由に。

f:id:shop_0761:20161202235534p:plain

VRKeyboardの方ではTickで適当にポーリングするBPComponentにしてます。

応用例

普通に音声認識してそのまま使ってもいいのですが、ちょっとあちこち手を加えてこんなことをしてみました。

音声認識した結果を使ってLipSync的なことをしています。これをLipSyncさせても面白いかもですね。

色々できるので遊んでみてください。

辛い目にあったお話

これ以降は今回の記事に至るまでに迷子になった余談なので、気が向いたら読んで下さい。

きっかけはこの辺

こんなのあるんだ と思って調べてみたら Pocketsphinxってのがベースらしく

と、以外にも日本語の音声認識プラグインが無いことを知りました。

しばらく経って、先程のwin10で動く音声認識のサンプルがあるのを知ったので、これUDP通信で実装するできそうと思ってました。

よく聞くJuliusとかでプラグインでも作ったほうがよさそうかなと思いましたが、あれはデフォのままだとかなりアレな感じなのでガツガツやるにはいいのかもしれません…(DNNベースでもHMMベースでもできます)

じゃあさっそくH社のUDPのサンプルを読みつつ進めていくと、デシリアライズの方法で引っかかりました。

UDP Socket Sender Receiver From One UE4 Instance To Another - Epic Wiki

こことか見てたんですが、日本語stringの場合文字コード周りで死にたくなりましたね…。C++から文字コードを日本語にする方法が見当たらなかったので、 お友達に聞くとpythonをかますか、http通信にしたほうがいいよと言われたので、今回の方法に落ち着きました。

UnrealC++を読む機会が出来たので、副産物的に前よりは抵抗感がなくなりまし た。

まとめ

そろそろデフォで音声認識ができてもいいんじゃないかなとは思います。

ただVR_keyboardで日本語の変換周りを扱っていると日本語難しいなと思ったので、当分ないだろうなと思ってしまいました。

明日はprince_ue4さんの「エフェクトネタやります」です。

【UE4】水彩風マテリアルを作ってみた

はじめに

Unreal Engine 4 (UE4) Advent Calendar 2016 8日目です。

qiita.com

我らがおぎまふさんやcom04さんなど、いろいろな方がトゥーン表現に挑戦されています。

最近ではMarketPlaceでもトゥーンなアセットが出てきたりしています。

いろいろ参考サイトをまとめていたのですが、com04さんの記事を見たほうが早いですね…

qiita.com

ですがやっぱり自分好みのものを作りたい…と思って探していたら参考になりそうなところを見つけました。

d.hatena.ne.jp

こちらのサイトではsoftImageですが、なんとかそれっぽくなりました。

マテリアルダメダメなので、練習ついでに作ってみました。

できたもの

つくりかた

ここから先は、先程の参考サイトを見た前提でお話を進めていきますね。(さらっとでおkです)

考え方、手順は参考サイトと同じなので それをどうやって再現したか という感じで進めます。

とりあえず今回は

  • BaseColor
  • Specular
  • Shadow

に当たる部分のマスクを愚直に作って色指定、その境目にNoiseを入れてなじませていきます。コンパイルが重いかも。

ついでに、各色をテクスチャではなく直で色指定しています。モデルによっては細かくマテリアルが分けてる 方が相性がいいです。処理負荷は気にしないことにします。

BaseColorのマスクを作る

f:id:shop_0761:20161202014231p:plain

BaseTextureを指定できますが、結局Desaturationしてしまうのでそのままでもいいかも。

Blurをかけます。

Blurノード

float4 output = 0;
float weightSum = 0;
float currentWeight = 1.0;

for (int i = 0; i < 10; ++i) {
    output += Texture2DSample(Material.Texture2D_0, Material.Texture2D_0Sampler, texCoord + i * stride) * currentWeight;
    weightSum += currentWeight;
}

output /= weightSum;

return output;

参考:

qiita.com

そして、ちょっとNoiseをのせたり。 もちろん、すでにあるNoiseノードでもいいかと思いますが今回はstylized RenderingのT_TexturedPaperを使用しています。

Specularのマスクを作る

f:id:shop_0761:20161202014328p:plain

こちらはおぎまふさんを見習ってLightVectorを擬似的に用意して、Specularの計算をします。

f:id:shop_0761:20161202014445p:plain

こうして出来た2つをDesaturationしてそれぞれマスクとしました。

ここまででとりあえず2色分塗ることが出来ました。

ShadowとEdgeのマスクを作る

f:id:shop_0761:20161202014544p:plain

f:id:shop_0761:20161202014646p:plain

ここで影色も塗らなきゃなりませんが、このままでは塗れないのでゴリ押しで解決します。

影色になる部分を一旦求めて、今の絵に黒で塗り直します。(いい方法が知りたい)

こうすると後からaddして色を乗せられます。

f:id:shop_0761:20161202014834p:plain

こちらはおぎまふさんのRimLightの実装をそのまま使ってますので関数の中身は割愛します。

水彩の参考サイトの完成絵を見るとエッジが2段あるように見える(実際は歪めたり、ノイズかけたり)のでRimLight_Rangeにちょっとaddして作ります。

NoiseありとなしのEdgeがあったほうがよかったので、分けて作ってます。

f:id:shop_0761:20161202015259p:plain

f:id:shop_0761:20161202015632p:plain

ついでにさっきのshadowマスクを使って、明るい方のEdgeと暗い方のEdgeを作り分けてます。

ここで影色も作ってます。

まとめる

f:id:shop_0761:20161202015742p:plain

最後にshadow側とBaseColor側をaddして完成です。 お好みでNormalMapも使えるようにswitchをつけたりしました。

こうすることでGraymanの胸のUnrealロゴが出せます。

余談

最初はこのマテリアルをPostProcessで実装していたのですが、マスクできるようになったけど色指定できない…ってなったのでやめました。

その時、最初に作っていた影色を少し淡くするPostProcessが出来たのでついでに載せておきます。

alweiさんのお手軽Toonのマテリアルにちょっと足すだけです。

全体

f:id:shop_0761:20161202021012p:plain

追加した部分

f:id:shop_0761:20161202021032p:plain

CustomDepthでマスクを作った結果を使ってなんかごにょごにょしました。

でこの結果を最後にaddして出力してます。

余談2

blurのコードを書いてるときに思いついたのですが、blurベースでedgeが取れそうだったのでやってみました。

f:id:shop_0761:20161207225818p:plain

このぐらいいけます。

ノードはこれだけ 面倒なSobelフィルタを作らなくても使えるかも。

f:id:shop_0761:20161207225837p:plain

Blurのコード

float3 output = 0;
float ScreenMult_X = GetPostProcessInputSize(0).zw.x;
float ScreenMult_Y = GetPostProcessInputSize(0).zw.y;

output += 1.0 * SceneTextureLookup(TexCoord + float2(ScreenMult_X * BlurAmount * -1.0, 0.0), SceneTextureID, true);
output += 1.0 * SceneTextureLookup(TexCoord + float2(ScreenMult_X * BlurAmount * 1.0, 0.0), SceneTextureID, true);

output += 1.0 * SceneTextureLookup(TexCoord + float2(ScreenMult_X * BlurAmount, 0.0), SceneTextureID, true);
output += 1.0 * SceneTextureLookup(TexCoord + float2(0.0, ScreenMult_Y * BlurAmount), SceneTextureID, true);

output += 1.0 * SceneTextureLookup(TexCoord + float2(0.0, ScreenMult_Y * BlurAmount * -1.0), SceneTextureID, true);
output += 1.0 * SceneTextureLookup(TexCoord + float2(0.0, ScreenMult_Y * BlurAmount * 1.0), SceneTextureID, true);

output /= 6.0;

return output;

SceneTextureIDを引数にすることで、任意のSceneTextureを指定できます。 outputは加算した分だけ割ります。

f:id:shop_0761:20161207230113p:plain

多分この順番通りでIDが振られてると思います 分からなかったらコードを読めばいいんだよ うん。

まとめ

なんとなくMaterialの演算が分かった気がします。もろもろの計算は試行錯誤の結果なので、「なんでこうなるの?」というより「色々やったらこれがよかった」って感じです。

作りたい絵を目指して、実際に手を動かしてみるとこの意味がわかるかと思います。すごい人になれば頭のなかで完成形をイメージしながらノードを組めるかと思いますが()

まずは作りたい絵を探しましょう!!

わからないこととかあれば、可能な限りお答えするのでTwitter(@shop_0761)等でご連絡ください。

明日は Epic社のおかずさん(@pafuhana1213)の「帰ってきたUE4のマーケットプレイスで購入したアセットを片っ端からレビューするマン」です。

鹿のレビューが懐かしい…

頭の悪いHMDのレビューをしてみる

はじめに

Oculus Rift Advent Calendar 2016の2日目です。

qiita.com

昨日は桜花一門さんのAllumetteが素敵な理由でした。

docs.google.com

N回目のVR元年ということで、いろいろHMD(Head Mount Display)が出てきました。

気付いたらうちにもたくさん生えてきました。

ということで、これらのHMDのレビューでもしようかと思います。

と言ってもだいたいのレビューはあちこちですでになされているので、別の観点からします。

題して

一番寝心地のいいHMDはどれだ選手権!!

f:id:shop_0761:20161119060017j:plain

すでに皆さんも一度は被って寝落ちしているかと思いますし、僕自身も手元にあるHMDを被ったまま(意図して)寝たことがあります。 ですが改めて記事になっているものはなかったので、チャンスだと思いました。

注)別に各HMD、コンテンツを批判したいわけではありません。どれもいいものですし、お世話になってます。

事前知識

VRについて全くわからない方はこちらのリンクとかを見てみるといいかもです。一つ目の動画は割りとイメージつかみやすいかも。

www.moguravr.com

www.moguravr.com

www.moguravr.com

www.youtube.com

www.youtube.com

評価

評価方法

実際に被って寝(落ち)ます。メガネかけてます。

Rift以外はヘッドホンを使います。

実験時間は寝てから起きるまで。最近あまり長く寝れないことが多いのでだいたい2-3時間です。

(そもそもほんとに眠いときは準備する気になれない)

評価基準

  1. 起きたときの没入感
  2. 寝返りのうちやすさ
  3. コンテンツの寝やすさ
  4. 被った状態での後頭部へのやさしさ
  5. 総合評価

をそれぞれ5段階で評価します。かなりアレなやつは☆になります。

結果

Rift

Mikulusの場合

mikulusについてはこちら。

www65.atwiki.jp

膝枕をしてもらうかのように調整してみました。 他にもたくさんやっている方がいるので、写真は割愛します。

この辺でも覗いてみてください。

twitter.com

起きたときの没入感 ★★★★

目を開けたら目があった。 びっくりした。

寝返りのうちやすさ ★★★★

ヘッドホンが付いているので便利。 しかも軽いのがいいですね。

あまりゴロゴロするとヘッドホンの部分が壊れてしまいそうなので、おとなしくしてました。

コンテンツの寝やすさ ★★★★★

あの これ 呼吸音と心拍音がいい感じに落ち着く感じ非常に良い…

こう看取られてる気分ですね…(看取られたい

被った状態での後頭部へのやさしさ ★★★★★

Riftの後頭部のつくりは以外にもクッションが効いてて、あまり違和感がありませんでした。

後頭部にもセンサーがあるそうなので、これを使ってなにか作れないかなとか思ったり。

総合評価 ★★★★

最初は寝るのにちょうどいいコンテンツを思いつかなくてVirtualDesktopにでもしようかと思ったらMikulusがよさそうだったので選びました。

参考:

store.steampowered.com

目をつぶってしまえば現段階での呼吸音の違和感もなにもなく快適でした。

というか呼吸音と心拍音が聞こえるだけの音声を聞けばいいのではという意見は受け付けません。

目を開けたらそこにいると思えるほうがいいのです。はい。

Riftだとメガネが厳しいHMDなので、そこさえなんとかなれば(というか被ってしまえば)意外とお布団でも使えることがわかりました。

HTC Vive(Pre)

The lab 丘の場合

The labについてはこちら。

store.steampowered.com

丘で横になったときはこんな感じ。鳥が飛んでます。

f:id:shop_0761:20161130230355p:plain

起きたときの没入感 ★★★

起きて外した時にあれ部屋が狭い…?っと軽く思うくらいには没入していたようです。

まあ曇り空なんですが。

寝返りのうちやすさ ★★

ちょっと重いので頭が持って行かれます。出来なくはないですね。イヤホンにしたらもっといいかも。

コンテンツの寝やすさ ☆

Thelabの丘で寝ると上で鳥が飛んでいます。いい感じに環境音があって快適…かと思いきやタイミングやら位置やらが悪かったのか例のロボット犬が周囲で暴れまくっています。

いやあの、ほんと戯れる分にはいいんですよ… 寝るのにはうるs…(めっちゃギュインギュインしてた

ロボット犬 On/Offできると嬉しい。

被った状態での後頭部へのやさしさ ★★★★

Viveだと後頭部からまっすぐコードが伸びてます。

f:id:shop_0761:20161120151847p:plain

このためコードのことを思うと頭の下にそのままコードがくることになると思います。このためちょっと違和感があるかなという感じでした。

工夫次第でよくなるかもって感じです。

総合評価 ★★★

ぱっと思いついたコンテンツがコレだったのですが、犬が…犬が…という思いで完全に失敗しました。

といっても、他にこういうのが思いつかなかったのでオススメが知りたいです。

Viveは以前VirtualDesktopをしながら寝ていたこともあるのですが、如何せん重い…首が疲れます。

寝ているとそれは多少軽減されるのですが、ちょっとでも動くとぐいっと持っていかれる感じがします。

PSVR

サマーレッスンのひかりちゃんの部屋のベッドの場合

サマーレッスンについてはこちら。

summer-lesson.bn-ent.net

ベッドの上に座った感じ

f:id:shop_0761:20161130225448p:plain

ベッドに寝っ転がった

f:id:shop_0761:20161130225506p:plain

起きたときの没入感 ★

そもそも寝れなかった 頭痛すぎ。

寝返りのうちやすさ ★

プレイエリアの外に出ると目を開けた時に気が散ってしまうので、なかなか動けません。 ヘッドホンをしているとさらに動けないです。イヤホンにしたらいいかも。

しかも全体的に大きめなので壊しそうであまり動けない。

コンテンツの寝やすさ ★★

まあ確かに誰かがいる部屋で寝てる感は出てるっぽいので、ぼちぼち。

どのタイミングで寝るかに迷うかも。(教えてる時、ハンコを押す前、押した後)

今回はハンコを押した後にしましたが、突然話しかけてきたりしてビビります。

教えてるときはBGMがかかってしまうのでやめました。ので、ハンコを押す前がいいかも。

場所を調整するのがかなり難しかったです。 なかなかベッドの位置に移動出来ないし(当たり前)、低すぎると暗転してしまいます。

被った状態での後頭部へのやさしさ ☆

良くない これは頭が痛い 後頭部のパーツが痛すぎる。

他のは薄めのバンドだったのにこれだけやたらしっかりしてるせいで、 寝っ転がった時にこの後頭部のパーツにばかり力がかかって痛い。

そのせいではずした後に頭が痛くなってしまった。

f:id:shop_0761:20161129023239j:plain

総合評価 ★

PSVRは寝るのに挑戦したのは3回ほどあります。一度だけ座椅子にもたれかかって寝ることに成功しましたが、 今回のように布団や床で寝ることを想定すると後頭部の出来のよさが仇になってしまっています。

後1回はAmazonPrimeVideoでアニメを見ていました。結局後頭部の痛みが気になり寝るにねれない状況でした。 よっぽど疲れている、眠い状況であれば寝付けるかもしれませんが、数時間でこのダメージなので ちょっと怖いですね…

番外編 GearVR + GalaxyS6 edge

niconicoVRの場合

info.nicovideo.jp

起きたときの没入感 ★★★

まあ単に動画を見ていただけなので、特にやべえコレ みたいなことにはなりませんでした。

寝返りのうちやすさ ★★★★★

これは超いい ほんとにいい モバイルの良さを思い知らされました。

なにより軽い。余計なコードがない。寝返りがうてる。こんなに違うものかと…

思わずゴロゴロ転がってしまいました。

コンテンツの寝やすさ ★★★

眠くなる動画とか見ればいいのでは 終了。

被った状態での後頭部へのやさしさ ★★★★★

こいつもやわらかバンドなので違和感は無いに等しい。 頭が痛くないのはいいことですね。

総合評価 ★★★

手元にあってすぐ試せるniconicoVRにしてみましたが、割りとパフォーマンスがいいのか 3時間くらい持ちそうです。一回も落ちてないっぽい。2時間半くらいで100%→28%だった。

正直GearVRなので寝ろと言わんばかりに熱くなっておしまいかと思ったら 長持ちしてびっくりしました。

余談ですが、起きてからGear VR Cooler!(物理)と題して、雪を詰めた袋をくっつけるだけの 記事を書こうかと思いましたが5秒でやめました。

参考: itachinx.hatenablog.com

考察

ということで、今回はRiftが一番良さそうという結果になりました。 ヘッドホンよりイヤホンがいいかもと思ったので完全に選択ミスですね。動けない。

一応どのHMDでも(AmazonPrimeVideoのような)映像を見るだけのものが出来ますが、せっかくなら いいところでお昼寝したいです。欲を言えば寝ても覚めても被って生活したいです。

UE4で言えばKiteDemoのマップは寝心地よさそうな気がします。

参考: www.youtube.com

また今回は扱わなかったハコスコなどのモバイル系は一晩も使えないのがネックですね。

ダンボールだと固定できないので、どうしてもという場合のみアロンアルファで顔にくっつけてください。

参考

http://www.hashiyansoft.com/contents/dc/death.html

hacosco.com

これからはVR Nevangelist(寝バンジェリスト)とでも名乗ってみようかな!!

ぜひこの記事を参考に寝心地のいいHMDを購入してみてはいかがでしょうか。

明日はnoshipuさんの「VRアプリ作って思った事とか書きます」です。

おまけ

ちなみにSAOのキリトくんが被っているナーブギア

f:id:shop_0761:20161119054153j:plain

ヘルメット系は詳しくないのですが、これとても首を痛めそうな気がします。

調べてみると、やっぱり何人かの方がヘルメットを被って寝たことがある模様。特に寝心地レビューみたいのが見当たらず残念。

アミュスフィアはこんな感じ

f:id:shop_0761:20161119054433j:plain

HoloLensに近い気がしますが、やはりPSVRの例から後頭部に優しくないのではと思ってしまいます。

なのでメディキュボイド型が最強なのでは!?!?

点滴してもらえそうだし。

f:id:shop_0761:20161119054537p:plain

やっぱりこっちのメガネも捨てきれませんね(もはやVRではない

こちらは確か作中では寝る時に外していたような気もします。

f:id:shop_0761:20161119055104j:plain

おまけ2

ちょっと調べてみるとこんなものがあったのを思い出しました。

www.digimonostation.jp

確かに寝る分にはいいかもしれませんが、VR空間で寝たいのでうーんという思い。

【UE4】SaveとLoad時のUserIndexについて

はじめに

時々SaveとLoadに苦戦するのでよくお世話になっているほげたつさんのサイトです。

hogetatu.hatenablog.com

ここには

セーブデータにはスロット名とユーザーインデックスが指定できます。 スロット名はセーブデータの名前、ユーザーインデックスはその中でのIDみたいなものですね。 ドラクエ冒険の書1とか冒険の書2とかそんなイメージです。

とあります。

もちろんこちらにも。

docs.unrealengine.com

For some platforms, master user index to identify the user doing the saving.

ただ実際に実装してみると、なにやら動作がおかしいので調べてみました。

ソースコード

ということで、Engineのソースコードを追います。UE4.13です。 ctrl+FとかでUserIndexをハイライトしておくと、見やすいかもしれません。

Runtime/Engine/Private/GameplayStatics.cpp

USaveGame* UGameplayStatics::LoadGameFromSlot(const FString& SlotName, const int32 UserIndex)
{
    USaveGame* OutSaveGameObject = NULL;

    ISaveGameSystem* SaveSystem = IPlatformFeaturesModule::Get().GetSaveGameSystem();
    // If we have a save system and a valid name..
    if(SaveSystem && (SlotName.Len() > 0))
    {
        // Load raw data from slot
        TArray<uint8> ObjectBytes;
        bool bSuccess = SaveSystem->LoadGame(false, *SlotName, UserIndex, ObjectBytes);
        if(bSuccess)
        {
                   (省略)
bool UGameplayStatics::SaveGameToSlot(USaveGame* SaveGameObject, const FString& SlotName, const int32 UserIndex)
{
    ISaveGameSystem* SaveSystem = IPlatformFeaturesModule::Get().GetSaveGameSystem();
    // If we have a system and an object to save and a save name...
    if(SaveSystem && SaveGameObject && (SlotName.Len() > 0))
    {
        (省略)
        // Stuff that data into the save system with the desired file name
        return SaveSystem->SaveGame(false, *SlotName, UserIndex, ObjectBytes);
    }
    return false;
}

とSaveもLoadもUserIndexに関わる処理はSaveGame、LoadGameを呼び出しているのでそちらへ。

Runtime/Engine/Public/SaveGameSystem.h

virtual bool SaveGame(bool bAttemptToUseUI, const TCHAR* Name, const int32 UserIndex, const TArray<uint8>& Data) override
    {
#if PLATFORM_HTML5_BROWSER
        return UE_SaveGame(TCHAR_TO_ANSI(Name),UserIndex,(char*)Data.GetData(),Data.Num());
#elif PLATFORM_HTML5_WIN32
        FILE *fp;
        fp=fopen("c:\\test.sav", "wb");
        fwrite((char*)Data.GetData(), sizeof(char), Data.Num(), fp);
        fclose(fp);
        return true;
#else
        return FFileHelper::SaveArrayToFile(Data, *GetSaveGamePath(Name));
#endif
    }
 virtual bool LoadGame(bool bAttemptToUseUI, const TCHAR* Name, const int32 UserIndex, TArray<uint8>& Data) override
    {
#if PLATFORM_HTML5_BROWSER
        char*  OutData;
        int        Size;
        bool Result = UE_LoadGame(TCHAR_TO_ANSI(Name),UserIndex,&OutData,&Size);
        if (!Result)
            return false; 
        Data.Append((uint8*)OutData,Size);
        ::free (OutData);
        return true;
#elif PLATFORM_HTML5_WIN32
        FILE *fp;
        fp=fopen("c:\\test.sav","rb");
        if (!fp)
            return false;
            // obtain file size:
        fseek (fp, 0 , SEEK_END);
        int size = ftell (fp);
        fseek (fp, 0 , SEEK_SET);
        Data.AddUninitialized(size);
        int result = fread (Data.GetData(),1,size,fp);
        fclose(fp);
        return true;
#else
        return FFileHelper::LoadFileToArray(Data, *GetSaveGamePath(Name));
#endif
    }

えーっとPlatformがHTML5のブラウザだけUserIndexを使っているように思います。

そしてこのUE_SaveGameとUE_LoadGameはこちらに。

Runtime/HTML5/HTML5JS/Private/HTML5JavaScriptFx.js

UE_SaveGame: function (name, userIndex, indata, insize) {
    // user index is not used.
    var _name = Pointer_stringify(name);
    var gamedata = Module.HEAPU8.subarray(indata, indata + insize);
    // local storage only takes strings, we need to convert string to base64 before storing.
    var b64encoded = base64EncArr(gamedata);
    $.jStorage.set(_name, b64encoded);
    return true;
  },

  UE_LoadGame: function (name, userIndex, outdataptr, outsizeptr) {
    var _name = Pointer_stringify(name);
    // local storage only takes strings, we need to convert string to base64 before storing.
    var b64encoded = $.jStorage.get(_name);
    if (b64encoded === null)
      return false;
    var decodedArray = base64DecToArr(b64encoded);
    // copy back the decoded array.
    var outdata = Module._malloc(decodedArray.length);
    // view the allocated data as a HEAP8.
    var dest = Module.HEAPU8.subarray(outdata, outdata + decodedArray.length);
    // copy back.
    for (var i = 0; i < decodedArray.length; ++i) {
      dest[i] = decodedArray[i];
    }
    Module.HEAP32[outsizeptr >> 2] = decodedArray.length;
    Module.HEAP32[outdataptr >> 2] = outdata;
    return true;
  },

いやあのこれ、UserIndex出番なくないですか…(引数として呼ばれているだけで未使用)

まとめ

現状だとUserIndexは出番がないようです。ちゃんと(?)設定していないはずのUserIndexでLoadしてもエラーが出ませんでした。

Forum等も漁りましたが、良さげな解答が見つからなかったので追ってみました。

どこか間違ってたり、新たに何か分かった時にはぜひ@shop_0761までお知らせください(更新します)