脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

Unityのmetaファイルが持つguidを変更する

前提

  • Unityでは各ファイルに対してメタファイルが自動で生成される
  • このmetaファイルの中でguidというパラメータが設定されている
  • 他のオブジェクトとの相関性などは、ファイル名ではなくこのguidをもとにして行われている
fileFormatVersion: 2
guid: 14f9hogehogehogehogefugaugasdfd7fc21a  //<== これ
timeCreated: 1467869181
licenseType: Free
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData: 
  assetBundleName: 
  assetBundleVariant: 

問題

  • スクリプトリファクタリングをするときなど、適当な名前のファイルとしてコピーし、後で同名ファイルを削除して置き換えるというようなことをした場合、ファイル名は同じだが生成されたmetaファイルのguidが異なるので、他のオブジェクトとの関連性がリセットされてしまっている。
  • もう一つ問題として、パッケージをexportして別プロジェクトへimportする場合があるが、このとき同じguidが使われていると全く別のファイルにも関わらず同じguidのオブジェクトが上書きされてしまう

解決方法

  • 上の方の問題に関してはそもそも該当のファイルを直接編集すればいいが、下のimport問題が少しやっかいで、この場合ファイルのguidを変えてやる必要がある
guidの変更
  • 試しにmetaファイルを削除してUnityを起動してみたところ、新しく新規にmetaファイルが作成されたのでいけるかと思ったが、まさかの消したはずのguidと同じguidが再度生成されていた。
  • なので現在は少し強引ではあるが、Duplicateで同じファイルを作成し(この時点で違うguidをもつmetaファイルが生成される)、これをもとにパッケージをexportすることにしている。
  • もちろんmetaファイルを直接編集してもいいのだが、低い確率で他のファイルが既に利用しているguidにしてしまった場合、問題の発見が困難になってしまう
    • DuplicateだとUnityの機能で行うので、Unityが重複のないguidをアサインしてくれる

他にいい方法があるような気がしないでもない・・・

Android端末で初回起動時にStreamingAssetsからPersistentDataディレクトリにデータをコピーする方法

UnityでStreamingAssetsに配置したファイルはアプリコンパイル時にも圧縮されないため、必要な情報の保存に利用できる。
しかしこのStreamingAssetsはアプリ内にStreamingAssetsという名前のディレクトリが作成されるわけではなく、いわゆるシムリンク的なもので、デバイス毎にどこに保存されるかは異なる。
その中でもAndroidの場合が少し曲者で、AndroidのStreamingAssets上のファイルはReadはできるがWriteができない。
なので通常は初回起動時にStreamingAssetsからPersistentDataディレクトリへファイルをコピーし、二回目以降はそちらを読み書きして使う方法がメジャーとなっている。

void Start(){
    if (!File.Exists (Application.persistentDataPath + "/" + filename)) {
        FileCopyFromStreamingToPersistent();
    }
}
  • 目的のファイルがpersistentDataディレクトリにない場合は初回起動とみなしてファイルをコピーする
void FileCopyFromStreamingToPersistent(){
	string path = Application.streamingAssetsPath + "/" + filename;
	WWW www = new WWW (path);
	while (!www.isDone) {
	}
	string toPath = Application.persistentDataPath + "/" + filename;
	File.WriteAllBytes (toPath, www.bytes);
}
  • 実際にコピーをするメソッドはこちら

PlayerPrefsとStreamingAssetsにおけるファイルの扱いの違い

Player Prefs StreamingAssets
Windows Android Windows Android
バイス上で保存される場所 システムレジストリ ShaderPreferences コンパイルしたアプリのDataディレクト -
ファイル内容の修正に関して regeditで編集可能 通常不可 テキストエディタで編集可能 通常不可
アプリ初回起動時のファイルの扱い あらかじめ作成しておくことは出来ない(初回起動時にはじめて作成される) あらかじめ作成しておくことが可能
- - WriteもReadも可能 Readのみ可能(編集したい場合は初回起動時にPersistentDataディレクトリにコピーし、二回目以降はそちらを利用する方法がメジャー)
特徴 セーブデータの保存などに利用される StreamingAssets以下に配置されたファイルはアプリのコンパイル時に圧縮されない

