20210430のUnityに関する記事は6件です。

[Unity / Addressable Assets System] 実機で自前のサーバーからbundleデータが読み込めない問題

基本的な導入方法はこちらのサイトを参考にさせて頂きました。エディタ上で読み込むところまでは特に問題なくできるかと思います。 https://note.com/graffity/n/n8620f244894a 現象 エディタ上では正常に読み込めているが、実機(iOS・Android端末)では読み込めないという現象。 試したこと ネット上の情報を参考にUnity内での設定を確認するも、特に問題は無し。 ローカルにエクスポートされたServerData以下のbundleファイルを消してみると、読み込めず。 ->エディタ上では正常にダウンロードしているように見えたが、実は失敗していて、代わりにローカルのファイルを読んでいたということが発覚。何らかの原因でサーバー上のbundleファイルが読めていない模様。 さらに調査を進めると、catalog_jsonファイルは読み込めているが、そこからサーバー上のbundleファイルを読むには至っていないことが分かった。 bundleファイルのパーミッションは「604」ということでユーザーが読んでくる分には問題なし。読んだファイルがどうにかなっている模様。 結論 アスキーモードによるjsonファイルの破損。 Filezillaの設定画面で転送形式を「バイナリ」にすることで解決。 アスキーモードだと、改行コード部分で修正が入ってしまうようで、今回はそれがjsonデータの破損につながってしまっていた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スマホゲームのプッシュ案

今回の主な話題:スマホゲームのプッシュ案、Unity UI特殊効果についてフロントエンドエンジニアとのコミュニケーション問題、ローエンドマシンでマルチスレッドレンダリングを有効にするかどうか、モバイル端末でRenderTextureメモリが大きくなる、自分で実現するTextストロークがDrawCall増加問題を引き起こす。 Android Q1:「クラッシュ・オブ・クラン」のようなゲームに対して、あなたの主要都市が他の誰かに襲われた場合、誰かがあなたを襲っているというプッシュ通知がスマアホに届きます。問題は、ゲームが強制終了されたということですが、なぜこの通知を受け取ることができるのですか?これはリアルタイムの通知であり、時間指定の通知ではありません。どうやってこれを実現できますか? ① こんな正確なプッシュ時間はクライアントが計算できないため、サーバーに頼ります。以前AndroidでAuroraPushを使用したことがありますが、あまり悪くないです。iOSにはサーバープッシュソリューションが提供されています。大体の原理は、私たちのサーバーからお知らせをAppleのサーバーまたはAuroraPushのサーバーに送信し、次にプレーヤー達に送信します。 ② Tencentの伝書鳩も使えます。プッシュは一般的にサーバープッシュがとローカルプッシュに分かれます。このような要件について、ローカルプッシュを採用する方がよりいいで、iOSシステムにはこのようなプッシュサービスがサポートしていますが、Androidには対応するAPIはありません。サーバーを自分で起動し、システムプロセスにバインドして、プロセスが強制終了されないようにする必要があります。しかし、今の各大手メーカーが独自のシステムを開発しており、このステップを達成することは困難です。一部のメーカーのアプリはシステムのホワイトリストに含まれており、バックグラウンドプロセスが強制終了されることはありません。 アセット管理 Q2: 私たちのゲームには、Animationとパーティクルを使って作成するUI特殊効果がたくさんありますが、これについてまだ1つの問題があります。パフォーマンス問題に注意しにくいで、私が一部の属性を変更すると、再びフレームを処理する必要があり、コミュニケーションコストが高いので、何か良い解決策ありませんか? ① 私のやり方は、アーティストが作成した特殊効果Prefabを直接使用することではなく、1つのツールを提供して新しいPrefabを生成します。 これの利点は、エクスポート時にテクスチャの数、パーティクルの数、アニメーションなどをチェックすることができます。事前にUIパーティクル特殊効果の標準を設定でき、エクスポート時にアセットが標準に合わないまた問題がある場合、エラーと表示してPrefabのエクスポートを却下します。これで、アーティストがSVNプログラムをアップロードできないため、問題のあるまたは効率に問題がある特殊効果に更新されません。 実際、このアイデアは特殊効果だけでなく、UIインターフェイス、キャラクター、シーンなどにも使用できます。Prefabが自動的に生成する時には、いくつかの追加ロジックを同時に生成することもできます。 ② 私のやり方は前のひとの方法と似ています。インポーターを使用して標準化されたアセットを強制することはできません。毎日0時にパッカーが起動するとアセットスキャンアクションを開始し、標準に合わない内容をスキャンして、レポートを生成します。 ③ 自分がTimelineエディター(Unity、Unrealの公式も利用可能)を作成します。エディターでアーティストに関する操作範囲(例えば、単一パーティクル特殊効果を再生する時の数またはモデル、アニメーション、マテリアルなどのアセットの使用範囲。)を設定します。最終的に特殊効果データを生成する時に、アセットとデータの検査及びアセット整理を行い、アセットの冗長性や不規則性を回避します。 利点: 1.アセットとデータが分離されており、アセット間に結合がないため、すばやく変更および調整できます。 2.データは編集モードで共有でき、衝突にすばやく対処できる共同制作にも便利です。 3.テンプレート化された特殊効果により、開発効率が大幅に向上します。 2つの点に注意する必要があります。 1、FBXアセットの冗長性。Unityは、関連付けられたモデルとアニメーションリソースをFBXパスとしてデフォルト設定します。私が採用した方法は、使用されたアセットをFBXから抽出してAssetファイルに作成することです。(Unity自体もこれを行いますが、事前に行って手伝ってあげますだけです。パッケージスピードも向上ですます。)Timelineにあるアセット依頼を新生成するアセットに変換します。 2.エディター自体は、再生機能(特にパーティクル)を出来る限りに実現する必要があります。 RenderTexture Q3: RenderTexture AAを1に、depthを0に設定しました。PC端末のメモリサイズは正しいけど、モバイル端末では約3倍になりました。これはなぜですが? ① 3倍までは間違ったはずです。UWA GOT Onlineサービスを介して各RenderTextureの具体的なパラメーターをチェックし、解像度、形式、およびその他のパラメーターを確認することをお勧めします。 ② メモリの変化は解像度が原因である可能性があります。RenderTextureのサイズは解像度に従うので、PCでRenderTextureの解像度とスマホでRenderTextureの解像度を比較してみることができます。 UI Q4: 画像のように、私たちがプロジェクトのために自分でテキストストロークを実現しました。私がUnityバッチ処理の理解により、DrawCallは2つあるはずですが、実際には4つあります。TextShaderOutlineのModifyMesh関数にあるSetUIVertex方法がバッチ処理の失敗を引き起こしたと推測されます。そうだった場合、原理はなぜですか?何か良い解決策ありませんか? 機能URL:TextureShaderOutline.rar 私のUnityバージュンは少し古いので、このプロジェクトを開くと乱雑になります。表示に問題があるように感じます。赤い字を左右にドラッグすると、色が変わります。これは非常に奇妙です。 ブログにある元方案を使って、このような重ね合わせ状況ではバッチ処理ができます。(条件はShaderが同じであり、カラーが違って、2つのShaderになります。) そして、Unity 2018に対して、方案を調整しました。 Unity 2018は、UV2とUV3を伝えられ、そしてtangent.zw normal.zもなんとか使用できます。ですから、UV1とUV2を使って、最も原始的なUV範囲を保存し、UV3とtangent.zwを使ってoutlinecolorを伝え、normal.zでoutlineborderを伝えます。これでカラーと幅変化はShaderを変更する必要がなく、バッチ処理できます。(z軸方向はズームできず、UIとそれが配置されているキャンバスはフラットである必要があることに注意してください。そうしないと、tangent.zとnormal.zの送信が不正確になります。) 問題主からの補充: ModifyMesh方法にあるpositionを削除してアップロードすると、バッチ処理出来るになりました。 UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。 UWA公式サイト:https://jp.uwa4d.com UWA公式ブログ:https://blog.jp.uwa4d.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

