Скрипт взгляда

Форум для всего, что связано с ИИ.

Скрипт взгляда

Сообщение Vect0r 27 сен 2010, 23:01

Всем привет.
Недавно начал изучать Unity [unity 3D] , поэтому вопрос, возможно ламерский.
Подскажите, пожалуйста, можно ли стандартными средствами реализовать взгляд ИИ подобный тому, что был в Commandos:
Изображение
То есть ИИ отслеживает попадание объектов в равнобедренный треугольник (или лучше даже сектор круга).

Курил FPS tutorial, но, там, как я понял, просто отслеживается луч от ИИ до игрока.
Видел тему "проверка на попадание точки в треугольник", но там не учитывается возможность скрываться за препятствиями

Пока что в голове зреет такое решение:
- с помощью CheckSphere и OverlapSphere отслеживать появление игрока в аггро-радиусе ИИ;
- просчитать угол между текущим направлением ИИ и направлением на игрока. Если угол больше определённого значения, то не реагировать на игрока.

Но мне кажется, это несколько криво и наверно есть какой-то прямой способ. Буду очень признателен, если подскажете.
Заранее, спасибо

P.S.: Попутно вопрос, как можно реализовать именно визуальное представление этой области взгляда? Это мне так, просто проверить правильность работы скрипта. ^_^
Когда-нибудь я таки сделаю игру [unity 3D]
Аватара пользователя
Vect0r
UNец
 
Сообщения: 7
Зарегистрирован: 27 сен 2010, 15:14
Откуда: PTZ
  • Сайт
  • ICQ

Re: Скрипт взгляда

Сообщение Paul Siberdt 27 сен 2010, 23:08

Про сферу и проверку углов - решение верное.
А чтобы рисовать сектор на экране, отсекая препятствия, придется сколько-то раз протрассировать лучик длинною в ту сферу и по результатам строить геометрию.
Можно еще создать карту проходимости, написать шейдер смешивания карты проходимости с маской сектора видимости и рисовать все в этом шейдере... но это уже изыски какие-то :)

Если не планируется визуализировать зрение пчелиного роя, вполне можно по сотне раз за кадр протрейсить из глаз пары персонажей.
Аватара пользователя
Paul Siberdt
Адепт
 
Сообщения: 5317
Зарегистрирован: 20 июн 2009, 21:24
Откуда: Moscow, Russia
Skype: siberdt
  • Сайт

Re: Скрипт взгляда

Сообщение Neodrop 28 сен 2010, 00:11

http://www.unity3d.ru/ANTARES/OnlineDem ... Range.html

viewtopic.php?f=12&t=1162&st=0&sk=t&sd=a&start=135#p18049

Определение зоны видимости идёт по вот таким зонам (картинок нет под рукой, дам ссылки)
http://forum.unity3d.com/attachment.php ... 1285573920
http://forum.unity3d.com/attachment.php ... 1285573920
Добавить neodrop в Skype
Изображение
"Спасибо!" нашему порталу, вы сможете сказать ЗДЕСЬ.
Если проблема не решается честно, нужно её обмануть! || Per stupiditas at Astra!
Страх порождает слабость. Бесстрашных поражают пули.
Протратившись на блядях байтах, на битах не экономят.
Аватара пользователя
Neodrop
Админ
 
Сообщения: 8480
Зарегистрирован: 08 окт 2008, 15:42
Откуда: Питер
Skype: neodrop
  • Сайт

Re: Скрипт взгляда

Сообщение Zaicheg 28 сен 2010, 08:52

Можно и без углов, просто сделать меш, соответствующий зоне, на него меш-коллайдер-триггер и проверять вхождения в триггер. Но это уже не универсально будет.
Дьяченко Роман
e-mail: _zaicheg.reg@gmail.com
skype: zaicheg12
vkontakte: _vk.com/zaichegq
Работа: _wie3.com _www.sanviz.com
Аватара пользователя
Zaicheg
Адепт
 
Сообщения: 3024
Зарегистрирован: 19 июн 2009, 15:12
Откуда: Череповец

Re: Скрипт взгляда

Сообщение Vect0r 28 сен 2010, 09:31

