CINEMA 4D+Unityでクリスマスツリーを作る

はじめに

この記事はカヤックUnityアドベントカレンダー2018の24日目の記事になります。
こんにちはハニカムと光り物が好きなカヤックエンジニアのオギワラです。

本日はクリスマスイブなのでイルミネーションを作り、その過程でのCINEMA4Dでのツールを使った簡単なモデリングやUnity上で3Dモデルを使う際のあれこれや画作りの話をかる〜くしようと思います。

まず完成したものがこちら。
f:id:OgiiiiiiiQiQiii:20181224125404p:plain

1.ツリーを作る : CINEMA4Dで回転ツールを使った

クリスマスといえばクリスマスツリーです。
なので、CINEMA4Dを用いてクリスマスツリーを作っていきたいと思います。

回転体ツールを使ったモデリング

Splineツールで線を書き

f:id:OgiiiiiiiQiQiii:20181224111127g:plain
Splineツールで線をかく

回転体を作るGeneratorツールのLatheを適用
f:id:OgiiiiiiiQiQiii:20181224111258g:plain
Splineで回転体を作る、Generatorツール内にある LetheをSplineの親に

LatheのObjectのSubdivision(分割数)を12に設定
これはのちのちクリスマスツリーっぽくするために12分割にします
f:id:OgiiiiiiiQiQiii:20181224111539g:plain
LetheのObjectウィンドウ内のSubdivision(分割数)を12に

後編集可能な状態にしてからPoint選択モードで一個おきに選択
f:id:OgiiiiiiiQiQiii:20181224111651p:plain
編集可能な状態にしてPoint選択モードで一個おきに選択

xz軸の縮小でギザギザに
f:id:OgiiiiiiiQiQiii:20181224111805g:plain
XZ軸で縮小してギザギザに

ツリーの造形ができました

f:id:OgiiiiiiiQiQiii:20181224111914p:plain
ツリー

2.作ったモデルをUnityへ : fbxでExportしてUnity

一旦作ったモデルをfbxに書き出してUnityにインポートします。
書き出しは
File>Export>FBX
で書き出せます、わかりやすい場所に保存しましょう。

f:id:OgiiiiiiiQiQiii:20181224111945p:plain
書き出します

しかし、今作ったオブジェクトをUnityのSceneにおいても不思議な見え方をしています...

f:id:OgiiiiiiiQiQiii:20181224112027p:plain
なんだか....

これには原因があるのでした...

3.ちゃんとツリーを出現させる : 法線の反転

真っ青...

f:id:OgiiiiiiiQiQiii:20181224112139p:plain
真っ青...

不思議な見え方のする原因はモデリング時に法線が反転していたというのが原因です。
Unityのスタンダードシェーダーが法線方向の裏は描画しない設定であるカリングがONになっているためです。
なのでスタンダードシェーダーのような両面描画ではないものでは表示されてないように見えるわけなのです。

モデルの法線方向がひっくり返ってるということでCINEMA4D側で治します。
メッシュを全選択してReverseNomalsでOK

f:id:OgiiiiiiiQiQiii:20181224112225g:plain
ひっくり返してオレンジに

直したfbxは法線方向を変えたのみなので先ほど入れたfbxに上書きするだけでUnity上で変更が適用されます。
やったー

f:id:OgiiiiiiiQiQiii:20181224112553p:plain
出てきました

UV変えたり法線変える程度では読み込みがおかしくなることはないのでその辺の修正の適用は上書きして差し替えると楽です。
※アニメーションをつけてる場合は階層を変えると壊れたりするので上書きはよろしくないです。

4.リッチなマテリアルへの下準備 : UV展開+テクスチャーの作成

しかし今のままでは真っ白で寂しい感じです。
形も地味だったので捻ったりしてもう少し良い感じの形にします。

f:id:OgiiiiiiiQiQiii:20181224112702p:plain
新たな木

今回はキャラクターモデリングではなく顔の書き込みとかの必要もないので、メッシュごとにマテリアルをつけて色分けしても良いですが、 テクスチャーで面ごとの色を変えたり反射感を変えたいのでUVを展開します。