シーンテクスチャのレベル割り戦略

今回の主な話題:シーンテクスチャ圧縮のテクニック、XLuaがゲーム内の配置テーブルを読み取る方式、AssetBundleがベイクシーンをロードする時のライト失効の解決策、OverDrawの最適化問題、複数のBMFontに対応するアートフォントを1つのDrawCallに最適化する方法。 Texture Q1: 1、シーンテクスチャを圧縮すると、ハイ、ミドル、ローエンドのモデルで区別できますか? 2、できない場合、どの配置に関係なく、モデルが同じメモリシーンテクスチャをロードすることを意味します。問題は、圧縮がより厳しく、効果がハイエンド設備ではあまり良くないですが、圧縮がそれほど厳しくなく、メモリがローエンド設備で非常に緊張であるということです。この場合、良い解決策はありますか? 3、次に次に不可解な質問があります。一般的に、一枚の2048×2048テクスチャがMipmapをオンにする場合、RGB24形式のメモリは16MB(12MB+約3MBのMipmap)であるはずです。ただし、スマホにパッケージすると、実機Profileの時に見たこの画像で、占用したメモリは4MBであります。Mipmapをオフすると正常になり、16で表示します。実機Profile時に取るのは本物のメモリ占用ではなく、ビデオメモリでありますが?それとも、これはUnity ProfileのBugですか? 補足:UWAでテストしたところ、同じ状況が見つかりました。Mipmapをオンにすると、2048×2048も4MBになります。 ① 区別できます。代償はパッケージサイズが大きくなり、ハイ設置やロー設置に従って、追加に異なるアセットのコードロジックをロードする必要があります。もちろん、現在のハードウェアに応じてどのリソースが適切かを判断するために小さなパッケージを使用し、そしてダウンロードすることは一般的な方法であります。(ただし、国内では完全なパッケージのやり方を使う方が多いです。) 2、異なる機械で異なるリソースをダウンロードする方法、または複数のテクスチャがパッケージに含まれている方法以外に、他の良い方式はないでしょうか?UnityのQualitySettings配置にあるTextureQualityは1つの行ける可能性のあるオプションです。メモリの比較は行っていませんが、以前の理解によると、Mipmapに基づいてビデオメモリを節約すると言うことはずです。これは問題主自分でテストできますが、これは問題主が欲しい異なる圧縮形式ではありません。 3、2048×2048のメモリ占用は何ですかも分かりませんので、他のフレンドの回答を見てください。しかし、問題主がすべてRGB24の形式を使用しますから、メモリが爆発しない方がおかしいでしょう。対応する目標設備が直接サポートしている圧縮形式を使用することをお勧めします。質の高い圧縮、特に3Dシーンで、Normalなどの特殊テクスチャを除いて、明らかな違いはありません。 ② 現在、多くのゲームがスマホモデルに応じて適応されます。ほとんどのゲームがAndroid Top 300に適応するようになった標準ETC2は、標準の圧縮形​​式として使用できます。iOSではiPhone 5sを考慮する際にPVRTC4が必要です。スマホモデルを検討しない場合は、 ASTCを使用できます。 標準パッケージでは、上記の形式でのみ圧縮を実行しますが、ハイエンドモデルでは、ユーザーが高解像度のリソースをダウンロードすることを選択できるようにすることができます。この部分の高解像度リソースは、画像の圧縮形式をASTCに変更し、AssetBundleを再びパッケージします。ユーザーが自分でダウンロードし、特定のゲーム内アイテムに報酬を与えることができます。 上記の戦略は、MMOなどの大形ゲームに適しています。カジュアルゲームの場合は、いくつかのリソースを2つの異なる圧縮形式で保存し、モデルに応じて異なるリソースをロードすることを選択できます。 ③ Unityバージョンは2018.3です。Texture Mipmap Steaming機能が有効になっている可能性があります。メモリBudgetが設定上の上限に達したため、エンジンはMipmap 1~nの内容だけをロードしました。元画像のメモリが12MBであるという問題に対して、第一層後のMipmapの統計は4MBくらいです。ですから、あなたの3番目の質問はこのようなものだと個人的に推測しています。 Lua Q2: 私たちがプロジェクトにLuaを使いました。主にUIロジックの記述とホットアップデートに使用したいです。UIロジックを作成するときは、Luaスクリプトにあるゲーム配置テーブルデータを読み取る必要があります。ネットでいくつの解決策を見つかりました。 1、C#レイヤーはLuaにテーブルチェックインターフェイスを提供します。このやり方のパフォーマンスは良くないと感じます。 2、ゲームExcel配置テーブルをLua Tableに転換し、Lua側で直接使用したいですが、オープンソースツールはまだ選択されていません。 3、他の方法。 ① 案2に対して、[TabtoyExcelエクスポーター]ツールをシェアします。Excel配置テーブルをLuaファイルに変換し、Luaで直接使用できます。 コード例: コード例 -- 検索パスを追加する package.path = package.path .. ";../?.lua" -- ロードする local t = require "Config" -- 生データへの直接アクセス print(t.Sample[1].Name) -- インデックスを介してアクセスする print(t.SampleByID[103].ID) print(t.SampleByName["Black Cat Detecti"].ID) ② GitHubでExcelをLuaにエクスポートするためのツールはたくさんありますが、本質は同じです。それらはすべて、既存のテーブルにいくつかのルールの変更と制約を加える必要があります。プロジェクトの形式に近いものを具体的に確認して、自分で適応する必要があります。 最初に私は2014年の初めにプロジェクトのエクスポーターを作成しましたが、継続的に改造されており、現在はツールXlsxToLuaになっています。 Lightmap Q3:AssetBundleを介してロードされたシーンでは、ライティング効果が見つかりませんでした。 問1、static属性が変更されていることがわかりました。これがバッチ処理に影響を与えますか? 問2、Shadowmaskが引用されていませんでした。これはLightmapLightを処理すると同じように処理したいですが、行けますか? 問3、最も重要なことは、AssetBundleを介してロードされたシーンがどのようにライト情報を込められますか? シーン全体がAssetBundleとしてパッケージする場合に問題はありませんが、共通リソースを利用すると、ライトは失効になることはテストからわかりました。 図1はUnity内のシーン情報であり、図2はAssetBundleを介してシミュレーションしてロードされたシーン情報です。 まとめします。 1、Shader Variantsの遺失。 2、AssetBundleパッケージするときにLightmapを最適化しました。 3、StaticはEditorでシーンに置いたオブジェクトに対してのみ有効であり、Runtime時にインスタンス化は有効ではなく、静的なバッチ処理は行いません。 解決案 1、Shader Variants Collectionを作成し、使用されたShaderの変種を正確に選択し、パッケージする時にShader Variants Collectionと使用されたShaderを1つのAssetBundleに込めさせます。これで、ShaderのAssetBundleはシーンを削除できるようにします。 2、Editor→Project Settings→Graphics→Shader Stripping Lightmap ModesをCustomに変更し、Lightmapベイクモードに従って対応するモードを選択します。主な原因は、AssetBundle時に開いたシーンに基づいてAutoがこれらのオプションを設置しますから。空きシーンの場合、Lightmapはありませんので、ShaderにあるLightmapの部分を最適化します。 3、Meshを手動でマージしてDrawCallを減らすことができます。詳細については、CombineInstance関連のAPIを参照してください。 Overdraw Q4: 最近、OverDrawの最適化を行っています。私たちのUIインターフェイスはウィンドウ表示されており、全画面をカバーしていないため、メインカメラは常にレンダリングしています。DrawCallとOverDrawを減らすために、メインカメラにスクリーンショットを撮り、弾き出すUIウィンドウの後ろに配置し、メインカメラを閉じて、UIインターフェイスを開くときのDrawCallを大幅に減らしました。これは方案Aであります。 ただし、背景にスクリーンショットは1つの全体であり、UIにカバーされる部分があるため、中のUIにカバーされた部分を掘り下げたいで、見える部分のみを残します。これでOverDrawを低下できます。これは方案Bです。 では問題が発生します。方案Aは方案Bよりも3つのDrawCalls低くなっていますが、OverDrawは0.4x多くなります。私たちのプロジェクトのCPUもGPUもボトルネックは発生していません。バッテリ消費量と温度のみを考えると、どちらの方案がより良いですか? まず第一に、私はAとBの両方が良い解決策であると言う必要があります!さらに、方案Bまで考慮することもできます。これは、問題主チームの自己要件と実行能力が非常に高いと言う意味です。 次に、方案Aでも方案Bでも、CPUとGPUはボトルネックに達していないから、実際にAもBも採用でき、どちらの方法の人工消費が低いと判別すれば大丈夫です。しかし、計算力から考えると、個人的には方案Bをお勧めします。3つDrawCallの増加はほとんど無視できますが、0.4xのOverDrawは無視できないコストです。 UI Q5: ゲーム内複数の戦闘フォント効果があり、複数のBMFontアートフォントに対応します。それらを1つのDrawCallに最適化する方法は?例えば、会心一撃、中毒、回避、ヒーリングなど、各種類のダメージと原因が異なるフォント効果を対応します。前の方案はBMFontを使って複数のフォントを作成し、UGUIの生成にあるカスタムフォントに対応します。これがもたらす問題は、さまざまな文字が同時に散在しているように見えると、UIのバッチ処理が中断され、多くのDrawCallが生成されることです。 1つの最適化案は、異なるアートフォントを異なるレイヤーに配置し、何種類のフォントがあれば何個のDrawCallを生成することです。ただし、この方法の明らかな問題は、ある種類のダメージが別の種類によって完全に隠されることです。望ましい効果は、さまざまなタイプのフォント効果を互いに散在させて存在することができることです。 現在考慮している解決策は、すべてのアートフォントをBMFontフォントファイルにすることです。異なる種類のダメージナンバーに対して、グループ化されたASCIIコードを使用して、同じnumberの異なる表現をアクセスします。 皆さんが使用している方案を聞きたいです。 私なら、「すべてのアートフォントを1つのBMFontフォントファイルにする」を選択します。異なるナンバーに対しては、他の文字を転換して使用すれば良いです。しかし、異なるアートフォントサイズが均一であるなどの問題に注意してください。これはすべて簡単に解決できます。 さらに、問題主に「会心一撃」や「中毒」のような単語を一つの字として処理することをお勧めします。対応する文字は特定のものを選択できます。これの利点は、後でタイ語や英語バージュンを作る時にアートフォントは連れている可能性が高いです。1つの字が1つの整体であれば、対応する文字を統合できます。 UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。 UWA公式サイト:https://jp.uwa4d.com UWA公式ブログ:https://blog.jp.uwa4d.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