Unityのオブジェクトをスクリプトから回転する方法

方法

YourObject.transform.Rotate (x, y, z);
YourObject.transform.rotation = Quaternion.Euler (x, y, z);

using UnityEngine;
using System.Collections;

public class Nouziru : MonoBehaviour {
    public GameObject cube;

    void  Start(){
        cube.transform.Rotate (10, 20, 30);
        ### または
        cube.transform.rotation = Quaternion.Euler (10, 20, 30);
    }
}

UnityでOculus Rift用に作成した高解像度のmp4動画がカクつくことに関する検証

UnityでOculus Rift用に動画コンテンツを作る際に、解像度によっては結構な頻度でカクつきが発生します。
原因や解決方法など色々調べたので備忘録もかねて書いておきたいと思います

Movie Texture

UnityにはWindowsプラットフォーム用にMovie Textureという機能が存在します。
これを使えば簡単に動画を再生できるのですが、動画によってはスムーズに再生されなかったり、そもそも再生されなかったりします

問題の動画

  • 解像度:4K
  • Frame rate: 25FPS
  • 動画サイズ: 350MB
  • 動画時間:120秒

そもそも再生できない問題

ファイルサイズ

350MBくらいの動画を再生しようとしたが、そもそも再生がはじまらない
編集ツールでファイルを分割して検証してみた

  • 4k + 10秒(38MB): 再生可能、ただし最初の方は映像が乱れる

⇒ファイルサイズが大きいと再生がはじまらないっぽい

フレームレート

今回検証に使った動画は25FPSだが、他の30FPSの動画を再生したところ問題なく動いた

⇒フレームレートは関係ないっぽい

再生はじめが乱れる問題

解像度
  • 4K(3842×1920)動画は再生はじめに映像が乱れる
  • 解像度を落として検証したところ・・・
    • 2K + 10秒の動画:再生可能&乱れない
    • 2K + 30秒の動画:再生可能&乱れない
    • 2K + 2分の動画:再生可能&乱れない

⇒解像度が高いと再生はじめが乱れるっぽい

考察

Unity DefaultのMovieTextureはファイルサイズが大きくなると再生自体が出来ない模様
さらに、ファイルサイズが小さくても1920pまでしか綺麗に再生できない模様


AVProVideo

Windows用に高解像度の360動画コンテンツを作る際に最もメジャーな(?)AssetであるAVProVideoでも検証してみた

普通に検証

再生は出来るが、すごいカクつく
Unityのログには以下のようなWarnログが表示される

[AVProVideo] Using software video decoder.......

対策

その1 起動オプションをつける

Unityをコマンドラインで実行し、"-force-d3d11-no-singlethreaded"オプションをつけると、warnログも消えて、表示もスムーズになる
ただし、このオプションはビルド時には反映されないため、ビルドしたアプリも同様にコマンドラインで実行して上記のオプションを指定しなければいけない

その2 Force DirectShow機能を使う

AVProVideoには前のversionとしてAVPro Windows MediaというAssetが存在し、そちらは既にAsset Storeでは公開終了しているものの、以下のサイトから無料パッケージがまだダウンロードできる
こちらを試してみたところ、カクツキなくスムーズに再生された

予想としては、

  1. AVPro Windows Mediaはcodecとして恐らくデフォルトでDirectShowを利用している
  2. しかし、AVProVideoは全プラットフォーム対応なので、Unityの標準であるQuickTimeを利用している
  3. 試しにQuickTimeで直接4kのmp4動画を再生してみたところ、Riftで見たときほどではないがカクついた

つまり、Unityが利用するcodecをDirectShowにして、適切なCodecを利用できるようにしてやれば解決する?

