Unityでカメラが水中に入った時にエフェクトを加えて映す

UnityのスタンダードアセットにあるWaterを使えば、簡単に湖や海を設置出来る事がわかりました。

Unityのスタンダードアセットにある水を使うと簡単に湖や海を綺麗に作成する事が出来ます。

しかしWaterは平面なので水の下に潜ってもその下には地上にある空間と同じようにカメラに表示されてしまいます。

水の中も地上と同じように表示されてしまう

↑のように水は平面なので下側を写しても地上と同じに表示されます。

上の画像の場合はかなり透明な水なのでそれほど違和感はありませんが、水の色がよくわかるようになると水の平面を潜った時にかなりの違和感が生じます。

そこで今回は水中に入った時にカメラの映像にエフェクトを加えて水中にいるような表現を作ってみたいと思います。

スポンサーリンク

水を設置する

まずはゲーム内に水を設置し、Scaleを調整してちょっとした湖を作成します。

水の設置については

Unityのスタンダードアセットにある水を使うと簡単に湖や海を綺麗に作成する事が出来ます。

を参照してください。

今回はAssets→StandardAssets→Environment→Water→Water→Prefabs→WaterProDaytimeを設置しました。

設置したWaterProDaytimeのインスペクタを表示しAdd ComponentからPhysics→Box Colliderを取り付けます。

Is Triggerにチェックを入れコライダをキャラクターを検知するエリアにします。

水にキャラクター検知エリアを設定

上のように水面から下にコライダのエリアを作ります。

横から見ると水面から下にコライダが伸びています。

これは水中にキャラクターがいる事を検知する為、水の中では常にコライダを使ってキャラクターを検知したい為です。

水にはWaterというタグを作り設定しておきます。

水のTagにWaterを設定

これはカメラ側から水を検知する時にこのタグを使って識別します。

カメラの設定

次にキャラクターを写すカメラの設定とスクリプトの取り付けを行います。

キャラクターの動きやキャラクターを追従するカメラの機能は

Unityでキャラクターをラジコン操作で動かす為の機能の作成とキャラクターを徐々に追いかけるカメラを作成していきます。

の記事で作ったラジコン操作キャラクターと徐々に追従するカメラ機能を使います。

カメラにはRigidbodyとBox Colliderコンポーネントを取り付けます。

Rigidbodyの設定

RigidbodyはIs Kinematicにチェックを入れスクリプトで移動の操作を行います。

Rigidbodyを取り付けたのは取り付けないとOnTriggerEnterやOnTriggerExitでの検知が出来ない為です。

CharacterController以外のゲームオブジェクトで移動する可能性があるものにはRigidbodyの機能を使っていなくても取り付けてIs Kinematicにチェックを入れておくといいです。

Rigidbodyが取り付けられていないゲームオブジェクトはその場から動かない物体と思われるので挙動がおかしくなったり動作しなくなる可能性があります。

Box Colliderの設定

Box Colliderのサイズを調整しカメラの描画範囲の開始位置のサイズと合わせていきます。

カメラの開始位置に合わせてコライダを調整

↑のようにカメラの開始位置からコライダで他のゲームオブジェクトを検出出来るようにサイズと位置を調整します。

↑の例ではキャラクターの目の辺りにカメラを置いて調整していますが、これはわかりやすくしただけで実際には3人称視点のカメラになります。

今回の機能はFPSにした場合でもカメラを目の位置に置けば同じように機能するのでどちらにしても問題はありません。

カメラのClipping PlaneのNearは0.1とカメラ位置から近い部分から描画するようにしておきます。

カメラが水中にいる時の処理スクリプト

カメラには水を検知するエリアを作成したので、水を検知した時にカメラの映像にエフェクトを加え水中にいるような表現をします。