Paul Siberdt, спасибо. Думаю, такие изыски с отображением мне особо без надобности, это уж так, факультативно=). В случае крайней нужды для отображения попробую копать Projector из урока 3D Platform Tutorial.

Neodrop, вот это наверно именно то, что нужно. Единственное только, не нашёл в русском мануале на SourceForge описание работы "AI Range Zones". Можно мне отдельную кнопочку "loshara" на текст с описанием? :ympray:

Zaicheg, об этом тоже думал, но тут опять же придётся тратить время на просчёт препятствий или вроде того.
Когда-нибудь я таки сделаю игру [unity 3D]
Аватара пользователя
Vect0r
UNец
 
Сообщения: 7
Зарегистрирован: 27 сен 2010, 15:14
Откуда: PTZ
  • Сайт
  • ICQ

Re: Скрипт взгляда

Сообщение Zaicheg 28 сен 2010, 09:35

Vect0r писал(а):Zaicheg, об этом тоже думал, но тут опять же придётся тратить время на просчёт препятствий или вроде того.

"A trigger doesn't collide with rigid bodies."
Дьяченко Роман
e-mail: _zaicheg.reg@gmail.com
skype: zaicheg12
vkontakte: _vk.com/zaichegq
Работа: _wie3.com _www.sanviz.com
Аватара пользователя
Zaicheg
Адепт
 
Сообщения: 3024
Зарегистрирован: 19 июн 2009, 15:12
Откуда: Череповец

Re: Скрипт взгляда

Сообщение Vect0r 28 сен 2010, 10:43

Ну, я про триггер понимаю тему. Просто тут возникает вот какая фича. Если человек стоит за стеной, как в приложенном файлике, то ии его "увидит", потому что меш его коснётся.

Хотя, пока рисовал картинку подумал, что можно было бы при срабатывании пытаться кинуть луч до игрока .Linecast, и если тот дойдёт, то только тогда включать "алярм, руссиш партизанен" и всё такое =).. Тогда вариант, конечно. Причём мешу можно было б задать прозрачность 0.4 для проверочки, и вообще красота была бы. Но, конечно, придётся тогда делать кучу мешей под разную площадь обзора. Поэтому наверно AI Range Zones будет лучше. Так что жду (popcorn)
У вас нет доступа для просмотра вложений в этом сообщении.
Когда-нибудь я таки сделаю игру [unity 3D]
Аватара пользователя
Vect0r
UNец
 
Сообщения: 7
Зарегистрирован: 27 сен 2010, 15:14
Откуда: PTZ
  • Сайт
  • ICQ

Re: Скрипт взгляда

Сообщение Vect0r 28 сен 2010, 15:08

Покурил YouTube, нашёл решение похожей задачи. Если кому интересно будет, можете посмотреть Только здесь решается надо ли наносить повреждения, но в принципе, адаптировать несложно, а решение двумя строчками получается.
Наверно буду пользовать этот способ, ибо уж очень просто всё делается.
Когда-нибудь я таки сделаю игру [unity 3D]
Аватара пользователя
Vect0r
UNец
 
Сообщения: 7
Зарегистрирован: 27 сен 2010, 15:14
Откуда: PTZ
  • Сайт
  • ICQ

Re: Скрипт взгляда

Сообщение Neodrop 28 сен 2010, 16:06

Neodrop, вот это наверно именно то, что нужно. Единственное только, не нашёл в русском мануале на SourceForge описание работы "AI Range Zones". Можно мне отдельную кнопочку "loshara" на текст с описанием? :ympray:


Качаем тут :
Добавить neodrop в Skype
Изображение
"Спасибо!" нашему порталу, вы сможете сказать ЗДЕСЬ.
Если проблема не решается честно, нужно её обмануть! || Per stupiditas at Astra!
Страх порождает слабость. Бесстрашных поражают пули.
Протратившись на блядях байтах, на битах не экономят.
Аватара пользователя
Neodrop
Админ
 
Сообщения: 8480
Зарегистрирован: 08 окт 2008, 15:42
Откуда: Питер
Skype: neodrop
  • Сайт

Re: Скрипт взгляда

Сообщение Akai 28 сен 2010, 18:37

Подскажите, пожалуйста, можно ли стандартными средствами реализовать взгляд ИИ подобный тому, что был в Commandos:

А что значит стандартными?

Алгоритм определения попадания игрока в поле зрения кого-либо следующий:
1. Построить для объекта (NPC, видеокамера и т.п.) так называемый viewing frustum, то есть ограничивающий объём, в который попадает всё, что объект потенциально видит.
2. Протестить view frustum с бибоксом управляемого персонажа (бибокс лучше брать не выровненный по осям — так будет точнее).
3. Если пересечений объёмов нет, то объект игрока не видит. Если же пересечения есть, то это значит, что игрок потенциально видим и необходимо сделать дополнительные проверки (они нужны для того, чтобы определить, нет ли между игроком и объектом других объектов, которые заслоняют игрока).
4. Протестить рейкастом вершины бибокса игрока. Если хотя бы одна из них будет принадлежать коллайдеру игрока, значит объект его видит. Можно включать тревогу, стрелять, звать на помощь и т.д.

Это дело можно и нужно слегка оптимизировать. Например, считать view frustum на старте уровня для каждого объекта, обладающего глазами и способного заметить игрока, а потом апдейтить его только при движениях объектов, а не пересчитывать с нуля каждый раз. Проецировать frustum не в бесконечность, а на определённую величину (у очкарика она будет меньше, у снайпера больше), то есть оптимизировать дальность плоскости отсечения. Для проверок рейкастом можно проверять не все вершины бибокса, а вырождать бибокс игрока в прямоугольник и проверять только его четыре точки.

А меш для отображения поля зрения проще всего строить в рантайме, так как все данные на руках (view frustum ведь всё равно придётся считать).

В принципе, здесь ничего сложного нет. Покурить можно инфу по классу GeometryUtility, по структуре Bounds (правда, и там и там используются выровненные по осям бибоксы, я бы пользовал не выровненные), ну и про рейкаст.

Если что-то не ясно, нужны какие-то пояснения, то я готов ещё больше нагнать туману... в смысле добавить подробностей.
Akai
UNец
 
Сообщения: 29
Зарегистрирован: 11 сен 2010, 08:26
Откуда: Вельск

Re: Скрипт взгляда

Сообщение Akai 03 окт 2010, 16:55

Если человек стоит за стеной, как в приложенном файлике, то ии его "увидит", потому что меш его коснётся.

Поэтому наверно AI Range Zones будет лучше.


AI Range Zones тоже этим болеют. Вот только что скачал антаресовские демки и посмотрел. Поставил перед персонажем ящики, а он меня всё равно видит. Тут одно из двух: либо у него рентгеновское зрение, либо AI Range Zones для такого рода проверок не подходят.

Мой вариант определённо лучше. Я его реализовал в коде. Всё проверено, всё работает. Получился практически полноценный модуль, реализующий зрение для объектов, управляющихся искусственным интеллектом (селекция производится по тэгам, но это легко можно изменить, например, на имена объектов).

Ничего сложного, тем более, что почти весь инструментарий уже готов. Нужно только разработать класс для фрустума и написать функцию проверки видимости объектов.

Класс для фрустума может выглядеть вот так например:

Код: Выделить всё
паблик класс Фрустум
{
    // Вершины фрустума
    паблик Вектор3[] вершины;
    // Текстурные координаты для меша
    паблик Вектор2[] ув;
    // Грани меша фрустума в виде индексов вершин
    паблик инт[] грани;
    // Плоскости, ограничивающие объём фрустума
    паблик Плейн[] плоскости;

    // Функция для расчёта фрустума
    паблик войд апдейт(Трансформ трансформ, флоат фов, флоат аспект, флоат ближнийЗ, флоат дальнийЗ);
    // Тест положения точки относительно фрустума
    паблик инт тестПоинт(Вектор3 п)
    // Тест положения бокса относительно фрустума
    паблик инт тестБаундс(Баундс б, аут инт[] в)
}


Самый минимум, ничего лишнего.
Akai
UNец
 
Сообщения: 29
Зарегистрирован: 11 сен 2010, 08:26
Откуда: Вельск

Re: Скрипт взгляда

Сообщение Akai 03 окт 2010, 16:56

