<?xml version="1.0" encoding="windows-1251"?>
<rss version="2.0">
<channel>
  <title>Сергей Резник</title>
  <link>http://sergio.gamedev.ru/</link>
  <description>Сергей Резник</description>
  <language>ru</language>
  <generator>http://skif.qrim.ru/</generator>
  <image>
    <url>http://www.gamedev.ru/_img/imggen/?s=395</url>
    <title>Сергей Резник</title>
    <link>http://sergio.gamedev.ru/</link>
  </image>
<item>
  <guid isPermaLink="true">http://sergio.gamedev.ru/articles/kinect_1</guid>
  <pubDate>Mon, 01 Aug 2011 06:40:13 GMT</pubDate>
  <title>Kinect SDK. Часть первая</title>
  <link>http://sergio.gamedev.ru/articles/kinect_1</link>
  <comments>http://sergio.gamedev.ru/forum/?id=150688</comments>
  <category>Kinect</category>
  <category>Xbox</category>
  <description>
&lt;p&gt;Получаем изображение с камер кинекта.&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;http://www.gamedev.ru/files/images/04136c45c07dfda586ad10b5a7f41fa4.jpg&quot; alt=&quot;Kinect | Kinect SDK. Часть первая&quot; /&gt;&lt;/p&gt;
&lt;br /&gt;==Введение==
&lt;br /&gt;После краткого &lt;a href=&quot;http://sergio.gamedev.ru/articles/kinectsdk&quot;&gt;знакомства с Kinect SDK&lt;/a&gt; давайте поизучаем его поближе и попытаемся получить данные с камер устройства. На момент написания статьи &lt;a href=&quot;http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/&quot;&gt;Kinect SDK&lt;/a&gt; все еще версии 1.00.11 от 16-ого июня и множество описанных (и довольно интересных) в справке функций не работают. Но это не страшно. Существующего функционала достаточно для исследований и написания простеньких приложений и игр. Собственно в этой статье я расскажу о том, как я прикручивал Kinect SDK в свой движок. Я буду использовать некоторые свои типы данных, но думаю они всем будут понятны. 
&lt;p&gt;==Подготовительная часть==
&lt;br /&gt;Итак, цель: сделать модуль-обертку над Kinect SDK для своего движка. Так как Kinect SDK доступен только для Windows, то всю реализацию мы завернем в private implementation. Но для начала создадим класс, который собственно и будет отвечать за работу с кинектом. Назовем его просто - Kinect. Думаю логично, что первым делом нужно проверить - а есть ли вообще у нас кинект? 
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;  &lt;span style=&quot;color: #0030fF; &quot;&gt;class&lt;/span&gt; KinectPrivate;
  &lt;span style=&quot;color: #0030fF; &quot;&gt;class&lt;/span&gt; Kinect
  {
  &lt;span style=&quot;color: #0030fF; &quot;&gt;public&lt;/span&gt;:
    &lt;span style=&quot;color: #0030fF; &quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;bool&lt;/span&gt; deviceAvailable&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;

  &lt;span style=&quot;color: #0030fF; &quot;&gt;public&lt;/span&gt;:
    Kinect&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;KinectDelegate*&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
    ~Kinect&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;

  &lt;span style=&quot;color: #0030fF; &quot;&gt;private&lt;/span&gt;:
    &lt;span style=&quot;color: #0030fF; &quot;&gt;friend&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;class&lt;/span&gt; KinectPrivate;

    KinectDelegate* _delegate;
    KinectPrivate* _private;
    &lt;span style=&quot;color: #0030fF; &quot;&gt;bool&lt;/span&gt; _deviceAvailable;
  };&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Средство такой проверки есть в Kinect SDK. Это метод &lt;b&gt;MSR_NUIGetDeviceCount&lt;/b&gt;. То есть:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;bool&lt;/span&gt; Kinect::deviceAvailable&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
{
  &lt;span style=&quot;color: #0030fF; &quot;&gt;int&lt;/span&gt; deviceCount = &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;;
  HRESULT result = MSR_NUIGetDeviceCount&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&amp;amp;deviceCount&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
  &lt;span style=&quot;color: #0030fF; &quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;result == S_OK&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; &amp;amp;&amp;amp; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;deviceCount &lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Так как вся работа с Kinect SDK будет осуществляться в PIMPL, то конструктор и деструктор нашего класса Kinect очевидны:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;Kinect::Kinect&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;KinectDelegate* delegate&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; : _delegate&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;delegate&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;, _private&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
{
  _deviceAvailable = Kinect::deviceAvailable&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
  &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_deviceAvailable&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; 
    _private = &lt;span style=&quot;color: #0030fF; &quot;&gt;new&lt;/span&gt; KinectPrivate&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
}

Kinect::~Kinect&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
{
  &lt;span style=&quot;color: #0030fF; &quot;&gt;delete&lt;/span&gt; _private;
}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Идем дальше.&lt;/p&gt;
&lt;p&gt;==Инициализая и настройка==&lt;/p&gt;
&lt;p&gt;Итак, допустим что у нас есть кинект, кабель для его соединения с компьютером (который поставляется вместе с кинектом, если тот покупался отдельно, либо стоит около 40 долларов) и все готово к работе. 
&lt;br /&gt;Инициализация происходит довольно просто. Мы при помощи флагов указываем какие данные мы хоти получать от устройства:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px; overflow: auto; overflow-x: auto; overflow-y:hidden; height:auto;&quot;&gt;&lt;pre&gt;HRESULT result = NuiInitialize&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX | NUI_INITIALIZE_FLAG_USES_SKELETON | NUI_INITIALIZE_FLAG_USES_COLOR&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Как видно, мы можем получать сразу практически все данные: цветное изображение, данные с камеры глубины + индекс игрока и скелет. Получение скелета мы тоже включим, но трогать пока не будем. 
&lt;br /&gt;Далее, для каждого типа данных нам необходимо открыть свой поток при при помощи метода &lt;b&gt;NuiImageStreamOpen&lt;/b&gt;. Описание этого метода из справки:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;HRESULT NuiImageStreamOpen&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;
   NUI_IMAGE_TYPE eImageType,
   NUI_IMAGE_RESOLUTION eResolution,
   DWORD dwImageFrameFlags_NotUsed,
   DWORD dwFrameLimit,
   HANDLE hNextFrameEvent,
   HANDLE *phStreamHandle
&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Теперь по порядку.
&lt;br /&gt;&lt;b&gt;eImageType&lt;/b&gt; - тип изображения, который определяет формат данных. 
&lt;br /&gt;&lt;b&gt;eResolution&lt;/b&gt; определяет размеры кадра (об этом далее). 
&lt;br /&gt;&lt;b&gt;dwImageFrameFlags_NotUsed&lt;/b&gt; пока не используется. 
&lt;br /&gt;&lt;b&gt;dwFrameLimit&lt;/b&gt; - количество кадров, которые будут буферизироваться. Оно не может быть больше чем NUI_IMAGE_STREAM_FRAME_LIMIT_MAXIMUM (сейчас это 4). Рекомендуют использовать значение 2.
&lt;br /&gt;&lt;b&gt;hNextFrameEvent&lt;/b&gt; - событие, которое будет сигнализировать нам о том, что новый кадр сформирован. Очень важный параметр (об этом далее)
&lt;br /&gt;&lt;b&gt;phStreamHandle&lt;/b&gt; - указатель, в который, в случае успешного выполнения, будет записан идентификатор потока.&lt;/p&gt;
&lt;p&gt;Теперь подробнее о разрешении изображения. В документации приведена таблица, которая описывает размеры кадра для каждого из типов данных. Так для &lt;b&gt;NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX&lt;/b&gt; разрешение может быть либо 80x60 либо 320x240. Для &lt;b&gt;NUI_IMAGE_TYPE_DEPTH&lt;/b&gt; - уже может быть до 640x480. А для &lt;b&gt;NUI_IMAGE_TYPE_COLOR&lt;/b&gt; - либо 640x480 либо 1280x1024. Подробнее об типах данных читайте ниже.
&lt;br /&gt;Как я уже сказал - идентификатор события - это очень нужный и полезный параметр. Он позволяет сделать нам хорошее многопоточное приложение. Для того, чтобы не тормозить основной поток, мы из другого потока будем получать сведения о том, что кадр уже готов и просто будем забирать этот кадр, вместо того, чтобы ждать его в основном потоке. Для каждого из типов данных нам понадобится одно событие. Также создадим событие, которое сообщит о завершении работы с кинектом. Обратите внимание, что событие должно быть &amp;quot;manual reset&amp;quot;. То есть после вызова SetEvent внутри Kinect SDK будет происходить вызов ResetEvent. Если создать не manual-reset событие, получим скорость обновления данных около 15 кадров в секунду. Да, забыл сказать, что в нормальном режиме имеем около 30-ти кадров в секунду.
&lt;br /&gt;Итак, создадим события для каждых типов данных:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;  _threadStopEvent = CreateEvent&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #0030fF; &quot;&gt;false&lt;/span&gt;, &lt;span style=&quot;color: #0030fF; &quot;&gt;false&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
  _kinectImageNextFrameEvent = CreateEvent&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #0030fF; &quot;&gt;true&lt;/span&gt;, &lt;span style=&quot;color: #0030fF; &quot;&gt;false&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
  _kinectDepthNextFrameEvent = CreateEvent&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #0030fF; &quot;&gt;true&lt;/span&gt;, &lt;span style=&quot;color: #0030fF; &quot;&gt;false&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
  _kinectSkeletonNextFrameEvent = CreateEvent&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #0030fF; &quot;&gt;true&lt;/span&gt;, &lt;span style=&quot;color: #0030fF; &quot;&gt;false&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;И откроем потоки. Следует заметить, что метода закрытия потока не существует - они освобождаются вместе с вызовом NuiShutdown(). Так как мы не гонимся за большим размером выходного изображения - будем использовать 640x480 для цветной картинки
&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;  result = NuiImageStreamOpen&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;2&lt;/span&gt;, 
    _kinectImageNextFrameEvent, &amp;amp;_kinectImageStream&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/p&gt;
&lt;p&gt;Для глубины и индекса игрока будем использовать максимально возможное разрешение - 320x240:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px; overflow: auto; overflow-x: auto; overflow-y:hidden; height:auto;&quot;&gt;&lt;pre&gt;  result = NuiImageStreamOpen&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX, NUI_IMAGE_RESOLUTION_320x240, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;2&lt;/span&gt;, 
    _kinectDepthNextFrameEvent, &amp;amp;_kinectDepthStream&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Кстати, для того, чтобы получать индекс игрока вместе с глубиной, нам обязательно нужно использовать флаг &lt;b&gt;NUI_INITIALIZE_FLAG_USES_SKELETON&lt;/b&gt; при инициализации. Как я уже говорил, включим слежение за скелетом, но трогать пока не будем:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;  result = NuiSkeletonTrackingEnable&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectSkeletonNextFrameEvent, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Теперь создадим поток, в котором будем обрабатывать события, приходящие от Kinect SDK:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;  _thread = CreateThread&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, threadFunc, &lt;span style=&quot;color: #0030fF; &quot;&gt;this&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Сразу рассмотрим как это все правильно выключить. Мы сообщаем потоку о том, что работа завершена, после чего завершаем поток и удаляем все события. Также вызываем метод NuiShutdown()
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;  &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_threadStopEvent&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
  {
    SetEvent&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_threadStopEvent&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
    &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_thread&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
    {
      WaitForSingleObject&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_thread, INFINITE&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
      CloseHandle&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_thread&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
    }

    CloseHandle&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_threadStopEvent&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
  }

  NuiShutdown&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;

  &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectSkeletonNextFrameEvent&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
    CloseHandle&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectSkeletonNextFrameEvent&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;

  &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectDepthNextFrameEvent&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
    CloseHandle&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectDepthNextFrameEvent&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;

  &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectImageNextFrameEvent&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
    CloseHandle&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectImageNextFrameEvent&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Метод, который выполняется в отдельном потоке предельно прост - мы в цикле ждем наступления одного из событий и после чего вызываем соответствующий метод:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;enum&lt;/span&gt; KinectEvent
{
  KinectEvent_Shutdown,
  KinectEvent_NextImageFrame,
  KinectEvent_NextDepthFrame,
  KinectEvent_NextSkeletonFrame,
  KinectEvent_max
};

DWORD WINAPI KinectPrivate::threadFunc&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;void&lt;/span&gt;* param&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
{
  std::cout &lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&quot;color: #00808F&quot;&gt;&amp;quot;Running kinect thread...&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt; std::endl;
  KinectPrivate* kp = &lt;span style=&quot;color: #0030fF; &quot;&gt;reinterpret_cast&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt;KinectPrivate*&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;param&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;

  HANDLE eventList&lt;span style=&quot;color: #a06000&quot;&gt;[&lt;/span&gt;KinectEvent_max&lt;span style=&quot;color: #a06000&quot;&gt;]&lt;/span&gt; = 
  {
    kp-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;_threadStopEvent,
    kp-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;_kinectImageNextFrameEvent,
    kp-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;_kinectDepthNextFrameEvent,
    kp-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;_kinectSkeletonNextFrameEvent,
  };

  DWORD eventIndex = &lt;span style=&quot;color: #0030fF; &quot;&gt;static_cast&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt;DWORD&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;-&lt;span style=&quot;color: #F04000; &quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
  DWORD numEvents = &lt;span style=&quot;color: #0030fF; &quot;&gt;sizeof&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;eventList&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; / &lt;span style=&quot;color: #0030fF; &quot;&gt;sizeof&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;HANDLE&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;

  &lt;span style=&quot;color: #0030fF; &quot;&gt;bool&lt;/span&gt; running = &lt;span style=&quot;color: #0030fF; &quot;&gt;true&lt;/span&gt;;
  &lt;span style=&quot;color: #0030fF; &quot;&gt;while&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;running&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
  {
    eventIndex = WaitForMultipleObjects&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;numEvents, eventList, &lt;span style=&quot;color: #0030fF; &quot;&gt;false&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
    &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;eventIndex == KinectEvent_Shutdown&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
    {
      running = &lt;span style=&quot;color: #0030fF; &quot;&gt;false&lt;/span&gt;;
    }
    &lt;span style=&quot;color: #0030fF; &quot;&gt;else&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;eventIndex == KinectEvent_NextImageFrame&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
    {
      kp-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;didGetNewImageFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
    }
    &lt;span style=&quot;color: #0030fF; &quot;&gt;else&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;eventIndex == KinectEvent_NextDepthFrame&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
    {
      kp-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;didGetNewDepthFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
    }
    &lt;span style=&quot;color: #0030fF; &quot;&gt;else&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;eventIndex == KinectEvent_NextSkeletonFrame&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
    {
      kp-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;didGetNewSkeletonFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
    }
  }

  std::cout &lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&quot;color: #00808F&quot;&gt;&amp;quot;Kinect thread has finished.&amp;quot;&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt; std::endl;
  &lt;span style=&quot;color: #0030fF; &quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;;
}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;==Получение RGB изображения==
&lt;br /&gt;Итак, мы подобрались к самому интересному. Если у нас получилось все правильно, то каждый раз, когда сформируется новый кадр будет вызван наш метод &lt;b&gt;didGetNewImageFrame&lt;/b&gt;. Внутри него мы должны будем получить новый кадр, получить сырые данные изображения и обязательно &amp;quot;зарелизить&amp;quot; полученный кадр, иначе кадров чере 5-8 все будет очень плохо (программа просто упадет).
&lt;br /&gt;Получение кадра происходит путем вызова метода &lt;b&gt;NuiImageStreamGetNextFrame&lt;/b&gt;. Открываем его в справке:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;HRESULT NuiImageStreamGetNextFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;
   HANDLE hStream,
   DWORD dwMillisecondsToWait,
   CONST NUI_IMAGE_FRAME **ppcImageFrame
&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;hStream&lt;/b&gt; - наш открытый поток
&lt;br /&gt;&lt;b&gt;dwMillisecondsToWait&lt;/b&gt; - количество миллисекунд, после которого данный метод вернет управление, в случае, если следующего кадра не будет.
&lt;br /&gt;&lt;b&gt;ppcImageFrame&lt;/b&gt; - указатель на указатель на структуру NUI_IMAGE_FRAME. Данный метод сам создаст нам объект, а потом его надо будет передать в метод &lt;b&gt;NuiImageStreamReleaseFrame&lt;/b&gt; для удаления.&lt;/p&gt;
&lt;p&gt;Так как мы точно знаем, что следующий кадр уже готов, то мы указываем &lt;b&gt;dwMillisecondsToWait&lt;/b&gt; равным нулю:
&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;  &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; NUI_IMAGE_FRAME* frame = &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;;
  HRESULT result = NuiImageStreamGetNextFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectImageStream, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &amp;amp;frame&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
  &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;FAILED&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;result&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/p&gt;
&lt;p&gt;В случае успеха у нас будет указатель на структуру NUI_IMAGE_FRAME, в которой много полей (часть из которых не используется), но более всего нам интересен указатель на &lt;b&gt;NuiImageBuffer&lt;/b&gt;, который собственно и хранит данные о изображении. У него есть метод, позволяющие узнать размер изображения - это &lt;b&gt;GetLevelDesc&lt;/b&gt; и метод &lt;b&gt;LockRect&lt;/b&gt; (не забываем потом вызывать UnlockRect!) который возвращает нам маленькую, но такую важную структуру &lt;b&gt;KINECT_LOCKED_RECT&lt;/b&gt;. Эта структура и содержит сырые данные изображения:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;typedef&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;struct&lt;/span&gt; _KINECT_LOCKED_RECT{
    INT    Pitch;
    &lt;span style=&quot;color: #0030fF; &quot;&gt;void&lt;/span&gt; * pBits;
} KINECT_LOCKED_RECT;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Небольшое отступление. Как я уже говорил - целью у нас является написать обертку для Kinect SDK. То есть мы не просто так получаем данные изображения. Их потом надо как-то использовать. Так вот, чтобы передать управление наружу я решил использовать паттерн делегирования, и написал вот такой класс:
&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;  &lt;span style=&quot;color: #0030fF; &quot;&gt;typedef&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;unsigned&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;short&lt;/span&gt;* KinectDepthData;
  &lt;span style=&quot;color: #0030fF; &quot;&gt;typedef&lt;/span&gt; vec4ub* KinectColorData;

  &lt;span style=&quot;color: #0030fF; &quot;&gt;class&lt;/span&gt; KinectDelegate
  {
  &lt;span style=&quot;color: #0030fF; &quot;&gt;public&lt;/span&gt;:
    &lt;span style=&quot;color: #0030fF; &quot;&gt;virtual&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;void&lt;/span&gt; kinectDidGetImageFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; vec2i&amp;amp; size, KinectColorData data&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; = &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;;
    &lt;span style=&quot;color: #0030fF; &quot;&gt;virtual&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;void&lt;/span&gt; kinectDidGetDepthFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; vec2i&amp;amp; size, KinectDepthData data&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; = &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;;
  };&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/p&gt;
&lt;p&gt;Наследуя этот класс, мы реализуем обработку данных с камеры. К слову сказать, данные изображения поступают в BGRA формате (для NUI_IMAGE_TYPE_COLOR), при этом A всегда равен нулю, что немного напрягает (может это разерезвированно для последующего использования?), а данные с камеры глубины хранятся в unsigned short. Но об этом дальше.&lt;/p&gt;
&lt;p&gt;Итак, цельный метод получения данных с камеры выглядит вот так:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px; overflow: auto; overflow-x: auto; overflow-y:hidden; height:auto;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;void&lt;/span&gt; KinectPrivate::didGetNewImageFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
{
  &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; NUI_IMAGE_FRAME* frame = &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;;
  HRESULT result = NuiImageStreamGetNextFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectImageStream, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &amp;amp;frame&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
  &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;FAILED&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;result&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;return&lt;/span&gt;;

  KINECT_SURFACE_DESC surfaceDescription = { };
  &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;!FAILED&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;frame-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;pFrameTexture-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;GetLevelDesc&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &amp;amp;surfaceDescription&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
  {
    KINECT_LOCKED_RECT lockedRect = { };
    &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;!FAILED&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;frame-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;pFrameTexture-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;LockRect&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &amp;amp;lockedRect, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
    {
      _kinect-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;_delegate-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;kinectDidGetImageFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;vec2i&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;surfaceDescription.Width, surfaceDescription.Height&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;, 
        &lt;span style=&quot;color: #0030fF; &quot;&gt;static_cast&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt;KinectColorData&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;lockedRect.pBits&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;

      frame-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;pFrameTexture-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;UnlockRect&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
    }
  }

  NuiImageStreamReleaseFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectImageStream, frame&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Что делать с этими данным дальше - решайте сами. Я запихиваю их в текстуру и вывожу на экран.&lt;/p&gt;
&lt;p&gt;==Получение изображения с камеры глубины==
&lt;br /&gt;В целом, процесс получения данных с камеры глубины идентичен получению цветных данных, вся соль в формате этих данных. Приведу метод получения данных с камеры глубины (он абсолютно такой же, как и в предыдущем разделе, за исключеним других переменных и констант):
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px; overflow: auto; overflow-x: auto; overflow-y:hidden; height:auto;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;void&lt;/span&gt; KinectPrivate::didGetNewDepthFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
{
  &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; NUI_IMAGE_FRAME* frame = &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;;
  HRESULT result = NuiImageStreamGetNextFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectDepthStream, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &amp;amp;frame&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
  &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;FAILED&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;result&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;return&lt;/span&gt;;

  KINECT_SURFACE_DESC surfaceDescription = { };
  &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;!FAILED&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;frame-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;pFrameTexture-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;GetLevelDesc&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &amp;amp;surfaceDescription&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
  {
    KINECT_LOCKED_RECT lockedRect = { };
    &lt;span style=&quot;color: #0030fF; &quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;!FAILED&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;frame-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;pFrameTexture-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;LockRect&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &amp;amp;lockedRect, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
    {
      _kinect-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;_delegate-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;kinectDidGetDepthFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;vec2i&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;surfaceDescription.Width, surfaceDescription.Height&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;, 
        &lt;span style=&quot;color: #0030fF; &quot;&gt;static_cast&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt;KinectDepthData&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;lockedRect.pBits&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
      frame-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;pFrameTexture-&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;UnlockRect&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
    }
  }

  NuiImageStreamReleaseFrame&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_kinectDepthStream, frame&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Теперь самое интересное - формат этих данных. Как я уже говорил каждая точка, это unsigned short. Данные построенны следующим образом: первые три бита хранят индекс игрока, следующие 12 бит - значение глубины и самый старший бит не используется. То есть
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;X -&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt; XXXXXXXXXXXX -&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt; XXX
^    ^               ^
не исп.              индекс игрока
     |
     – глубина&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Индекс игрока может быть 0 (если игроков нет), 1 или 2. Получить его можно с помощью побитного умножения:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;unsigned&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;short&lt;/span&gt; playerIndex = value &amp;amp; &lt;span style=&quot;color: #F04000; &quot;&gt;0x7&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;
Оставшуюся часть сдвигаем вправо на 3 бита: 
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;value = value &lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&quot;color: #F04000; &quot;&gt;3&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;
Теперь у нас есть значение от 0 до 4095. Чтобы запихнуть его в RGBA текстуру (состоящую из байтов) нужно поделить значение на 16 - получим значения в диапазоне от 0 до 255. Теперь можно играться с этим как угодно. Например выводить глубину, а игроков подсвечивать цветами, или оставлять только игроков, итд. Вот например:
&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;http://www.gamedev.ru/files/images/depth-visualized.jpg&quot; alt=&quot;Kinect depth visualized | Kinect SDK. Часть первая&quot; /&gt;&lt;/p&gt;
&lt;p&gt;На этом все. В следующей части я постараюсь рассказать о получении скелета, а так же о том, как совместить данные с RGB камеры и камеры глубины (да да, все не так просто - камеры разнесены на некоторое расстояние). Спасибо за внимание.&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://sergio.gamedev.ru/shaderarthd_end</guid>
  <pubDate>Sun, 31 Jul 2011 22:48:12 GMT</pubDate>
  <title>ShaderArt HD закончен.</title>
  <link>http://sergio.gamedev.ru/shaderarthd_end</link>
  <category>shaderart</category>
  <description>
&lt;p&gt;После чуть меньше чем трех месяцев упорных боев с движками, шейдерами и ошибками в коде четыре участника представили на суд зрителей свои демки. Ознакомится с ними можно здесь (желательно иметь DX11 видеокарту):&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Chaos_Optima&lt;/b&gt;: &lt;a href=&quot;http://rghost.ru/16167591&quot;&gt;ссылка&lt;/a&gt;, &lt;a href=&quot;http://www.gamedev.ru/code/forum/?id=147202&amp;amp;page=61#m913&quot;&gt;пост&lt;/a&gt; из обсуждения
&lt;br /&gt;&lt;b&gt;Che@ter&lt;/b&gt;: &lt;a href=&quot;http://rghost.ru/16320351&quot;&gt;ссылка&lt;/a&gt;, &lt;a href=&quot;http://www.gamedev.ru/code/forum/?id=147202&amp;amp;page=62#m916&quot;&gt;пост&lt;/a&gt; из обсуждения
&lt;br /&gt;&lt;b&gt;SNVampyre&lt;/b&gt;: &lt;a href=&quot;http://ifolder.ru/24954820&quot;&gt;ссылка&lt;/a&gt;, &lt;a href=&quot;http://www.gamedev.ru/code/forum/?id=147202&amp;amp;page=62#m921&quot;&gt;пост&lt;/a&gt; из обсуждения
&lt;br /&gt;&lt;b&gt;coordBox&lt;/b&gt;: &lt;a href=&quot;http://rghost.ru/16357511&quot;&gt;ссылка&lt;/a&gt;, &lt;a href=&quot;http://www.gamedev.ru/code/forum/?id=147202&amp;amp;page=62#m924&quot;&gt;пост&lt;/a&gt; из обсуждения&lt;/p&gt;
&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;http://www.gamedev.ru/files/images/shart_probe4.jpg&quot; alt=&quot;SHart_probe4 | ShaderArt HD закончен.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Выбираем лучшего:
&lt;br /&gt;&lt;object type=&quot;application/x-shockwave-flash&quot; data=&quot;http://static.99widgets.com/polls/swf/poll.swf?id=93655:1&amp;amp;lang=ru&quot; width=&quot;250&quot; height=&quot;213&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.99widgets.com/polls/swf/poll.swf?id=93655:1&amp;amp;lang=ru&quot; /&gt;&lt;param name=&quot;bgcolor&quot; value=&quot;#FFFFFF&quot; /&gt;&lt;embed src=&quot;http://static.99widgets.com/polls/swf/poll.swf?id=93655:1&amp;amp;lang=ru&quot; type=&quot;application/x-shockwave-flash&quot; bgcolor=&quot;#FFFFFF&quot; width=&quot;250&quot; height=&quot;213&quot;&gt;&lt;/embed&gt;&lt;br /&gt;&lt;a href=&quot;http://www.casinoschule.com/roulette.html&quot;&gt;Roulette&lt;/a&gt;, &lt;a href=&quot;http://www.99polls.com/&quot;&gt;polls&lt;/a&gt;, &lt;a href=&quot;http://www.fxbeing.com/&quot;&gt;FX&lt;/a&gt;, &lt;a href=&quot;http://www.casinophiles.com/royal-vegas-casino.htm&quot;&gt;Royal vegas&lt;/a&gt;, &lt;a href=&quot;http://www.onlinecasinoau.com/casino-games.html&quot;&gt;Casino Games&lt;/a&gt;&lt;/object&gt;&lt;/p&gt;
&lt;div class=&quot;offtop&quot;&gt;Спасибо &lt;b&gt;Dimich&lt;/b&gt; за голосовалку.
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://sergio.gamedev.ru/articles/kinectsdk</guid>
  <pubDate>Fri, 17 Jun 2011 19:22:39 GMT</pubDate>
  <title>Знакомство с Kinect SDK</title>
  <link>http://sergio.gamedev.ru/articles/kinectsdk</link>
  <comments>http://sergio.gamedev.ru/forum/?id=148855</comments>
  <category>Kinect</category>
  <category>project natal</category>
  <description>
&lt;p&gt;Давайте проведем небольшой обзор недавно вышедшей Kinect SDK. &lt;br /&gt;К счастью, SDK написан на С++. После его установки мы видим всего лишь 6 файлов в папке &lt;b&gt;include&lt;/b&gt;, а так же шесть динамически подключаемых библиотек (.dll). Классы и константы начинаются с аббревиатуры NUI - Natural User Interface. Открываем справку и начинаем изучение.&lt;/p&gt;
&lt;p&gt;Подключение SDK видится очень простым:
&lt;br /&gt;&lt;i&gt;To compile a NUI-based project, include MSR_NuiApi.h in your project, link against the .LIB file, and ensure that the .DLL is on your path when you run your project.&lt;/i&gt; 
&lt;br /&gt;Переходим с следующему разделу, и видим 4 подраздела: API, Image Camera API, Skeleton API и класс NuiImageBuffer. Рассмотрим основные интересные моменты каждого раздела.&lt;/p&gt;
&lt;p&gt;В разделе &lt;b&gt;API&lt;/b&gt; описаны инициализация и выключение системы. При инциализации нужно указывать какие подсистемы наше приложение будет использовать: &lt;b&gt;DEPTH_AND_PLAYER_INDEX, COLOR, SKELETON, DEPTH&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Следующий раздел: &lt;b&gt;Image Camera API&lt;/b&gt;
&lt;br /&gt;С помощью этого API можно получить данные с камер. Открываем поток методом NuiImageStreamOpen. Следует отметить параметры для этого метода: 
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;enum&lt;/span&gt; _NUI_IMAGE_TYPE {
    NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX = &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;,
    NUI_IMAGE_TYPE_COLOR,
    NUI_IMAGE_TYPE_COLOR_YUV,
    NUI_IMAGE_TYPE_COLOR_RAW_YUV,
    NUI_IMAGE_TYPE_DEPTH,
    NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX_IN_COLOR_SPACE,
    NUI_IMAGE_TYPE_DEPTH_IN_COLOR_SPACE,
    NUI_IMAGE_TYPE_COLOR_IN_DEPTH_SPACE,
} NUI_IMAGE_TYPE;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Некоторые из этих параметров не поддерживаются в текущем SDK. А так же параметр, которые задает разрешение изображения:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;enum&lt;/span&gt; _NUI_IMAGE_RESOLUTION {
    NUI_IMAGE_RESOLUTION_INVALID = -&lt;span style=&quot;color: #F04000; &quot;&gt;1&lt;/span&gt;,
    NUI_IMAGE_RESOLUTION_80x60 = &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;,
    NUI_IMAGE_RESOLUTION_320x240,
    NUI_IMAGE_RESOLUTION_640x480
    NUI_IMAGE_RESOLUTION_1280x1024, 
} NUI_IMAGE_RESOLUTION;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Как видим - самое большое разрешение 1280х1024. &lt;/p&gt;
&lt;p&gt;Далее получаем кадры с помощью &lt;b&gt;NuiImageStreamGetNextFrame&lt;/b&gt;. Можно задать время, через которое данный метод вернет управление, если изображение не будет получено. 
&lt;br /&gt;Так же можно настроить угол камеры: &lt;b&gt;NuiCameraElevationSetAngle&lt;/b&gt;. Замечание к данной функции: &lt;i&gt;Warning You should tilt the Kinect sensor as few times as possible, to minimize wear on the camera and to minimize tilting time. The camera motor is not designed for constant or repetitive movement, and attempts to use it that way may cause degradation of motor function.&lt;/i&gt; Вобщем лучше это не использовать. &lt;/p&gt;
&lt;p&gt;Следующий раздел: &lt;b&gt;Skeleton API&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Включаем отслеживание скелета методом &lt;b&gt;NuiSkeletonTrackingEnable&lt;/b&gt; и затем получаем кадры методом &lt;b&gt;NuiSkeletonGetNextFrame&lt;/b&gt;. Этот метод возвращает нам вот такую структуру:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;struct&lt;/span&gt; _NUI_SKELETON_FRAME {
    LARGE_INTEGER liTimeStamp;
    DWORD dwFrameNumber;
    DWORD dwFlags;
    Vector4 vFloorClipPlane;
    Vector4 vNormalToGravity;
    NUI_SKELETON_DATA SkeletonData&lt;span style=&quot;color: #a06000&quot;&gt;[&lt;/span&gt;NUI_SKELETON_COUNT&lt;span style=&quot;color: #a06000&quot;&gt;]&lt;/span&gt;;
} NUI_SKELETON_FRAME;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;
Среди прочего в этой структуре содержится положение пола и вектор направления ускорения свободного падения. Все расчитывается приблизительно. 
&lt;br /&gt;Интересно отметить: &lt;i&gt;If the number of tracked skeletons is less than NUI_SKELETON_COUNT&lt;/i&gt; при этом NUI_SKELETON_COUNT = 6. Это намек на то, что можно отслеживать до 6 человек? 
&lt;br /&gt;Внутри структуры NUI_SKELETON_DATA помимо прочего находится массив костей, для которых указанно &lt;b&gt;расстояние до камеры в метрах&lt;/b&gt;. Всего отслеживается 20 костей (голова, позвоничник, таз, колени, локти, итд).&lt;/p&gt;
&lt;p&gt;Класс &lt;b&gt;NuiImageBuffer&lt;/b&gt; содержит в себе данные изображения. Интересно отметить методы LockRect, который предоставляет доступ к данным в виде
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;void&lt;/span&gt; * pBits;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Еще есть API для работы со звуком, но это мы разберем в другой раз.
&lt;br /&gt;В целом Beta SDK выглядит довольно простым и интересным в использовании. Не дождусь, когда у меня будет переходник чтобы опробовать его.&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://sergio.gamedev.ru/infernus2</guid>
  <pubDate>Mon, 23 May 2011 15:42:30 GMT</pubDate>
  <title>Infernus: verse 2</title>
  <link>http://sergio.gamedev.ru/infernus2</link>
  <comments>http://sergio.gamedev.ru/forum/?id=147839</comments>
  <category>3D</category>
  <category>iOS</category>
  <category>iPad</category>
  <category>iPhone</category>
  <category>OpenGL</category>
  <category>мои проекты</category>
  <description>
&lt;p&gt;Совершенно недавно &lt;a href=&quot;http://tundramobile.com&quot;&gt;TundraMobile&lt;/a&gt; (одним из разработчиков в которой являюсь я) совместно с &lt;a href=&quot;http://www.motalen.com&quot;&gt;Motalen&lt;/a&gt;, закончили работу над крупным проектом: &lt;b&gt;Infernus: verse 2&lt;/b&gt;. &lt;br /&gt;Игра-квест, в которой вы просыпаетесь в тюремной камере, не помните ничего и никого. Вам предстоит выбраться сначала из этой камеры (все это было в verse 1), а теперь из здания на (необитаемом?) острове. Для этого вам нужно будет находить разные предметы и подбирать пароль к системе охраны. А потом найти &lt;font color=&quot;white&quot;&gt;что-то&lt;/font&gt; и разбить &lt;font color=&quot;white&quot;&gt;какую-то штуку&lt;/font&gt; и вы окажетесь на свободе!&lt;/p&gt;
&lt;p&gt;Мы старались выжать из мобильных устройств (в число которых входит iPhone, iPad и устройства с Android) максимум производительности в графическом плане. И похоже нам это удалось (на iPhone 4 игра в среднем показывает 25-30 к/с). В игре очень много графических эффектов и постобработки, мультитач управление (насколько мне известно - это первая 3Д игра на андроид с мультитачем) и отличная звуковая составляющая. Игра была представлена на Google I/O 2011 и понравилась многим (по словам нашего партнера: &lt;i&gt;huge game companies complemented it as I/O saying &amp;quot;wow, thats amazing&amp;quot;&lt;/i&gt;). Вот несколько скриншотов:&lt;/p&gt;
&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;
&lt;br /&gt;&lt;img src=&quot;http://www.gamedev.ru/files/images/hall.png&quot; alt=&quot;hall | Infernus: verse 2&quot; /&gt;
&lt;br /&gt;Конечно все показывать не имеет смысла :)
&lt;/p&gt;
&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;
&lt;br /&gt;&lt;img src=&quot;http://www.gamedev.ru/files/images/tv.png&quot; alt=&quot;tv | Infernus: verse 2&quot; /&gt;&lt;img src=&quot;http://www.gamedev.ru/files/images/telescope.png&quot; alt=&quot;telescope | Infernus: verse 2&quot; /&gt;
&lt;/p&gt;
&lt;p&gt;Infernus verse 2 уже можно &lt;s&gt;скачать&lt;/s&gt; купить в &lt;a href=&quot;http://ax.search.itunes.apple.com/WebObjects/MZSearch.woa/wa/search?media=software&amp;amp;restrict=false&amp;amp;submit=media&amp;amp;term=Infernus+verse%202&quot;&gt;AppStore&lt;/a&gt; и &lt;a href=&quot;https://market.android.com/details?id=com.motalen.verse2&quot;&gt;Android-Market&lt;/a&gt;. Также доступна бесплатная демка ;)
&lt;br /&gt;Если кто-то хочет начать &amp;quot;с начала&amp;quot; - можно бесплатно скачать &lt;b&gt;Infernus: verse 1&lt;/b&gt;, которая так же выходила для Bada OS и заняла 3-е место в конкурсе &lt;a href=&quot;http://developer.bada.com/challenge/main.do?menu=CM01010000&amp;amp;regionID=L000000000&quot;&gt;Developer Challenge&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PS: будем благодарны (и можем поделиться промо-кодом), если кто-нибудь опубликует сслыку или напишет небольшой обзор к игре.&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://sergio.gamedev.ru/shaderarthd</guid>
  <pubDate>Thu, 05 May 2011 20:32:41 GMT</pubDate>
  <title>ShaderArt HD</title>
  <link>http://sergio.gamedev.ru/shaderarthd</link>
  <comments>http://sergio.gamedev.ru/forum/?id=147289</comments>
  <category>shaderart</category>
  <description>
&lt;p&gt;Приглашаем всех желающих к участию в новом конкурсе по программированию шейдеров - &lt;b&gt;Shader Art HD&lt;/b&gt; (пятый по счету конкурс).
&lt;br /&gt;Главным идейным вдохновителем этого конкурса стал &lt;b&gt;&lt;a href=&quot;http://www.gamedev.ru/users/?id=15228&quot;&gt;Аврелий&lt;/a&gt;&lt;/b&gt;. Он же предоставил отличную сцену для этого конкурса, за что ему большое спасибо. &lt;/p&gt;
&lt;p&gt;На этот раз мы будем делать самую настоящую картину - натюрморт. 
&lt;br /&gt;Исполнение остается на совести автора: кто-то захочет сделать супер-реалистичную фотографию, кто-то сделает картину маслом, ну а кто-то может захочет сделать рисунок в карандаше. Вот так выглядит рендер предоставленной сцены:
&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;http://www.gamedev.ru/files/images/shart_probe4.jpg&quot; alt=&quot;SHart_probe4 | ShaderArt HD&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Условия конкурса:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;1) приложение должно выводить изображение в реал-тайме, то есть:
&lt;br /&gt;1.1) не должно содержать заранее просчитанных текстур и картинок
&lt;br /&gt;1.2) количество кадров в секунду - не менее 10-ти в разрешении 1920x1080 (тестироваться приложения будут на GTX 460 SE)&lt;/p&gt;
&lt;p&gt;2) сцена не должна быть статической:
&lt;br /&gt;2.1) может меняться положение источника света (желательно сделать так, чтобы положением источника управлял пользователь)
&lt;br /&gt;2.2) камера может менять положение (допускается ограничение перемещения камеры)&lt;/p&gt;
&lt;p&gt;3) возможность сохранить изображение рендера (не через PrintScreen) для использования в качестве обоев.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Предварительная дата окончания&lt;/b&gt; конкурса - 5 июня. По желанию участников конкурс может быть продлен.
&lt;br /&gt;&lt;b&gt;Победители&lt;/b&gt;, как всегда, будут определены народным голосованием. 
&lt;br /&gt;&lt;b&gt;Скачать&lt;/b&gt; сцену для конкурса можно здесь: &lt;a href=&quot;http://www.gamedev.ru/download/scene.zip&quot;&gt;http://www.gamedev.ru/download/scene.zip&lt;/a&gt; (4,73 Мб)&lt;/p&gt;
&lt;p&gt;Перейти к &lt;a href=&quot;http://www.gamedev.ru/code/forum/?id=147202&quot;&gt;обсуждению&lt;/a&gt;.&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://sergio.gamedev.ru/shader_art</guid>
  <pubDate>Fri, 06 Aug 2010 21:17:16 GMT</pubDate>
  <title>Shader art 2010</title>
  <link>http://sergio.gamedev.ru/shader_art</link>
  <comments>http://sergio.gamedev.ru/forum/?id=136599</comments>
  <category>Art</category>
  <category>шейдеры</category>
  <description>