今回は二通りのやり方を作ってみます。

  • UIとBlurを使った水中表現
  • FogとBlurを使った水中表現
  • の2つです。

    Blurは両方ともに使いますが、これはカメラの映像をぼやけさせる機能です。

    UnityのStandardAssetsのBlurを使用してカメラに映る画像をぼかしてみます。

    UIの場合はCanvasの子要素にPanelを設置しカメラが水中に入った部分に色を塗り水中の色の表現をさせます。

    UIの場合は水面の高さに合わせてPanelのサイズを変えるだけなので波打っていると水中部分との隙間が出来たり、水中の平面部分が目立ちます。

    Fogの場合はカメラが半分水中に入ったらFog(霧)の設定を変更し、水中にいるかのような表現をさせます。

    Fogの場合はカメラが半分水中に入った時にカメラ全体に霧を発生させますので多少違和感は生じます。

    どちらにしても多少は問題がありそうです。(^_^;)

    それではスクリプトを作成しましょう。

    カメラには新しいスクリプトUnderWaterCameraを作成し取り付けます。

    列挙型でUIとFogモードを選択出来るようにしています。

    modeは水中表現のモード
    waterは水のゲームオブジェクト
    waterPanelはUIモードの時にサイズを変化させるPanel
    waterRectはUIモードの時のPanelのRectTransform
    isInWaterは水にカメラが接触しているかどうか
    blurはカメラをぼかすスクリプト
    normalFogColorはFogモードの時の標準の霧の色
    normalFogDensityはFogモードの時の標準の深さ
    inWaterFogColorはFogモードの時の水中の色
    inWaterFogDensityはFogモードの時の霧の深さ

    を表しています。

    Startメソッドではコンポーネントの取得とFogの設定を取得しています。
    Fogの設定はRenderSettingsから取得・変更出来ます。

    Updateメソッドではモードによって処理を分けています。

    UIモードの時でカメラが水に接触(厳密にはコライダとの接触)している場合、

    カメラの中心が水の平面部分より上の場合Panelのサイズを水の平面部分のところまでにします。

    Camera.main.WorldToViewportPoint (water.position).yで水の位置をワールド座標からビューポート(カメラの0~1の範囲に変換したもの)のY座標の位置を取得し、PanelのYのScaleをそのビューポートの位置にします。

    カメラの中心が水の平面部分より下に来た場合はPanelのScaleを全て1に設定し、画面全体のサイズにします。

    Fogモードの時はカメラが水に接触した時点でFogを有効にし水中用の設定に切り替えています。

    水との接触がなくなったら元の設定に戻しています。

    もしFogを水中以外でも使っている場合はFogのオン・オフをせず設定値を切り替えるだけの処理にします。

    OnTriggerEnter、OnTriggerExitでカメラが水と接触しているかしていないかを判定し、isInWaterフラグのオン・オフやBlurの無効をしています。

    UI部分は

    UIモードの時に使うUI

    ↑のように作成しました。

    Panelは最初は無効化しておきます。

    PanelのSource ImageはBackgroundとなっており完全にカメラ全体に適応せず角が丸まったりしていますので、全体を覆いたい場合は別のSource Imageを設定するか、

    Source ImageをNoneにしてColorだけを利用してください。

    これでカメラの機能も出来ました。

    カメラのインスペクタの設定は

    水中カメラのインスペクタの設定

    ↑のようになります。

    Blurは最初は表示させたくない為に名前の横のチェックを外し無効化しておきます。

    水中表現の確認をする

    機能が完成したので水中を表現出来るか見てみましょう。

    ↑のようになりました。

    水に設定したコライダのサイズによってはうまくいかない場合もありますのでどこからを水中とするか?の調整が必要になってきます。

    水中に入った時にもキャラクターが普通に歩いていますが・・・・(^_^;)

    水に入ったら泳いだり、移動処理を変えたりといった事も必要になってきますね。

    それはまた今度記事にしたいと思います。

    スポンサーリンク

    記事をシェアして頂ける方はこちら

    フォローして頂くとやる気が出ます