Полезный скрипт для камеры.

Части и запчасти к проектам, дополнительное программное обеспечение.

Полезный скрипт для камеры.

Сообщение nazgul30 14 мар 2012, 09:26

Написал полезный, как мне кажется, скрипт для камеры.
Основные возможности и преимущества по сравнению со стандартным скриптом MouseOrbit:
[V] Возможность вращения камеры вокруг объекта по эллипсу. Очень удобно для объектов формы параллелепипеда, например вагона поезда. Расположение камеры устанавливается при нажатии на кнопку "Set camera position".
[V] Возможность скроллинга.
[V] Отображение в окне редактора Scene траектории движения камеры, а также дистанции от камеры до цели.
[V] Возможность panning у мыши (Не знаю как на русский переводится). Работает подобно кнопке с рукой в редакторе - около кнопок Move, Rotate, Transform.

Скрипт мыши:
Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;

/// <summary>
/// Перечисление кнопок мыши.
/// </summary>
public enum MOUSE_BUTTON{
        NONE,
        MOUSE_LEFT,
        MOUSE_CENTER,
        MOUSE_RIGHT
}

/// <summary>
/// Скрипт для вращения камеры вокруг объекта по эллипсу.
/// Возможность скроллинга и плавной остановки вращения
/// </summary>
public class MouseEllipseOrbit : MonoBehaviour {
        //цель
        public Transform target;
        //кнопка вращения
        public MOUSE_BUTTON mouseButtonOrbit = MOUSE_BUTTON.MOUSE_RIGHT;
       
        //Паннинг
        public bool isPanning;
        //Кнопка паннинга
        public MOUSE_BUTTON mouseButtonPan = MOUSE_BUTTON.MOUSE_CENTER;
        //Скорость паннинга
        public float panningSpeed = 5;
        //слой, в котором находится плоскость паннинга.
        public int panningLayer;
       
        //полуоси эллипса
        public float a = 10;
        public float b = 10;
       
        private float distance = 10;
       
        //скорость вращения по x
        public float xSpeed = 250;
        //скорость вращения по y
        public float ySpeed = 120;
       
        //Минимальный предел просмтра по оси y
        public float yMinLimit = -20;
        //Максимальный предел просмтра по оси y
        public float yMaxLimit = 80;
       
        private float x = 0;
        private float y = 0;
       
        //Скроллинг
        public bool isScrolling = true;
        //Скорость скроллинга
        public float scrollSpeed = 1;
        //Минимальная дистанция скроллинга
        public float scrollMinDistance = 1;
        //Максимальная дистанция скроллинга
        public float scrollMaxDistance = 10;
       
        private float angle;
       
        private Vector3 newTargetPosition;
       
        private Vector3 angles;
       
        void Awake(){
                angles = transform.eulerAngles;
        }
       
        void Start(){
                newTargetPosition = target.position;
               
            x = angles.y;
            y = angles.x;
               
                // Make the rigid body not change rotation
                if (rigidbody)
                        rigidbody.freezeRotation = true;
                orbit(); scroll();
        }
       
        void LateUpdate () {
                //вращение
                if( (mouseButtonOrbit == MOUSE_BUTTON.NONE) ||
                         (mouseButtonOrbit == MOUSE_BUTTON.MOUSE_LEFT && Input.GetMouseButton(0)) ||
                          (mouseButtonOrbit == MOUSE_BUTTON.MOUSE_RIGHT && Input.GetMouseButton(1)) ||
                           (mouseButtonOrbit == MOUSE_BUTTON.MOUSE_CENTER && Input.GetMouseButton(2))
                  )
                        orbit();
               
                if(isPanning)
                        panning();
                if(isScrolling)
                        scroll();
                transform.localPosition = (transform.localRotation) * new Vector3(0, 0, -distance);    
        }
       
        private void orbit(){
                if (target) {
                    x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
                    y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
                       
                        calcRotation(x,y);
                        calcDistance();
                }
        }
       
        private void panning(){
                //передвижение мыши
                if( (mouseButtonPan == MOUSE_BUTTON.NONE) ||
                         (mouseButtonPan == MOUSE_BUTTON.MOUSE_LEFT && Input.GetMouseButton(0)) ||
                          (mouseButtonPan == MOUSE_BUTTON.MOUSE_RIGHT && Input.GetMouseButton(1)) ||
                           (mouseButtonPan == MOUSE_BUTTON.MOUSE_CENTER && Input.GetMouseButton(2))
                  )
                        snap();
                       
                        target.position = Vector3.Lerp(target.position, newTargetPosition, Time.deltaTime*panningSpeed);
        }
       
