Вписывание объекта в камеру

Программирование на Юнити.

Вписывание объекта в камеру

Сообщение maksimov 10 авг 2017, 13:34

Есть некое квадратное поле, и камера, которая всегда смотрит в его середину.
При этом, камера может менять свою высоту над полем (сохраняя при этом угол наклона), или менять свой угол наклона (меняя при этом, соответственно, высоту).


Максимально допустимая высота должна быть всегда такая, при которой поле полностью заполняет весь экран.

Как, зная разрешение экрана и угол наклона камеры, вычислить максимально допустимую высоту?

Превышена максимально допустимая высота камеры, для данного угла наклона и разрешения.
Изображение
Камера находится на максимально допустимой высоте, для данного угла наклона и разрешения.
Изображение


* * *
Что-то, не получается решить данную задачку. =(
Единственный вариант, который пока пришёл в голову: бить лучами в верхние правый и левый углы, и если там пусто - уменьшать чуть-чуть высоту, пока там не появится поле.
Но это конечно бред. Нужно какое-то математическое решение... =(
Красота — не прихоть полубога, а хищный глазомер простого столяра.
Аватара пользователя
maksimov
UNITрон
 
Сообщения: 154
Зарегистрирован: 19 фев 2013, 11:48
  • Сайт

Re: Вписывание объекта в камеру

Сообщение Bill Gates 14 авг 2017, 10:37

Можно проецировать точки из углов прямоугольника в screen space и проверять находятся ли они вне или внутри экрана.
Bill Gates
UNIт
 
Сообщения: 127
Зарегистрирован: 16 июл 2015, 11:27

Re: Вписывание объекта в камеру

Сообщение snezhok_13 14 авг 2017, 11:53

Bill Gates писал(а):Можно проецировать точки из углов прямоугольника в screen space и проверять находятся ли они вне или внутри экрана.

А если нормализованные координаты получить, то легко получить отношение на которое нужно маштабировать) всмысле пределы.
Разработка игр, немножко игровая журналистика, сейчас делаем Календарь: даты выхода игр
Аватара пользователя
snezhok_13
UNIверсал
 
Сообщения: 450
Зарегистрирован: 09 сен 2013, 11:12
Skype: s.coremission
  • Сайт

Re: Вписывание объекта в камеру

Сообщение maksimov 16 авг 2017, 13:39

Bill Gates писал(а):Можно проецировать точки из углов прямоугольника в screen space и проверять находятся ли они вне или внутри экрана.


Можно. Самоочевидно, что можно. Я об этом даже написал в изначальном посте.
Красота — не прихоть полубога, а хищный глазомер простого столяра.
Аватара пользователя
maksimov
UNITрон
 
Сообщения: 154
Зарегистрирован: 19 фев 2013, 11:48
  • Сайт

Re: Вписывание объекта в камеру

Сообщение maksimov 06 фев 2018, 10:41

snezhok_13 писал(а):А если нормализованные координаты получить, то легко получить отношение на которое нужно маштабировать) всмысле пределы.

А можно пожалуйста по подробнее?
Красота — не прихоть полубога, а хищный глазомер простого столяра.
Аватара пользователя
maksimov
UNITрон
 
Сообщения: 154
Зарегистрирован: 19 фев 2013, 11:48
  • Сайт

Re: Вписывание объекта в камеру

Сообщение Leonin 10 фев 2018, 16:12

Я бы использовал Camera.WorldToScreenPoint, чтобы определять, что углы в пределах экрана. Похоже на задачу, которая возникает, чтобы камера не забегала за пределы карты в играх жанра стратегия.
Аватара пользователя
Leonin
UNец
 
Сообщения: 44
Зарегистрирован: 12 янв 2018, 16:59

Re: Вписывание объекта в камеру

Сообщение maksimov 03 окт 2018, 11:18

Leonin писал(а):Похоже на задачу, которая возникает, чтобы камера не забегала за пределы карты в играх жанра стратегия.

Если только визуально. =)
По "логике", тут всё совсем по другому.

Leonin писал(а):Я бы использовал Camera.WorldToScreenPoint, чтобы определять, что углы в пределах экрана.

=)

В начальном посте сразу написал: "да, можно сделать "фигово", через камеру. но хочется сделать "хорошо" - через математику".

В результате, уже второй человек пишет: "это можно сделать через камеру!" )))


