Unity3D симулятор “Smart snake with stereo vision”

Автор: | 11.02.2019

Статья на стадии разработки !!!

Постановка задачи
Движение змейки к цели по прямой
Вид с камер на голове змейки
Вид с камер на глазах змейки
Изображения (RawImage) с камер

Обработка изображений
Обход преград

Полезные ссылки

Постановка задачи

В статье Игра “Snake” на Unity3D было рассмотрено, как создать игру «Змейка».

Змейка двигается вперед и меняет направление движения под управлением клавиш влево/вправо. Задача игрока — обойти препятствия и направить змейку к яблоку.

Ниже исследуется возможность создания на основе этой игры симулятора интеллекта змейки со стереозрением. В чем конкретно заключается задача? При запуске приложения змейка самостоятельно (без управления игроком) двигается к яблоку в обход всех преград.

Для реализации задачи необходимо:

  1. Направить змейку к цели — по прямой.
  2. Установить  камеры в глазах змейки.
  3. Обработать изображения от камер.
  4. Менять траекторию движения для обхода преград.

В 3-х статьях Виртуальный квадрокоптер на Unity + OpenCV рассмотрена задача управления квадракоптером на основе изображений от 2-х установленных на нем видеокамер.  Используем результаты этой работы для реализации нашей задачи.

Движение змейки к цели по прямой

За движение змейки отвечает скрипт Player, который прикреплен к голове (Head). Объявляем в  скрипте открытую переменную  target.  В функции Update() вызываем метод  transform.LookAt(target):

...
public class Player : MonoBehaviour
{

public Transform target;
...
 public void Update()
 {
...
 transform.LookAt(target);
 _controller.Move(transform.forward * speed * Time.deltaTime /* * vertical*/);
}
...

В Unity инициализируем  переменную target объектом Food (перетаскиваем объект из окна Hierarchy к параметру Target в окне Inspector).

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

При этом управление змейки клавишами влево/вправо будет заблокировано. После столкновения с препятствием (кубиком) движение заканчивается (Game Over!). Наша задача — научить змейку самостоятельно обходить препятствия.