#8-おまけ「VIVE Pro Eyeのアイトラッキングで計測できるデータについて(適宜更新)」【初心者】HTC VIVE Pro Eyeを使ってUnityでVRの開発を行ってみる.

はじめに 研究費でHTC VIVE Pro Eyeを購入した.16万なので個人で買うには高すぎる代物だが今後は安くなるかもしれないし一応メモ書きしていく. 環境一覧 SteamVR 1.15.19 Unity 2020.1.17f1 SRanipalRuntime 1.3.2.0 SDK SteamVR Plugin 2.7.2 sdk1.14.15 Vive SRanipalRuntime Plugin 13.3.0 インテル® Core™ i7-7700K NVIDIA GeForce GTX 1070 環境作成編 #1 Unityのセットアップをする 2021年 1月更新 #2 プロジェクトを作ってみる 2021年 1月更新 #3 VR開発のための環境を整える 2021年 2月更新 コントローラやHMDから入力を得る #4 VIVEコントローラのボタン入力を取得する 2021年 2月更新 #5 トリガーの押し具合やトラックパッドの位置情報の入力を取得する 2021年 2月更新 #6 ヘッドマウントディスプレイとコントローラの位置座標と回転を取得する 2021年 2月更新 #7 VIVE Pro Eyeの視線トラッキングを有効化(セットアップ)する 2021年 4月更新 #8 VIVE Pro Eyeのアイトラッキングを使って瞬きや視線を取得する 2021年 4月更新 #8-おまけ VIVE Pro Eyeのアイトラッキングで計測できるデータについて(適宜更新) (この記事)2021年 4月更新 今回の記事では,前回#8-1で取得した目のデータについて調べたことをちょっとづつ追加していきます. ゆったり追加するので更新は遅めになるかもしれないです.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

