[Unity]平行投影モデルを透視投影ステージ内に立たせる方法

#はじめに
　このページはUnityにおいて平行投影モデルを透視投影ステージ内に立たせる方法を示したものである。
　ここでの透視投影はFoV60°、SceneのFoVを弄っていないものとする。
　また、応用としてこのプログラムを利用したFoVの違う透視投影モデルを併用する方法とドリーズームの方法を示す。
#この方法を使用すると
　Unity3Dにおいて、平行投影したモデルと透視投影した3Dモデルとを共存することができる。
　3DCGアニメーション作品に使用されている画角の違うモデルを同一画面に表示、合成することができるようになる。
　下画像はUnityちゃんを平行投影した3Dモデル、床と壁を透視投影した3Dモデルとして表示したものである。
　![image001.gif](https://qiita-image-store.s3.amazonaws.com/0/186860/b4b60be8-761d-871d-5ba0-4ad20a6ad908.gif)



#考え方
- 一点透視図法の上に零点透視図法を合成して表示する方法で実装する。

#使う事例
- 画角を統一した時に起こる3Dモデルの変形を起こしたくない時。
- 別々のパースでモデルを表示したい時。

#実装方法
- 下記URLと同様の手法でレイヤー、カメラ、Depth、モデルレイヤーを設定し、全Cameraのサイズを1として設定する。
[Mtk's Blog: [Unity3D] 透視投影と平行投影を合成するには[ユニティちゃん]](http://blog.fujiu.jp/2014/08/unity3d-unity-chan.html)

- OrthographicカメラをMainCameraタグを持つCameraの子にする。
- Orthographicカメラで表示するモデルに下記プログラムを追加する。

```csharp:PerspectiveMove.cs
using UnityEngine;
using System.Collections;

public class PerspectiveMove : MonoBehaviour {
    public Camera orthocamera;
    public Transform p_top;
    public Transform p_center;
    public Transform p_bottom;
    public Transform ScalePoint;
    public Transform PositionPoint;

    void LateUpdate () {//Updateだと表示ずれが起こる。
        int n = 1;

        if(Camera.main.WorldToViewportPoint(ScalePoint.position).z != 0)//0距離以外
        transform.localScale =
            Vector3.one * 2 * Mathf.Tan(60 / 2 * Mathf.Deg2Rad)
            * Vector3.Distance(p_bottom.position, p_top.position)
            / Camera.main.WorldToViewportPoint(ScalePoint.position).z;
        //ピンホールカメラのためzのみでOK。zはカメラからの距離。

        if (transform.localScale.x < 0)    n = -1;
        //(transform.localScale.x < 0)の時カメラの後ろ。
        transform.position = 
            orthocamera.ViewportToWorldPoint(Camera.main.WorldToViewportPoint(PositionPoint.position))
            + Camera.main.transform.forward * 100 * n;//カメラから距離を取ってカメラと被らないようにさせているだけ
        
        transform.rotation = p_bottom.rotation;
    }
}
```
- 下画像同様にScene上で表示されたモデルの3Dモデルの一番上、中央、一番下の位置にTransformオブジェクトを置き、一番上をp_top、中央をp_center、一番下をp_bottomとしてPerspectiveMove.csに適用する。

![image006.gif](https://qiita-image-store.s3.amazonaws.com/0/186860/dc12af13-b79d-4172-c76a-8d119a844278.gif)![image007.gif](https://qiita-image-store.s3.amazonaws.com/0/186860/f6358a6f-b221-b877-fb59-961db61edf96.gif)


#オプション
##モデルのサイズ変更
- PlayerTopの座標とPlayerBottomの座標の距離を変えることで変更可能。

##サイズ変更座標と位置座標の変更
- サイズ変更座標はScalePoint、位置座標はPositionPointを変えることで変更可能。

#応用
##FoVの違う透視投影モデルを併用する方法
　PerspectiveMove.csのtransform.localScaleとtransform.positionに下記を代入するよう書き換えることで実装できる。
　また、この時のカメラはどちらもPerspectiveでなければならない。

```csharp:transform.localScaleの値
Vector3.one * 2 / 3 
/ Mathf.Tan(Camera.main.fieldOfView / 2 * Mathf.Deg2Rad)
* Mathf.Tan(orthocamera.fieldOfView / 2 * Mathf.Deg2Rad)
* Vector3.Distance(p_bottom.position, p_top.position);
```
```csharp:transform.positionの値
orthocamera.ViewportToWorldPoint (Camera.main.WorldToViewportPoint (PositionPoint.position));
```
##ドリーズームの方法
　ドリー用カメラをMainCameraの子として作成し、MainCameraと同じ設定にする。
　DepthをMainCamera < ドリー用カメラ < orthocameraにすることで実装できる。

#ライセンス
![image020.gif](https://qiita-image-store.s3.amazonaws.com/0/186860/6eaf4d04-74e6-fb45-be22-4858dbbf21d3.gif)
この作品は[ユニティちゃんライセンス条項](http://unity-chan.com/contents/license_jp/)の元に提供されています