今回はLatheツールで作ったオブジェクトなので最初から綺麗に開けてます。

f:id:OgiiiiiiiQiQiii:20181224112735p:plain
LehteツールなどGeneratorツールで作られたオブジェクトのUVは綺麗

今回はこれだとテクスチャーが作りにくいので
テクスチャを作りやすいように配置を変えていきます。

f:id:OgiiiiiiiQiQiii:20181224112858g:plain
移動したいとこのUVを選択してずらす

f:id:OgiiiiiiiQiQiii:20181224113005p:plain
一段目

f:id:OgiiiiiiiQiQiii:20181224113047p:plain
二段目

f:id:OgiiiiiiiQiQiii:20181224113108p:plain
三段目

f:id:OgiiiiiiiQiQiii:20181224113137p:plain
木の幹も開きます

今回はこんな感じでそれぞれのオブジェクトのUVを設定しました。
またfbxに書き出してUnity側に入れます。

f:id:OgiiiiiiiQiQiii:20181224113213g:plain
このように

新たにMaterial作成しツリーの各パーツに適用
Albedoに
f:id:OgiiiiiiiQiQiii:20181224113359p:plain
しろと黒のTexture

このテクスチャーを貼ると
ツリーが面おきに白黒に

ちなみにこのテクスチャーをAlbedo、Emission、Metallicに貼ると

f:id:OgiiiiiiiQiQiii:20181224113442p:plain
Albedo

f:id:OgiiiiiiiQiQiii:20181224113515p:plain
Emission

f:id:OgiiiiiiiQiQiii:20181224113552p:plain
Metallic

Metallicは金属か金属じゃないかを表現し
Smoothnessは表面の滑らかさで反射のボケなどの表現ができるもので
テクスチャーを作成する場合は白と黒が金属についてでSmoothnessはアルファチャンネルに持たせることができ一つのテクスチャで表現します。

なので光らせたい部分、反射させたい部分、金属にしたい部分を考えながらUV展開してテクスチャーを作ると捗ります。

UV展開って手間な感じがしますが、
オブジェクトの作り方によっては綺麗な開き方をしていない事もあり
Unity側でグローバルイルミネーションを焼いたときとか変な見え方になったりすることなどUnityで扱う時に不便を感じることも多々もあるので自分で使いやすいようにUVを展開したほうが何かと便利なので出来ると良いです。

6.全体の明るさを決める : ライティング設定

ライティングをあれこれする前に色々と置いてクリスマスツリー近づけました。

f:id:OgiiiiiiiQiQiii:20181224113710p:plain
色々置いた

とりあえずDirectionalLightを撤去

f:id:OgiiiiiiiQiQiii:20181224113740p:plain
一気に暗くなります

地面以外撤去

f:id:OgiiiiiiiQiQiii:20181224113810p:plain
寂しい...

Unityのスフィアを追加

f:id:OgiiiiiiiQiQiii:20181224113832p:plain
Sphereを置くことで物に対してはどのような光になるかわかります

シーンが壊れちゃった時のようなめちゃくちゃ心配になる画ですが大丈夫です。

この状態でWindow>Rendaring>Lighting

f:id:OgiiiiiiiQiQiii:20181224113918p:plain
Lightingウィンドウをだす

でLightingのウィンドウを出します。
Lightingウィンドウとは

三つのタブがありますが基本的にSceneタブのみをいじります。
全体的な明かりを設定するAmbientLightや、
反射光など計算できリアルな光を演出するGlobal Illumination(以後GI)など
ライト関係を設定するウィンドウです。
ここでスカイボックスも変えることができます。
画像から明るさなどを取得できるHDRI画像からキューブマップを作りskyマテリアルを用意することで好きな環境を適用することができます。

EnvironmentLightingのSourceは三種類あり
skyのマテリアルからの明るさを適用するSkybox

f:id:OgiiiiiiiQiQiii:20181224114009p:plain
設定しているskyboxの色合いが反映される