 Вид с камер на голове змейки

В игровом приложении  «Змейка» установлена только одна камера. Она установлена таким образом, чтобы   просматривать по возможности все поле и нацелена на голову змейки. Последнее прописано в скрипте LookAt, который прикреплен к камере.

Теперь прикрепим камеру к голове и направим, куда смотрит голова (на объект Food). Для этого прежде всего модифицируем скрипт LookAt. Здесь определяем положение камеры (position и rotation) в  переменной from.

using UnityEngine;
public class LookAt : MonoBehaviour
{
// положение камеры
 public Transform from;
 // цель, на которую смотрит камера
 public Transform target;
 public void Update()
 {
 transform.position = from.position;
 transform.rotation = from.rotation;
 if (target != null)
 {
 // Смотрим всегда на цель
 transform.LookAt(target);
 }
 }
}

Значение переменной from инициализируем в Unity редакторе головой змейки. Для этого из окна Hierarchy перетаскиваем голову змейки (Head) в окно Inspector к параметру From. Также изменим  значение переменной target — перетаскиваем объект Food к параметру Target.

Запускаем приложение (Play), получаем вот такой результат. Змейка перемещается в направлении яблока. Об этом свидетельствует то, что яблоко постоянно находится посредине между глаз.

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

Вид с камер на глазах змейки

Наличие на сцене только одной камеры не решает поставленной задачи симуляции стереозрения. Кроме этого, не представлена наглядно общая картина размещения объектов на сцене. Поэтому главную камеру (Main Camera) поставим на прежнее место, она будет показывать размещение объектов на сцене. А для создания стереопары добавим на сцену еще 2 камеры — Camera_right и Camera_left . Сделаем камеры  дочериными (child objects) к голове.

Положение (from) и направление взгляда (target) камер по прежнему будем прописывать в скрипте LookAt, который прикрепляется к каждой из 3-х камер.

Параметр From камер Camera_right и Camera_left инициализируется  глазами змейки с соответствующими именами — Right_eye и Left_eye. Параметр Target для этих камер инициализируется яблоком (объектом Food).

Параметр from основной камеры в исходном игровом приложении не использовался — положение камеры устанавливалось вручную. Поскольку скрипт LookAt универсальный для всех камер, требуется для основной камеры создать пустой объект (CreateObject > Create Empty) и расположить его в точке, откуда хорошо просматривается поле. Этот объект используется для инициализации параметра From. Параметр Target для этой камеры инициализируется головой змейки (Head).

Итак, у нас есть 3 камеры. Для одной сцены может быть активна только лишь одна из камер. Возникает вопрос, как они будут переключаться?

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

Чтобы наблюдать за поведением змейки периодически необходимо включать и основную камеру.

Для обеспечения такой функциональности модифицируем скрипт Game.cs. Добавим в него три открытые переменные и условия, обеспечивающие переключение камер

public class Game : MonoBehaviour
{
 public GameObject cam;
 public GameObject camleft;
 public GameObject camright;
...
public void Update()
{
 if (cam.active == false)
 {
if (camleft.active == true)
 {
 camleft.active = false;
 camright.active = true;
 }
else //if (camleft.active == false)
 {
 camleft.active = true;
 camright.active = false;
 }
 }
...

Активизируем в окне Hierarchy объект GameManager, к которому прикреплен скрипт Game.cs, а в окне Inspector инициализируем переменные  cam, camleft и camright   соответствующими камерами — основная, а также камеры для левого и правого глаз.

Перед запуском приложения в окне Inspector включаем основную камеру.

Результат запуска будет следующим:

Если отключить основную камеру (перед запуском или во время него) и включить хотя бы одну из камер, установленных на глазах змейки, то результат  будет следующим:

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

Изображения (RawImage) с камер

Стереозрение —  трехмерное представление окружающего мира по изображениям от двух камер, работающих синхронно. Мы пока смоделировали только  виды на  окружающий мир с различных точек. А нам необходимо получить изображения, подобные тому, которое получаем от цифровой камеры — растровая картинка в форматах RAW или JPEG. Как перейти от вида к изображению, используя возможности Unity3D? Основная идея изложена в этой статье.

Для начала нам нужно создать текстуры, в которые будут помещаться изображения с камер на глазах змейки. Для этого в папке Assets добавляем папку CamTxtra, жмем правую кнопку, затем Create -> Render Texture и создаем 2-е текстуры с именами Left и Right.

Для каждой из камер (Camera_left и Camera_right) в свойство Target Texture перетаскиваем текстуры с соответствующими именами.

Чтобы бы видеть текстуры камер на сцене создадим 2-а объекта Canvas (GameObject > UI > Canvas) с именами Canvas_left и Canvas_right. Этот объект служит для отображения элементов управления (как правило, двухмерных) на сцене. Далее добавляем  объекты RawImage (GameObject > UI > RawImage) и делаем их «дочериными» для каждого из объектов Canvas.

В параметр Texture каждого из объектов RawImage  перетаскиваем соответствующую текстуру (Left и Right).

В Inspector помощью инструмента Rect Transform для объектов RawImage позиционируем картинки в наиболее удобное место на сцене. Это проще всего сделать с включенной вкладкой Game.

Комментируем в файле Game.cs код, который отвечал за переключение камер (см. раздел Вид с камер на глазах змейки). Запускаем приложение (Play) и видим, как меняются картинки с камер, пока змейка перемещается.

Картинки от камер расположены на сцене соответственно: слева — картинка от камеры левого глаза, справа — картинка от правого глаза.

Обратите внимание на один из кадров сцены:

На нем видим, что кубик, который находится справа от змейки, почему-то отображается только в левой камере. Вначале напрашивается предположение, все, что справа, должно отображаться, прежде всего, в правой камере.

Этому есть объяснение. Вектор взгляда (главная ось камер) для обоих глаз направлена от глаза  к яблоку — как на рисунке показано стрелками. Вектора пересекаются и направлены противоположно от точки выхода (справа налево и наоборот). Когда змейка приближается к яблоку, угол между векторами увеличивается. Поэтому кубик справа не попал в поле зрения камеры правого глаза, а в левой камере он частично видим.

 

 

Полезные ссылки:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *