Unity×Verdaccioで自作UnityPackageをバージョン管理する

f:id:Sokuhatiku:20180815160400p:plainこんにちは、株式会社Synamonのエンジニアの岡村(@Sokuhatiku)です。

前回、任意のフォルダにPackage.jsonを定義することで、ローカルパス参照でUnityPackageManagerに載せることが出来る方法を書きました。

ただし、その方法はローカルのファイルパスを直接指定してパッケージとして扱うというもので、バージョン管理やチーム内での共有のしやすさに難がありました。

今回、その部分の解決策を見つけました。それと近いタイミングで、@kohki_nakajiさんに前回の記事を紹介して頂けて、さらに、今回の記事にも興味があると言って頂けたため、手順を纏めてみました。

おことわり

※今回はUnityとnpmの狭間に自作パッケージを無理やりねじ込む所に焦点を当てている為、LAN内に公開する方法には触れていません。ご了承ください。

※今回紹介する方法はハックです。公式サポートされている機能ではないので、今後情報が古くなったり、利用できなくなる可能性が大いにあります。

自作パッケージレジストリ

前回、UnityPackageManager(以下、upm)はnpmの仕組みを利用しているという所まで調査できていました。

upmとnpmのもつjsonを比べてみると非常によく似ていた為、npmのレジストリを立て、Nodeの代わりにUnityPackageを置けば、そこからダウンロード出来るのではないかという予想を立てました。

そこで、Verdaccioというツールを利用して、ローカル環境にnpmレジストリを立ててみたところ、いくつかハマりどころがあったものの、最終的には上手くいきました。 github.com

Verdaccioは、npmのレジストリを好きな場所に立てる事ができるツールです。また、uplinkとして他のレジストリを設定した場合、自身が持っていないパッケージをそちらからダウンロードすることが出来るようになります。

ハマりどころ

先にハマりどころを紹介しておきます。

upmはポート付きアドレスを認識しない

Verdaccioを立てると4873番ポートで起動するのですが、そのままlocalhost:4873をUnityにレジストリとして設定しても、パッケージの読み込みに失敗します。 簡単な解決方法は、verdaccio側に80番ポートで待受させることです。

upmはスコープを認識しない

npmには@{ユーザー名}/{名前}というパッケージ名にする事でパッケージ名の重複を防ぐ、スコープという機能がありますが、これをupmは認識しません。不正なパッケージ名として弾かれてしまいます。

VerdaccioのuplinkにUnityのレジストリを登録しないとプロジェクトオープンに失敗する

Unityはプロジェクトを開く際に、パッケージの問い合わせを行います。その際、Unity側のパッケージが取得できなければ、ロード失敗になります。

VerdaccioにUnityのレジストリを登録しているとパッケージのアップロードに失敗する

Verdaccioは、パッケージのアップロード時に既存のパッケージを確認するのですが、Unityのレジストリが返してくるjsonを解釈できないらしく、エラーが出てアップロードが止まってしまいます。 今回はその解決策として、unity公式のパッケージ名に必ず付いている、「com.unity」ドメインにのみuplinkを設定することで対処しています。(なので、com.unityでパッケージをアップロードしようとすると失敗します。)

Unity上のGUIに自作パッケージは出てこない

UnityのPackage Manager GUIのAllタブに表示されるパッケージ一覧はどうやら別の手段で取得しているらしく、自作パッケージをアップロードしてもリストに表示されません。インストールにはmanifest.jsonを弄る必要があります。

…さあ、これらを踏まえてレジストリを立てましょう。

レジストリを立てる

今回はnpmの事を知らない人向けに(僕もよく知らなかったので…)インストール方法から書いていこうと思います。環境はWindows10です。

Verdaccioはnpmからインストールしますので、まずnpmを入手する必要があります。npmはNode.jsのパッケージマネージャーであり、Node.jsをインストールすると付いてきます。

Node.js

Node.jsのインストールが終わったらnpmコマンドが使えるようになるので、コマンドプロンプトを開いてverdaccioをインストールします。

npm install -g verdaccio

npmの提供するアプリ(Node)はデフォルトだとコマンドを叩いたディレクトリにインストールされますが、今回は-g引数を使い、PCのどこからでも触れるようグローバルインストールを行います。

インストールが終わったら起動します。

verdaccio

f:id:Sokuhatiku:20180814211838p:plain

何も設定をいじっていない状態なので、localhost:4873でアクセス出来るはずです。 f:id:Sokuhatiku:20180815145236p:plain

設定の変更

Verdaccioを一度立ち上げたことで設定ファイルが作成されます。UnityPackageを配布するために、設定を変更しましょう。一度Verdaccioを落とします。

設定ファイルは、%APPDATA%\verdaccio\config.yamlに生成されているはずです。

ファイルを開き、次のように書き換えます。