単色の明るさを適用するColor
f:id:OgiiiiiiiQiQiii:20181224114048p:plain
Color

下からの光、上からの光、中間地点の明かりの色を選択できるグラデーション
f:id:OgiiiiiiiQiQiii:20181224114156p:plain
グラデーション

今回はグラデーションを使います。

f:id:OgiiiiiiiQiQiii:20181224114226p:plain
こんな感じになりました

こんな感じに。

Unityのライティング設定ではGIをベイクしたり、AmbientLightを設定したり、リアルタイムにEmissionの適用されたオブジェクトなどの光物の反射を適用するかなどの設定ができます。
ただ、GIは綺麗に焼こうとすると時間がものすごくかかったり、焼けてもいい感じにならなかったりと絵作りに時間がないときは辛いです。 なので今回はAmbientLightの設定程度に留めます。

GIをベイクすることで柔らかな影も表現できるのですが
柔らかい陰影をつけるAmbientOculusion(以後AO)はPostProcessの力を利用するか先ほどのテクスチャー作成のようにAO用のテクスチャーを作ってしまったほうが時間も短く綺麗にできるので作れる環境があるならそっちの方が良いのかもです。

7.光と陰と反射でのっぺりさせない画に : C4DでAOテクスチャー作成とライトの配置

まだまだなんだかのっぺりした印象です。
Lightingウィンドウでの設定でも触れたAOを適用すると陰影がついてメリハリがつきます。
AOはいくつかの方法でつけることができ
今回は時間もかからず綺麗にできるCINEMA4Dを使った方法を紹介します。

CINEMA4Dで柔らかい陰影をつける(AO)を作る方法

テクスチャーを現状に基づき焼き付けてくれるBakeTextureタグを使ってAOをTextureに焼きます。

f:id:OgiiiiiiiQiQiii:20181224114308g:plain
BakeTextureタグ

ここで書き出したテクスチャーをUnityに取り込み地面のMaterialのOcclusionに貼り付けるとこうなります。
f:id:OgiiiiiiiQiQiii:20181224114427p:plain
花に重みが出ました

ツリーや花の下に影がつきました。
いい感じに影がついて今までよりも立体を感じられます。

UV展開の時に触れましたがもしこの工程でUVが重なってたりすると思い通りの影がつかなかったりします...
なのでAOテクスチャーに変な影が出てきた場合はUVも疑ってみましょう。

さらに影をつけたい動かないオブジェクト分やるとこうなります。

f:id:OgiiiiiiiQiQiii:20181224114516p:plain
ついでに花を青くしました

ツリーの凹み部分とかむしろ影が高すぎなくらいなのでこの辺はマテリアルで調整していきましょう。

この方法のAOは綺麗で時間もそんなにかからないという利点がありますが
テクスチャーなので動かないオブジェクトにのみ有効です。
焼き付ける時も動かないオブジェクトだけで焼かないと不自然な影ができてしまうことも...
リアルタイムに動くものが多い時はUnityのPostProcessが有効なので状況に応じて使い分けると良いと思います。(ただしこちらは不自然にすみっぽくなってしまうというデメリットが)

RefrectionProbeを置く

RefrectionProbeは設定した範囲内のレンダリング結果から反射や色を設定してくれちゃう機能です。
反射がSkyboxだけみたいなことにならなくなります。
やることは範囲を調整してBox Projectionにチェックを入れて位置を調整するくらいです。
反射物を扱うときにはとても有効なものです。

Lightを設置する

反射を利用してオブジェクトの形状を感じやすくなるように嘘のライトを設置したり
実際に光る予定のものの中にPointLightを置いたりして行きます。

f:id:OgiiiiiiiQiQiii:20181224114549p:plain
光を置きました

最後に反射をよりScene上の物に忠実になるRefrectionProbeをおきます。

でも光るはずのものが光っているように見えません。

8.光り物を光らしたりして絵をリッチにする : ポストプロセス

光り物を光っているように見せる+仕上げとして
Post Processing Stack v2を導入します。