&lt;p&gt;Начинаем новый конкурс по шейдерам!&lt;/p&gt;
&lt;p&gt;На этот раз сцена будет очень простая - всего лишь набор кубиков. Выглядит она вот так (стандартный рендер 3ds max):
&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;http://www.gamedev.ru/files/images/57096_1281128114_render.jpg&quot; alt=&quot;render | Shader art 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Задание участникам&lt;/b&gt;: сделать данную сцену как можно более реалистичной, учитывая следующие факторы:
&lt;br /&gt;1) сцена не должна содержать текстур. При этом допускается использование &amp;quot;служебных&amp;quot; текстур (как то текстура с шумом, случайными нормалями, карты нормалей и пр.). Использование текстур не допускается (для того, чтобы сцена не зависила от арта)
&lt;br /&gt;2) материалы объектов на сцене выбираются участником произвольно. Предполагаются следующие материалы: пластик, металл, стекло, кожа, мех, дерево и др.
&lt;br /&gt;3) не следует забывать, что мы &lt;u&gt;не делаем offline рендер&lt;/u&gt;. Приложение должно давать не менее 15 кадров в секунду. Производительность будет замеряна на следующей конфигурации: Intel Core 2 Quad 2/5GHz, 2GB RAM, nVidia 220GT
&lt;br /&gt;4) минимальное разрешение 640x480&lt;/p&gt;
&lt;p&gt;Допускается как GPU так и CPU рендер.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Сроки&lt;/b&gt; проведения конкурса будут объявлены позже (1-2 месяца). При желании участников сроки могут быть продлены.
&lt;br /&gt;&lt;b&gt;Победители&lt;/b&gt; будут определены жюри, состав которого будет объявлен позже.&lt;/p&gt;
&lt;p&gt;Скачать сцену можно здесь: &lt;b&gt;&lt;a href=&quot;http://www.gamedev.ru/files/?id=57095&quot;&gt;cubes&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://sergio.gamedev.ru/warballz</guid>
  <pubDate>Sun, 02 May 2010 22:06:46 GMT</pubDate>
  <title>Первый день разработки новой игры - WarBallZ</title>
  <link>http://sergio.gamedev.ru/warballz</link>
  <description>