Verdaccio for Unitypackage

(リビジョンでどのように書き換えたか分かります。)

完了したら、もう一度Verdaccioを起動しましょう。設定ファイルでポートを変更したので、今度はポート無しのlocalhostでアクセスできるようになります。

ユーザーの作成

次にアップロードするためのユーザーを作成します。

npm adduser --registry http://localhost/

User名、Password、Emailアドレスを順番に聞かれるので設定してください。このユーザー情報はVerdaccioのwebページにサインインするのに使うと共に、Verdaccioにパッケージをアップロードする際にも自動的に使用されます。

パッケージのアップロード

パッケージの作り方に関しては、前回の記事を参照してください。

Unity Package Managerに自作Packageを登録する方法 - Synamon’s Engineer blog

パッケージを作ったら、package.jsonのあるディレクトリに移動して、以下のコマンドを叩きます。

npm publish --registry "http://localhost/"

これでパッケージのアップロードは完了です。

インポート先のプロジェクトの設定

後は、作ったパッケージをインポートしたいプロジェクトの、Packages\manifest.jsonを設定します。

dependenciesに、"{パッケージ名}": "{パッケージのバージョン}"を追加して、dependenciesキーの後ろに"registry": "http://localhost/"を追加してください。

このようになるはずです(dependenciesの中身はプロジェクトによって異なります。)

{
  "dependencies": {
    "com.test.testpackage": "0.8.2",
    "com.unity.package-manager-ui": "1.9.11",
    "com.unity.postprocessing": "2.0.10-preview",
    "com.unity.progrids": "3.0.3-preview.0"
  },
  "registry": "http://localhost/"
}

"com.test.testpackage": "0.8.2"の部分を自作パッケージの名前とバージョンに変換してください。あと、"registry"の前のコンマを忘れずに!)

以上です。お疲れ様でした。これでUnityを起動すると、パッケージが読み込まれているはずです。

バージョンを変えて複数回アップロードすると、UI上からバージョン切替も出来ます。

ちなみにアップロードしたパッケージの削除は以下のコマンドです。

npm unpublish {パッケージ名} --force --registry "http://localhost/"

あとがき

今回、自作パッケージのバージョン管理や、バージョン名でインストール(=ローカルにファイルをコピーしてくる必要が無い)まで解決することが出来ましたが、まだ問題点があります。

個人的に大きいのはパッケージ間の依存関係を解決できない事です。パッケージ内のdependencyに他のパッケージを指定してもロードして貰えません。 流石にここはupmの内部挙動のため、外からハックして解決するのは難しいのでは、と感じています。

とはいえ、今回で、チーム内で前提アセットを配布+git管理するといった使い方はかなりやりやすくなったと思います。Unityの公式対応が待てない方は是非試してみてください。

また、上手くいかなかったり、もっといい方法があれば是非教えてください。

100万ポリゴンのCADデータを3000ポリゴンにリトポする

こんにちは。株式会社Synamonで開発責任者(CDO)をしている西口([@nishiguchi3d])です。

みなさんはVRでCADのデータを見たいと思ったことはありませんか?

Unityにインポートして表示させるだけなら大して難しくないですがやはり問題になるのがそのポリゴン数と質感付けの部分じゃないでしょうか?

今回は実際に使用したデータをもとにVRに適したデータを作成しUnityで表示するところまで解説してみたいと思います。 

 ポリゴン数を削る

こちらが今回使用するBECKHOFFのEPCのCADデータです。細部まで作り込んであるのでこの段階で1,150,374ポリゴンあります。

f:id:Synamon:20180727015713j:plain

 ポリゴン数もさることながらこのディティールの3角ポリゴンのデータをUV展開するのかと思うとゾッとしますね!なのでこれをリトポ(リトポロジー)して可能な限りポリゴン数を削減していきます。

そしてこれがリトポ後のデータ3,132ポリゴンです(画像は3角化した後のものです)

f:id:Synamon:20180727020157j:plain

リトポといいましたが本当はハイポリデータを下敷きにして全部1から作り直しました、形状的にそのほうが早く綺麗にできそうと判断したからです。シルエットが変わらないように大きいディティールはそのまま、テクスチャで表現できそうな小さい凸凹は大胆に削って再構成していくのがポイントです。

f:id:Synamon:20180728165054g:plain

中央に見えるくぼみは最初削った状態で作ったんですがVRに持っていって確認したらNormalマップだけでは穴が空いていないのがバレバレだったので空けました。

 

UVを展開します、3000ポリゴン程度ならUV展開も楽々ですね!

f:id:Synamon:20180728140041j:plain f:id:Synamon:20180728140335j:plain 

画像は3角ポリゴン化した後のものになりますが、実際には三角ポリゴン化する前のほうが連続面の選択やエッジの選択がやりやすいので開きやすいです。