Post Processing Stack v2はUnity2018から使用できるようになったカメラのエフェクトをかけるアセットです。
導入の仕方は
Window> PackageManagerでウィンドウを開き
ALLを選択
Post ProcessingStackV2を選択しInstallします。
InProject側でPost Processing Stack v2が確認できれば導入完了です。

f:id:OgiiiiiiiQiQiii:20181224130007g:plain
表示までが長い...

使い方は
カメラにPostProcessLayerコンポーネントを追加し
LayerをPostProcessingに

f:id:OgiiiiiiiQiQiii:20181224130139g:plain
カメラの方の設定

空のオブジェクトを作り、PostProcessVolumeコンポーネントを追加し
空のオブジェクトのレイヤーはPostProcessingに
PostProcessVolumeコンポーネントのisGlobalにチェックを入れます。
PostProcessProfileを作り
先ほどの空のオブジェクトのPostProcessVolumeコンポーネントにアタッチ。
f:id:OgiiiiiiiQiQiii:20181224130212g:plain
Volume側の設定

あとはエフェクトを追加してパラメータをいじるのみでエフェクトがかかります。
f:id:OgiiiiiiiQiQiii:20181224130309g:plain
少々ややこしいですが今までよりエフェクトを管理しやすくなりました。

今回は光り物を光り物として見えるようにBloomとミニチュア風になるボケを入れるDepth Of Fieldを使用して仕上げて行きます。
光り物は多いので大袈裟にならない程度にブルームを入れてエミッションを適用してるオブジェクトが光っているように見せます。

あれこれ調節して
最終的にこんな画になりました。

f:id:OgiiiiiiiQiQiii:20181224125404p:plain
木も増やしました

以上でクリスマスツリーを作りつつUnityで使用しやすいモデルを作成する話と画作りの話を終わります。

さいごに

UnityのアドベントカレンダーのはずがほとんどCINEMA4Dを使用した部分が多いのですが
自分がUnityで3Dモデルを扱うに当たってつまずいたポイントなども盛り込んだのでお役に立てれば幸いです。
それでは良いクリスマスを!

明日は清水によるグローバルイルミネーション(GI)を使わないプロジェクトでやっておくべきことの話です。

動画配信ソフト「OBS」をPythonで操るぞ~

はじめに

こんにちは~。 会社のみんなから「ポン太郎」と呼ばれている技術部新卒の井上宗汰です!(同期に井上がもう一人いる)

「なんだか全然仕事できなさそ~」って感じのあだ名ですが、毎日を全力で生きているので何卒。

最近はイベント関係で使うシステムの構築をやったりしてるxR系のUnityエンジニアとしてお仕事してます。

さてさて、今回は、案件の関係でOBS(という動画配信でよく使われているソフト)をWebsocket経由でAPI叩いて操作したので、その知見の共有をしたいと思います。

これで外部アプリと連携させて、不具合が起きた時にそれをトリガーにして「しばらくお待ちください」みたいな放送事故っぽいアレを自動で出したりできますね! (動画配信していた頃の、灰色の高校時代を思い出しながら書いたので、なにやら心臓の調子が悪い気がした)

f:id:xabutoon:20181221230608p:plain
OBS(OpenBroadCasterSoftware)

環境

  • Windows10(x64)
  • OBS
  • Python3.5.4
  • obs-websocket(こやつでwebsocketでやりとりできるようになる)

github.com

  • obs-ws-rc(Python3.5+でobs-websocketを操れるようになる。うれし~) github.com

Python3.5+でなくても、Python2/3・JavaScript・C#を使えるから、好きなやつを選んでみてね

構築

とにもかくにも、まずは環境構築ですね。 OBSとPython3.5+を入れる。 (ここら辺は割愛) 次にobs-websocket! これはインストーラーが用意されているので、それを使いましょう。

github.com

こんな感じで、ツール以下に「Websocketサーバーの設定」という項目が現れたらインストールは成功です!うれしー!(パンパンパン!)

f:id:xabutoon:20181221220405p:plain

最後にobs-ws-rc。以下のコマンド一発でオーケー。