&lt;p&gt;Официально считаю сегодняшний день (3-е мая, час ночи) началом разработки нового проекта, который мы будем делать вместе с &lt;a href=&quot;http://www.gamedev.ru/users/?id=26638&quot;&gt;S_L_A_V_A&lt;/a&gt;. У нас для этого все готово: есть довольно неплохой диздок, есть &lt;a href=&quot;http://casual.gamedev.ru/forum/?id=129666&quot;&gt;прототип&lt;/a&gt; игры и есть желание. Постараюсь писать проект без говнокода и без смешивания в кучу всяких несовместимых вещей (типа логики и рендера) - в дальнейшем есть идеи портировать игру на iPhone (для этого есть заранее закупленый iPod Touch 3G :)).
&lt;br /&gt;А теперь я иду спать...&lt;/p&gt;
&lt;p&gt;правка: хм... под началом разработки я понимаю готовую структуру проекта, а не голословные заявления ;)&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://sergio.gamedev.ru/dynamic</guid>
  <pubDate>Wed, 21 Apr 2010 22:07:03 GMT</pubDate>
  <title>Обратные задачи динамики и моделирование движения ЛА</title>
  <link>http://sergio.gamedev.ru/dynamic</link>
  <description>
&lt;p&gt;В настоящее время усиленно занимаюсь проектом нашей кафедры &amp;quot;Системы и процессы управления&amp;quot; - моя задача состоит в моделировании движения беспилотного летательного аппарата. Не так давно решил переписать все, что было наработано за два года. Собственно уже неделю сижу ночами - пишу. В общем задача состоит в том, чтобы по известной задаваемой траектории найти такое управление летательным аппаратом, которое бы приводило к воспроизведению этой траектории. Нелегкая это работа, я вам скажу. За четыре дня так и не добрался даже до прямого интегрирования уравнений движения, не говоря уж о решении обратной задачи динамики. Зато написал адский шаблонный класс для работы с полиномами и сплайнами. Сегодня добавил модель гравитационного поля Земли и модель стандартной атмосферы. Кому интересно (или пригодиться) могу показать:
&lt;br /&gt;Модель гравитационного поля Земли - по заданным широте, высоте и долготе вычисляется вектор ускорения свободного падения в геоцентрической СК с учетом центробежной силы, после чего он преобразуется в (если не ошибаюсь в термине) географическую систему координат:
&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;typedef&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;double&lt;/span&gt; PRECISION;
&lt;span style=&quot;color: #0030fF; &quot;&gt;typedef&lt;/span&gt; vector3&lt;span style=&quot;color: #a06000&quot;&gt;&amp;lt;&lt;/span&gt;PRECISION&lt;span style=&quot;color: #a06000&quot;&gt;&amp;gt;&lt;/span&gt; vec3p;