Вот, кстати, реализация через камеру (я её сделал собственно сразу же, в первые же 10 минут, как возникла задача):
Синтаксис:
Используется csharp
private void Start()
        {
            Transform prevTarget = target;
            target = GameObject.Find("Quad").transform;
           
            for (int s = minSlope; s <= maxSlope * 10; s += 1)
            {
                maxDistance[s] = 14;

                bool done = false;
                while (!done)
                {
                    SetPosition(maxDistance[s], s);

                    RaycastHit hit;
                    Ray ray1 = Camera.main.ScreenPointToRay(new Vector3(0, Screen.height, 0));
                    Ray ray2 = Camera.main.ScreenPointToRay(new Vector3(Screen.width, Screen.height, 0));

                    if (!Physics.Raycast(ray1, out hit) || !Physics.Raycast(ray2, out hit))
                    {
                        maxDistance[s] -= 0.05f;
                    }
                    else
                    {
                        done = true;
                    }
                }
            }

            target = prevTarget;
            distance = Mathf.Min(distance, maxDistance[slope]);
        }

        private void Update()
        {
            if (Input.GetKey(KeyCode.LeftShift))
            {
                if (Input.GetAxis("Mouse ScrollWheel") > 0)
                {
                    slope = Mathf.Min(slope + 1, maxSlope);
                    distance = Mathf.Min(distance + 1.0f, maxDistance[slope]);
                }
                else if (Input.GetAxis("Mouse ScrollWheel") < 0)
                {
                    slope = Mathf.Max(slope - 1, minSlope);
                    distance = Mathf.Min(distance + 1.0f, maxDistance[slope]);
                }
            }
            else
            {
                if (Input.GetAxis("Mouse ScrollWheel") < 0)
                {
                    distance = Mathf.Min(distance + 1.0f, maxDistance[slope]);
                }
                if (Input.GetAxis("Mouse ScrollWheel") > 0)
                {
                    distance = Mathf.Max(distance - 1.0f, minDistance);
                }
            }
        }


        // Update is called once per frame
        private void LateUpdate()
        {
            SetPosition(distance, slope);
        }

        private void SetPosition(float d, int s)
        {
            var height = target.position.y + d * (s/10.0f);
           
            transform.position = target.position;
            transform.position -= Quaternion.Euler(0, 90, 0) * Vector3.forward * d;
            transform.position = new Vector3(transform.position.x, height, transform.position.z);

            // Always look at the target
            transform.LookAt(target);
        }
 


Работает... Но согласитесь, "это же какой-то... позоррр..." =(
Красота — не прихоть полубога, а хищный глазомер простого столяра.
Аватара пользователя
maksimov
UNITрон
 
Сообщения: 154
Зарегистрирован: 19 фев 2013, 11:48
  • Сайт

Re: Вписывание объекта в камеру

Сообщение IDoNotExist 03 окт 2018, 12:44

1) Получаешь баунд своего поля в мировых координатах;
2) Получаешь с этого баунда 8 угловых точек (если плоский то можно 4, не суть);
3) Переводишь эти точки в локальные координаты трансформа камеры;
4) Находишь минимальные/максимальные значения по x,y координатам (локальным естественно);
5) Дальше простая теорема пифагора, тебе нужно найти неизвестный катет (расстояние до камеры), тебе известен другой катет (см. 4 пункт) и противолежащий угол (FOV камеры).
Аватара пользователя
IDoNotExist
Адепт
 
Сообщения: 1432
Зарегистрирован: 23 мар 2011, 09:18
Skype: iamnoexist

Re: Вписывание объекта в камеру

Сообщение maksimov 03 окт 2018, 13:56

IDoNotExist писал(а):1) Получаешь баунд своего поля в мировых координатах;

Зачем?
Поле у меня квадратное, фиксированного размера. Я координаты его углов знаю априори.

IDoNotExist писал(а):4) Находишь минимальные/максимальные значения по x,y координатам (локальным естественно);
5) Дальше простая теорема пифагора, тебе нужно найти неизвестный катет (расстояние до камеры), тебе известен другой катет (см. 4 пункт) и противолежащий угол (FOV камеры).

Вот это - поясните пожалуйста.
Красота — не прихоть полубога, а хищный глазомер простого столяра.
Аватара пользователя
maksimov
UNITрон
 
Сообщения: 154
Зарегистрирован: 19 фев 2013, 11:48
  • Сайт

Re: Вписывание объекта в камеру

Сообщение IDoNotExist 03 окт 2018, 14:43

maksimov писал(а):Зачем?
Поле у меня квадратное, фиксированного размера. Я координаты его углов знаю априори.

Хоспаде, ну так переходи к пункту 3.

maksimov писал(а):Вот это - поясните пожалуйста.


Думаю сможешь адаптировать под себя? Если баунд не нужен, тогда вместо BoundsCorners() передавай координаты своих углов, а так же центр своего поля.
Синтаксис:
Используется csharp
        /// <summary>
        /// Подстраивает камеру так, чтобы в неё попал весь гейм объект
        /// </summary>
        public static void LookAtGameObject(this Camera cam)
        {
                Transform trs = cam.transform;

                Bounds worldBounds = cam.gameObject.GetBounds();

                Matrix4x4 tfmMat = Matrix4x4.TRS(worldBounds.center, trs.rotation, Vector3.one);
                Matrix4x4 tfmMatInv = tfmMat.inverse;

                //точки баунда переводим в будущие локальные координаты камеры, чтобы посчитать нужный размер
                Vector3[] localPnts = worldBounds.BoundsCorners().Select((p) => tfmMatInv.MultiplyPoint3x4(p)).ToArray();

                float maxH = Math.Abs(localPnts.Max((p) => p.y));
                float maxW = Math.Abs(localPnts.Max((p) => p.x));

                float fowTan = Mathf.Tan(cam.fieldOfView * 0.5f * Mathf.Deg2Rad);
                float fowWidthTan = Mathf.Tan(cam.GetHorizontalFOV() * 0.5f * Mathf.Deg2Rad);

                float wDist = maxW / fowWidthTan;
                float hDist = maxH / fowTan;

                float distance = Math.Max(wDist, hDist);

                trs.position = worldBounds.center - trs.forward * distance;
        }

        /// <summary>
        /// Отдаёт горизонтальный FOV для камеры в зависимости от aspect
        /// </summary>
        public static float GetHorizontalFOV(this Camera cam)
        {
                float vFOVInRads = cam.fieldOfView * Mathf.Deg2Rad;
                float hFOVInRads = 2f * Mathf.Atan(Mathf.Tan(vFOVInRads * 0.5f) * cam.aspect);
                return hFOVInRads * Mathf.Rad2Deg;
        }
 
Аватара пользователя
IDoNotExist
Адепт
 
Сообщения: 1432
Зарегистрирован: 23 мар 2011, 09:18
Skype: iamnoexist

Re: Вписывание объекта в камеру

Сообщение maksimov 05 окт 2018, 11:04

IDoNotExist писал(а):Думаю сможешь адаптировать под себя?

Не смогу. =)
Тут решается вообще другая задача, совершенно обратная той, которая у меня. Тут "камеру подстраивают так, чтобы в неё попал весь гейм объект". А мне нужно "камеру подстроить так, что бы она вся попала в гейм объект." )))

Ещё раз:
Есть поле. Квадратное, фиксированного размера. Камера всегда смотрит в его середину (transform.LookAt(target);).
При этом, камера может:
а. приближаться/отдаляться к/от середине поля (угол её наклона при этом есно сохраняется. изменяются лишь её координаты по Y и Z)
б. изменять свой угол наклона по отношению к полю (при этом, кроме угла наклона камеры, меняются соответственно и её координаты по Y (так как она по прежнему должна смотреть в центр поля)).

Так вот... задача - найти максимально допустимую высоту камеры (координату по Y), при которой для данного угла наклона и разрешения экрана, поле заполняет весь экран.

=(
Красота — не прихоть полубога, а хищный глазомер простого столяра.
Аватара пользователя
maksimov
UNITрон
 
Сообщения: 154
Зарегистрирован: 19 фев 2013, 11:48
  • Сайт

Re: Вписывание объекта в камеру

Сообщение IDoNotExist 05 окт 2018, 11:30

maksimov писал(а):Тут решается вообще другая задача, совершенно обратная той, которая у меня. Тут "камеру подстраивают так, чтобы в неё попал весь гейм объект". А мне нужно "камеру подстроить так, что бы она вся попала в гейм объект." )))

Ну лол же, эта задача решается по аналогичному алгоритму, всё что тебе надо сделать, это поставить условие перед назначением позиции в основном методе, т.е.
Синтаксис:
Используется csharp
if(Vector3.Distance(trs.position, worldBounds.center) > distance)
    trs.position = worldBounds.center - trs.forward * distance;
 

distance если тебе угодно, это и будет твоя искомая макс. высота по Y, хотя по моему это определение в корне не верно, ибо тебе нужна макс. дистанция от центра объекта до позиции камеры, а это уже не только Y, но тебе виднее.
Аватара пользователя
IDoNotExist
Адепт
 
Сообщения: 1432
Зарегистрирован: 23 мар 2011, 09:18
Skype: iamnoexist


Вернуться в Скрипты

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

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