pip install obs-ws-rc

これで環境構築は終わり!

ドキュメント

まず、ドキュメントを覗いてみましょー

https://obs-ws-rc.readthedocs.io/en/latest/

リクエストの実行サンプル。

"""Example shows how to send requests and get responses."""

import asyncio

from obswsrc import OBSWS
from obswsrc.requests import ResponseStatus, StartStreamingRequest
from obswsrc.types import Stream, StreamSettings


async def main():

    async with OBSWS('localhost', 4444, "password") as obsws:

        # We can send an empty StartStreaming request (in that case the plugin
        # will use OBS configuration), but let's provide some settings as well
        stream_settings = StreamSettings(
            server="rtmp://example.org/my_application",
            key="secret_stream_key",
            use_auth=False
        )
        stream = Stream(
            settings=stream_settings,
            type="rtmp_custom",
        )

        # Now let's actually perform a request
        response = await obsws.require(StartStreamingRequest(stream=stream))

        # Check if everything is OK
        if response.status == ResponseStatus.OK:
            print("Streaming has started")
        else:
            print("Couldn't start the stream! Reason:", response.error)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

どうやら別で用意したRTMPのストリームをOBSに持ってくるサンプル?のようですね。 脳死でこれ実行しても、OBSとのコネクションはうまくいきますが、stream_settingsをちゃんとやらんと当然エラーになってしまうので、テックブログ記事のサンプルとしては、何だかしょぼい感じになってしまいます。

それはとても嫌な事なので『「海藻に張り付くダンゴウオのイラスト」の画像を配信していたが、トラブルが発生したのでコマンドから「お辞儀をしている猫のイラスト」に差し替える』というシチュエーションを想定して解説していくことにします。 (いらすとやさん、いつもありがとう)

お辞儀をしている猫のイラスト | かわいいフリー素材集 いらすとや

海藻に張り付くダンゴウオのイラスト | かわいいフリー素材集 いらすとや

実践 ~OBSの準備~

まずはOBS側の準備。 「ソース」の項目から「画像」を選択。

f:id:xabutoon:20181221230825p:plain

名前を「海藻に張り付くダンゴウオのイラスト」にして作成。

f:id:xabutoon:20181221231117p:plain

「参照」から画像を選択。

f:id:xabutoon:20181221231648p:plain

「お辞儀をしている猫のイラスト」も同じ要領で作成。とりあえず真ん中に配置しておきましょう。

......あぁ!なんと、ダンゴウオの上に猫が重なってしまいました!これでは既に放送事故ですッ!!!

f:id:xabutoon:20181221232813p:plain

猫は非表示にしておきましょう。 なんか目っぽいやつをクリック。

f:id:xabutoon:20181221233009p:plain

最後に先ほど登場した「Websocketサーバー設定」をクリック。 基本デフォルト設定ですが、今回は認証ありでいきます。パスワードは「dangouo」にしました。 「Enable System Tray Alert」をTrueにすれば、OBSとの接続・切断時にWindowsの通知が来るので、必要に応じて切り替えると良いでしょう。

f:id:xabutoon:20181221234257p:plain

実践 ~スクリプト作成~

さっきのサンプルとドキュメントをヒントに実装していきます。

https://obs-ws-rc.readthedocs.io/en/latest/obswsrc.html

最終的なコード。

現在のシーンを取得して、そいつが持ってる映像ソース(ここではダンゴウオと猫)の表示・非表示を入れ替えてるだけ。

マジでそれだけ。

import asyncio

from obswsrc import OBSWS
from obswsrc.requests import ResponseStatus, GetCurrentSceneRequest,SetSourceRenderRequest