#8「VIVE Pro Eyeのアイトラッキングを使って瞬きや視線を取得する」【初心者】HTC VIVE Pro Eyeを使ってUnityでVRの開発を行ってみる.

はじめに 研究費でHTC VIVE Pro Eyeを購入した.16万なので個人で買うには高すぎる代物だが今後は安くなるかもしれないし一応メモ書きしていく. 環境一覧 SteamVR 1.15.19 Unity 2020.1.17f1 SRanipalRuntime 1.3.2.0 SDK SteamVR Plugin 2.7.2 sdk1.14.15 Vive SRanipalRuntime Plugin 13.3.0 インテル® Core™ i7-7700K NVIDIA GeForce GTX 1070 環境作成編 #1 Unityのセットアップをする 2021年 1月更新 #2 プロジェクトを作ってみる 2021年 1月更新 #3 VR開発のための環境を整える 2021年 2月更新 コントローラやHMDから入力を得る #4 VIVEコントローラのボタン入力を取得する 2021年 2月更新 #5 トリガーの押し具合やトラックパッドの位置情報の入力を取得する 2021年 2月更新 #6 ヘッドマウントディスプレイとコントローラの位置座標と回転を取得する 2021年 2月更新 #7 VIVE Pro Eyeの視線トラッキングを有効化(セットアップ)する 2021年 4月更新 #8 VIVE Pro Eyeのアイトラッキングを使って瞬きや視線を取得する(この記事)2021年 4月更新 今回の記事では, 1.Unityでアイトラッカーのプログラムをするための準備をする. 2.実際に値を取得してみる(関数を使った方法). 3.実際に値を取得してみる(データの中身を参照する方法). 4.焦点情報を使ったサンプルプログラムを動かしてみる. という流れ. 1.Unityでアイトラッカーのプログラムをするための準備をする. いつもどおりSteamVR Plugin ,Vive SRanipalRuntime Pluginを追加したプロジェクト上でVR用のカメラを追加しておきます.(この辺りの設定は過去記事を参照してください) 今回はスクリプト落とし込む為のオブジェクトをタブ上で右クリックし「Create Empty」で作成します. 当たり判定などがないプログラムを動かすためだけのGameObjectを作成されます. /ViveSR/Scripts/Eyeフォルダ内にある"SRanipal_Eye_Framework"を先ほど作成したGameObject内にドラックアンドドロップで追加します. このスクリプトから色々と呼び出していく形なのでGameObjectじゃなくてもいいので絶対にオブジェクトに追加しておく. この後プログラムをしていく中で焦点情報を出すときにメインカメラを起点に計測を行うのでVR用に追加したカメラの設定からTagを参照し,もしタグが「MainCamera」になっていなければ設定しておく. もしTagになければAdd Tag...から追加して変更しておく. これで下準備は完了です. 2.実際に値を取得してみる(関数を使った方法). 前回記事の最後に紹介した解凍したフォルダ内の..SDK(v1.3.3.0等)/SDK/2_Unity/Document/EyeにあるDocument_Unityから開発のためのドキュメントを使用してプログラムを書いていきます. 取得できるデータや内容はバージョンによって大きく変わるのでもしコピペで動かなかったり変な値が出力されるときにはドキュメントを参照してください. まずは関数を使ってプログラムを書いていきます. 取得できるデータは, ①瞳孔位置 ②まぶたの開き具合 ③視線情報 ④焦点情報 になっています. ※焦点情報に関しては当たり判定のあるオブジェクトがないといけないので3Dオブジェクトを適宜追加しておいてください.(焦点情報にはゲームによく使われるRayという当たり判定を使用しているため) いつも通りC#スクリプトを作成していきます. 今回はとりあえずVIVEsampleというスクリプト作成します. VIVEsample.cs using System.Collections; using System.Collections.Generic; using UnityEngine; namespace ViveSR { namespace anipal { namespace Eye { public class VIVEsample : MonoBehaviour { //⓪取得呼び出し----------------------------- //呼び出したデータ格納用の関数 EyeData eye; //------------------------------------------- //①瞳孔位置-------------------- //x,y軸 //左の瞳孔位置格納用関数 Vector2 LeftPupil; //左の瞳孔位置格納用関数 Vector2 RightPupil; //------------------------------ //②まぶたの開き具合------------ //左のまぶたの開き具合格納用関数 float LeftBlink; //右のまぶたの開き具合格納用関数 float RightBlink; //------------------------------ //③視線情報-------------------- //origin:起点,direction:レイの方向 x,y,z軸 //両目の視線格納変数 Vector3 CombineGazeRayorigin; Vector3 CombineGazeRaydirection; //左目の視線格納変数 Vector3 LeftGazeRayorigin; Vector3 LeftGazeRaydirection; //右目の視線格納変数 Vector3 RightGazeRayorigin; Vector3 RightGazeRaydirection; //------------------------------ //④焦点情報-------------------- //両目の焦点格納変数 //レイの始点と方向(多分③の内容と同じ) Ray CombineRay; /*レイがどこに焦点を合わせたかの情報.Vector3 point : 視線ベクトルと物体の衝突位置,float distance : 見ている物体までの距離, Vector3 normal:見ている物体の面の法線ベクトル,Collider collider : 衝突したオブジェクトのCollider,Rigidbody rigidbody:衝突したオブジェクトのRigidbody,Transform transform:衝突したオブジェクトのTransform*/ //焦点位置にオブジェクトを出すためにpublicにしています. public static FocusInfo CombineFocus; //レイの半径 float CombineFocusradius; //レイの最大の長さ float CombineFocusmaxDistance; //オブジェクトを選択的に無視するために使用されるレイヤー ID int CombinefocusableLayer = 0; //------------------------------ //1フレーム毎に実行 void Update() { //おまけ------------------------------------ //エラー確認ViveSR.Error.がWORKなら正常に動いている.(フレームワークの方に内蔵済みだからいらないかも) if (SRanipal_Eye_API.GetEyeData(ref eye) == ViveSR.Error.WORK) { //一応機器が正常に動いてる時の処理をここにかける } //------------------------------------------- //⓪取得呼び出し----------------------------- SRanipal_Eye_API.GetEyeData(ref eye); //------------------------------------------- //①瞳孔位置---------------------(HMDを被ると検知される,目をつぶっても位置は返すが,HMDを外すとと止まる.目をつぶってるときはどこの値返してんのか謎.一応まぶた貫通してるっぽい???) //左の瞳孔位置を取得 if (SRanipal_Eye.GetPupilPosition(EyeIndex.LEFT, out LeftPupil)) { //値が有効なら左の瞳孔位置を表示 Debug.Log("Left Pupil" + LeftPupil.x + ", " + LeftPupil.y); } //右の瞳孔位置を取得 if (SRanipal_Eye.GetPupilPosition(EyeIndex.RIGHT, out RightPupil)) { //値が有効なら右の瞳孔位置を表示 Debug.Log("Right Pupil" + RightPupil.x + ", " + RightPupil.y); } //------------------------------ //②まぶたの開き具合------------(HMDを被ってなくても1が返ってくる??謎) //左のまぶたの開き具合を取得 if (SRanipal_Eye.GetEyeOpenness(EyeIndex.LEFT, out LeftBlink, eye)) { //値が有効なら左のまぶたの開き具合を表示 Debug.Log("Left Blink" + LeftBlink); } //右のまぶたの開き具合を取得 if (SRanipal_Eye.GetEyeOpenness(EyeIndex.RIGHT, out RightBlink, eye)) { //値が有効なら右のまぶたの開き具合を表示 Debug.Log("Right Blink" + RightBlink); } //------------------------------ //③視線情報--------------------(目をつぶると検知されない) //両目の視線情報が有効なら視線情報を表示origin:起点,direction:レイの方向 if (SRanipal_Eye.GetGazeRay(GazeIndex.COMBINE, out CombineGazeRayorigin, out CombineGazeRaydirection, eye)) { Debug.Log("COMBINE GazeRayorigin" + CombineGazeRayorigin.x + ", " + CombineGazeRayorigin.y + ", " + CombineGazeRayorigin.z); Debug.Log("COMBINE GazeRaydirection" + CombineGazeRaydirection.x + ", " + CombineGazeRaydirection.y + ", " + CombineGazeRaydirection.z); } //左目の視線情報が有効なら視線情報を表示origin:起点,direction:レイの方向 if (SRanipal_Eye.GetGazeRay(GazeIndex.LEFT, out LeftGazeRayorigin, out LeftGazeRaydirection, eye)) { Debug.Log("Left GazeRayorigin" + LeftGazeRayorigin.x + ", " + LeftGazeRayorigin.y + ", " + LeftGazeRayorigin.z); Debug.Log("Left GazeRaydirection" + LeftGazeRaydirection.x + ", " + LeftGazeRaydirection.y + ", " + LeftGazeRaydirection.z); } //右目の視線情報が有効なら視線情報を表示origin:起点,direction:レイの方向 if (SRanipal_Eye.GetGazeRay(GazeIndex.RIGHT, out RightGazeRayorigin, out RightGazeRaydirection, eye)) { Debug.Log("Right GazeRayorigin" + RightGazeRayorigin.x + ", " + RightGazeRayorigin.y + ", " + RightGazeRayorigin.z); Debug.Log("Right GazeRaydirection" + RightGazeRaydirection.x + ", " + RightGazeRaydirection.y + ", " + RightGazeRaydirection.z); } //------------------------------ //④焦点情報-------------------- //radius, maxDistance,CombinefocusableLayerは省略可 if (SRanipal_Eye.Focus(GazeIndex.COMBINE, out CombineRay, out CombineFocus/*, CombineFocusradius, CombineFocusmaxDistance, CombinefocusableLayer*/)) { Debug.Log("Combine Focus Point" + CombineFocus.point.x + ", " + CombineFocus.point.y + ", " + CombineFocus.point.z); } //------------------------------ } } } } } 今回はGameObject内にスクリプトを追加します. 適宜コメントアウトをしながら動作確認をしみてください. 3.実際に値を取得してみる(データの中身を参照する方法). 次にデータの中身を参照する方法を使ってプログラムを書いていきます. 取得できるデータは, ①どのぐらいまぶたを開いてるか ②視線の起点の座標(角膜の中心)mm単位 ③瞳孔の位置 ④瞳孔の直径 になっています. 前回と同様にC#スクリプトを作っていきます. とりあえずVIVEsample2というスクリプト作成します. VIVEsample2.cs using System.Collections; using System.Collections.Generic; using UnityEngine; namespace ViveSR { namespace anipal { namespace Eye { public class VIVEsample2 : MonoBehaviour { //⓪取得呼び出し----------------------------- //呼び出したデータ格納用の関数 EyeData eye; //------------------------------------------- //①どのぐらいまぶたを開いてるか----------------- //呼び出したデータ格納用の関数 float LeftOpenness; float RightOpenness; //------------------------------------------- //②視線の起点の座標(角膜の中心)mm単位------ //呼び出したデータ格納用の関数 Vector3 LeftGazeOrigin; Vector3 RightGazeOrigin; //------------------------------------------- //③瞳孔の位置------------------------------- //呼び出したデータ格納用の関数 Vector2 LeftPupilPosition; Vector2 RightPupilPosition; //------------------------------------------- //④瞳孔の直径------------------------------- //呼び出したデータ格納用の関数 float LeftPupiltDiameter; float RightPupiltDiameter; //------------------------------------------- //1フレーム毎に実行 void Update() { //⓪取得呼び出し----------------------------- SRanipal_Eye_API.GetEyeData(ref eye); //------------------------------------------- //①どのぐらいまぶたを開いてるか----------------- //左目を開いてるかが妥当ならば取得 なぜかHMD付けてなくてもTrueがでる,謎. if (eye.verbose_data.left.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_EYE_OPENNESS_VALIDITY)) { LeftOpenness = eye.verbose_data.left.eye_openness; Debug.Log("Left Openness:" + LeftOpenness); } //右目を開いてるかが妥当ならば取得 なぜかHMD付けてなくてもTrueがでる,謎. if (eye.verbose_data.right.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_EYE_OPENNESS_VALIDITY)) { RightOpenness = eye.verbose_data.right.eye_openness; Debug.Log("Right Openness:" + RightOpenness); } //------------------------------------------- //②視線の起点の座標(角膜の中心)mm単位------ - //左目の眼球データ(視線原点)が妥当ならば取得 目をつぶるとFalse 判定精度はまあまあ if (eye.verbose_data.left.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_GAZE_ORIGIN_VALIDITY)) { LeftGazeOrigin = eye.verbose_data.left.gaze_origin_mm; Debug.Log("Left GazeOrigin:" + LeftGazeOrigin.x + ", " + LeftGazeOrigin.y + ", " + LeftGazeOrigin.z); } ////右目の眼球データ(視線原点)が妥当ならば取得 目をつぶるとFalse 判定精度はまあまあ if (eye.verbose_data.right.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_GAZE_ORIGIN_VALIDITY)) { RightGazeOrigin = eye.verbose_data.right.gaze_origin_mm; Debug.Log("Right GazeOrigin:" + RightGazeOrigin.x + ", " + RightGazeOrigin.y + ", " + RightGazeOrigin.z); } //------------------------------------------- //③瞳孔の位置------------------------------- //左目の瞳孔の正規化位置が妥当ならば取得 目をつぶるとFalse 判定精度は微妙 if (eye.verbose_data.left.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_PUPIL_POSITION_IN_SENSOR_AREA_VALIDITY)) { LeftPupilPosition = eye.verbose_data.left.pupil_position_in_sensor_area; Debug.Log("Left Pupil Position:" + LeftPupilPosition.x + ", " + LeftPupilPosition.y); } ////右目の瞳孔の正規化位置が妥当ならば取得 目をつぶるとFalse 判定精度は微妙 if (eye.verbose_data.right.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_PUPIL_POSITION_IN_SENSOR_AREA_VALIDITY)) { RightPupilPosition = eye.verbose_data.right.pupil_position_in_sensor_area; Debug.Log("Right GazeOrigin:" + RightPupilPosition.x + ", " + RightPupilPosition.y); } //------------------------------------------- //④瞳孔の直径------------------------------- //左目の瞳孔の直径が妥当ならば取得 目をつぶるとFalse 判定精度はまあまあ if (eye.verbose_data.left.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_PUPIL_DIAMETER_VALIDITY)) { LeftPupiltDiameter = eye.verbose_data.left.pupil_diameter_mm; Debug.Log("Left Pupilt Diameter:" + LeftPupiltDiameter); } ////右目の瞳孔の直径が妥当ならば取得 目をつぶるとFalse 判定精度はまあまあ if (eye.verbose_data.right.GetValidity(SingleEyeDataValidity.SINGLE_EYE_DATA_PUPIL_DIAMETER_VALIDITY)) { RightPupiltDiameter = eye.verbose_data.right.pupil_diameter_mm; Debug.Log("Right Pupilt Diameter:" + RightPupiltDiameter); } //------------------------------------------- } } } } } 今回はGameObject内にスクリプトを追加します. 適宜コメントアウトをしながら動作確認をしみてください. VIVEsampleと同時に動かすこともできますがデータの呼び出しが2つになってしまうのでうまく⓪以外の部分を組み合わせてください. 次回の記事で取得したデータについて細かく解説していきます.暇なときに適宜更新していきます... 4.焦点情報を使ったサンプルプログラムを動かしてみる. 今回抜き出したデータを使って焦点位置を表示するサンプルを作成していきます. 今回の記事で作成したスクリプトのVIVEsample.csの④にある焦点情報を使っていきます. まずは3つの3Dオブジェクトと視線位置を示すために赤く色づけした小さな玉のオブジェクトを作成します. 焦点位置は当たり判定を応用して計測しているのでオブジェクトにコライダーと呼ばれる当たり判定があることを確認します. 自作のオブジェクト作成するさいにはしっかりと当たり判定を入れておきましょう. なぜか赤の球が白になっていますが実際に動かすとこんな感じで焦点位置が表示されます. 今回はとりあえずの動作確認なので今後はこれを活用したシステムを作ってみたいなと思います. 次回はVIVE pro eyeのAR機能をいじっていきたいと思います.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】軽量ブルームエフェクト作ってみた