対策として、以下の過去ポストにしたがって、
portaltan.hatenablog.com

  1. 高解像度mp4動画を低コストで再生できるLAV filterをインストール
  2. codec tweakerでH.264再生時のデフォルトcodecをLAVに変更
  3. UnityのAVProVideoのpropertyで、Media Player > Platform Specific > Windows > Force DirectShowにチェックを入れる
  4. TimeScaleにもチェックいれておく

以上の設定を行ったところ、実行時に特別なオプションを指定しなくともスムーズに動画が再生されるようになった


注意

Force DirectShow機能は途中から導入されたようなので、古いversionだと項目自体がありません

追記

AVProVideo (Windows)だとそもそもDirectShow前提なのか項目がなかった。
替わりにHardwareDecordingの項目があって、それにチェックをいれるとスムーズに再生された。
f:id:portaltan:20161013105052p:plain

AVProVideoでOculus Rift用の360動画アプリを作成する

以前GearVR用の360動画アプリの作成方法を載せましたが、今回はOculus Rift用の開発方法を書きたいと思います
portaltan.hatenablog.com

使用ツール

AVProVideo

GearVRではEasyMovieTextureを利用しましたが、RiftではAVProVideoを利用します。
AVProVideoは色々種類がありますが、とりあえずお試しとしては全プラットフォーム対象の無料版があるので、そちらを利用するとよいかと思われます
portaltan.hatenablog.com

UnityにはデフォルトでMovieTextureという動画再生の機能がありますが、こちらは再生できる解像度が低いです。
(一応こちらがMovieTextureの使い方です)
portaltan.hatenablog.com

開発方法

1. Oculus Utilityのimport

まずはいつも通りOculusが提供しているUnity用のUtilityをimportします
Developers — Build The Future | Oculus
f:id:portaltan:20160909195713p:plain

2. AVProVideoのImport

次にAVProVideoのimportをします。
(今回はトライアル版を利用します)
http://renderheads.com/product/avpro-video/
f:id:portaltan:20160909195920p:plain

3. OVRCameraRigと360SphereVideoのPrefabの配置

まずはOVRCameraRigを配置し、次に360SphereVideoというPrefabも同様にHierarchyにD&Dで配置します
f:id:portaltan:20160909200107p:plain
(不要なMainCameraとLightは削除しました)

4. 動画の取り込み

再生したい動画ファイルをAssets/StreamingAssetsの下に配置します。
(今回はAVProVideoをimportするとデフォルトでついてくるSampleSphere.mp4を利用します)

5. 動画の指定

次に取り込んだ動画を再生対象として指定します

  1. 360SphereVideoの子オブジェクトのAVPro Video Media playerオブジェクトのInspectorを開きます。
  2. Media Player(Script)の緑色のボタン(BROWSE)を選択します
  3. 動画を選択するウィンドウが開くので再生したい動画を選択します

f:id:portaltan:20160909200530p:plain

6. 確認

以上で設定は完了です。Editorの再生ボタンを押して実際に再生されることを確認しましょう
f:id:portaltan:20160909201131p:plain

UnityのApplication.Quit()がWindows環境でフリーズしたりしなかったりする

Application.Quit()によるアプリのフリーズ

Unityのversionを5.3.6p1にあげたところ、Application.quit()が動いたり動かなかったりするようになってしまいました
動かないときはアプリ自体がフリーズして最終的にはクラッシュしてしまいます

調べてみると色々なversionで多くの人が同じ問題に遭遇しているらしいのですが、根本的な原因に関しての記述は見つかりませんでした。

対応策も人によって様々なのですが、自分がうまくいった方法は、Application.quit()後すぐにreturnして、明示的にそれ以降の処理をスキップさせる方法です

void Update ()
{
    if (終了させるためのトリガー){
        Application.Quit();
	return;
    }

    // 以降いろんな処理
}

これでいまのところは正常に動いています。