        private void snap(){
                Ray ray = camera.ScreenPointToRay(Input.mousePosition);
                RaycastHit hit = new RaycastHit();
                if(Physics.Raycast(ray, out hit, 4000, ~panningLayer)){
                        newTargetPosition = hit.point;
                }
        }
               
        private void calcRotation(float x, float y){
                 y = clampAngle(y, yMinLimit, yMaxLimit);
                 Quaternion rotation= Quaternion.Euler(y, x, 0);
                 transform.rotation = rotation;
        }
       
        private void calcDistance(){
                Vector3 targetDir =  transform.position - target.position;
                float angle = Vector3.Angle(targetDir,target.forward);
                float numerator = Mathf.Pow(a,2) *  Mathf.Pow(b,2);
                       
                float denominator = Mathf.Pow(a,2)* Mathf.Pow(Mathf.Sin(angle*Mathf.Deg2Rad),2) +
                Mathf.Pow(b,2)* Mathf.Pow(Mathf.Cos(angle*Mathf.Deg2Rad),2);
       
                distance = Mathf.Sqrt (numerator/denominator);         
        }
       
        private void scroll(){
                //приблизить
                if ((Input.GetAxis("Mouse ScrollWheel")) > 0){
                        if (distance >= scrollMinDistance)      {
                                float dist1 = distance;
                                distance  +=- (Input.GetAxis("Mouse ScrollWheel"))*scrollSpeed;
                                float k = dist1 / distance;
                                a = a/k;
                                b = b/k;
                        }
                }
                //отдалить
                if ((Input.GetAxis("Mouse ScrollWheel")) < 0){
                        if (distance <= scrollMaxDistance){
                                float dist1 = distance;
                                distance +=- (Input.GetAxis("Mouse ScrollWheel"))*scrollSpeed;
                                float k = dist1 / distance;
                                a = a/k;
                                b = b/k;
                        }
                }
        }
       
        private float clampAngle (float angle,float min,float max) {
                if (angle < -360)
                        angle += 360;
                if (angle > 360)
                        angle -= 360;
                return Mathf.Clamp (angle, min, max);
        }
       
        public void init ()
        {
            x = angles.y;
            y = angles.x;
                orbit(); scroll();
               
        }
       
        public void setTargetPosition(Vector3 targetPos){
                newTargetPosition = targetPos; 
        }
}

 


Два скрипта для редактора:
Синтаксис:
Используется csharp
using UnityEngine;
using UnityEditor;
/// <summary>
/// Editor для MouseEllipseOrbit.
/// </summary>
[CustomEditor(typeof(MouseEllipseOrbit))]
public partial class MouseEllipseOrbitEditor : Editor {
       
        public void OnSceneGUI(){
                MouseEllipseOrbit meo = target as MouseEllipseOrbit;
                if(meo && meo.target != null){
                        //Стрелка X
                        Handles.color = Color.red;
                        Vector3 maxX = meo.target.position+Vector3.forward*meo.a;
                        Handles.ArrowCap(0,maxX,Quaternion.LookRotation(meo.target.forward),
                                         HandleUtility.GetHandleSize(maxX)/2);
                       
                        //Стрелка Y
                        Handles.color = Color.green;
                        Vector3 maxY = meo.target.position+Vector3.right*meo.b;
                        Handles.ArrowCap(0,maxY,Quaternion.LookRotation(meo.target.right),
                                         HandleUtility.GetHandleSize(maxY)/2);                 
       
                        Ellipse ellipse = new Ellipse(meo.target.position, meo.a, meo.b,
                                                      Color.blue);                     
                        //Эллипс
                //      Handles.color = Color.green;
                        Handles.DrawLine(meo.transform.position, meo.target.position);
                        ellipse.DrawEllipse();
                       
                        //Надпись около камеры
                        Vector3 targetDir =  meo.transform.position - meo.target.position;
                        float angle = Vector3.Angle(targetDir, meo.target.forward);
                        float distance = ellipse.calcDistance(angle);
                        Vector3 labPos = meo.transform.position;
                        Handles.Label(labPos, "Distance: "+distance+"\nAngle "+angle);
                       
                        //Кнопка установки камеры
                       
                        Rect pos = new Rect(Screen.width/2-75,0, 150,50);
                        Handles.BeginGUI();
                                GUILayout.BeginArea(pos);
                                        if(GUILayout.Button("Set camera position"))
                                                setCameraPosition(meo);
                                GUILayout.EndArea();
                        Handles.EndGUI();
                }
        }