概要 本記事はモバイル向けな高速なブルームエフェクトを自作してみた記事になります。 環境 Unity2019.4.13f1 BuiltIn RenderPipeline を使用しております。 自作ブルーム 今回作成したポストプロセスのブルームエフェクト。 工夫点 白飛び防止 ブルームをかけると強度によっては画面が白っぽくなりますが、 シェーダー側で色空間を調整することで白飛び防止できます。 ガンマからリニアへ #if UNITY_COLORSPACE_GAMMA col.rgb = GammaToLinearSpace(col.rgb); #endif リニアからガンマへ #if UNITY_COLORSPACE_GAMMA col.rgb = LinearToGamma(col.rgb); #endif なるべくドローコールを落とす。 アップサンプルの過程を省略してしまいました。これによってドローコールがダウンサンプルの回数分減らせます。 処理負荷比較 5年くらい前のAndroid galaxy端末での処理負荷の比較です。 平均10MSほど早くなっています。 それでいて見た目も本家と引けをとらないです! プロジェクトデータ 準備中です。。 まとめ 白飛びしにくく、ドローコールも抑えめなブルームエフェクトを自作してみました。 ライセンス表記 本記事ではUnityChanのCandyRockStarを使用させていただいております。 © Unity Technologies Japan/UCL
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む