&lt;span style=&quot;color: #0030fF; &quot;&gt;#define&lt;/span&gt; EARTH_LONG_RADIUS          PRECISION&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;6378136&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;49&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #0030fF; &quot;&gt;#define&lt;/span&gt; EARTH_ECCENTRICITY_SQUARE  PRECISION&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;00669438&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #0030fF; &quot;&gt;#define&lt;/span&gt; EARTH_PARAMETER_MU         PRECISION&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;3&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;9860009&lt;/span&gt;e+&lt;span style=&quot;color: #F04000; &quot;&gt;14&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #0030fF; &quot;&gt;#define&lt;/span&gt; EARTH_PARAMETER_C20        PRECISION&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;-&lt;span style=&quot;color: #F04000; &quot;&gt;1082&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;63&lt;/span&gt;e-&lt;span style=&quot;color: #F04000; &quot;&gt;6&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
&lt;span style=&quot;color: #0030fF; &quot;&gt;#define&lt;/span&gt; EARTH_ANGULAR_VELOCITY     PRECISION&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;7&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;292116&lt;/span&gt;e-&lt;span style=&quot;color: #F04000; &quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;

...

&lt;span style=&quot;color: #0030fF; &quot;&gt;void&lt;/span&gt; Ce2Geolocation::calculateGravity&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;
{
 PRECISION N = EARTH_LONG_RADIUS / ::sqrt&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;1&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt; - EARTH_ECCENTRICITY_SQUARE * et::sqr&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;sin&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_latitude&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
 PRECISION NH = N + _altitude;
 vec3p R&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt; NH - EARTH_ECCENTRICITY_SQUARE * N&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; * sin&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_latitude&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;, NH * cos&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_latitude&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; * cos&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_longitude&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;, NH * cos&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_latitude&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; * sin&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_longitude&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
 PRECISION r = R.length&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
 PRECISION rp3 = r * r * r;
 PRECISION g1 = &lt;span style=&quot;color: #F04000; &quot;&gt;1&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;5&lt;/span&gt; * EARTH_PARAMETER_C20 * et::sqr&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;EARTH_LONG_RADIUS / r&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
 PRECISION RX5 = &lt;span style=&quot;color: #F04000; &quot;&gt;1&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt; - &lt;span style=&quot;color: #F04000; &quot;&gt;5&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt; * et::sqr&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;R.x / r&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
 vec3p local_gravity = g1 * vec3p&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;2&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt; + RX5, RX5, RX5&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; - vec3p&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;1&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
 local_gravity *= R * EARTH_PARAMETER_MU / rp3;
 _gravity = local_gravity - vec3p&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;, -sqr&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;EARTH_ANGULAR_VELOCITY&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; * R.y, -sqr&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;EARTH_ANGULAR_VELOCITY&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; * R.z&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
 _gravity = &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;Quaternionp&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_longitude, &lt;span style=&quot;color: #F04000; &quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; * Quaternionp&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;-_latitude, &lt;span style=&quot;color: #F04000; &quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;.invtransform&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;_gravity&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;; 
}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/p&gt;
&lt;p&gt;На фоне модели гравитационного поля Земли математическая модель стандартной атмосферы выглядит совсем игрушкой:
&lt;div style=&quot;background: #f2f2f2; padding: 5px; margin: 4px; overflow: auto; overflow-x: auto; overflow-y:hidden; height:auto;&quot;&gt;&lt;pre&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;class&lt;/span&gt; Ce2StandartAthmosphere
{
 &lt;span style=&quot;color: #0030fF; &quot;&gt;public&lt;/span&gt;:
  &lt;span style=&quot;color: #0030fF; &quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION getDensity&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION&amp;amp; atAltitude, &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION&amp;amp; gravity&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
};