        private void setCameraPosition(MouseEllipseOrbit meo){
                Transform camera = meo.transform;
                Transform target = meo.target;
               
                camera.LookAt(target);
                Ellipse ellipse = new Ellipse(meo.target.position,meo.a,meo.b);
                Vector3 targetDir =  meo.transform.position - meo.target.position;
                float angle = Vector3.Angle(targetDir,meo.target.forward);
                float distance = ellipse.calcDistance(angle);
                camera.localPosition = (camera.localRotation) * new Vector3(0, 0, -distance);  
        }
       
        class Ellipse {
                private Vector3 centr = Vector3.zero;
                private float a;
                private float b;
                private Color color;
               
                public Ellipse (Vector3 centr, float a, float b)
                {
                        this.centr = centr;
                        this.a = a;
                        this.b = b;
                }

               
                public Ellipse (Vector3 centr, float a, float b, Color color)
                {
                        this.centr = centr;
                        this.a = a;
                        this.b = b;
                        this.color = color;
                }
               
                public float calcDistance(float angle){
                        float numerator = Mathf.Pow(a,2) *  Mathf.Pow(b,2);
                        float denominator = Mathf.Pow(a,2)* Mathf.Pow(Mathf.Sin(angle*Mathf.Deg2Rad),2) +
                                Mathf.Pow(b,2)* Mathf.Pow(Mathf.Cos(angle*Mathf.Deg2Rad),2);
                        float distance = Mathf.Sqrt (numerator/denominator);
                        return distance;
                }
               
                Vector3 Evaluate(float t){
                        float y = Mathf.Sqrt( -Mathf.Pow(t,2)+Mathf.Pow(a,2))*b/a;
                        return (centr - new Vector3(y,0,t));
                }
               
                Vector3 MinusEvaluate(float t){
                        float y = -Mathf.Sqrt( -Mathf.Pow(t,2)+Mathf.Pow(a,2))*b/a;
                        return (centr - new Vector3(y,0,t));
                }
               
                public void DrawEllipse(){
                        Handles.color = color;
                        float delta = a/40;
                        for(int i = 0; i<80; i++){
                                float t = -a+i*delta;
                    float t1 = -a+(i+1)*delta;
                                Vector3 t1v = Evaluate(t1);
                                Handles.DrawLine(Evaluate(t), t1v);
                                Handles.DrawLine(MinusEvaluate(t), MinusEvaluate(t1));
                        }      
                        Handles.DrawLine(centr-new Vector3(0,0,-a),centr-new Vector3(0,0,a));
                        Handles.DrawLine(centr-new Vector3(-b,0,0),centr-new Vector3(b,0,0));
               
                }
        }
}
 


Синтаксис:
Используется csharp
using UnityEngine;
using UnityEditor;

public partial class MouseEllipseOrbitEditor : Editor {

        public override void OnInspectorGUI ()  {
                MouseEllipseOrbit meo = target as MouseEllipseOrbit;
                if(!meo)
                        return;
               
                EditorGUI.indentLevel  = 1;

                meo.target = EditorGUILayout.ObjectField("Target",meo.target, typeof(Transform), true) as Transform;
                meo.mouseButtonOrbit = (MOUSE_BUTTON)EditorGUILayout.EnumPopup("Orbit Button", meo.mouseButtonOrbit);
               
                panningMode(meo);
                ellipseAxis(meo);
                scrollSettings(meo);
                mouseAxisSettings(meo);
               
                if (GUILayout.Button("Set camera position")){
                        setCameraPosition(meo);                        
                }      
        }
       
        private bool showPadding = true;
        private void panningMode(MouseEllipseOrbit meo){
                meo.isPanning = EditorGUILayout.Toggle("Panning mode",meo.isPanning);
                EditorGUI.indentLevel++;       
                if(meo.isPanning){
                        showPadding = EditorGUILayout.Foldout(showPadding,"Panning");
                        if(showPadding){
                                EditorGUI.indentLevel++;
                                meo.mouseButtonPan = (MOUSE_BUTTON)EditorGUILayout.EnumPopup("Pan Button", meo.mouseButtonPan);
                                meo.panningSpeed = EditorGUILayout.FloatField("Pan Speed",meo.panningSpeed);
                                EditorGUI.indentLevel--;
                        }
                }
                EditorGUI.indentLevel--;
        }
       
        private bool showEllipseAxis = true;
        private void ellipseAxis(MouseEllipseOrbit meo){
                showEllipseAxis = EditorGUILayout.Foldout(showEllipseAxis,"Ellipse axis");
                EditorGUI.indentLevel++;
                if(showEllipseAxis){
                        EditorGUI.indentLevel++;
                        meo.a = EditorGUILayout.FloatField("A axis", meo.a);
                        meo.b = EditorGUILayout.FloatField("B axis", meo.b);
                        EditorGUI.indentLevel--;
                }      
                EditorGUI.indentLevel--;
        }
       
        private bool showMouseAxisSettings = true;
        private void mouseAxisSettings(MouseEllipseOrbit meo){
                showMouseAxisSettings = EditorGUILayout.Foldout(showMouseAxisSettings,"Mouse axis settings");
                EditorGUI.indentLevel++;
                if(showMouseAxisSettings){
                        EditorGUI.indentLevel++;
                        meo.xSpeed = EditorGUILayout.FloatField("X axis speed", meo.xSpeed);
                        meo.ySpeed = EditorGUILayout.FloatField("Y axis speed", meo.ySpeed);
                        meo.yMinLimit = EditorGUILayout.FloatField("Y min limit", meo.yMinLimit);
                        meo.yMaxLimit = EditorGUILayout.FloatField("Y max limit", meo.yMaxLimit);
                        EditorGUI.indentLevel--;
                }                      
                EditorGUI.indentLevel--;
        }
       
        private bool showScrollSettings = true;
        private void scrollSettings(MouseEllipseOrbit meo){
                meo.isScrolling = EditorGUILayout.Toggle("Scrolling mode",meo.isScrolling);
                EditorGUI.indentLevel++;
                if(meo.isScrolling){
                        showScrollSettings = EditorGUILayout.Foldout(showScrollSettings,"Mouse axis settings");
                        if(showScrollSettings){
                                EditorGUI.indentLevel++;
                                meo.scrollSpeed = EditorGUILayout.FloatField("Scroll speed", meo.scrollSpeed);
                                meo.scrollMinDistance = EditorGUILayout.FloatField("Scroll min distance", meo.scrollMinDistance);
                                meo.scrollMaxDistance = EditorGUILayout.FloatField("Scroll max distance", meo.scrollMaxDistance);
                                EditorGUI.indentLevel--;
                        }      
                }
                EditorGUI.indentLevel--;
        }
}
 


Пакет в приложении:) В пакете есть префаб с уже настроенной камерой и пример сцены
У вас нет доступа для просмотра вложений в этом сообщении.
Последний раз редактировалось nazgul30 05 апр 2012, 03:37, всего редактировалось 1 раз.
nazgul30
UNIт
 
Сообщения: 76
Зарегистрирован: 08 сен 2010, 18:10

Re: Полезный скрипт для камеры.

Сообщение DanielDem 14 мар 2012, 17:27

Спасибо большое, отличная работа!
Да прибудет с Вами сила...
Аватара пользователя
DanielDem
UNITрон
 
Сообщения: 174
Зарегистрирован: 07 янв 2010, 13:27
Откуда: Россия
  • ICQ

Re: Полезный скрипт для камеры.

Сообщение nazarsokol 19 сен 2013, 14:31

спасибо
nazarsokol
UNец
 
Сообщения: 1
Зарегистрирован: 19 сен 2013, 14:29

Re: Полезный скрипт для камеры.

Сообщение ktoizhan 17 мар 2016, 19:05

Красава! Супер! :-bd . Огромное спасибо!
ktoizhan
UNец
 
Сообщения: 1
Зарегистрирован: 17 мар 2016, 18:31


Вернуться в Компоненты (Копилка)

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4