カメラを操作してUnityChanの写真を撮ろう。

1.床の作成
Cubeを作成しFloorにリネーム。トランスフォームは以下

2.UnityChanのダウンロード
UnitychanをDownloadする。
http://unity-chan.com/download/download.php?id=UnityChan&v=1.2.1

3.バグの修正
Unityのバージョン違いによって発生すバグを修正する
AutoBlink.csから以下のように1行コメントアウトする

//
//AutoBlink.cs
//オート目パチスクリプト
//2014/06/23 N.Kobayashi
//
using UnityEngine;
using System.Collections;
//using System.Security.Policy;

namespace UnityChan
{
	public class AutoBlink : MonoBehaviour
	{

4.UnityChanの配置
Prefabsにはいっているunitychan_dynamicをシーンに配置

トランスフォームは以下

今回不要なIdleChangerとFaceUpdateはオフにしておこう

5.ライトの設定
プレファブからDirectional light for UnityChanをシーンに配置し、予めあったDirectional Lightは削除する

ライトの設定をしよう。以下のようにLightコンポーネントを修正する

6.確認
カメラのtransformを以下のように設定して再生してみよう。

以下のように表示されれば成功だ

カメラを回す

では実際にこのUnityChanを映すカメラ設定を考えてみよう

7.RotateAround
新規スクリプトからCamConを以下のように作成し、mainカメラにアタッチ

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CamCon : MonoBehaviour
{
    public Transform target;
    
    void Update()
    {
        //(中心点、回転軸、回転速度)今回は1秒間に40度回す設定
        transform.RotateAround(target.position, Vector3.up, 40f*Time.deltaTime);
    }
}

TargetにUnityChan_dynamicを登録

実行してみよう。

UnityChanを中心にカメラが回ることがわかる。現在のカメラ位置から対象を中心に回すときにRotateAroundは便利だ。

8.キー入力に対応
この動きを利用してキー入力で見るアングルを変更できるようにする。
Camcon.csを以下のように変更する

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CamCon : MonoBehaviour
{
    public Transform target;
    
    void Update()
    {
        //(中心点、回転軸、回転速度)今回は1秒間に40度回す設定
        //transform.RotateAround(target.position, Vector3.up, 40f*Time.deltaTime);

        if (Input.GetKey(KeyCode.RightArrow)) {
            transform.RotateAround(target.position, Vector3.up, -40f * Time.deltaTime);
        }
        if (Input.GetKey(KeyCode.LeftArrow)) {
            transform.RotateAround(target.position, Vector3.up, 40f * Time.deltaTime);
        }
        if (Input.GetKey(KeyCode.UpArrow)) {
            transform.RotateAround(target.position, transform.right, 40f * Time.deltaTime);
        }
        if (Input.GetKey(KeyCode.DownArrow)) {
            transform.RotateAround(target.position, transform.right, -40f * Time.deltaTime);
        }
    }
}

左右上下キーでアングルを変えられるようになった。上下の切り替えの際にはカメラの横軸を支点に回るようにする

9.カメラ位置の調整
アングルだけではなく、カメラの高さなども調整できるようにしよう。
以下のようにCamCon.csを変更する
位置の調整はVimライクにH,J,K,Lキーで変更する

10.ズーム機能
ズームできるようにしよう。以下のようにCamCon.csに追記する

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CamCon : MonoBehaviour {
    public Transform target;
    float fov = 60f;//field of viewの既定値

    void Update() {
        //(中心点、回転軸、回転速度)今回は1秒間に40度回す設定
        //transform.RotateAround(target.position, Vector3.up, 40f*Time.deltaTime);

        if (Input.GetKey(KeyCode.RightArrow)) {
            transform.RotateAround(target.position, Vector3.up, -40f * Time.deltaTime);
        }
        if (Input.GetKey(KeyCode.LeftArrow)) {
            transform.RotateAround(target.position, Vector3.up, 40f * Time.deltaTime);
        }
        if (Input.GetKey(KeyCode.UpArrow)) {
            transform.RotateAround(target.position, transform.right, 40f * Time.deltaTime);
        }
        if (Input.GetKey(KeyCode.DownArrow)) {
            transform.RotateAround(target.position, transform.right, -40f * Time.deltaTime);
        }
        if (Input.GetKey(KeyCode.J)) {
            transform.Translate(0f, -0.5f * Time.deltaTime, 0f);
        }
        if (Input.GetKey(KeyCode.K)) {
            transform.Translate(0f, 0.5f * Time.deltaTime, 0f);
        }
        if (Input.GetKey(KeyCode.L)) {
            transform.Translate(0.5f * Time.deltaTime, 0f, 0f);
        }
        if (Input.GetKey(KeyCode.H)) {
            transform.Translate(-0.5f * Time.deltaTime, 0f, 0f);
        }
        if (Input.GetKey(KeyCode.Z)) {
            fov -= 10f * Time.deltaTime;
        }
        if (Input.GetKey(KeyCode.W)) {
            fov += 10f * Time.deltaTime;
        }
        //(変数,最小値,最大値)
        fov = Mathf.Clamp(fov, 10f, 150f);
        //fovの設定
        Camera.main.fieldOfView = fov;
    }
}

Zで拡大、Wで引くことができる。お好みのアングルを探して究極の1枚を撮影していただきたい。

(参考)
RotateAroundを使わずにSinとCosで回す例
この方法だと回転しながら徐々に対象に近づくなど細かい制御が可能

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CamCon2 : MonoBehaviour
{
    public Transform target;
    public Transform aim;
    Vector3 cameraPos;
    float sec;
    float dist=1.74f;
    void Update()
    {
        sec += Time.deltaTime;
        dist -= Time.deltaTime * 0.2f;
        dist = Mathf.Max(1.0f, dist);
        cameraPos.x = target.position.x + Mathf.Cos(sec*0.6f) * dist;
        cameraPos.y = aim.position.y;
        cameraPos.z = target.position.z + Mathf.Sin(sec*0.6f) * dist;
        transform.position = cameraPos;
        transform.LookAt(aim);
    }
}

マウスを使って回す場合

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CamCon3 : MonoBehaviour {
    //被写体とカメラの距離
    public float distance = 5f;
    //y軸回転の初期値 (Unitychanを前から見る)
    public float rotY = 180f;
    //x軸回転の初期値
    public float rotX = 0f;
    //ドラッグの距離に対する角度変化の度合い(画面幅で360度)
    public float rotAngle = 360f;
    //映す対象(Unitychan)が入る
    public Transform target;
    //注視点のオフセット(上方にして顔などに合わせる)
    public Vector3 offset;

    //ドラッグを始めた地点
    Vector2 slideStartPos;
    //前フレームのマウスの位置
    Vector2 prevPos;
    //前フレームと現在のマウス位置のずれ量(x,y)
    Vector2 delta;
    //ドラッグ中か?
    bool isDrag = false;

    //fieldOfView:ズーム値の初期値
    float fov = 60f;

    void Update() {
        /**ドラッグの決定**/
        //カチっとマウスを「押し下げ」された
        if (Input.GetMouseButtonDown(0)) {
            slideStartPos = Input.mousePosition;//座標を記録
        }
        //マウスが押され続けている
        if (Input.GetMouseButton(0)) {
            //もし画面幅の1割の量動かしたらドラッグとみなす
            if (Vector2.Distance(slideStartPos, Input.mousePosition) >= Screen.width * 0.1f) {
                isDrag = true;
            }
        }
        //マウスが押されていなかったらisDragはfalse
        if (!Input.GetMouseButton(0)) {
            isDrag = false;
        }

        /**ドラッグによる変位量を求める**/
        //ドラッグされていたら
        if (isDrag) {
            Vector2 pos = Input.mousePosition;
            delta = pos - prevPos;//前フレームのマウス位置との差をみる

        } else {
            delta = Vector2.zero;
        }
        prevPos = Input.mousePosition;//prevを更新

        /**マウス座標の変位量によってどれだけカメラを動かすのかを求める**/
        if (isDrag) {
            //ドラッグ量に対する感度を求める
            float anglePerPixel = rotAngle / Screen.width;
            //ドラッグの横成分はy回転
            rotY += delta.x * anglePerPixel;
            //0~360を循環
            rotY = Mathf.Repeat(rotY, 360f);
            //ドラッグの縦成分はx回転
            rotX -= delta.y * anglePerPixel;
            //-60~60に挟み込む
            rotX = Mathf.Clamp(rotX, -60f, 60f);

        }

        /**カメラ位置、カメラの角度の決定**/
        if (target != null) {
            //注視点の設定
            Vector3 lookPosition = target.position + offset;
            //カメラを動かすベクトルを作成(q*vecでベクトルを回す)
            Vector3 relativePos = Quaternion.Euler(rotX, rotY, 0) * new Vector3(0, 0, -distance);
            //カメラの位置を決定
            transform.position = lookPosition + relativePos;
            //注視点にカメラを向ける
            transform.LookAt(lookPosition);
        }

        /**fov(FieldOfView:ズーム)の決定**/
        //マウスホイールによってfovの値を操作
        fov += Input.GetAxis("Mouse ScrollWheel");
        //10~150に挟み込む
        fov = Mathf.Clamp(fov, 10f, 150f);
        //fovの値を決定
        Camera.main.fieldOfView = fov;
    }
}