...

&lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION Ce2StandartAthmosphere::getDensity&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION&amp;amp; atAltitude, &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION&amp;amp; gravity&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; 
{
 &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION R = &lt;span style=&quot;color: #F04000; &quot;&gt;8&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;31447&lt;/span&gt;; &lt;span style=&quot;color: #808080&quot;&gt;// universal gas constant &lt;/span&gt;
 &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION standartPressure = &lt;span style=&quot;color: #F04000; &quot;&gt;101325&lt;/span&gt;;
 &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION temperatureLapseRate = &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;0065&lt;/span&gt;;
 &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION standartTemperature = &lt;span style=&quot;color: #F04000; &quot;&gt;288&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;15&lt;/span&gt;;
 &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION airMolarMass = &lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;0289644&lt;/span&gt;; 
 &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION air_temperature = standartTemperature - temperatureLapseRate * atAltitude;
 &lt;span style=&quot;color: #0030fF; &quot;&gt;const&lt;/span&gt; PRECISION air_density = standartPressure * pow&lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #F04000; &quot;&gt;1&lt;/span&gt;.&lt;span style=&quot;color: #F04000; &quot;&gt;0&lt;/span&gt; - atAltitude * temperatureLapseRate / standartTemperature, &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;gravity * airMolarMass&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; / &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;R * temperatureLapseRate&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt; &lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
 &lt;span style=&quot;color: #0030fF; &quot;&gt;return&lt;/span&gt; air_density * airMolarMass / &lt;span style=&quot;color: #a06000&quot;&gt;(&lt;/span&gt;R * air_temperature&lt;span style=&quot;color: #a06000&quot;&gt;)&lt;/span&gt;;
}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://sergio.gamedev.ru/blog</guid>
  <pubDate>Mon, 19 Apr 2010 19:52:13 GMT</pubDate>
  <title>Блог</title>
  <link>http://sergio.gamedev.ru/blog</link>
  <comments>http://sergio.gamedev.ru/forum/?id=132601</comments>
  <description>
&lt;p&gt;&lt;b&gt;19.04.2010&lt;/b&gt;
&lt;br /&gt;Вот у меня есть персональная страница на GameDev.ru ура! Буду потихоньку её наполнять. Планов много, а времени - мало :)
&lt;div class=&quot;offtop&quot;&gt;twitter style :)
&lt;/div&gt;&lt;/p&gt;</description>
</item>
</channel>
</rss>