При расчёте фрустума сразу же пересчитываются не только восемь угловых точек, но и ограничивающие плоскости. Точки — это очевидно — нужны для построения меша фрустума. Текстурные координаты фиксированные, как и массив граней (формируется из индексов точек) — в процессе работы они не изменяются (грани — всегда, а вот текстурные координаты никто не мешает анимировать, это легко сделать). Классы точки (Vector3, Vector2) и плоскости (Plane) уже готовы, писать ничего не нужно (юнититим уже всё сделала). Эти классы содержат весь необходимый функционал. Класса же для фрустума в Юнити нет. Есть класс камеры. По большому счёту, можно использовать его, но, на мой взгляд, это очень неудобно: в нём слишком много лишнего, да и заточен он всё-таки под другое.

Расчёт фрустума тривиален и может выполняться несколькими различными способами.

Есть относительно простой через матрицы. Делается это так: рассчитываются матрица вида (нужны положение наблюдателя и направление координатных осей) и матрица проекций (нужны Z-координаты плоскостей отсечения — ближней и дальней, угол поля зрения и отношение ширины вьюпорта к его высоте). Расчёт не сложен. Далее матрица проекций умножается на матрицу вида (именно в таком порядке) и получается матрица отсечения, из которой уже можно получить формирующие фрустум плоскости в виде нормали и расстояния до начала координат (как известно, плоскость можно задать несколькими способами — это один из). Плоскости необходимо нормализовать (а вот этого Юнити, к сожалению, не умеет, нужно писать собственную функцию). Чтобы затем построить меш фрустума, необходимо произвести дополнительные расчёты (определить точки пересечения плоскостей).

Я сначала пошёл этим путём, но по каким-то причинам (их я так и не определил точно), он у меня не заработал. Следует однако высказать кое-какие соображения (даже подозрения — вдруг кому-то пригодится). Дело в том, что есть определённые нюансы при расчёте как матриц, так и плоскостей для DirectX и OpenGL. Эти API используют по-разному ориентированные системы координат (DirectX — левостороннюю, OpenGL — правостороннюю). Не имея возможности определить, с какой графической подсистемой работает Юнити, невозможно корректно рассчитать матрицы и плоскости фрустума.

После ряда неудачных экспериментов я решил считать фрустум по-другому. Можно обойтись и без матриц, имея те же самые данные, но воспользоваться векторной, а не линейной алгеброй. В этом способе сначала рассчитываются угловые точки фрустума, а затем, если необходимо, формируются плоскости. С этим всё получилось, практически сразу заработало. Оценить способы по затратам производительности, к сожалению, возможности не было (профайлер, кажется, в про-версии только, да? У меня этот пункт меню недоступен).

Я всё время говорю о плоскостях, но должно быть, не всем ясно, для чего они нам. Точки-то понятно — без них меш не сделать. А зачем плоскости? А вот зачем: они позволяют очень быстро произвести отбраковку точек (определить взаимное положение). Вот, например, как будет выглядеть функция определения положения точки относительно фрустума:

Код: Выделить всё
    паблик инт тестПоинт(Вектор3 п)
    {
        флоат расстояние;

        цикл для и от 0 до 6
        {
            расстояние = плейн[и].получитьРасстояниеДоТочки(п);

            если расстояние > 0
            {
                вернуть результат «снаружи»;
            }
            иначе
            {
                если расстояние = 0
                {
                    вернуть результат «на плоскости»;
                }
            }
        }
        вернуть результат «внутри»;
    }


Также несложно рассчитывается положение, например, сферы относительно фрустума (по центру и радиусу) или бибокса (по четырём или восьми точкам). Я при расчёте бибокса для дополнительных расчётов ещё сохраняю информацию о том, какие именно точки лежат внутри или снаружи.
Последний раз редактировалось Akai 03 окт 2010, 17:01, всего редактировалось 1 раз.
Akai
UNец
 
Сообщения: 29
Зарегистрирован: 11 сен 2010, 08:26
Откуда: Вельск

Re: Скрипт взгляда

Сообщение Akai 03 окт 2010, 16:57

После того, как разработан класс фрустума, необходимо написать класс, который будет инициализировать фрустум и анализировать информацию, предоставляемую им. Этот класс обязательно должен иметь информацию о: плоскостях отсечения, FOV и отношении сторон вьюпорта (aspect ratio) — без этого невозможно рассчитать фрустум.

Инициализация фрустума сведётся к расчёту его точек и плоскостей, а также к созданию меша (если он требуется для визуализации, конечно, понятно, что это нужно далеко не всегда). Создание меша в Юнити в рантайме тривиально. Код будет выглядеть следующим образом:

Код: Выделить всё
    void Start()
    {
        // Расчёт фрустума, для него необходимо: координаты положения наблюдателя — объекта,
        // FOV, aspect и Z-координаты плоскостей отсечения
        frustum.update(thisGameObject.transform, fieldOfView, aspectRatio, nearClipping, farClipping);
        // Создаём меш
        frustumMesh = new Mesh();
        // Заполняем меш данными вершин, граней и текстурных координат
        frustumMesh.vertices = frustum.vertices;
        frustumMesh.triangles = frustum.triangles;
        frustumMesh.uv = frustum.uv;
        // Пересчитываем нормали (чтобы меш корректно освещался)
        frustumMesh.RecalculateNormals();
        // Создаём игровой объект
        GameObject frustumObject = new GameObject();
        // Задаём узнаваемое имя (необязательное действие)
        frustumObject.name = "Frustum of " + thisGameObject.name;

        // А вот этого ни в коем случае не делаем!
        // Нельзя привязывать меш фрустума к родителю, потому что в этом случае
        // он будет наследовать его трансформации, и перестанет корректно отображаться.
        // Вернее так: меш фрустума перестанет адекватно отражать в пространстве положение
        // рассчитанного фрустума (дело в том, что тот сразу считается в мировых координатах)
        // Если хочется встраивать объект фрустума в иерархию сцены, то придётся делать поправку:
        // вручную переводить координаты вершин в локальное пространство и обратно
        //frustumObject.transform.parent = thisGameObject.transform;

        // Создаём меш-филтер для доступа к данным меша
        MeshFilter frustumMeshFilter = frustumObject.AddComponent("MeshFilter") as MeshFilter;
        // Связываем меш с ним
        frustumMeshFilter.mesh = frustumMesh;
        // Создаём меш-рендерер для отрисовки меша
        MeshRenderer frustumRenderer = frustumObject.AddComponent("MeshRenderer") as MeshRenderer;
        // Устанавливаем материал (шаг необязательный, но созданный без материала меш будет выглядеть непрезентабельно)
        frustumRenderer.material = frustumMaterial;
    }


Далее каждый кадр придётся пересчитывать вершины фрустума, заново заполнять массив вершин меша фрустума и пересчитывать нормали.

Для определения видимости какого-нибудь объекта (пусть это будет игрок), необходимо проделать ряд тестов. Прежде всего, получить положение игрока и его ограничивающий объём (бибокс) и протестировать на попадание во фрустум. Все необходимые функции содержатся в классе фрустума. Результатом будет являться не только общий ответ, находится ли бибокс во фрустуме, но и ответы для всех его точек. После этого останется только проверить те точки, которые находятся внутри фрустума (какая никакая, а оптимизация). Однако для корректного определения этого недостаточно. Может возникнуть ситуация, когда между игроком и объектом находятся другие объекты, которые заслоняют игрока (стена, ящик, автомобиль и т.п.). В этом случае достаточно лайнкаста из точек бибокса игрока в точку, где расположен объект, для которого производятся расчёты (обратный способ — от объекта к игроку — может тоже сработает, но, надо заметить, что у меня такая проверка не работала). После лайнкаста достаточно всего лишь проверить коллайдер, который вернёт функция.

Как видите, несложно. И всё прекрасно работает.
Akai
UNец
 
Сообщения: 29
Зарегистрирован: 11 сен 2010, 08:26
Откуда: Вельск

Re: Скрипт взгляда

Сообщение Akai 03 окт 2010, 17:06

Ах да, чуть не забыл. Есть один случай, когда моя проверка работать не будет. В какой ситуации это произойдёт, предоставляю догадываться самостоятельно. В принципе, в большинстве случаев ею можно и пренебречь.
Akai
UNец
 
Сообщения: 29
Зарегистрирован: 11 сен 2010, 08:26
Откуда: Вельск


Вернуться в Искуственный Интеллект

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

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