もしリトポせずに3角ポリゴンで構成されたハイポリのモデルをUV展開するとなると大変です。自動展開ツール等あるので出来ないわけではないですが細かくUVを制御することができなくなるので後の工程で苦労するかもしれません。

テクスチャにディティールをベイクする

 UVも開いたのでハイポリのディティールをローポリモデルにベイクしていきます。

f:id:Synamon:20180728143130j:plain f:id:Synamon:20180728143149j:plain

まずはNormalマップ、MODOとSubstance Painterの2つで焼き比べてみましたが今回はMODOのNormalを採用しました。どうしてもうまく焼けない部分は設定を変えながら焼いた複数枚のマップをPhotoshopで合成してます。一発でうまく焼くのはなかなか難しいです。ちなみにオブジェクトを3角ポリゴンに変換せずにNormalをベイクしてUnityに持っていくと見た目が変わってしまったりするのでベイク前に3角ポリゴンに変換してから焼いてます。

f:id:Synamon:20180728143334j:plain f:id:Synamon:20180728143401j:plain

Ambient occlusion(AO)はSubstance Painterのものを採用しました、これも2つのソフトで焼いてみて綺麗だった方を選びました。今回のモデルは凹凸が多いのでAOが入ると立体感が出ていい感じですね。

 

あとはSubstance Painterで質感をつければ完成です。後はUnityに持っていってStandardShaderのマテリアルで設定して終了。

f:id:Synamon:20180728144142j:plain

f:id:Synamon:20180728144733j:plain

 上:Substance painter 下:Unity 

 まとめ

最近はオートリトポやプロシージャルの技術も進んできているのでもっと簡単に軽くて綺麗なデータを作れるようになるかもしれませんが、やはり主役となるモデルは一手間かけるとぐっと存在感が増すので、時間をかけて作り込むか簡単に済ませるかは登場するオブジェクトの重要度によって選択するといいと思います。

メッシュ情報を焼いたテクスチャを使ってTexturePaintする

こんにちは。株式会社Synamonでエンジニアとして『NEUTRANS』の開発をしている岡村(@Sokuhatiku)です。今回は、過去のイベント参加時に作った、立体的なメッシュに対して自然なテクスチャペイントを行う手法を紹介します。

Unity内で立体的なメッシュ(キャラクターなど)に対して動的にペイントする時、一般的には描画したい点のメッシュ情報を取得し、UV座標を使ってテクスチャに書き込むという方法が取られると思います。

その際に

  1. UVが重複していることにより他の部分にも同時に描画されてしまう
  2. UVの切れ目でペイントが途切れてしまう
  3. UVが伸びてペイントが歪んでしまう

といった、UVに起因するいくつかの問題が出てきます。

1に関しては、重複が起こらないようUV展開をすることで、手間をかければ解決することが可能です。しかし、立体物に対してペイントする場合、どうしてもメッシュの何処かにUVの切れ目や歪みが現れてしまい、2、3の問題が出てきてしまいます。

去年(2017年)開催された「例のカノジョ ハッカソン」というイベントに参加した際、例のカノジョや例の部屋をインク的なもので塗りたくる必要があったのですが、扇風機のような複雑なオブジェクトに対してペイントをしようとすると、UVの問題が顕著に出てしまいました。

続きを読む

Unity Package Managerに自作Packageを登録する方法

Unity2018で、パッケージマネージャという仕組みが新しく搭載されました。後々、AssetStoreで販売されているアセットが全てパッケージマネージャに対応するという展望がUnite2018にて語られています。詳しい仕様を調べてみた所、カスタムパッケージの読み込みが可能であるようなので、新規プロジェクトを作成してパッケージ化し、やり方をまとめてみました。

Package Managerとは?

今まで、外製のAssetをプロジェクトに取り込む際は、.unitypackage形式のパッケージファイルをプロジェクトにドラッグ&ドロップする方法が一般的でした。Assetをファイルとして扱え、展開が自動で行われる為、共有の利便性が高いのが特徴です。

一方で、バージョン管理の難しさや、AssetStoreから入手したAssetがProjectビューを散らかし、どれがどのパッケージのファイルなのか分からなくなる、などの欠点がありました。 特にPluginsフォルダは荒れやすく、アンインストール時に苦戦した経験のある方は多いと思います。

Package Managerは、外部のAssetを参照という形で保持します。プロジェクトのルートフォルダ上に"Packages"フォルダが作成され、その中のmanifest.jsonというファイルがパッケージの名前とバージョンを管理します。

これにより、Asset同士が完全に切り分けられ、Project内にそのプロジェクトで作成したファイルのみが入るほか、パッケージにバージョンや依存関係を定義することが出来るので、非常に手軽にパッケージ管理が行えるようになります。