async def main():

    async with OBSWS('localhost',4444,"dangouo") as obsws:

        response = await obsws.require(GetCurrentSceneRequest())

        if response.status == ResponseStatus.OK:
            print('//////////////////////////////////////////////')
            print("Connected.")
            print('//////////////////////////////////////////////')
            print("CurrentScene`s name is "+str(response.name))
            print('//////////////////////////////////////////////')

            print("The scenes that CurrentScene has")
            print('//////////////////////')
            for src in response.sources:
                print(src)
                print('//////////////////////')
                if src['render'] == True:
                    setReq = await obsws.require(SetSourceRenderRequest(source = src['name'],render=False))
                else:
                    setReq = await obsws.require(SetSourceRenderRequest(source = src['name'],render=True))
        else:
            print("Couldn't connect!:", response.error)
        

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

帰ってきた辞書のrenderキーを参照して、ブーリアンのステータスを入れ替えています。 実行するとこんな感じ。辞書のrenderキー見ると、ちゃんと猫とダンゴウオが入れ替わってることがわかります。 放送事故の被害を最小限に抑えることができました。

$ python TestObsWebsocket.py
//////////////////////////////////////////////
Connected.
//////////////////////////////////////////////
CurrentScene`s name is ▒V▒[▒▒
//////////////////////////////////////////////
The scenes that CurrentScene has
//////////////////////
{'cy': 400.0, 'cx': 335.0, 'volume': 1.0, 'render': True, 'source_cx': 335, 'source_cy': 400, 'x': 780.0, 'name': '▒▒▒▒▒V▒▒▒▒▒Ă▒▒▒L▒̃C▒▒▒X▒g', 'y': 355.0, 'type': 'image_source'}
//////////////////////
{'cy': 609.0, 'cx': 609.0, 'volume': 1.0, 'render': False, 'source_cx': 609, 'source_cy': 609, 'x': 646.0, 'name': '▒C▒▒▒ɒ▒▒▒t▒▒▒_▒▒▒S▒E▒I▒̃C▒▒▒X▒g', 'y': 223.0, 'type': 'image_source'}

あ、あれ、、、

も、文字化けしてるぅぅ~~~!、。?。!

OBS側で、シーン名とソース名を日本語にしてるからですね。かっこわるー

f:id:xabutoon:20181222005229p:plain

「シーン」を「TestScene」、各ソース名を「neko」「dangouo」に変更。(右クリックして「名前を変更」)

$ python TestObsWebsocket.py
//////////////////////////////////////////////
Connected.
//////////////////////////////////////////////
CurrentScene`s name is TestScene
//////////////////////////////////////////////
The scenes that CurrentScene has
//////////////////////
{'type': 'image_source', 'render': False, 'source_cx': 335, 'name': 'neko', 'y': 355.0, 'volume': 1.0, 'cx': 335.0, 'source_cy': 400, 'x': 780.0, 'cy': 400.0}
//////////////////////
{'type': 'image_source', 'render': True, 'source_cx': 609, 'name': 'dangouo', 'y': 223.0, 'volume': 1.0, 'cx': 609.0, 'source_cy': 609, 'x': 646.0, 'cy': 609.0}
//////////////////////

当然、ちゃんと直りましたね。

あと、他の処理に応用させる上で気を付けてほしいのがこの一文。

from obswsrc.requests import ResponseStatus, GetCurrentSceneRequest,SetSourceRenderRequest

他の処理を使った実装を行う際は、protocol reference のrequest項目から探すことになると思いますが、GetCurrentSceneRequest、SetSourceRenderRequestのように、referenceに載ってる項目に「Request」をつけてモジュールをインポートしてあげてください。(どうすればよいのか30分くらい迷った。descriptionのリンク切れてたし、、)

https://obs-ws-rc.readthedocs.io/en/latest/protocol.html

RequesField、ResponseFieldの各要項を見ながら臨機応変に対応してもらえれば他の処理にも応用できると思います。

あとがき

ここだけの話、まともなPython実践歴2日ではありましたが、立派なpythonistaになれるように精進していこうと思えるいい機会でした。 拙い記事ではありましたが、最後まで読んでいただきありがとうございました!

ちなみにですが、カヤックでは体験型コンテンツの制作も行っており、xR・ハードウェア志向エンジニアを募集しております。

www.kayac.com

www.kayac.com

明日のアドベントカレンダーの担当は長堂さんです!この後の記事もぜひお楽しみに〜