このような仕組みはパッケージ管理システムと呼ばれ、VisualStudioやAtomの拡張機能、RubyGemsやnpm等で広く使われています。(Unity Package Managerはnpmを利用しているそうです。)

パッケージ管理システム - Wikipedia

Custom Packageの導入方法

カスタムパッケージの導入はまだ裏技的な方法であることを踏まえ、導入は自己責任でお願いします。

より詳しい情報が公式のマニュアルに記載されています。(英語)

Unity Package Manager | Package Manager UI website

また、カスタムパッケージの作り方は以下の情報を参考にしました。(英語)

UPM: How to make a custom package · GitHub

作り方

パッケージ化したいフォルダ(以下、パッケージ)と、パッケージをインポートしたいプロジェクト(以下、プロジェクト)を用意します。パッケージは別のUnityプロジェクトのAssetフォルダ以下でも大丈夫です。

まず、パッケージ内にAssembly Definitionを定義します。

パッケージ内のスクリプトがアセンブリの外に出ているとスクリプトが読み込まれなくなってしまう為、全てのスクリプトを別アセンブリに退避する必要があります。

次に、パッケージ内に、「package.json」を追加します。

package.jsonの記述例は以下のとおりです。

{
    "name": "com.hoge.mypackage",
    "displayName": "MyPackage",
    "version": "1.0.0",
    "unity": "2018.1",
    "description": "This is my hogehoge Package.",
    "keywords": ["Script", "Test"],
    "category": "Controllers",
    "dependencies": { }
}
パラメータ名 説明
"name" パッケージの名前(システム識別用)。
"displayName" 人が読むための名前。
"version" パッケージのバージョン。
"unity" 対応するUnityのバージョン。
"description" 人が読むためのパッケージの説明。
"keywords" 恐らく検索用。(現在は未使用)
"category" 恐らく検索用。(現在は未使用)
"dependencies" 依存するパッケージ名とそのバージョンを、"com.hoge.mypackage": "1.0.0"のように書く。 バージョン内に"exclude"と記入することでパッケージのインストールをさせないように出来るほか、ファイルパスを入力することでローカルファイルに依存させることが出来る。

package.jsonを作成することで、そのフォルダがパッケージとして認識されるようになります。次はプロジェクトにインポートするのですが、2018年5月12日現在、自作したパッケージをUnity内のPackageManagerウィンドウを利用してインポートする事は出来ないので、 手動でパッケージ管理ファイルを書き換える必要があります。

プロジェクトをUnity2018で開いたことがある場合、Assetsと同じ階層にPackagesというフォルダがあるので、その中にある、「manifest.json」を編集します。

manifest.jsonの記述例は以下のとおりです。

{
    "dependencies": {
        "com.hoge.mypackage": "file:../../CustomPackage"
    }
}
パラメータ名 説明
"dependencies" プロジェクトが依存するパッケージの名前とバージョン。バージョン欄にパッケージフォルダへのパスを書くことで、ローカルのパッケージを取り込むことが出来る。

manifest.jsonを保存し、Unityプロジェクトを開くと、パッケージがインストールされているはずです。PackageManagerウィンドウにpackage.jsonに書いた情報が表示されていれば成功です。

スクリプト以外のアセットの利用方法

パッケージの内容はProjectビューに表示されないという特徴のため、Prefab含め、スクリプト以外のパッケージ内のAssetを直接利用する事は出来ません。 取り出す方法としては

  • スクリプトファイルのインスペクタに表示されるDefault referencesにアタッチする。
  • Resourcesフォルダに入れてResources.Load()する。
  • エディタ拡張でAssetDatabaseから取ってくる。
  • その場合、"Assets/"ではなく、"Packages/[com.hoge.mypackage]/"以下を指定してやるとロード出来る。

が考えられます。

Unity2018.2(beta)から、パッケージの内容が見られるようになりました!

Unity 2018.2からPackagesから取得したパッケージがProjectビューに映るようになり、ECSの内部コードも確認できるようになりました。

【Unity】ECSのメモリレイアウトとその周辺 - テラシュールブログ

まとめ

UnityPackageやAssetStoreから持ってきたアセットはProjectを汚すのが常でした。Pluginsに全てのファイルを入れてくれているアセットもあったりましたが、不意の展開で迷子になってしまったり、内部でしか使わないファイルがずらずら並ぶのが見えたりしてしまうので、パッケージマネージャの仕組みは素晴らしいと思います。

スクリプト以外のアセットをどうするのかとか、社内ツールをパッケージ化した時バージョン合わせをどうするかとか、不便な部分はまだ多いですが、今後アップデートで改善されていくことでしょう。 現状はまだゴリゴリ導入するには怖い部分も多いですが、触れておくと正式対応時にスムーズに移行できるかもしれません。