<?xml version="1.0" encoding="windows-1251"?>
<rss version="2.0">
<channel>
  <title>Gamedev Lecture</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/</link>
  <description>Gamedev Lecture</description>
  <language>ru</language>
  <generator>http://skif.qrim.ru/</generator>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/lecture36</guid>
  <pubDate>Sat, 01 Aug 2009 18:24:59 GMT</pubDate>
  <title>Лекция #36. Обзор VM скриптовых языков (Lua, AngelScript). Часть 2. [Лектор - Black_Phoenix]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/lecture36</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=123901</comments>
  <category>angelscript</category>
  <category>Lua</category>
  <category>vm</category>
  <description>
&lt;p&gt;Лекция Black_Phoenix с обзором VM скриптовых языков Lua и AngelScript. Часть вторая.
&lt;p&gt;[19:00] &amp;lt;Black_Phoenix&amp;gt; Это вторая часть лекции о вирутальных машинах/скриптовых языках AngelScript и Lua. В первой части лекции было рассмотрено различие между ними (вкратце), а также виртуальная машина LVM (языка Lua)
&lt;br /&gt;[19:00] &amp;lt;Black_Phoenix&amp;gt; Первую часть лекции можно найти по этой ссылке: &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=4446&quot;&gt;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=4446&lt;/a&gt;
&lt;br /&gt;[19:01] &amp;lt;Black_Phoenix&amp;gt; В второй части будет кратко рассмотрено виртуальную машину AngelScript, и также то, как можно биндить Lua и AngelScript в ваших програмах.
&lt;br /&gt;[19:02] &amp;lt;Black_Phoenix&amp;gt; AngelScript сравнительно новый проект - он был начат примерно в 2003ем году некиим Андреасом Джонсоном. Это достаточно интересный скриптовый движок - он есть strong-typed как уже раньше говорилось, и он достаточно близок к С
&lt;br /&gt;[19:03] &amp;lt;Black_Phoenix&amp;gt; В основе AngelScript сидит виртуальная машина AngelScript. Она по своей архитектуре чем-то напоминает архитектуру ARM, и даже ненмого х86.
&lt;br /&gt;[19:04] &amp;lt;Black_Phoenix&amp;gt; Одинм из бонусов такой архитектуры (и вообще движка в целом) есть то, что AngelScript умеет вызывать прибинденые функции С по stdcall (или ещё некоторым конвенциям) - т.е. в принципе ничего биндить как в Lua не надо.
&lt;br /&gt;[19:05] &amp;lt;Black_Phoenix&amp;gt; Здесь достаточно указать функцию (её сигнатуру), её входную точку (т.е. указатель на функцию), и то какие она типы принимает или отдаёт.
&lt;br /&gt;[19:05] &amp;lt;Black_Phoenix&amp;gt; Весь AngelScript основан на принципах ООП - структура движка достаточно модульная, и разобраться в его работе совершенно не составляет труда.
&lt;br /&gt;[19:06] &amp;lt;Black_Phoenix&amp;gt; Как и в прошлый раз при рассмотрении Lua начнём рассматривать AngelScript с самого начала. В начале создаёться обьект asIScriptEngine - собвственно сам скриптовый движок (точнее это интерфейс к нему). 
&lt;br /&gt;[19:07] &amp;lt;Black_Phoenix&amp;gt; Для этого вызваеться функция asCreateScriptEngine() [as_scriptengine.cpp:161], которая проверяет настройки платформы (размеры всех базовых типов, также порядок байт), и создаёт сам движок - asCScriptEngine [as_scriptengine.h:76].
&lt;br /&gt;[19:07] &amp;lt;Black_Phoenix&amp;gt; Да кстати, здесь используеться такое же обозначение как в прошлой лекции - ссылки на исходные коды выглядят вот так: [имя файла:номер строки]
&lt;br /&gt;[19:08] &amp;lt;Black_Phoenix&amp;gt; В принципе этот &amp;quot;движок&amp;quot; и есть стейтом для виртуальной машины, также она привязывает к себе другие блоки - компилятор, интерпретатор, менеджер памяти, сборщик мусора.
&lt;br /&gt;[19:08] &amp;lt;Black_Phoenix&amp;gt; Перед рассмотрением самого стейта имеет смысл посмотреть на asCObjectType [as_objecttype.h:112] - базовый тип обьекта в AngelScript.
&lt;br /&gt;[19:09] &amp;lt;Black_Phoenix&amp;gt; Каждый обьект наследуется от этого класса - и предоставляет AngelScript информацию о своём названии, базовом типе (ссылка на acIObjectType - интерфейс), настройкам, и размере.
&lt;br /&gt;[19:09] &amp;lt;Black_Phoenix&amp;gt; Реализация операций над обьектом зделана через такие себе Behaviours - поведение обьекта в разных ситуациях - при добавлении, отнимании, и т.п. В AS есть такой тип как asEBehaviours - энумерация всех возможных поведений [angelscript.h:135]
&lt;br /&gt;[19:11] &amp;lt;Black_Phoenix&amp;gt; В принципе тут всё понятно - хотя видно разницу против типов Lua. Так вот, стейт движка хранит в себе списки всех зарегистрированых типов, синонимов к типам (typedefs), и энумераций (registeredObjTypes, registeredTypeDefs, registeredEnums).
&lt;br /&gt;[19:11] &amp;lt;Black_Phoenix&amp;gt; Также тут храниться таблица всех глобальных функций и переменных (registeredGlobalProps, registeredGlobalFuncs), информация о шаблонах (templateTypes), адреса всех глобальных переменных, вообще все функции (scriptFunctions) котрые были где-либо обявлены.
&lt;br /&gt;[19:11] &amp;lt;Black_Phoenix&amp;gt; Здесь же есть функции для получения и работы со всеми этими таблицами и информацией.
&lt;br /&gt;[19:12] &amp;lt;Black_Phoenix&amp;gt; Вообще в этом &amp;quot;движке&amp;quot; полно классных и интересных функций - все их рассматривать долго, но стоит уделить некоторым внимание. Тут есть много функций подобных RegisterObjectType - регистрация собственных типов, свойств, функций.
&lt;br /&gt;[19:13] &amp;lt;Black_Phoenix&amp;gt; Тут есть загрузка скриптовых модулей, представленная GetModule(), которая возвращает интерфейс к модулю (asIScriptModule [angelscript.h:594]), от которого позже можно получить индексы всех функций модуля, переменных, и т.п.
&lt;br /&gt;[19:14] &amp;lt;Black_Phoenix&amp;gt; Модули проименованы, и модуль без имени (вместо указателя на строку просто 0) ссылаеться на глобальный контекст - через него можно получать глобальные переменные и функции
&lt;br /&gt;[19:14] &amp;lt;Black_Phoenix&amp;gt; Кстати все функции как уже говорилось находяться в одной таблице - ScriptFunctions, и &amp;quot;индексом функции&amp;quot; возвращаемым всеми разными модулями есть именно индекс функции в этой таблице (массиве)
&lt;br /&gt;[19:15] &amp;lt;Black_Phoenix&amp;gt; А вот что нас интересует, это CreateContext(). Если брать аналогию с Lua, то здесь движок - global_State, а контекст - это собственно то, что задаёт состояние самой виртуальной машины, её выполнение.
&lt;br /&gt;[19:16] &amp;lt;Black_Phoenix&amp;gt; Контекстом выполнения являеться asIScriptContext [angelscript.h:656] - здесь есть функции для подготовки, запуска, остановки текущего выполнение, для установки аргументов передаваемых в скрипт (функцию), получения возвращённого значения, обработки исклю
&lt;br /&gt;[19:16] &amp;lt;Black_Phoenix&amp;gt; чений, и функции для отладки скрипта.
&lt;br /&gt;[19:16] &amp;lt;Black_Phoenix&amp;gt; Реальной имплементацией контекста есть asCContext [as_context.h:60].
&lt;br /&gt;[19:17] &amp;lt;Black_Phoenix&amp;gt; Тут есть прямой указатель на двоичные данные байткода, указатель на стек, указатель на текущую функцию, стек вызовов функций, данные о последнем исключении, ссылка на коллбеки (коллбек который вызываеться для каждой строки, и для исключений).
&lt;br /&gt;[19:17] &amp;lt;Black_Phoenix&amp;gt; Стек задаётся указателем на стек-фрейм функции - stackFramePointer, и указателем на сам стек - stackPointer.
&lt;br /&gt;[19:17] &amp;lt;Black_Phoenix&amp;gt; Байткод кстати достаточно интересный. Каждая инструкция виртуальной машины может быть от 1 до 18 байт в длину - в зависимости от передаваемых параметров. 
&lt;br /&gt;[19:18] &amp;lt;Black_Phoenix&amp;gt; Набор опкодов чем-то напоминает ARM архитектуру, и вообще архитектуры разных процесоров в целом. Здесь есть 174 опкода, которые есть всемя возможными комбинациями операндов
&lt;br /&gt;[19:19] &amp;lt;Black_Phoenix&amp;gt; Кстати, операции прибавления, множения и всё такое выполняються в 64 битах - если исходное значение меньше чем 64 бита, то оно должно быть приведено к 64-битному значению
&lt;br /&gt;[19:20] &amp;lt;Black_Phoenix&amp;gt; Полный список опкодов есть здесь: &lt;a href=&quot;http://www.everfall.com/paste/id.php?3kep988a627d&quot;&gt;http://www.everfall.com/paste/id.php?3kep988a627d&lt;/a&gt; (немного табуляция сломалась)
&lt;br /&gt;[19:21] &amp;lt;Black_Phoenix&amp;gt; Операндом может быть константа (передаётся в инструкции), регистр (в AS есть один регистр, называеться он &amp;quot;register1&amp;quot; или просто &amp;quot;v&amp;quot;), либо значение со stack-frame функции (тогда оно обозначается как &amp;quot;vn&amp;quot; где n это сдвиг относительно stackFramePointer).
&lt;br /&gt;[19:21] &amp;lt;Black_Phoenix&amp;gt; Кстати в AngelScript есть удобная и полезная функция, которая выводит в файл скомпилированый байткод - надо просто скомпилировать библиотеку в режиме отладки (должен существовать дефайн AS_DEBUG)
&lt;br /&gt;[19:22] &amp;lt;Black_Phoenix&amp;gt; Для примера скомпилируем вот такой код: &amp;quot;int a = 10; int b = 20; sin(a+b)&amp;quot; (если у нас уже определена функция sin(float). В результате будет сгенерирован вот такой байткод: &lt;a href=&quot;http://www.everfall.com/paste/id.php?v8e2lo7qn0ut&quot;&gt;http://www.everfall.com/paste/id.php?v8e2lo7qn0ut&lt;/a&gt; (и записан в файл)
&lt;br /&gt;[19:23] &amp;lt;Black_Phoenix&amp;gt; В первой колонке будет находиться сдвиг инструкции в байткоде (в байтах), во второй колонке размер stack frame функции (текущий), звёздочка обозначает меченые опкоды (для отладки), дальше название опкода и передаваемые параметры.
&lt;br /&gt;[19:23] &amp;lt;Black_Phoenix&amp;gt; Цифры между минусами (например &amp;quot;- 1,13 -&amp;quot;) показывают номер строки (1) и столбца (13) той части скрипта, для которой следует байткод.
&lt;br /&gt;[19:23] &amp;lt;Black_Phoenix&amp;gt; Интересный опкод SUSPEND - он вызывает коллбек для каждой строки. Вообще он не являеться необходимым - но его нельзя отключить (его добавление зашито в компилятор AngelScript).
&lt;br /&gt;[19:24] &amp;lt;Black_Phoenix&amp;gt; Без него прервать выполнение кода будет невозможно (либо пока выполнение не выйдет из блока в котором храниться байткод)
&lt;br /&gt;[19:24] &amp;lt;Black_Phoenix&amp;gt; Кстати, недавно была дискуссия о новой JIT для AngelScript - пока правда только для платформы ARM. (Её можно прочитать здесь &lt;a href=&quot;http://www.gamedev.net/community/forums/topic.asp?topic_id=537993&quot;&gt;http://www.gamedev.net/community/forums/topic.asp?topic_id=537993&lt;/a&gt;). Пока что насколько я знаю пока что нету рабочей JIT AngelScript.
&lt;br /&gt;[19:25] &amp;lt;Black_Phoenix&amp;gt; В принципе в общем здесь всё - более технические детали очень легко узнать самим. Стоит заметить что здесь тоже есть сборка мусора, которая производится периодически, и просто убирает все элементы на которых больше нету ссылок.
&lt;br /&gt;[19:26] &amp;lt;Black_Phoenix&amp;gt; А вот теперь самая полезная часть лекции - о том как собственно биндить AngelScript и Lua. Надеюсь вы читали/смотрели последнюю лекцию, и знаете основные понятия Lua и то, как она работает.
&lt;br /&gt;[19:26] &amp;lt;Black_Phoenix&amp;gt; Я постараюсь приводить примеры с комментариями для этой части лекции, возможно будут задержки (при заливании кода на everfall.com). Я уделил немного больше внимания Lua, поскольку она более популярна, и более сложна в освоении
&lt;br /&gt;[19:27] &amp;lt;Black_Phoenix&amp;gt; Начнём с простого - просто создадим стейт Lua. Для этого надо вызвать lua_open() или lua_newstate() - это одно и тоже (но lua_open(), он же luaL_newstate() подставляет malloc, free, realloc как обычные функции работы с памятью).
&lt;br /&gt;[19:28] &amp;lt;Black_Phoenix&amp;gt; У нас получаеться такой код (надо не забыть закрыть Lua, и высвободить её ресурсы): &lt;a href=&quot;http://www.everfall.com/paste/id.php?3f2uig2twqt2&quot;&gt;http://www.everfall.com/paste/id.php?3f2uig2twqt2&lt;/a&gt;
&lt;br /&gt;[19:28] &amp;lt;Black_Phoenix&amp;gt; (этот, и следущие исходные коды будут на С, я опустил заголовки и всё такое для краткости)
&lt;br /&gt;[19:29] &amp;lt;Black_Phoenix&amp;gt; Стоило бы кстати ещё загрузить стандартные библиотеки. Это можно зделать вызовом luaL_openlibs(),&amp;nbsp; передав туда наш стейт (вообще, во все функции Lua надо передавать стейт lua_State, это же С)
&lt;br /&gt;[19:30] &amp;lt;Black_Phoenix&amp;gt; Если позволите, в дальшейнем я опущу обработку ошибок от вызовов функций Lua - её можете потом добавить сами. Ну, разве что кроме только вывода ошибок в самом скрипте (об этом чуть ниже)
&lt;br /&gt;[19:30] &amp;lt;Black_Phoenix&amp;gt; Теперь у нас есть готовая среда для запуска скрипта. Для начала просто запустим некоторою строку (скажем &amp;quot;myvar = 200; print(&apos;Variable is &apos;..myvar)&amp;quot;). Для этого есть замечательная функция luaL_dostring()
&lt;br /&gt;[19:31] &amp;lt;Black_Phoenix&amp;gt; Теперь наш код выглядит так (помните, мы загрузили функцию print вместе со стандартной библиотекой): &lt;a href=&quot;http://www.everfall.com/paste/id.php?rc6659i1hciq&quot;&gt;http://www.everfall.com/paste/id.php?rc6659i1hciq&lt;/a&gt;
&lt;br /&gt;[19:31] &amp;lt;Black_Phoenix&amp;gt; Продолжим. Мы теперь можем запускать строчку - как теперь загрузить целый скрипт? Вообще, вызов luaL_dostring() это два вызова других функций - luaL_loadstring() который компилирует наш скрипт в байткод, и возвращает его на стек, и lua_pcall() для его запуска.
&lt;br /&gt;[19:32] &amp;lt;Black_Phoenix&amp;gt; Т.е. реально мы компилируем наш скрипт как одну функцию - что-то вроде &amp;quot;function script() ..сюда идёт всё что мы передали в loadstring.. end&amp;quot;, а затем её вызываем. Если мы просто вызовем loadstring, а потом очистим стек, то байткод будет убран сборщиком мусора.
&lt;br /&gt;[19:32] &amp;lt;Black_Phoenix&amp;gt; Давайте пока у нас есть просто скрипт, в котором прописана логика функции TakeDamage (получить урон) нашего персонажа (мы кстати делаем мморпг сервер).
&lt;br /&gt;[19:33] &amp;lt;Black_Phoenix&amp;gt; Она принимает количество жизней, и возвращает новое количество жизней (после получегого урона). Т.е. это просто логика поведения сервера
&lt;br /&gt;[19:33] &amp;lt;Black_Phoenix&amp;gt; Наш скрипт будет таким: &lt;a href=&quot;http://www.everfall.com/paste/id.php?yiwylnxxdfiq&quot;&gt;http://www.everfall.com/paste/id.php?yiwylnxxdfiq&lt;/a&gt;
&lt;br /&gt;[19:33] &amp;lt;Black_Phoenix&amp;gt; А вот так мы его запустим: &lt;a href=&quot;http://www.everfall.com/paste/id.php?0wx6ujrwy0tc&quot;&gt;http://www.everfall.com/paste/id.php?0wx6ujrwy0tc&lt;/a&gt; 
&lt;br /&gt;[19:34] &amp;lt;Black_Phoenix&amp;gt; И вдруг он не работает! Казалось бы что не так, ведь вроде всё правильно. Нам бы не помешал вывод ошибок в консоль - а зделать это очень просто. Lua построена так, что компилятор в случае ошибки, вернёт нам её текст на стеке.
&lt;br /&gt;[19:35] &amp;lt;Black_Phoenix&amp;gt; Мы просто должны напечатать эту строчку если значение, возвращённое luaL_dostring не ноль. Изменим нашу програму вот так: &lt;a href=&quot;http://www.everfall.com/paste/id.php?vx1odvpfar0t&quot;&gt;http://www.everfall.com/paste/id.php?vx1odvpfar0t&lt;/a&gt;
&lt;br /&gt;[19:35] &amp;lt;Black_Phoenix&amp;gt; И вот мы видим ошибку: &amp;quot;1: &apos;end&apos; expected near &apos;&amp;lt;eof&amp;gt;&apos;&amp;quot;. И тут понимаем, что забыли дописать в конец строки &amp;quot;\n&amp;quot;, ведь у нас там есть коментарий, который собой коментирует наш end. 
&lt;br /&gt;[19:36] &amp;lt;Black_Phoenix&amp;gt; Добавляем &amp;quot;\n&amp;quot;, у нас получаеться вот такой код: &lt;a href=&quot;http://www.everfall.com/paste/id.php?67piuhoqn8wd&quot;&gt;http://www.everfall.com/paste/id.php?67piuhoqn8wd&lt;/a&gt; и он успешно запускаеться.
&lt;br /&gt;[19:37] &amp;lt;Black_Phoenix&amp;gt; Пора приступать к самому движку нашей ММОРПГ, а именно - наш персонаж должен получать урон. Скрипт уже обрабатывает наше событие, осталось его только вызвать.
&lt;br /&gt;[19:38] &amp;lt;Black_Phoenix&amp;gt; Для этого мы хотим получить функцию TakeDamage из глобальной таблицы (а наша функция, заметьте глобальная). В Lua для этого используется вызов lua_getglobal который возвращает указатель функции на стек (делает PUSH).
&lt;br /&gt;[19:39] &amp;lt;Black_Phoenix&amp;gt; Дальше запихнём наши текущие жизни на стек через функцию lua_pushinteger (есть такие-же функции для всех типов Lua, кроме таблиц), и вызовем получение урона (у нас на стеке всё уже как надо, просто запускаем интерпретатор через lua_call).
&lt;br /&gt;[19:39] &amp;lt;Black_Phoenix&amp;gt; Не забудем правильно указать количество аргументов, и результатов которые мы ждём, и потом не забудем забрать результат со стека.
&lt;br /&gt;[19:39] &amp;lt;Black_Phoenix&amp;gt; Получение результата выполняеться функциями lua_tonumber, lua_tostring, и т.д. Результат будет нас ждать начиная с текущего положения на стеке.
&lt;br /&gt;[19:40] &amp;lt;Black_Phoenix&amp;gt; (оно правильно устанавливаеться вызваной функцией, переданые параметры будут убраны)
&lt;br /&gt;[19:41] &amp;lt;Black_Phoenix&amp;gt; Вот такой у нас код получился: &lt;a href=&quot;http://www.everfall.com/paste/id.php?i2qpb2wdla4u&quot;&gt;http://www.everfall.com/paste/id.php?i2qpb2wdla4u&lt;/a&gt;
&lt;br /&gt;[19:41] &amp;lt;Black_Phoenix&amp;gt; Запускаем, видим что жизней стало 75. Повод отпраздновать! Теперь наша ММОРПГ достигла версии 0.99 BETA
&lt;br /&gt;[19:42] &amp;lt;Black_Phoenix&amp;gt; Это классно, но мало. Хочется что-бы скрипт мог вызывать наши функции (функции написаные на С). Зделаем функцию на С - RandomDamage, которая вернёт случайное повреждение для нашего героя.
&lt;br /&gt;[19:43] &amp;lt;Black_Phoenix&amp;gt; Любая С функция вызываемая Lua должна быть за таким шаблоном: &amp;quot;int &amp;lt;function name&amp;gt;(lua_State *L)&amp;quot;, т.е. нам надо всегда возвращать целое, и принимать указатель на стейт. Возвращаемое значение - код ошибки (если всё хорошо, то это будет 1).
&lt;br /&gt;[19:43] &amp;lt;Black_Phoenix&amp;gt; Итак, мы написали нашу функцию (она у нас будет принимать два значения - нижний и верхний порог случайного повреждения). Не забываем что параметры следуют за самой функцией, а при вызове функции вершина стека указывает на первый аргумент (на стеке).
&lt;br /&gt;[19:44] &amp;lt;Black_Phoenix&amp;gt; Зарегистрировать функцию просто - есть удобная функция lua_register().
&lt;br /&gt;[19:45] &amp;lt;Black_Phoenix&amp;gt; У нас получился вот такой код (не забудем поправить скрипт для вызова нашей С функции): &lt;a href=&quot;http://www.everfall.com/paste/id.php?imu8u3iqifrj&quot;&gt;http://www.everfall.com/paste/id.php?imu8u3iqifrj&lt;/a&gt;
&lt;br /&gt;[19:45] &amp;lt;Black_Phoenix&amp;gt; Всё хорошо, но дедлайн нашей ММОРПГ близиться, и пора бы уже выделить героя в отдельный обьект. В Lua это делается достаточно легко - мы просто зделаем таблицу, в которой будут храниться жизни и броня героя (как-бы обьект).
&lt;br /&gt;[19:46] &amp;lt;Black_Phoenix&amp;gt; Кстати, размер скрипта растёт, пора бы его зделать в отдельном файле. Создадим файл &amp;quot;rpg.lua&amp;quot;, и засунем туда вот такой код (инициализация игрока, и его методы): &lt;a href=&quot;http://www.everfall.com/paste/id.php?0zat0o73e5xt&quot;&gt;http://www.everfall.com/paste/id.php?0zat0o73e5xt&lt;/a&gt;
&lt;br /&gt;[19:47] &amp;lt;Black_Phoenix&amp;gt; Заметьте обьявление функций героя - если мы пишем так, как в скрипте, то мы добавляем функции в таблицу &amp;quot;HERO&amp;quot;. Это будет &amp;quot;базовый класс&amp;quot; нашего героя. Мы также зделали функцию &amp;quot;utilNewHero&amp;quot; которая создаст нового героя (возможно с параметрами)
&lt;br /&gt;[19:47] &amp;lt;Black_Phoenix&amp;gt; Создавать героя мы будем из нашей програмы - а затем менять его характеристики и вызывать его функции.
&lt;br /&gt;[19:47] &amp;lt;Black_Phoenix&amp;gt; Итак, сначала мы вызовем utilNewHero. Потом мы инициализируем нашу таблицу (вызовем для неё функцию Initialize) - а дальше просто будем работать с нашим героем.
&lt;br /&gt;[19:48] &amp;lt;Black_Phoenix&amp;gt; Кстати, вызов у нас непростой - здесь мы должны передать нашего героя в функцию - так, что-бы работал SELF.
&lt;br /&gt;[19:49] &amp;lt;Black_Phoenix&amp;gt; Для того что-бы это работало (а это эквивалентно вызову some_hero:Initialize(..)) нам надо будет передать нашу таблицу героя как первый параметр функции
&lt;br /&gt;[19:50] &amp;lt;Black_Phoenix&amp;gt; Т.е. some_hero:Initialize() - тоже самое что и Initialize(some_hero,...), только компилятор Lua об этом знает (по тому, как была определена функция)
&lt;br /&gt;[19:50] &amp;lt;Black_Phoenix&amp;gt; Сейчас я покажу код, и детально опишу что мы делаем с нашим героем. Вот такой код у нас получился: &lt;a href=&quot;http://www.everfall.com/paste/id.php?h0msm6bef8rq&quot;&gt;http://www.everfall.com/paste/id.php?h0msm6bef8rq&lt;/a&gt;
&lt;br /&gt;[19:51] &amp;lt;Black_Phoenix&amp;gt; (Я буду ссылаться на строки файла, они отмечены по ссылке)
&lt;br /&gt;[19:52] &amp;lt;Black_Phoenix&amp;gt; Для начала вызовем создание нашего героя - utilNewHero. Вызов такой как мы раньше видели, просто получаем функцию из глобальной таблицы, и вызываем её через lua_call
&lt;br /&gt;[19:53] &amp;lt;Black_Phoenix&amp;gt; Хочу заметить, что адресация стека, которая используеться в API lua достаточно странная. Здесь -1 это текущий элемент на стеке, -2 это предыдущий, -3 это ещё раньше...
&lt;br /&gt;[19:53] &amp;lt;Black_Phoenix&amp;gt; А вот положительные значения - это сдвиг относительно указателя base. 1 это base+1, и так далее
&lt;br /&gt;[19:54] &amp;lt;Black_Phoenix&amp;gt; Также есть специальные индексы - индексы из глобальной таблицы, и прочие. Но они нас не интересуют
&lt;br /&gt;[19:55] &amp;lt;Black_Phoenix&amp;gt; Итак, строчки 29-30 это создание героя. Мы говорим Lua что хотим передать 0 параметров, и получить 1 результат (таблица героя). Наш герой будет на стеке с адресом -1
&lt;br /&gt;[19:56] &amp;lt;Black_Phoenix&amp;gt; Дальше мы хотим вызвать somehero:Initialize(..) - а это вызов HERO.Initialize(somehero,...). В строчке 35 мы получаем указатель на таблицу-базовый класс HERO
&lt;br /&gt;[19:56] &amp;lt;Black_Phoenix&amp;gt; Теперь по адресу -1 таблица HERO, по адресу -2 таблица героя
&lt;br /&gt;[19:56] &amp;lt;Black_Phoenix&amp;gt; В строчке 36 мы получаем поле из таблицы - HERO.Initialize.
&lt;br /&gt;[19:57] &amp;lt;Black_Phoenix&amp;gt; Теперь по адресу -1 находиться функция HERO.Initialize (её туда запихнул вызов lua_getfield), по адресу -2 - HERO, по адресу -3 - таблица героя
&lt;br /&gt;[19:57] &amp;lt;Black_Phoenix&amp;gt; нам больше таблица HERO не нужна, убираем её со стека на строчке 37
&lt;br /&gt;[19:58] &amp;lt;Black_Phoenix&amp;gt; Теперь таблица героя передвинулась на позицию -2. Не забывайте что нам её надо передать первым параметром (а щас на стеке идёт сначала таблица, потом функция)
&lt;br /&gt;[19:58] &amp;lt;Black_Phoenix&amp;gt; Поэтому вызовом lua_pushvalue (фактически скопировать значение) мы копируем ссылку на таблицу, и заносим на стек
&lt;br /&gt;[19:59] &amp;lt;Black_Phoenix&amp;gt; За ним мы запихиваем жизни героя и его имя (так, как надо для вызова инициализации). Наш стек выглядит так: (-1) &amp;quot;John Jackson&amp;quot; | (-2) 125 | (-3) таблица героя | (-4) HERO.Initialize | (-5) таблица героя
&lt;br /&gt;[19:59] &amp;lt;Black_Phoenix&amp;gt; Мы вызваем функцию, и наш герой готов к бою
&lt;br /&gt;[20:00] &amp;lt;Black_Phoenix&amp;gt; После вызова функции со стека будет убрано всё, до указателя функции (и он тоже)
&lt;br /&gt;[20:00] &amp;lt;Black_Phoenix&amp;gt; Т.е. у нас будет стек такой: (-1) таблица героя (и это всё)
&lt;br /&gt;[20:01] &amp;lt;Black_Phoenix&amp;gt; Мы получаем &amp;quot;health&amp;quot; из таблицы нашего героя, а потом и &amp;quot;name&amp;quot;. Заметьте как адрес таблицы меняеться после добавления новых значений на стек
&lt;br /&gt;[20:02] &amp;lt;Black_Phoenix&amp;gt; Мы печатаем информацию, и правильно получаем &amp;quot;Our heroes life is 125 percent, our hero is Mr. John Jackson&amp;quot;. Не забудьте убрать значения со стека, иначе они там и остануться! Для этого надо вызвать lua_pop, аргументом есть количество значений которые надо убрать
&lt;br /&gt;[20:03] &amp;lt;Black_Phoenix&amp;gt; Пора в битву - в строчках 58-60 мы снова получаем указатель, теперь на Hero.TakeDamage; также как на строчках 35-37
&lt;br /&gt;[20:03] &amp;lt;Black_Phoenix&amp;gt; Мы просто запихиваем таблицу героя на стек, и вызываем нашу функцию. Наш герой потерпел урон, и мы это проверим строками 67-71 (тоже самое что раньше)
&lt;br /&gt;[20:04] &amp;lt;Black_Phoenix&amp;gt; Нам правильно будет указано сообщение &amp;quot;Mr. John Jackson got hurt! :( His life is now 123 %%&amp;quot;. А наша таблица всё ещё находиться на стеке!
&lt;br /&gt;[20:05] &amp;lt;Black_Phoenix&amp;gt; Пора бы её сохранить в глобальной таблице - для этого есть (моя персонально любимая функция) lua_setglobal - она сохраняет текущий элемент в вершине стека в глобальную переменну
&lt;br /&gt;[20:05] &amp;lt;Black_Phoenix&amp;gt; Поскольку мы убрали &amp;quot;health&amp;quot; и &amp;quot;name&amp;quot; со стека, в вершине будет наша таблица - и она сохраниться в переменную &amp;quot;johnhero&amp;quot;
&lt;br /&gt;[20:06] &amp;lt;Black_Phoenix&amp;gt; Вызов lua_setglobal зделает POP - и уберёт текущее значение со стека. А нам John ещё нужен, поэтому мы просто заново получим его из глобальной таблицы (строчка 79) - и он будет снова на стеке.
&lt;br /&gt;[20:07] &amp;lt;Black_Phoenix&amp;gt; На строках 81-82 указано как можно не убирая значение со стека добавить его в глобальную таблицу - просто банально продублировать. Теперь у нас есть 2 ссылки на Джона - johnhero и john_is_the_hero
&lt;br /&gt;[20:08] &amp;lt;Black_Phoenix&amp;gt; Проверим что обе таблицы - это просто две ссылки на одну и туже таблицу. Просто запустим простой скрипт - поменяем жизни в одной таблице и увидим что они меняються в другой (строки 88-90)
&lt;br /&gt;[20:09] &amp;lt;Black_Phoenix&amp;gt; Наш сервер почти готов. Теперь вам должно быть легче работать с Lua. Единственное что я ещё хочу добавить это то, как можно создавать новые таблицы из C кода (или менять уже существующие)
&lt;br /&gt;[20:10] &amp;lt;Black_Phoenix&amp;gt; Допустим мы хотим програмно создать нового героя. Для этого мы сначала вывовем &amp;quot;lua_newtable(L)&amp;quot; - создание новой таблицы, и PUSH её на стек.
&lt;br /&gt;[20:11] &amp;lt;Black_Phoenix&amp;gt; Для редактирования таблицы теперь есть два пути. Первый путь добавить/изменить значение которое уже лежит на стеке с заданым ключём - через lua_setfield
&lt;br /&gt;[20:11] &amp;lt;Black_Phoenix&amp;gt; Для этого надо что-бы в текущей позиции на стеке была таблица, и нужно указать индекс добавляемого элемента. Например:
&lt;br /&gt;[20:12] &amp;lt;Black_Phoenix&amp;gt; lua_pushinteger(L,123); lua_newtable(L); lua_setfield(L,-2,&amp;quot;my_integer&amp;quot;); //целое число находиться в позиции -2, таблица - в -1
&lt;br /&gt;[20:13] &amp;lt;Black_Phoenix&amp;gt; Есть второй, более красивый способ - использование lua_rawset(). Эта функция принимает индекс таблицы которую мы редактируем, и запихивает туда значения заданые парой ключ-значение которые находяться сейчас на стеке
&lt;br /&gt;[20:13] &amp;lt;Black_Phoenix&amp;gt; Создать нового героя для нашего мморпг сервера мы могли бы вот так:
&lt;br /&gt;[20:13] &amp;lt;Black_Phoenix&amp;gt; lua_newtable(L);
&lt;br /&gt;[20:14] &amp;lt;Black_Phoenix&amp;gt; lua_pushstring(L,&amp;quot;health&amp;quot;); lua_pushnumber(L,125); lua_rawset(L,-3); //-3 = идекс таблицы, щас у нас два значения в таком порядке: ключ - значение
&lt;br /&gt;[20:14] &amp;lt;Black_Phoenix&amp;gt; lua_pushstring(L,&amp;quot;name&amp;quot;); lua_pushstring(L,&amp;quot;Jack Johnson&amp;quot;); lua_rawset(L,-3);
&lt;br /&gt;[20:15] &amp;lt;Black_Phoenix&amp;gt; после этого в положении -1 (текущем положении стека) у нас будет наш новый герой (lua_rawset() делает POP два раза)
&lt;br /&gt;[20:15] &amp;lt;Black_Phoenix&amp;gt; По биндингу Lua это пока всё. Планировалось ещё рассмотреть сохранение состояния скриптов Lua - но это будет в отдельной лекции.
&lt;br /&gt;[20:16] &amp;lt;Black_Phoenix&amp;gt; Теперь кратко о биндинге AngelScript - я покажу только основы, а дальше очень легко разобраться самому - интерфейсы достаточно понятны и назначение функций очевидно.
&lt;br /&gt;[20:17] &amp;lt;Black_Phoenix&amp;gt; Для начала нам просто надо создать движок: asCreateScriptEngine(). После этого AngelScript уже будет готов к выполнению скриптов. Наш код будет выглядеть так: &lt;a href=&quot;http://www.everfall.com/paste/id.php?jrf5pr0gcxix&quot;&gt;http://www.everfall.com/paste/id.php?jrf5pr0gcxix&lt;/a&gt;
&lt;br /&gt;[20:18] &amp;lt;Black_Phoenix&amp;gt; Нам скорее всего захочеться также смотреть ошибки скрипта. Это очень просто - нужно просто установить коллбек который будет вызываться при ошибке. AS передаёт структуру, которая содержит текст ошибки, и её позицию (строка, столбец).
&lt;br /&gt;[20:19] &amp;lt;Black_Phoenix&amp;gt; Вот пример установки такого коллбека: &lt;a href=&quot;http://www.everfall.com/paste/id.php?jf3pvkr2qgkl&quot;&gt;http://www.everfall.com/paste/id.php?jf3pvkr2qgkl&lt;/a&gt;
&lt;br /&gt;[20:20] &amp;lt;Black_Phoenix&amp;gt; И наконец биндинг С функций - тут с этим очень просто. Нужно просто зарегистрировать нашу функцию как функцию глобальную (или функцию модуля, класса...).
&lt;br /&gt;[20:21] &amp;lt;Black_Phoenix&amp;gt; Мы передаём сигнатуру функции: &amp;quot;&amp;lt;возвращаемый тип&amp;gt; &amp;lt;название функции&amp;gt;(&amp;lt;тип 1&amp;gt;, &amp;lt;тип 2&amp;gt;, ..)&amp;quot;, указатель на точку входа, и параметры которые нужно передавать и возвращать.
&lt;br /&gt;[20:22] &amp;lt;Black_Phoenix&amp;gt; Есть специальный макрос asFUNCTIONPR который правильно скастует вашу функцию так, как нужно для AngelScript. Получаеться такой код: &lt;a href=&quot;http://www.everfall.com/paste/id.php?9an52g7stcyy&quot;&gt;http://www.everfall.com/paste/id.php?9an52g7stcyy&lt;/a&gt;
&lt;br /&gt;[20:23] &amp;lt;Black_Phoenix&amp;gt; Если мы захотим запускать из файла, нам надо будет просто передать текст файла в ExecuteString, либо зделать свой контекст (CreateContext()), скомпилировать туда исходный код, и запустить.
&lt;br /&gt;[20:23] &amp;lt;Black_Phoenix&amp;gt; Это пока всё, можно задавать вопросы.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/lecture36?page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=4446</guid>
  <pubDate>Sat, 25 Jul 2009 17:37:23 GMT</pubDate>
  <title>Лекция #36. Обзор VM скриптовых языков (Lua, AngelScript). Часть 1. [Лектор - Black_Phoenix]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=4446</link>
  <category>angelscript</category>
  <category>Lua</category>
  <category>vm</category>
  <description>
&lt;p&gt;Лекция Black_Phoenix с обзором VM скриптовых языков Lua и AngelScript. Часть первая.
&lt;p&gt;[20:01:32] &amp;lt;Black_Phoenix&amp;gt; Короче я просто програмист, занимаюсь много чем, в т.ч. виртуальными машинами. Написал VM эмулятор PII, также специальную VM &amp;quot;ZCPU&amp;quot; для одной игровой модификации (внутриигровой микропроцессор, для цифровых схем).
&lt;br /&gt;[20:01:54] &amp;lt;Black_Phoenix&amp;gt; На данный момент я пишу ОС которая полностью основана на виртуальной машине, но это не тема этой лекции
&lt;br /&gt;[20:02:19] &amp;lt;Black_Phoenix&amp;gt; В этой лекции будет рассмотрено общее сравнение AngelScript и Lua (как кто-то попросил), а также небольшой глубокий экскурс в то, как они работают (т.е. сами вирутальные машины, интерпретаторы).
&lt;br /&gt;[20:02:52] &amp;lt;Black_Phoenix&amp;gt; Перед началом экскурса в сами VM рекомендуеться достать исходные коды [AngelScript 2.16.3] и [Lua 5.1.4]. Ссылки (действительная на момент лекции): &lt;a href=&quot;http://www.angelcode.com/angelscript/sdk/files/angelscript_2.16.3.zip&quot;&gt;http://www.angelcode.com/angelscript/sdk/files/angelscript_2.16.3.zip&lt;/a&gt; &lt;a href=&quot;http://www.lua.org/ftp/lua-5.1.4.tar.gz&quot;&gt;http://www.lua.org/ftp/lua-5.1.4.tar.gz&lt;/a&gt;
&lt;br /&gt;[20:03:11] &amp;lt;Black_Phoenix&amp;gt; Я буду ссылаться на файлы (в принципе пока нужна только Луа)
&lt;br /&gt;[20:03:36] &amp;lt;Black_Phoenix&amp;gt; В этой части лекции будет общее описание Lua и AngelScript, а также детальное описание движка Lua. Во второй части будет описание движка AngelScript, и информация о том, как их надо биндить (и возможно некоторые малоизвестные фичи).
&lt;br /&gt;[20:04:10] &amp;lt;Black_Phoenix&amp;gt; Итак, сначала общее. И AngelScript и Lua являються скриптовыми языками для использования в программах и играх. Lua была создана в 1993 году, и на данный момент используеться в очень многих проектах. AngelScript был создан в 2003 году, и пока я не встречал прое
&lt;br /&gt;[20:04:11] &amp;lt;Black_Phoenix&amp;gt; ктов которые его используют (т.е. лично не встречал).
&lt;br /&gt;[20:04:40] &amp;lt;Black_Phoenix&amp;gt; Для начала синтаксис: Lua использует свой синтаксис. Синтаксис AngelScript чем-то похож на синтаксис С++, он также поддерживает классы и наследование.
&lt;br /&gt;[20:04:56] &amp;lt;Black_Phoenix&amp;gt; Lua написана на чистом С, AngelScript написан на С++, его код достаточно объектно-ориентированый.
&lt;br /&gt;[20:05:21] &amp;lt;Black_Phoenix&amp;gt; (лично мне больше нравиться как написан AS, хотя там много C++-изма)
&lt;br /&gt;[20:05:41] &amp;lt;Black_Phoenix&amp;gt; В обоих языках пошаговый интерпретатор. Есть возможность отлаживать построчно, компилировать и запускать байткод. 
&lt;br /&gt;[20:05:47] &amp;lt;_ShaMan_&amp;gt; remark: список проектов, которые используют AngelScript, можно увидеть здесь: &lt;a href=&quot;http://www.angelcode.com/angelscript/users.asp&quot;&gt;http://www.angelcode.com/angelscript/users.asp&lt;/a&gt;
&lt;br /&gt;[20:06:06] &amp;lt;Black_Phoenix&amp;gt; В обоих движках есть поддержка coroutines (псевдо-паралельного выполнения), и поддержка multithreading (мультипоточности). Вообще в AngelScript несколько лучше реализована загрузка и сохранение байткода - более очевидно
&lt;br /&gt;[20:06:37] &amp;lt;Black_Phoenix&amp;gt; В второй части лекции (которая будет через неделю) я постараюсь показать как это делать с Lua (без сторонних утилит :) )
&lt;br /&gt;[20:07:05] &amp;lt;Black_Phoenix&amp;gt; Lua - стековая виртуальная машина (хотя формально регистровая), AngelScript - регистровая (почти).
&lt;br /&gt;[20:07:31] &amp;lt;Black_Phoenix&amp;gt; Что важно, Lua есть почти для всех языков и платформ которые вам встретяться. С код достаточно легко компилируеться везде, и единственная привязка Lua к ОС это функции перераспределения памяти (не считая дополнительных библиотек).
&lt;br /&gt;[20:07:41] &amp;lt;Black_Phoenix&amp;gt; AngelScript есть на всех современных платформах (игровых консолях, разных ОС, также на iPhone). Известно что он компилируеться под MSVC++, GNUC, MinGW, DJGPP.
&lt;br /&gt;[20:08:06] &amp;lt;Black_Phoenix&amp;gt; Вообще насколько я знаю поддержка iPhone вам не нужна будет, на AppStore не принимаються виртуальные машины
&lt;br /&gt;[20:08:46] &amp;lt;Black_Phoenix&amp;gt; Lua требует биндинга каждой функции по своему, AS работает с функциями без биндинга (надо только сообщить движку о них). Lua использует свой стек для передачи параметров - и туда-же нужно их возвращать. AS вызывает функции по stdcall (точнее она сама 
&lt;br /&gt;[20:08:47] &amp;lt;Black_Phoenix&amp;gt; подбирает способ вызова совместимый).
&lt;br /&gt;[20:09:21] &amp;lt;Black_Phoenix&amp;gt; Достаточно субьективно скажу, что Lua быстрее чем AS - здесь overhead при вызове функций, а также в garbage collectore меньше. Но в принципе по тестам они более-менее на одном уровне (по тому что я видел AS проигрывает Lua всего не более чем на 10%)
&lt;br /&gt;[20:09:51] &amp;lt;Black_Phoenix&amp;gt; Вообще при правильной архитектуре движка скорость скриптового движка не должна иметь значения
&lt;br /&gt;[20:10:11] &amp;lt;Black_Phoenix&amp;gt; В лекции я буду ссылаться на код вот так: [имя файла:номер строки], например [lvm.c:64]. В этой части пока только на исходники Lua
&lt;br /&gt;[20:10:48] &amp;lt;Black_Phoenix&amp;gt; Используеться такая терминология:
&lt;br /&gt;[20:11:04] &amp;lt;Black_Phoenix&amp;gt; (момент, я залью на everfall.com)
&lt;br /&gt;[20:11:27] &amp;lt;Black_Phoenix&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?pt9ys4s20uk0&quot;&gt;http://www.everfall.com/paste/id.php?pt9ys4s20uk0&lt;/a&gt; вот
&lt;br /&gt;[20:11:47] &amp;lt;Black_Phoenix&amp;gt; Это кроме основных понятий которые должны быть знакомы. Почти всё есть на википедии (я проверял)
&lt;br /&gt;[20:12:08] &amp;lt;Black_Phoenix&amp;gt; Итак, Lua. В ядре луа сидит Lua virtual machine (LVM). LVM - формально регистровая VM, но вам врут, она не регистровая (регистрами там и не пахнет) - она всё ещё стековая.
&lt;br /&gt;[20:12:27] &amp;lt;Black_Phoenix&amp;gt; Опкоды LVM могут читать и писать на стек (это задаёться смещением), а также со списка констант который существует у каждой функции.
&lt;br /&gt;[20:13:05] &amp;lt;Black_Phoenix&amp;gt; В принципе она регистровая - здесь напрямую нету операций PUSH/POP для изменения стека, но тем не менее стек - основная структура данных, скелет Луа
&lt;br /&gt;[20:13:27] &amp;lt;Black_Phoenix&amp;gt; Нашу экскурсию мы будет начинать с [lua.h:110]. В этом месте определены основные функции - lua_newstate(...) lua_close(...), создание стейта для виртуальной машины.
&lt;br /&gt;[20:13:50] &amp;lt;Black_Phoenix&amp;gt; Для создания LVM вы должны их вызвать (они вообще вызываються автоматом при вызове lua_open(). Фактически lua_open() это просто вызов lua_newstate(..)).
&lt;br /&gt;[20:14:08] &amp;lt;Black_Phoenix&amp;gt; Итак, что такое стейт виртуальной машины? Это структура данных которая полностью определяет текущее состояние VM.
&lt;br /&gt;[20:14:30] &amp;lt;Black_Phoenix&amp;gt; В LVM определение стейта (это struct) содержиться в файле [lstate.h:100] (вообще строго говоря в LVM существует два стейта - глобальный и per-thread стейт).
&lt;br /&gt;[20:15:03] &amp;lt;Black_Phoenix&amp;gt; При вызове lua_newstate(...) будет создан новый lua_State (локальный/per-thread стейт, [lstate.h:100]), а также будет создан глобальный стейт (global_State, [lstate.h:68]). Далее для каждого нового треда LVM будет создаваться новый lua_State.
&lt;br /&gt;[20:15:28] &amp;lt;Black_Phoenix&amp;gt; Вообще global_State должен быть только одним - иметь их больше чем один смысла не имеет.
&lt;br /&gt;[20:15:58] &amp;lt;Black_Phoenix&amp;gt; SIDE-NOTE: луа поддерживает мультипоточность - при этом вы должны совершить такие действия: создать глобальный стейт LVM и создать главный поток (lua_newstate() или lua_open(), тоже самое). Дальше средствами ОС вы создаёте ещё один поток, в котором вызываете
&lt;br /&gt;[20:15:59] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp; lua_newthread(), и запускаете скрипт.
&lt;br /&gt;[20:16:44] &amp;lt;Black_Phoenix&amp;gt; Сама Lua - полностью threadsafe, насколько я смотрел везде в критических местах есть защита от конкуренции нескольких потоков
&lt;br /&gt;[20:16:56] &amp;lt;Black_Phoenix&amp;gt; В результате у вас у каждого потока будет lua_State, и собственно свой статус LVM. Теперь использование обоих потоков идёт аналогично и паралельно.
&lt;br /&gt;[20:17:15] &amp;lt;Black_Phoenix&amp;gt; Вам возможно надо будет создать свой враппер/биндинг, поскольку в стандартной Lua нету библиотек для мультипоточности (т.е. что-бы это можно было вызывать из скриптов).
&lt;br /&gt;[20:17:45] &amp;lt;Black_Phoenix&amp;gt; Все потоки могут вызывать глобальные функции друг друга, почему будет сказано потом.
&lt;br /&gt;[20:18:10] &amp;lt;Black_Phoenix&amp;gt; Итак, теперь кратко о том, что же задают global_State и lua_State. Если вы использовали LVM/Lua то вы заметили, что почти в каждую функцию надо передавать &amp;quot;lua_State *L&amp;quot; - указатель на per-thread стейт (далее - просто &amp;quot;стейт луа&amp;quot;).
&lt;br /&gt;[20:18:53] &amp;lt;Black_Phoenix&amp;gt; Итак, lua_State ([lstate.h:100]) содержит в себе такие поля: &lt;a href=&quot;http://www.everfall.com/paste/id.php?1ng1yo9ft9n6&quot;&gt;http://www.everfall.com/paste/id.php?1ng1yo9ft9n6&lt;/a&gt; (желательно ознакомиться)
&lt;br /&gt;[20:19:26] &amp;lt;Black_Phoenix&amp;gt; Это всё задаёт состояние скрипта, и упс, я забыл туда про garbage collector дописать :)
&lt;br /&gt;[20:20:11] &amp;lt;Black_Phoenix&amp;gt; Про global_State ([lstate.h:68]) я расскажу кратко (он в принципе менее интересен чем lua_State): &lt;a href=&quot;http://www.everfall.com/paste/id.php?0qak518m03km&quot;&gt;http://www.everfall.com/paste/id.php?0qak518m03km&lt;/a&gt;
&lt;br /&gt;[20:20:39] &amp;lt;Black_Phoenix&amp;gt; Он менее интересен, в основном он только следит за всеми ресурсами и мусоросборщиком.
&lt;br /&gt;[20:21:40] &amp;lt;Black_Phoenix&amp;gt; В LVM есть несколько базовых типов - они все захардкожены прямо в виртуальную машину. На данный момент они такие [lua.h:74]: &lt;a href=&quot;http://www.everfall.com/paste/id.php?5h2cpg36h0yq&quot;&gt;http://www.everfall.com/paste/id.php?5h2cpg36h0yq&lt;/a&gt;
&lt;br /&gt;[20:22:16] &amp;lt;Black_Phoenix&amp;gt; (различие между LUA_TLIGHTUSERDATA и LUA_TUSERDATA в том, как будут сравниваться два обьекта)
&lt;br /&gt;[20:23:10] &amp;lt;Black_Phoenix&amp;gt; LVM теоретически позволяет добавлять новые типы (надо только создать #define-ы, и функции для работы с типом, возможно поправить парсер), но я ещё не видел что-бы их добавляли прямо в VM
&lt;br /&gt;[20:23:28] &amp;lt;Black_Phoenix&amp;gt; Для типов подобных vector, color обычная таблица должна подойти
&lt;br /&gt;[20:24:03] &amp;lt;Black_Phoenix&amp;gt; Внутри LVM все типы называються общим именем TValue - типизированое значение. Оно задаёться структурой lua_TValue [lobject.h:73], которая содержит в себе числовой аналог этого типа (lua_Number), тип этого значения (например LUA_TTABLE), ссылку на свой обьект (GCObject), а 
&lt;br /&gt;[20:24:03] &amp;lt;Black_Phoenix&amp;gt; также указатель на двоичные данные.
&lt;br /&gt;[20:24:42] &amp;lt;Black_Phoenix&amp;gt; lua_Number - это обычно 64-битный флоат, если не ошибаюсь. Но это можно перенастроить
&lt;br /&gt;[20:26:00] &amp;lt;Black_Phoenix&amp;gt; Стек в LVM - это просто стек из этих lua_TValue. base, top, stack, и другие в стейте lua_State - всё это указатели на элемент на стеке, которые имеют тип StkId [lobject.h:193].
&lt;br /&gt;[20:26:24] &amp;lt;Black_Phoenix&amp;gt; StkId - не более чем просто указатель на lua_TValue, и так-же определяеться (как *TValue)
&lt;br /&gt;[20:27:01] &amp;lt;Black_Phoenix&amp;gt; При создании локального стейта создаёться стек (stack_init(...) в f_luaopen(...) [lstate.c:70]) размером BASE_STACK_SIZE + EXTRA_STACK_SIZE (обычно это 40 записей), и вершина стека устанавливаеться в его начало.
&lt;br /&gt;[20:27:59] &amp;lt;Black_Phoenix&amp;gt; Щас я попробую показать картинку того, куда указывают эти указатели
&lt;br /&gt;[20:28:48] &amp;lt;Black_Phoenix&amp;gt; Так, картинка будет чуть позже
&lt;br /&gt;[20:29:19] &amp;lt;Black_Phoenix&amp;gt; Итак, что происходит со стеком при вызове функции? Вызов любой функции Lua (не С) выполняеться вызовом lua_call(...) [lapi.c:776].
&lt;br /&gt;[20:29:24] &amp;lt;Black_Phoenix&amp;gt; При вызове функции требуеться указать количество параметров которые передаються, и количество параметров которые ожидаються на выходе.
&lt;br /&gt;[20:29:46] &amp;lt;Black_Phoenix&amp;gt; SIDE-NOTE: вызов C-функции выполняеться вызовом lua_pcall(...) - protected call, который защищает стек Lua от &amp;quot;повреждения&amp;quot;. Оба способа вызова, как будет щас показано, почти одно и то-же.
&lt;br /&gt;[20:31:03] &amp;lt;Black_Phoenix&amp;gt; Все аргументы функции находяться на стеке, сразу после самой функции (которая тоже запихиваеться на стек). Stack-frame формально начинаеться как-раз с самой функции (вообще реально запихиваеться только указатель на функцию)
&lt;br /&gt;[20:32:09] &amp;lt;Black_Phoenix&amp;gt; При возвращении из функции все результаты будут на стеке, начиная с начала stack frame функции (обычно). Агрументы и результаты находяться на стеке в порядке pusha на стек.
&lt;br /&gt;[20:32:47] &amp;lt;Black_Phoenix&amp;gt; Результаты могут находиться и за аргументами (точнее оно так почти всегда), реально при выходе из функции она сама указывает где на стеке результаты
&lt;br /&gt;[20:33:05] &amp;lt;Black_Phoenix&amp;gt; Результаты - это то что возвращаеться return-ом, и может быть несколько (return x,y,z)
&lt;br /&gt;[20:33:37] &amp;lt;Black_Phoenix&amp;gt; lua_call(...) проводит нужные проверки, и запускает виртуальную машину если вызываемая функция - не C функция. Это проверяеться вызовом luaD_precall(...) [ldo.c:264] - по сути это самая важная часть LVM.
&lt;br /&gt;[20:34:09] &amp;lt;Black_Phoenix&amp;gt; luaD_precall(...) запихивает новый CallInfo на стек вызваных функций, сохраняет текущий PC, запоминает текущее состояние стека.
&lt;br /&gt;[20:34:31] &amp;lt;Black_Phoenix&amp;gt; (PC - указатель инструкций, здесь он прямо указывает на двоичные данные, где находиться следущая инструкция)
&lt;br /&gt;[20:34:55] &amp;lt;Black_Phoenix&amp;gt; Если функция - С-функция, то проверяем что на стеке есть минимум места (равный LUA_MINSTACK значений), и вызываем функцию. Поскольку эта лекция - только общий обзор внутренностей, то какие именно функции здесь используються останеться тайной (сам
&lt;br /&gt;[20:34:55] &amp;lt;Black_Phoenix&amp;gt; и посмотрите по [ldo.c:307]).
&lt;br /&gt;[20:34:58] &amp;lt;Black_Phoenix&amp;gt; сами*
&lt;br /&gt;[20:35:44] &amp;lt;Black_Phoenix&amp;gt; SIDE-NOTE: в Lua 5.1.4 есть глюк, который позволяет C-функции нарушить стек вернув слишком много результатов. Для этого есть патч на оффициальном сайте.
&lt;br /&gt;[20:35:57] &amp;lt;Black_Phoenix&amp;gt; Если же это функция Lua, то будет подготовлен вызов функции (и возможно будет вызов hook-функции, если такова была установлена).
&lt;br /&gt;[20:36:23] &amp;lt;Black_Phoenix&amp;gt; Если вы внимательно слушали (читали), то заметили что я сначала сказал что стек создаётся размером в 40 записей. Но ведь можно делать огромную рекурсию - как это происходит?
&lt;br /&gt;[20:36:53] &amp;lt;Black_Phoenix&amp;gt; На самом деле, если посмотреть на то, как ведёт себя стек, можно заметить, что при достижении 50% заполнености стека его размер будет увеличен на 200%, пока этого нельзя будет зделать, или пока количество рекурсивных вызовов не превысит некото
&lt;br /&gt;[20:36:53] &amp;lt;Black_Phoenix&amp;gt; рое значение.
&lt;br /&gt;[20:37:43] &amp;lt;Black_Phoenix&amp;gt; Изменение размера стека производиться функцией luaD_reallocstack(..) [ldo.c:141] - она вызываеться автоматически, но вообще её можно вызывать и самому. Освобождённое место будет возвращено програме.
&lt;br /&gt;[20:38:18] &amp;lt;Black_Phoenix&amp;gt; LVM будет прерывать рекурсивные вызовы если их слишком много, что-бы стек не вырос до коллосальных размеров. К тому же сам стек ограничиваеться максимальным размером (если не ошибаюсь MAX_SIZET байт, обычно это 65536 байт).
&lt;br /&gt;[20:39:02] &amp;lt;Black_Phoenix&amp;gt; Ваши С-функции вызываемые Lua могут падать. Если вы правильно вернёте код ошибки (не ноль), то она даже восстановит стек и выдаст пользователю сообщение. (И работа скрипта будет продолжена)
&lt;br /&gt;[20:39:42] &amp;lt;Black_Phoenix&amp;gt; Итак, теперь о самой LVM. LVM основана на очень простом интерпретаторе (в Lua 5.1.4 используеться просто пошаговое выполнение инструкций). Каждый шаг - одна инструкция.
&lt;br /&gt;[20:40:28] &amp;lt;Black_Phoenix&amp;gt; Выполнение будет продолжаться пока скрипт не напорёться на ошибку, либо пока не будет вызван &amp;quot;return&amp;quot;, либо пока установленый hook (если таковой есть) не закончиться с ошибкой.
&lt;br /&gt;[20:41:07] &amp;lt;Black_Phoenix&amp;gt; Таким образом прерывать выполнение скрипта можно только из самого скрипта, либо контролируя его выполнение хуком.
&lt;br /&gt;[20:42:03] &amp;lt;Black_Phoenix&amp;gt; Я точно не смог найти где (и вообще ли) ограничиваеться откуда будет браться байткод - могу точно сказать только то, что парсер всегда будет ставить RETURN как последнюю инструкцию в скрипте (и он будет прерван)
&lt;br /&gt;[20:42:33] &amp;lt;Black_Phoenix&amp;gt; Формат у опкодов такой (в скобках - сначала позиция в битах, потом размер в битах): [lopcodes.h:37] &lt;a href=&quot;http://www.everfall.com/paste/id.php?ry0zq4z4v1vk&quot;&gt;http://www.everfall.com/paste/id.php?ry0zq4z4v1vk&lt;/a&gt;
&lt;br /&gt;[20:43:07] &amp;lt;Black_Phoenix&amp;gt; Опкод сам определяет, нужно ли брать B или Bx. Каждый параметр - 8-бит смещения (unsigned) на стеке относительно указателя стека base; 8ой бит параметров В и С указывает брать ли значение из регистра (памяти), или из константы.
&lt;br /&gt;[20:43:52] &amp;lt;Black_Phoenix&amp;gt; Если значение берёться из константы, то параметр - индекс в список констант текущей функции. В Lua достаточно замудрено с тем, как значение собственно получается, поэтому обяснять здесь не буду.
&lt;br /&gt;[20:45:22] &amp;lt;Black_Phoenix&amp;gt; В LVM есть 38 опкодов, полный список их можно достать здесь: &lt;a href=&quot;http://www.everfall.com/paste/id.php?4xs8bzkw0fld&quot;&gt;http://www.everfall.com/paste/id.php?4xs8bzkw0fld&lt;/a&gt; ([lopcode.h:154])
&lt;br /&gt;[20:46:02] &amp;lt;Black_Phoenix&amp;gt; В списке опкодов R(A) - это как-бы регистр №A, но реально это значение полученое по смещению A относительно указателя стека base. Как видите, хотя она называеться регистровой, она всё таки остаётся стековой VM.
&lt;br /&gt;[20:46:53] &amp;lt;Black_Phoenix&amp;gt; В общем дожно быть всё понятно по виртуальной машине. Почти все их опкодов понятны, возможно кроме некоторых
&lt;br /&gt;[20:48:24] &amp;lt;Black_Phoenix&amp;gt; Опкоды FORLOOP, FORPREP существуют для подготовки и выполнения цикла for (цикл while выполняеться через jmp). CLOSURE &amp;quot;создаёт&amp;quot; новую функцию. Это и другие опкоды в деталях будет рассмотрено позже, щас только общий экскурс
&lt;br /&gt;[20:48:59] &amp;lt;Black_Phoenix&amp;gt; Итак, теперь можно наконец поговорить о парсере Lua, а также о крутых штуках - например о глобальной таблице (точнее таблице глобальных переменных и функций).
&lt;br /&gt;[20:50:06] &amp;lt;Black_Phoenix&amp;gt; Сам парсер - рекурсивный, компилирует используя набор синтаксических правил ([lparser.c:1])
&lt;br /&gt;[20:50:27] &amp;lt;Black_Phoenix&amp;gt; Таблица глобальных переменных - обычная таблица Луа которая в себе хранит все глобальные функции и переменные (всё что не помечено как local). Если обявляеться функция или переменная без ключевого слова local, то она будет занесена в эту таблиц
&lt;br /&gt;[20:50:27] &amp;lt;Black_Phoenix&amp;gt; у.
&lt;br /&gt;[20:50:31] &amp;lt;Black_Phoenix&amp;gt; таблицу*
&lt;br /&gt;[20:50:55] &amp;lt;Black_Phoenix&amp;gt; При вызове lua_newstate() будет создан новый локальный стейт, и новый глобальный стейт - а также новая таблица глобальных переменных.
&lt;br /&gt;[20:51:16] &amp;lt;Black_Phoenix&amp;gt; При вызове lua_newthread() таблице глобальных переменных нового стейта будет присвоена таблица из другого стейта (который передаётся в lua_newthread()).
&lt;br /&gt;[20:52:00] &amp;lt;Black_Phoenix&amp;gt; Это значит что при создании нового потока можно использовать уже существующие глобальные функции. При добавлении новых глобальных функций одним из скриптов она будет доступна и всем другим потокам.
&lt;br /&gt;[20:52:37] &amp;lt;Black_Phoenix&amp;gt; Причём она станет доступной прямо во время выполнения другого скрипта - можно создать систему сигналов основаную на этом.
&lt;br /&gt;[20:52:46] &amp;lt;Black_Phoenix&amp;gt; Кстати, в таблице глобальных переменных и функций кроеться небольшой, но существенный облом.
&lt;br /&gt;[20:53:03] &amp;lt;Black_Phoenix&amp;gt; Он кроеться в том, что парсер глобальные переменные добавляет в таблицу, как и положено (для этого есть специальный опкод). Скажем мы компилируем код &amp;quot;gvar = 100; myvar = 200&amp;quot;, при этом парсер запустит такой код:
&lt;br /&gt;[20:53:11] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  LOADK 00000000 00000ACF //Загрузка строки &amp;quot;gvar&amp;quot;
&lt;br /&gt;[20:53:17] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  SETGLOBAL 00000000 00000ACE //Засовываем в таблицу &amp;quot;100&amp;quot; с ключём &amp;quot;gvar&amp;quot;
&lt;br /&gt;[20:53:17] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  LOADK 00000000 00000AD1 //Загрузка строки &amp;quot;myvar&amp;quot;
&lt;br /&gt;[20:53:17] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  SETGLOBAL 00000000 00000AD0 //myvar = 200
&lt;br /&gt;[20:53:17] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  RETURN 00000000 1 //завершение работы VM
&lt;br /&gt;[20:53:36] &amp;lt;Black_Phoenix&amp;gt; Так вот, а тепер обратимся к этим переменным (вызовем код &amp;quot;print(gvar)&amp;quot;):
&lt;br /&gt;[20:53:45] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  GETGLOBAL 00000000 00000BA4 //Получить переменную за ключём &amp;quot;print&amp;quot;
&lt;br /&gt;[20:53:45] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  GETGLOBAL 00000001 00000BA5 //Получить переменную за ключём &amp;quot;gvar&amp;quot;
&lt;br /&gt;[20:53:45] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  CALL 00000000 2 0 //Вызвать функцию, расположеную на base+0 в стеке (с 2 значениями на стеке, 0 значений полученых назад)
&lt;br /&gt;[20:53:45] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  RETURN 00000000 1 //завершаем работу VM
&lt;br /&gt;[20:54:13] &amp;lt;Black_Phoenix&amp;gt; Для сравнения запустим код &amp;quot;local lvar = 100; print(lvar)&amp;quot;:
&lt;br /&gt;[20:54:23] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  LOADK 00000000 00000BCD //Загрузка значения lvar
&lt;br /&gt;[20:54:23] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  GETGLOBAL 00000001 00000BCE //Загрузка &amp;quot;print&amp;quot;
&lt;br /&gt;[20:54:23] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  MOVE 00000002 00000000 //Просто переносим +0 в +2 (на стеке)
&lt;br /&gt;[20:54:23] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  CALL 00000001 2 0 //print...
&lt;br /&gt;[20:54:24] &amp;lt;Black_Phoenix&amp;gt;&amp;nbsp;  RETURN 00000000 1 //завершаем работу VM
&lt;br /&gt;[20:54:43] &amp;lt;Black_Phoenix&amp;gt; (LOADK это просто загрузка значения/константы)
&lt;br /&gt;[20:55:05] &amp;lt;Black_Phoenix&amp;gt; И здесь можно заметить облом - вызовы локальных переменных и функций обращаются к таблице значений, куда компилятор неким ему ведомомым образом позапихивал наши переменные.
&lt;br /&gt;[20:55:09] &amp;lt;Black_Phoenix&amp;gt; А вот вызов глобальной функции (или переменной) будет запрашивать у таблицы глобальных переменных её адрес - каждый раз при обращении.
&lt;br /&gt;[20:55:31] &amp;lt;Black_Phoenix&amp;gt; Желательно избегать глобальных функций, а особенно глобальных переменных - при росте их количества они будут всё более и более тормозить.
&lt;br /&gt;[20:56:21] &amp;lt;Black_Phoenix&amp;gt; Кстати, всегда при сравнении сравниваеться &amp;quot;A &amp;lt; B&amp;quot;. Если написано &amp;quot;A &amp;gt; B&amp;quot;, то парсер превратит это в сравнение &amp;quot;B &amp;lt; A&amp;quot;
&lt;br /&gt;[20:56:46] &amp;lt;Black_Phoenix&amp;gt; Все стандартные библиотеки (table, string, io) - это просто таблицы с функциями. Обращение к ним вызывает GETGLOBAL для полчучения таблицы, и GETTABLE для получения значения из таблицы.
&lt;br /&gt;[20:56:57] &amp;lt;Black_Phoenix&amp;gt; Т.е. все библиотеки Lua создаються как просто добавление таблицы с функциями в глобальную таблицу.
&lt;br /&gt;[20:57:22] &amp;lt;Black_Phoenix&amp;gt; Для этого есть функция luaI_openlib [lauxlib.c:242]. Здесь будет проверено загружена ли эта библиотека (есть ли имя этой таблицы в таблице &amp;quot;_LOADED&amp;quot;), и затем создано таблицу с функциями.
&lt;br /&gt;[20:58:54] &amp;lt;Black_Phoenix&amp;gt; В завершение кратко о сборщике мусора - он постоянно чистит уже не используемые ресурсы, а также ресурсы оставленые/забытые на стеке
&lt;br /&gt;[20:59:51] &amp;lt;Black_Phoenix&amp;gt; Каждый обьект который может быть убран сборщиком помечаеться как чёрный, серый, или белый - что значит что сборщик должен убрать обьект, должен проверить надо ли его убирать, и что он вообще не должен этот обьект трогать
&lt;br /&gt;[21:00:55] &amp;lt;Black_Phoenix&amp;gt; Существует также очистка таблиц - поиск &amp;quot;слабых&amp;quot; элементов, но это уже детали сборщика мусора.
&lt;br /&gt;[21:01:45] &amp;lt;Black_Phoenix&amp;gt; В принципе это всё, теперь можно задавать вопросы (если _ShaMan_&amp;nbsp; снимет +m). Желательно вопросы по LVM/Lua - на вопросы по AngelScript я отвечу в следущей лекции
&lt;br /&gt;[21:02:33] &amp;lt;Black_Phoenix&amp;gt; &lt;a href=&quot;http://users.d2k5.com/Black%20Phoenix/files/luastack.png&quot;&gt;http://users.d2k5.com/Black%20Phoenix/files/luastack.png&lt;/a&gt; вот кстати картинка о которой я говорил
&lt;br /&gt;[21:03:07] &amp;lt;Black_Phoenix&amp;gt; top - указатель вершины стека, base - начало stack frame, stack + stack_end - просто для проверок выхода за границы&lt;/p&gt;
&lt;p&gt;Вопросы:
&lt;br /&gt;[21:03:22] &amp;lt;gamer3d&amp;gt; как расшифровываеться LOADK 00000000 00000ACF ?
&lt;br /&gt;[21:04:22] &amp;lt;Black_Phoenix&amp;gt; Загрузка на стек со смещением +0 относительно BASE. Значение для загрузки береться из списка констант за номером 0xACF (или немного другим номером, не суть)
&lt;br /&gt;[21:05:06] &amp;lt;Black_Phoenix&amp;gt; Я немного модифицировал VM что-бы она выводила запускаемый код, она неправильно выводит номера констант
&lt;br /&gt;[21:06:28] &amp;lt;Black_Phoenix&amp;gt; Есть ещё LOADNIL (загрузка nil, фактически удаление), и LOADBOOL. Кстати LOADNIL почти сразу удаляет значение, высвобождая память&lt;/p&gt;
&lt;p&gt;[21:08:24] &amp;lt;gamer3d&amp;gt; а отлаживать lua код как?
&lt;br /&gt;[21:09:31] &amp;lt;Black_Phoenix&amp;gt; Надо поставить hook, он будет вызываться перед каждой инструкцией. Дополнительный API в [ldebug.c] позволит находить номер строки, делать отладку построчно, смотреть весь стек удобным образом&lt;/p&gt;
&lt;p&gt;[21:10:57] &amp;lt;DDMZ&amp;gt; как правильно использовать коуротины?
&lt;br /&gt;[21:13:11] &amp;lt;Black_Phoenix&amp;gt; Должна быть библиотека &amp;quot;coroutine&amp;quot; в которой можно создать и работать с короутинами
&lt;br /&gt;[21:14:08] &amp;lt;Black_Phoenix&amp;gt; Надо вызвать coroutine.create(&amp;lt;функция&amp;gt;), что вернёт значение типа TTHREAD, с которым потом можно будет работать - есть функции coroutine.status, coroutine.resume, coroutine.yield
&lt;br /&gt;[21:15:27] &amp;lt;Black_Phoenix&amp;gt; Вообще коротуны тоже вызывают lua_newthread - они создают новый стейт (который кстати и есть тем, что прячеться за TTHREAD), и потом VM будет переключаться автоматически между ними (если не ошибаюсь)
&lt;br /&gt;[21:15:59] &amp;lt;Black_Phoenix&amp;gt; [lbaselib.c:490] - здесь сама имплементация библиотеки coroutines&lt;/p&gt;
&lt;p&gt;[21:17:14] &amp;lt;gamer3d&amp;gt; как делать save game/load game если в игре используется lua?
&lt;br /&gt;[21:17:45] &amp;lt;Black_Phoenix&amp;gt; gamer3d, детально об этом будет в следущей лекции, но по мне правильно выполнить такие шаги:
&lt;br /&gt;[21:18:12] &amp;lt;Black_Phoenix&amp;gt; 1) сохранить глобальную таблицу (возможно кроме таблиц библиотек)
&lt;br /&gt;[21:18:34] &amp;lt;Black_Phoenix&amp;gt; 2) если не хочеться возиться слежением за загружеными скриптами, сохранить весь байткод
&lt;br /&gt;[21:19:07] &amp;lt;Black_Phoenix&amp;gt; 3) сохранить lua_State и возможно global_State (интересует стек вызваных функций, и стек Lua)
&lt;br /&gt;[21:19:30] &amp;lt;Black_Phoenix&amp;gt; Это метод влоб - я бы предложил просто дать скриптам коллбек &amp;quot;OnGameSave&amp;quot;
&lt;br /&gt;[21:19:51] &amp;lt;Black_Phoenix&amp;gt; Пусть они сами вернут таблицу которую надо сохранить - ведь всё-таки можно и вернуть self :)&lt;/p&gt;
&lt;p&gt;[21:21:36] &amp;lt;DDMZ&amp;gt; как правильно загрузить скрипт в луастейт?
&lt;br /&gt;[21:22:51] &amp;lt;Black_Phoenix&amp;gt; DDMZ, luaL_loadbuffer или luaL_loadfile если хочешь прямо грузить
&lt;br /&gt;[21:23:07] &amp;lt;Black_Phoenix&amp;gt; dofile/dostring это тоже самое, но ещё вызывают lua_call
&lt;br /&gt;[21:24:03] &amp;lt;DDMZ&amp;gt; чтобы грузить из памяти luaL_loadbuffer , и в один луастейт мы можем загрузить один скрипт? а если больше, то их склеить вручную и потом загрузит&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=4446&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2921</guid>
  <pubDate>Sun, 20 Apr 2008 16:47:05 GMT</pubDate>
  <title>Лекция #35. Компрессия векторных данных [Лектор - Rageous]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2921</link>
  <category>аппроксимация</category>
  <category>битстрим</category>
  <category>векторные данные</category>
  <category>сжатие</category>
  <category>сплайны</category>
  <description>
&lt;p&gt;&lt;b&gt;Полная форматированная версия лога лежит &lt;a href=&quot;http://rageous.jino-net.ru/mydocs/Postgraduate/LectureCompression&quot;&gt;здесь&lt;/a&gt;.&lt;/b&gt;
&lt;p&gt;18:02:06&amp;nbsp; Rageous: лекция, которую я сегодня читаю, посвящена моим исследованиям в области компрессии векторных данных
&lt;br /&gt;18:02:30&amp;nbsp; Rageous: в связи с тем, что мне уже задавали вопросы, что есть векторные данные, я проясню этот вопрос отдельно
&lt;br /&gt;18:02:52&amp;nbsp; Rageous: здесь и далее под векторными данными я буду подразумевать функции f(t), где t - время, а f(t) - функция, возвращающая некоторое рациональное значение
&lt;br /&gt;18:03:16&amp;nbsp; Rageous: с подобными данными мы работаем каждый день: в играх это анимации персонажей, пути перемещения объектов, траектории движения физических тел
&lt;br /&gt;18:03:35&amp;nbsp; Rageous: в софте это информация по трекингу машин автопарка, к примеру
&lt;br /&gt;18:03:58&amp;nbsp; Rageous: здесь, к примеру, можно увидеть сохраненный путь автомобиля. сохраненные данные используются для анализа скорости, времени и количества остановок:
&lt;br /&gt;&lt;img src=&quot;http://www.gamedev.ru/files/images/gps_tiny.png&quot; alt=&quot;gps_tiny | Лекция #35. Компрессия векторных данных [Лектор - Rageous]&quot; /&gt;
&lt;br /&gt;18:04:21&amp;nbsp; Rageous: здесь зеленоградский автопарк предоставил свои данные для анализа дорожной обстановки на одной из самых нагруженных московских трасс, чем облегчил жизнь множеству автомобилистов:
&lt;br /&gt;&lt;img src=&quot;http://www.gamedev.ru/files/images/zelgps_tiny.png&quot; alt=&quot;zelgps_tiny | Лекция #35. Компрессия векторных данных [Лектор - Rageous]&quot; /&gt;
&lt;br /&gt;18:04:47&amp;nbsp; Rageous: итак, векторные данные полезны. часто бывает полезно их сохранять. к сожалению их объем нередко далек от &amp;quot;незначительного&amp;quot;
&lt;br /&gt;18:05:17&amp;nbsp; Rageous: в связи с этим возникает вопрос об их компрессии
&lt;br /&gt;18:05:54&amp;nbsp; Rageous: к примеру, если вы хотите сохранить реплей заезда в автосимуляторе, чтобы поделиться им с друзьями, вам придется думать о том, как переслать по интернету до десятка мегабайт данных
&lt;br /&gt;18:06:56&amp;nbsp; Rageous: если же вы занимаетесь ПО и хотите хранить годами информацию по имеющимся в вашем распоражении автомобилям или морским судам или самолетам или еще чему - вы можете легко столкнуться с проблемой огромного объема этих сведений
&lt;br /&gt;18:07:19&amp;nbsp; Rageous: к счастью существуют архиваторы :)
&lt;br /&gt;18:07:48&amp;nbsp; Rageous: и к сожалению сжатие векторных данных - одно из самых низких для большинства современных алгоритмов
&lt;br /&gt;18:08:00&amp;nbsp; Rageous: так, например, zip сжимает такие данные в 2-3 раза
&lt;br /&gt;18:08:17&amp;nbsp; Rageous: rar и 7zip обеспечивают сжатие до 25 раз, но делают это весьма медленно
&lt;br /&gt;18:09:07&amp;nbsp; Rageous: слабым местом архиваторов является то, что они предоставляют lossless (без потерь) компрессию, а так же не располагают сведениями о структуре предоставленных им данных
&lt;br /&gt;18:10:17&amp;nbsp; Rageous: целью, которую я ставил перед собой, когда начинал заниматься компрессией векторных данных, было сжатие в 100-1000 раз при скорости достаточной, чтобы осуществлять это сжатие в реальном времени без серьезного удара по производительности основного приложения
&lt;br /&gt;18:10:34&amp;nbsp; Rageous: итак, что я делал
&lt;br /&gt;18:11:17&amp;nbsp; Rageous: первое - все данные были разбиты на отдельные потоки вида v(t), где v - это функция времени, возвращающая одно или несколько рациональных чисел
&lt;br /&gt;18:12:07&amp;nbsp; Rageous: имеющиеся данные были слегка изменены, чтобы избавиться от избыточности: вместо полных матриц 4*4 трансормации я писал вектора и нормализованные (3 компоненты) кватернионы
&lt;br /&gt;18:12:48&amp;nbsp; Rageous: потоки, объединяющие в себе несколько флоатов для одного момента времени пригодились для записи нормализованных кватернионов - уменьшив погрешность
&lt;br /&gt;18:13:27&amp;nbsp; Rageous: второе - так как данные нужно было сжимать и сохранять в реальном времени, все данные были разбиты на пакеты фиксированной длины (обычно порядка 30-90 секунд)
&lt;br /&gt;18:14:09&amp;nbsp; Rageous: в памяти одновременно находятся два пакета: текущий и прошлый. прошлый сжимается вместе с наполнением текущего, что позволяет избежать пиковых нагрузок при сохранении пакета в файл или иное хранилище
&lt;br /&gt;18:14:33&amp;nbsp; Rageous: после сохранения сжатого пакета его место, соот-но, занимает текущий, а текущий начинает наполняться новыми данными
&lt;br /&gt;18:16:08&amp;nbsp; Rageous: третье - данные в библиотеку приходят очень часто. в играх - раз в кадр. в софте - при каждом замере. в большинстве ситуаций это означает избыточность данных, т.к. объект, который движется почти прямолинейно, создает такой же объем сведений, как и объект, который бешенно меняет свою позицию и ориентацию
&lt;br /&gt;18:16:19&amp;nbsp; Rageous: чтобы избавиться от этой избыточности нужно провести аппроксимацию
&lt;br /&gt;18:16:54&amp;nbsp; Rageous: наиболее частым и простым подходом в данной ситуации является аппроксимация кусочно-линейным сплайном
&lt;br /&gt;18:17:01&amp;nbsp; Rageous: или, проще говоря, ломаной
&lt;br /&gt;18:17:31&amp;nbsp; Rageous: фиттинг (вычисление минимального набора необходимых ключей) для такого сплайна осуществляется очень просто и быстро
&lt;br /&gt;18:18:03&amp;nbsp; Rageous: но результат оставляет желать лучшего как с т.з. компрессии, так и с т.з. внешнего вида полученных после обработки данных
&lt;br /&gt;18:18:15&amp;nbsp; Rageous: машина начинает двигаться &amp;quot;угловато&amp;quot;
&lt;br /&gt;18:18:49&amp;nbsp; Rageous: вторым подходом является фиттинг сплайнов более высокого порядка - квадратичных и кубических сплайнов
&lt;br /&gt;18:19:25&amp;nbsp; Rageous: сразу скажу, несмотря на интуитивно-большую гибкость кубических, я остановился на квадратичных
&lt;br /&gt;18:19:46&amp;nbsp; Rageous: это связано с тем, что фиттинг кубических сплайнов - весьма сложный процесс, который требует тонкой настройки
&lt;br /&gt;18:20:02&amp;nbsp; Rageous: в противном случае на сплайне появляются выбросы, которые сводят на нет все преимущества
&lt;br /&gt;18:20:10&amp;nbsp; Rageous: либо же компрессия становится чрезвычайно низкой
&lt;br /&gt;18:20:41&amp;nbsp; Rageous: неплохая статья с исходниками по кубическим сплайнам находится здесь: &lt;a href=&quot;http://alglib.sources.ru/interpolation/spline3.php&quot;&gt;http://alglib.sources.ru/interpolation/spline3.php&lt;/a&gt;
&lt;br /&gt;18:21:00&amp;nbsp; Rageous: про фиттинг можно почитать здесь: &lt;a href=&quot;http://www.stanford.edu/~boyd/cvx/examples/cvxbook/Ch06_approx_fitting/html/fig6_20.html&quot;&gt;http://www.stanford.edu/~boyd/cvx/examples/cvxbook/Ch06_approx_fi&amp;hellip; /fig6_20.html&lt;/a&gt; и здесь: &lt;a href=&quot;http://ask.metafilter.com/50554/Generating-Bezier-curves-from-discrete-point-sets&quot;&gt;http://ask.metafilter.com/50554/Generating-Bezier-curves-from-dis&amp;hellip; te-point-sets&lt;/a&gt;
&lt;br /&gt;18:21:22&amp;nbsp; Rageous: что же квадратичный сплайн. я взял сплайн безье: &lt;a href=&quot;http://ru.wikipedia.org/wiki/Кривая_Безье&quot; rel=&quot;nofollow&quot;&gt;http://ru.wikipedia.org/wiki/Кривая_Безье&lt;/a&gt;
&lt;br /&gt;18:21:54&amp;nbsp; Rageous: он имеет очень простую формулу, которая легко обращается, дабы вычислить опорную точку по имеющимся точкам начала и конца, а так же некоторой промежуточной
&lt;br /&gt;18:22:05&amp;nbsp; Rageous: потому его фиттинг легко объяснить на пальцах:
&lt;br /&gt;18:22:24&amp;nbsp; Rageous: мы берем весь пакет данных, вычисляем для него усредненную опорную точку
&lt;br /&gt;18:22:55&amp;nbsp; Rageous: с ней прогоняем функцию оценки ошибки. если ошибка слишком велика, делим данные пополам - и проводим ту же процедуру с первой половиной
&lt;br /&gt;18:23:37&amp;nbsp; Rageous: так - до тех пор, пока не найдем кусок данных максимальной длины, который можно представить в виде начальной, конечной точек и опорного значения (P1 в формулах на вики)
&lt;br /&gt;18:24:09&amp;nbsp; Rageous: с оставшимися данными процесс повторяется до тех пор, пока весь пакет не будет представлен в виде наборов квадратичных сплайнов&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2921&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/blog/?id=2915</guid>
  <pubDate>Mon, 14 Apr 2008 23:39:51 GMT</pubDate>
  <title>Лекция по компрессии векторных данных на канале #Ogre3D</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/blog/?id=2915</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=79405</comments>
  <category>irc</category>
  <category>Ogre3D</category>
  <category>лекция</category>
  <description>
&lt;p&gt;19.04.08 в 18:00 МСК на канале #Ogre3D состоится лекция по компрессии векторных данных. Лектор - &lt;a href=&quot;http://dtf.ru/person/info.php?id=4654&quot;&gt;Rageous&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Огромная просьба ко всем, кто собирается присутствовать: прислать в личку (на сайте или в ирке) свои ФИО и место работы/учебы. Это нужно для отчетности по кандидатской работе. Заранее спасибо!&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2800</guid>
  <pubDate>Mon, 07 Jan 2008 11:40:11 GMT</pubDate>
  <title>Мини-лекция. Как написать самую ацтойную игру. [Лектор - DDMZ]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2800</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=75108</comments>
  <category>бред</category>
  <category>деньги</category>
  <category>игра</category>
  <category>концепт</category>
  <category>отстой</category>
  <description>
&lt;p&gt;Если вы хотите написать самую отстойную игру, разбогатеть и прославиться, то эта лекция для вас.
&lt;br /&gt;В лекции раскрываются некоторые тайны известных разработчиков игр.
&lt;p&gt;&amp;lt;DDMZ&amp;gt; Для начала нужно выбрать правильную операционную систему.
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; Лучше всего выбрать операционную систему DOS поскольку она с трудом работает под виндовсом. Либо накрайний случай выбрать сам виндовс
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; Следущим шагом должен стать выбор языка програмирования, приэтом неважно какой язык програмирования вы уже знаете. Чем хуже знаком вам выбраный язык програмирования тем отстойнее получится игра
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; Лидер среди языков програмирования BASIC, поскольку даже если вам этот язык програмирования знаком игра всеравно получится отстойной
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; далее нужно представить себе как будет выглядеть игра, придумать концепт.
&lt;br /&gt;&amp;lt;Dorfe[notebook]&amp;gt; танк с сиськами + табуретки?..
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; Что угодно ...
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; Исходя от того что вы там задумали, внешний вид, и т.п. вам нужно полностью отказатся от графического режима, таким образом вам непотребуется тратить свои сылы на рисование графики
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; в качестве устройства вывода звука лучше всего подходит PCSpeaker посокльку это устройство стандартное и у вашей игры будет большая совместимость. И ещё один существенный плюс вам ненужно замарачиватся со всякими там хитросплетениями работы звуковых карт
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; На этом шаге уже можно представлять себя рокфелером гребущим лопатой деньги. поскольку создаваемую таким образом игру нужно продавать например как шаровары, ведь даже такие скудные труды должны окупатся, а люди с чувством юмора и при деньгах ещё неперевелись. неужно незабыть навешать всяческой защиты и кучу прозьб о регистрации, которые будут закрывать основной игровой процесс чтобы у игрока сложилось впечатление о том что:
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; игра действительно стоящая, хоть сам игровой процесс и невидно из-за прозьб о регистрации
&lt;br /&gt;&amp;lt;Dorfe[notebook]&amp;gt; ых, этим кстати и занимаемся =) вешаем рекламу в игры
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; следующий шаг это взять ранее придуманый концепт, опсание и начать програмировать. Незабыв гденить предупредить общественность о том что разрабатывается некая игра под строгой секретностью, дабы заинтересовать больше игроков к моменту выхода игры
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; При програмировании небрезговать использовать кучу опереатаров print и go to
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; пока игра находитсмя в разработке, можно подливать интерес к игре ожидающих игроков, выкладыванием на формуах всяких красочных концептов и скриншотов
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; приэтом откуда сделаны скриншоты неособо важно...
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; чем на дольший срок затянется разработка тем больше игроков заинтересуется вашей игрой к моменту выхода
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; а если вы ещё и несколько раз перенесёте дату выхода, то это будет просто кассовый сбор, поскольку пресса будет пестрить о том что какаято секретная игра которую все ждут переносится. Игроки уже будут грезить супер спец эффектами этой игры
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; когда вы уже будите заканчивать игру, нивкоем случае неделайте демо версию, поскольку в демке нет прозьб о регистрации которые закрывают собой полностью игровой процесс, и игроки увидят насколько ваша игра отстойна...
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; в итоге у вас должно получится что то типа тетриса или крестиков ноликов, ибо это проще всего спрограмировать, накрайняк должна получится игра угадай число которое задумал копьютер...
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; вот таким образом можно создать самую отстойную игру и приэтом заработать кучу денег.
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; Игра будет признана просто величайшим отстоем с момента игровой индустрии!
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; люди будут хотеть купить эту игру и посмотреть насколько она интересна/отстойна
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; Выйдет куча журналов, где будет говорится только о вашей игре и насколько она отстойна
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; везде будет упоминатся ваше имя! такчто вы ещё и прославитеь =)
&lt;br /&gt;&amp;lt;DDMZ&amp;gt; лекция окончена, если есть вопросы отвечу&lt;/p&gt;
&lt;p&gt;Полный лог лекции здесь: &lt;a href=&quot;http://www.everfall.com/paste/id.php?023e2v1b5ynw&quot;&gt;http://www.everfall.com/paste/id.php?023e2v1b5ynw&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2526</guid>
  <pubDate>Sun, 29 Jul 2007 09:25:00 GMT</pubDate>
  <title>Лекция #34. Top-secrets of projective grid. [Лектор - Denton]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2526</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=68422</comments>
  <description>
&lt;p&gt;Из лога вырезан мусор, некоторые места подправлены. Полный лог: &lt;a href=&quot;http://www.everfall.com/paste/id.php?phy8s5l4zxe8&quot;&gt;http://www.everfall.com/paste/id.php?phy8s5l4zxe8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Denton&amp;gt; Итак. сегодня я расскажу о том, чтоже такое projective grid
&lt;br /&gt;&amp;lt;Denton&amp;gt; и о том, как и где можно её использовать.
&lt;p&gt;&amp;lt;Denton&amp;gt; данный способ был использован для реализации водной поверхности
&lt;br /&gt;&amp;lt;Denton&amp;gt; Projective grid, на русский язык переводится как проективная сетка, это сетка которая получается в результате проецирования вершин сетки с экраных координат в 3д пространство
&lt;br /&gt;&amp;lt;Denton&amp;gt; Основная идея проективной сетки заключается в достижении максимальной теселяции при приближении к виртуальной камере и уменьшении при удалении вершин от виртуальной камеры
&lt;br /&gt;&amp;lt;Denton&amp;gt; Для чего же можно её применить...
&lt;br /&gt;&amp;lt;Denton&amp;gt; В следствии того что сетка около камеры получается высокой плотности( количество вершин на квадратную единицу 3д пространства высокое), а с удалением от горизонта сетка становится более разреженная,&amp;nbsp; её удобно использовать для рендеринга сетки меша, используемого для рендеринга водной поверхности
&lt;br /&gt;&amp;lt;Denton&amp;gt; Мной использовался данный способ лишь для рендеринга водной поверхности, но также предполагается, что возможно будет использовать&amp;nbsp; данный способ и для рендеринга слоя облаков для открытых пространств
&lt;br /&gt;&amp;lt;Denton&amp;gt; Если данная лекция пройдёт успешно, и реализация слоя облаков удасться, по этому поводу будет ещё одна лекция
&lt;br /&gt;&amp;lt;Denton&amp;gt; хочется также сказать что данный способ был реализован в других играх жанра стратегии
&lt;br /&gt;&amp;lt;Denton&amp;gt; в частности не так давно вышедшей Supreme Commander
&lt;br /&gt;&amp;lt;Denton&amp;gt; но там она с некоторыми доработками&lt;/p&gt;
&lt;p&gt;&amp;lt;Denton&amp;gt; Далее будет рассказано о том, как получить проективную&amp;nbsp; сетку и как можно её использовать для рендеринга поверхности воды
&lt;br /&gt;&amp;lt;Denton&amp;gt; В начале напомню как происходит рендеринг воды в принципе
&lt;br /&gt;&amp;lt;Denton&amp;gt; а) Создаётся плоскоская сетка
&lt;br /&gt;&amp;lt;Denton&amp;gt; б) С использованием шумовой функции создаётся карта высот и в соответствие с ней сдвигаются вершины
&lt;br /&gt;&amp;lt;Denton&amp;gt; немного не точно выразился. Не с шумовой функцией, а с волновой.
&lt;br /&gt;&amp;lt;Denton&amp;gt; Спасибо washth
&lt;br /&gt;&amp;lt;Denton&amp;gt; в) Полученная геометрия выводится на экран
&lt;br /&gt;&amp;lt;Denton&amp;gt; с применением различных заранее подготовленных, либо отсчитаных в рендертаргет текстур и шейдеров
&lt;br /&gt;&amp;lt;Denton&amp;gt; В обычном случае сетка лежит в плоскости разбивается на треугольники, чем ближе к камере – тем мельче треугольники.&lt;/p&gt;
&lt;p&gt;&amp;lt;Denton&amp;gt; Возможны применения различных способов тесселяции
&lt;br /&gt;&amp;lt;Denton&amp;gt; но в любом случае это делается вручную при изменении определённых параметров
&lt;br /&gt;&amp;lt;Denton&amp;gt; Для создания карты высот используются какие либо волновые функции,&amp;nbsp; например шум Перлина
&lt;br /&gt;&amp;lt;Denton&amp;gt; Используется несколько октав, каждая из которых делает карту шума более мелкой и в итоге карты шумов всех октав сумируются&lt;/p&gt;
&lt;p&gt;&amp;lt;Denton&amp;gt; На этом рисунке &lt;a href=&quot;http://img444.imageshack.us/img444/3627/58435634rk6.jpg&quot;&gt;http://img444.imageshack.us/img444/3627/58435634rk6.jpg&lt;/a&gt; обозначены:
&lt;br /&gt;&amp;lt;Denton&amp;gt; Sbase - плоскость в которой расположена сетка
&lt;br /&gt;&amp;lt;Denton&amp;gt; Supper – верхний предел смещений вершин согласно карте высот
&lt;br /&gt;&amp;lt;Denton&amp;gt; Slower – нижний предел смещения вершин согласно карте высот
&lt;br /&gt;&amp;lt;Denton&amp;gt; Nbase – нормаль к плоскости Sbase
&lt;br /&gt;&amp;lt;Denton&amp;gt; Vdisplaceble - объём в котором будут смещатся вершины
&lt;br /&gt;&amp;lt;Denton&amp;gt; Тут &lt;a href=&quot;http://img444.imageshack.us/img444/3671/64592334sq0.jpg&quot;&gt;http://img444.imageshack.us/img444/3671/64592334sq0.jpg&lt;/a&gt;&amp;nbsp; отображено как смещаются вершины согласно карты шума&lt;/p&gt;
&lt;p&gt;&amp;lt;Denton&amp;gt; это всё было известно и ранее. ничего нового тут нет. вопросы есть по этому?
&lt;br /&gt;&amp;lt;paladinrus&amp;gt; где происходит смещение?
&lt;br /&gt;&amp;lt;paladinrus&amp;gt; ведь не у всех есть геометрические шейдеры
&lt;br /&gt;&amp;lt;paladinrus&amp;gt; тогда программно?
&lt;br /&gt;&amp;lt;Denton&amp;gt; можно и на CPU их смещать
&lt;br /&gt;&amp;lt;Black_Phoenix&amp;gt; Есть вопрос
&lt;br /&gt;&amp;lt;NULL_PTR&amp;gt; вершины смещай в вертексном шейдере&lt;/p&gt;
&lt;p&gt;&amp;lt;paladinrus&amp;gt; и ещё
&lt;br /&gt;&amp;lt;paladinrus&amp;gt; может я ошибаюсь но при дифферд шейдинге можно смещать в пиксельном шейдере?
&lt;br /&gt;&amp;lt;Denton&amp;gt; в пиксельном шейдере смещать вершины нельзя
&lt;br /&gt;&amp;lt;Denton&amp;gt; при дифер шейдинге в пиксельном происходил расчёт освещения
&lt;br /&gt;&amp;lt;Denton&amp;gt; а в текстурах были координаты вершин
&lt;br /&gt;&amp;lt;paladinrus&amp;gt; ну
&lt;br /&gt;&amp;lt;paladinrus&amp;gt; и что нам мешает поменять координаты
&lt;br /&gt;&amp;lt;Denton&amp;gt; можно и менять
&lt;br /&gt;&amp;lt;Denton&amp;gt; тогда для задания вершин в сетке необходимо использовать r2vb
&lt;br /&gt;&amp;lt;Denton&amp;gt; т.е. данные с текстуры использоваться как координаты вершин.
&lt;br /&gt;&amp;lt;Denton&amp;gt; а при деффер шейдинге, насколько мне известно мы зная координаты вершин получали текстуру
&lt;br /&gt;&amp;lt;paladinrus&amp;gt; ну я это и имел ввиду, ок, вопросов нет&lt;/p&gt;
&lt;p&gt;&amp;lt;Denton&amp;gt; тогда&amp;nbsp; поехали дальше
&lt;br /&gt;&amp;lt;Denton&amp;gt; Принцип построения проективной сетки для меша поверхности воды, состоит из следующих этапов
&lt;br /&gt;&amp;lt;Denton&amp;gt; а) создание плоскости расположенной перпендикулярно вектору направления взгляда виртуальной камеры
&lt;br /&gt;&amp;lt;Denton&amp;gt; б) проектирование угловых вершин полученой плоскости на плоскость Sbase
&lt;br /&gt;&amp;lt;Denton&amp;gt; проектирование в данном случае - с учётом матрицы проектора. в нашем случае - виртуальной камеры
&lt;br /&gt;&amp;lt;Denton&amp;gt; в) смещение вершин в соответствии с картой высот.
&lt;br /&gt;&amp;lt;Denton&amp;gt; г) вывод полученого меша на экран.
&lt;br /&gt;&amp;lt;Denton&amp;gt; также у меня дальше будут использоваться следующие обозначения:
&lt;br /&gt;&amp;lt;Denton&amp;gt; Vcam – объём занимаемый конусом камеры
&lt;br /&gt;&amp;lt;Denton&amp;gt; Vvisible – пересечение объёмов Vcam и Vdisplaceable
&lt;br /&gt;&amp;lt;Denton&amp;gt; также считаем что нормали к Supper и Slower равны
&lt;br /&gt;&amp;lt;Denton&amp;gt; и равны также нормали к Sbase
&lt;br /&gt;&amp;lt;Denton&amp;gt; Vcam - объём создаваемый ближней плоскостью отсечения, дальней, и гранями фрустума
&lt;br /&gt;&amp;lt;Denton&amp;gt; те части объёма Vdisplaceable которые попадаёт в Vcam и есть Vvisible
&lt;br /&gt;&amp;lt;Denton&amp;gt; Если сравнивать как и что должно получиться, то удобнее всего взять настольную лампу и тонкую прозрачную бумагу
&lt;br /&gt;&amp;lt;Denton&amp;gt; нарисовать на ней ручкой равномерную сетку, и закрыть этой бумагой конус настольной лампы
&lt;br /&gt;&amp;lt;Denton&amp;gt; После включения лампы можно будет увидеть что спроецированные нарисованные точки на бумаге, на стол уже не будут равномерно удалены друг от друга
&lt;br /&gt;&amp;lt;Denton&amp;gt; По мере их отдаления от лампы, они будут находится на более дальнем расстоянии друг от друга
&lt;br /&gt;&amp;lt;Denton&amp;gt; Примерно это будет выглядеть так:
&lt;br /&gt;&amp;lt;Denton&amp;gt; &lt;a href=&quot;http://img528.imageshack.us/img528/9441/77454362vf8.jpg&quot;&gt;http://img528.imageshack.us/img528/9441/77454362vf8.jpg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Denton&amp;gt; Как же создаётся плоскость расположенная перпендикулярно вектору направления взгляда виртуальной камеры…
&lt;br /&gt;&amp;lt;Denton&amp;gt; Для начала необходимо найти точки пересечения Vdisplaceable с конусом видимости камеры, с frustum’ом
&lt;br /&gt;&amp;lt;Denton&amp;gt; Полученые координаты будут находится в modelview matrix в пространстве виртуальной камеры.
&lt;br /&gt;&amp;lt;Denton&amp;gt; как находить пересечения я думаю не стоит объяснять.
&lt;br /&gt;&amp;lt;Denton&amp;gt; Далее для построения плоскости которая была бы параллельна вектору направления взгляда камеры, необходимо получить экранные координаты вершин
&lt;br /&gt;&amp;lt;Denton&amp;gt; Далее необходимо найти минимальный и максимальные координаты вершин на экране
&lt;br /&gt;&amp;lt;Denton&amp;gt; т.е. берётся каждая вершина и находится минимальный X, максимальный X среди них. И аналогично с Y
&lt;br /&gt;&amp;lt;Denton&amp;gt; С учётом этих значений строится матрица проектора, с помощью которой и будут найдены точки в мировой системе координат
&lt;br /&gt;&amp;lt;Denton&amp;gt; Матрица строится так: &lt;a href=&quot;http://www.everfall.com/paste/id.php?y7hw8s2se8sl&quot;&gt;http://www.everfall.com/paste/id.php?y7hw8s2se8sl&lt;/a&gt;
&lt;br /&gt;&amp;lt;Denton&amp;gt; Теперь умножая на эту матрицу вершины (0,0) (1,0) (0,1) (1,1) можно получить 4 вершины трапеции, которая будет лежать в плоскости Sbase
&lt;br /&gt;&amp;lt;Denton&amp;gt; следует сказать, что полученные координаты будут гомогенными. иными словами 4д вектора
&lt;br /&gt;&amp;lt;Denton&amp;gt; Далее между данными вершинами строится сетка по тривиальному алгоритму – стороны трапеции делятся на равные участки и строится сетка. 
&lt;br /&gt;&amp;lt;Denton&amp;gt; тут в принципе есть одна особенность
&lt;br /&gt;&amp;lt;Denton&amp;gt; при расчёте координат сетки используются гомогенные координаты.
&lt;br /&gt;&amp;lt;Denton&amp;gt; т.е. для расчёта ширины между двумя строками, берётся Yдальнее - Yближнее в гомогенных координатах
&lt;br /&gt;&amp;lt;Denton&amp;gt; это нужно для того, чтобы сетка была равномерной на экране виртуальной камеры
&lt;br /&gt;&amp;lt;Denton&amp;gt; а при переводе в декартовую системы координат получится что сетка рястягивается с увеличением расстояния от камеры
&lt;br /&gt;&amp;lt;Denton&amp;gt; После этих действий со стороны наблюдателя сетка будет иметь вид: &lt;a href=&quot;http://img207.imageshack.us/img207/1530/23414408qp1.jpg&quot;&gt;http://img207.imageshack.us/img207/1530/23414408qp1.jpg&lt;/a&gt;
&lt;br /&gt;&amp;lt;Denton&amp;gt; а с вида камеры сетка будет абсолютно равномерна.
&lt;br /&gt;&amp;lt;Denton&amp;gt; что это даёт...
&lt;br /&gt;&amp;lt;Denton&amp;gt; если камера направлена в сторону горизонта, и у нас размер сетки 128х128, то большая часть вершин сетки будет около камеры что обеспечит хорошую детальность перед камерой.
&lt;br /&gt;&amp;lt;Denton&amp;gt; и если опустить камеру &amp;quot;под ноги&amp;quot;, получим те же самые 128х128 вершин
&lt;br /&gt;&amp;lt;Denton&amp;gt; но использоваться они будут для более малой площади поверхности.
&lt;br /&gt;&amp;lt;Denton&amp;gt; т.е. фактически все вершины используются только для видимой части поверхности
&lt;br /&gt;&amp;lt;Denton&amp;gt; и совсем не важно - огромный у нас океан или маленькая лужа. количество вершин на водную поверхность не нужно делать сильно большим.
&lt;br /&gt;&amp;lt;Denton&amp;gt; так же есть некоторые особенности в реализации.
&lt;br /&gt;&amp;lt;Denton&amp;gt; в частности при нахождения матрица проектора.
&lt;br /&gt;&amp;lt;Denton&amp;gt; если смотреть в небо, то может получится так называемый эффект back firing
&lt;br /&gt;&amp;lt;Denton&amp;gt; когда у нас сетка будет отрисовываться с обратной стороны камеры.
&lt;br /&gt;&amp;lt;Denton&amp;gt; для борьбы с этим создаётся дополнительная виртуальная камера
&lt;br /&gt;&amp;lt;Denton&amp;gt; которая используется для перевода найденых вершин пересечения Vcam и Vdisplaceable
&lt;br /&gt;&amp;lt;Denton&amp;gt; в экранные координаты
&lt;br /&gt;&amp;lt;Denton&amp;gt; для получения экранных координат вершин&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2526&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/game_orhetecture</guid>
  <pubDate>Thu, 14 Jun 2007 21:20:10 GMT</pubDate>
  <title>Лекция #33. Плюсы и минусы игровых &quot;орхетектур&quot;. [Лектор - dDIMA]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/game_orhetecture</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=67296</comments>
  <description>
&lt;p&gt;Disclaimer: из лога вырезаны куски, ну и так далее. &lt;a href=&quot;http://www.everfall.com/paste/id.php?nwwkchotfkn0&quot;&gt;полный лог&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[21:00] &amp;lt;dDIMA&amp;gt; Всем доброго getlocaltime();&lt;/p&gt;
&lt;p&gt;[21:00] &amp;lt;dDIMA&amp;gt; Тема сегодняшней лекции - &amp;quot;Плюсы и минусы игровых &amp;lt;орхетектур&amp;gt;&amp;quot;.
&lt;br /&gt;[21:01] &amp;lt;dDIMA&amp;gt; Я постараюсь кратко рассказать про основные решения, которые приходится принимать на верхнем уровне разработки игрового проекта, какие здесь бывают варианты реализации, чем они плохи и хороши.
&lt;br /&gt;[21:01] &amp;lt;dDIMA&amp;gt; Предварительно одно небольшое предупреждение&amp;nbsp; я, разумеется, буду приводить разные примеры из жизни&amp;nbsp; с какими интересными вещами мне приходилось встречаться, но ссылок на конкретные компании и конкретные игровые движки приводить не буду.
&lt;br /&gt;[21:01] &amp;lt;dDIMA&amp;gt; И на вопросы &amp;lt;у кого именно встретилось такое г.&amp;gt; отвечать тоже, естественно, не буду :)
&lt;br /&gt;[21:01] &amp;lt;dDIMA&amp;gt; Ни на канале, ни в привате.&lt;/p&gt;
&lt;p&gt;[21:01] &amp;lt;dDIMA&amp;gt; Сразу &amp;lt;с места в карьер&amp;gt; - первый ключевой вопрос&amp;nbsp; это каким образом ведется разделение кода на столь модное понятие &amp;lt;движок&amp;gt; и &amp;lt;игра&amp;gt;.
&lt;br /&gt;[21:02] &amp;lt;dDIMA&amp;gt; Можно явно выделить 2 крайних подхода, ну и соответственно, множество промежуточных вариантов.
&lt;br /&gt;[21:02] &amp;lt;dDIMA&amp;gt; &lt;a href=&quot;http://www.ddima.ru/articles/v_lecture1/engine_game.jpg&quot;&gt;http://www.ddima.ru/articles/v_lecture1/engine_game.jpg&lt;/a&gt; (&lt;a href=&quot;http://www.gamedev.ru/files/images/?id=48038&quot;&gt;http://www.gamedev.ru/files/images/?id=48038&lt;/a&gt;)
&lt;br /&gt;[21:03] &amp;lt;dDIMA&amp;gt; Левая картинка иллюстрирует подход, при котором игровой движок и сама игра не разделаются по сущностям.
&lt;br /&gt;[21:03] &amp;lt;dDIMA&amp;gt; Мы начинаем разработку игры (ширина трапеций символизирует объем кода, по оси Y вниз идет время) под названием Project 1.
&lt;br /&gt;[21:03] &amp;lt;dDIMA&amp;gt; Когда игра сделана и (дай бог) выпущена, мы на основе всего имеющегося кода делаем второй проект (естественно, схожего жанра).
&lt;br /&gt;[21:03] &amp;lt;dDIMA&amp;gt; К середине разработки второго проекта мы сильно разрослись и решаем запустить третий проект.
&lt;br /&gt;[21:03] &amp;lt;dDIMA&amp;gt; Для этого мы копируем полное содержимое Project 2 в Project 3 и продолжаем разработку.
&lt;br /&gt;[21:03] &amp;lt;dDIMA&amp;gt; Незадолго до окончания второго проекта начинаются работы по четвертому проекту, а третий проект бренчуется в Project 5.
&lt;br /&gt;[21:04] &amp;lt;dDIMA&amp;gt; Правая картинка иллюстрирует подход с организацией отдельного независимого движка (это центральный ствол &amp;lt;дерева&amp;gt;), на котором &amp;lt;висят&amp;gt; отдельные ветки Project1 ... Project5.
&lt;br /&gt;[21:04] &amp;lt;dDIMA&amp;gt; Мы тщательно следим за тем, чтобы главный ствол рос и развивался,
&lt;br /&gt;[21:04] &amp;lt;dDIMA&amp;gt; и чтобы в него не попадали разные паразитные части, которые Project specific
&lt;br /&gt;[21:04] &amp;lt;dDIMA&amp;gt; и которые в будущем могут не позволить нам нормально развивать движок для других нужд.
&lt;br /&gt;[21:05] &amp;lt;dDIMA&amp;gt; Естественно, что в случае достаточно мощного и полного движка не все его части будут использованы.
&lt;br /&gt;[21:05] &amp;lt;dDIMA&amp;gt; Это символизируют дополнительные линии, отсекающие части главного ствола для нужд того или иного проекта.&lt;/p&gt;
&lt;p&gt;[21:05] &amp;lt;dDIMA&amp;gt; Каковы плюсы и минусы указанных решений?&lt;/p&gt;
&lt;p&gt;[21:05] &amp;lt;dDIMA&amp;gt; Вариант слева выглядит достаточно простым и удобным для реализации
&lt;br /&gt;[21:05] &amp;lt;dDIMA&amp;gt; к тому же позволяет использовать максимум имеющегося кода в новых проектах.
&lt;br /&gt;[21:05] &amp;lt;dDIMA&amp;gt; Однако он не лишен существенных недостатков.
&lt;br /&gt;[21:06] &amp;lt;dDIMA&amp;gt; Ключевая проблема в организации такого способа работы&amp;nbsp; это тесное переплетение разных &amp;lt;системных&amp;gt; и &amp;lt;игровых&amp;gt; подсистем в один чудовищный клубок.
&lt;br /&gt;[21:06] &amp;lt;dDIMA&amp;gt; Причем чем дальше&amp;nbsp; тем сильнее этот клубок завязывается.
&lt;br /&gt;[21:06] &amp;lt;dDIMA&amp;gt; Я видел примеры игровых движков, в которых базовая система анимации персонажей имела режимы анимации Male, Female и MegoBoss
&lt;br /&gt;[21:06] &amp;lt;dDIMA&amp;gt; причем логика применения анимационных секвенций зависела от этого флага!
&lt;br /&gt;[21:06] &amp;lt;dDIMA&amp;gt; Второй нюанс&amp;nbsp; тупое выделение полного проекта в новый бренч обязательно должно сопровождаться рефактором и удалением старых более не нужных объектов
&lt;br /&gt;[21:07] &amp;lt;dDIMA&amp;gt; В противном случае объем неиспользуемого в проекте &amp;lt;мусора&amp;gt; будет сильно возрастать и может достигать цифр в 20-40% общего объема кода
&lt;br /&gt;[21:07] &amp;lt;dDIMA&amp;gt; А это и лишние перекомпиляции и усложненная навигация, и общая потеря понимания, что происходит в проекте
&lt;br /&gt;[21:08] &amp;lt;dDIMA&amp;gt; Третий аспект - переплетение системного и игрового кода приводит к тому, что общая разработка библиотеки для нескольких одновременно идущих проектов становится крайне сложной задачей
&lt;br /&gt;[21:08] &amp;lt;dDIMA&amp;gt; На левом рисунке есть пересечение по времени между Project 4, 5 и 3, но совместная разработка какой-нибудь новой компоненты (например, сетевой игры) потребует достаточно долгой и мучительной вставки требуемого кода в исходники
&lt;br /&gt;[21:08] &amp;lt;dDIMA&amp;gt; (проверено на собственном опыте)
&lt;br /&gt;[21:08] &amp;lt;dDIMA&amp;gt; Потому что весь код представляет из себя большой &amp;lt;клубок&amp;gt;,
&lt;br /&gt;[21:08] &amp;lt;dDIMA&amp;gt; и вам потребуется править несколько сотен файлов по дюжине строк, чтобы оно все взлетело
&lt;br /&gt;[21:09] &amp;lt;dDIMA&amp;gt; Фактически это приводит к тому, что компания остается &amp;lt;компанией одного проекта&amp;gt;, так как...
&lt;br /&gt;[21:09] &amp;lt;dDIMA&amp;gt; на приведенном рисунке активный код продолжает использоваться только в линии Project 1 - 2 - 3 - 5, причем не самым оптимальным способом :(
&lt;br /&gt;[21:09] &amp;lt;dDIMA&amp;gt; Когда объемы данных начинают конфликтовать с заложенными в движок ограничениями, наступает коллапс
&lt;br /&gt;[21:09] &amp;lt;dDIMA&amp;gt; Вы более не можете создавать игры, основываясь на такой технологии,
&lt;br /&gt;[21:09] &amp;lt;dDIMA&amp;gt; вам надо будет бросать имеющуюся разработку и фактически начинать делать новый движок с нуля
&lt;br /&gt;[21:10] &amp;lt;dDIMA&amp;gt; Цикл развития компании по такой схеме составляет 5-8 лет, после чего технология распадается
&lt;br /&gt;[21:10] &amp;lt;dDIMA&amp;gt; Картинка справа выглядит посимпатичнее - в ней имеется четко выделенный ствол, который растет и развивается
&lt;br /&gt;[21:10] &amp;lt;dDIMA&amp;gt; Если главный движок качественно написан и состоит из достаточно независимых модулей, то вы можете разрабатывать новые компоненты движка, причем одновременно для всех текущих проектов
&lt;br /&gt;[21:10] &amp;lt;dDIMA&amp;gt; Минусы данного подхода заключаются в том, 
&lt;br /&gt;[21:10] &amp;lt;dDIMA&amp;gt; что для создания такой структуры проекта требуется крайне высокая квалификация программистов,
&lt;br /&gt;[21:11] &amp;lt;dDIMA&amp;gt; а также наличие отдельных людей, которые разрабатывают и модернизируют движок, не привязываясь к нуждам отдельно взятых проектов
&lt;br /&gt;[21:11] &amp;lt;dDIMA&amp;gt; Ибо как только в движок пролезает game specific код, начинаются проблемы у всех остальных команд
&lt;br /&gt;[21:11] &amp;lt;dDIMA&amp;gt; Крайне важно обеспечивать единость движка для всех проектов
&lt;br /&gt;[21:11] &amp;lt;dDIMA&amp;gt; Как только вы для собственного удобства делаете отдельные бренчи системного движка для отдельных игр, вы мгновенно переползаете в вариант разработки, представленный на левой картинке, со всеми вытекающими последствиями
&lt;br /&gt;[21:12] &amp;lt;dDIMA&amp;gt; Также из минусов подхода отмечу, что универсальность практически всегда означает определенную потерю перформанса
&lt;br /&gt;[21:12] &amp;lt;dDIMA&amp;gt; Делая универсальное решение вы теряете возможность сэкономить на каких-то game-specific моментах и, естественно, решение оказывается не самым высокопроизводительным
&lt;br /&gt;[21:12] &amp;lt;dDIMA&amp;gt; Цикл развития компании по такой схеме составляет 10-15 лет.
&lt;br /&gt;[21:12] &amp;lt;dDIMA&amp;gt; Технология либо обновляется в течение этого времени,
&lt;br /&gt;[21:12] &amp;lt;dDIMA&amp;gt; либо распадается в том случае, если заложенные архитектурные ограничения оказываются непреодолимыми на новом железе, платформе и т. п.
&lt;br /&gt;[21:13] &amp;lt;dDIMA&amp;gt; Цифры чисто практические на текущем железе, с ростом next-next-генов время может сокращаться
&lt;br /&gt;[21:13] &amp;lt;dDIMA&amp;gt; Естественно, в чистом виде оба подхода встречаются редко.
&lt;br /&gt;[21:14] &amp;lt;dDIMA&amp;gt; Большинство компаний стремится иметь выделенный системный код, но при этом &amp;lt;не гнушаются&amp;gt; возможностью скопировать чего-нибудь побольше из проекта в проект
&lt;br /&gt;[21:14] &amp;lt;dDIMA&amp;gt; Что касается начинающих разработчиков, то я, конечно же, ратую за второй подход, но скорее всего, первые ваши 2-3 пилотных проекта не смогут выдержать строгую схему движок-игра
&lt;br /&gt;[21:14] &amp;lt;dDIMA&amp;gt; Первый вариант разработки можно применять только при условии внимательного анализа, а что же на самом деле в проекте является универсальным, а что&amp;nbsp; специфичным для игры
&lt;br /&gt;[21:15] &amp;lt;dDIMA&amp;gt; Такой анализ должен сопровождаться постоянным рефактором (хотя о его вреде я еще скажу ниже)
&lt;br /&gt;[21:15] &amp;lt;dDIMA&amp;gt; и стремлением выделить &amp;lt;на будущее&amp;gt; универсальный системный и игровой код
&lt;br /&gt;[21:15] &amp;lt;dDIMA&amp;gt; Так,
&lt;br /&gt;[21:16] &amp;lt;dDIMA&amp;gt; Первый вопрос я кратко осветил :)
&lt;br /&gt;[21:16] &amp;lt;dDIMA&amp;gt; теперь плавно переходим ко второму пункту лекции, 
&lt;br /&gt;[21:16] &amp;lt;dDIMA&amp;gt; если есть вопросы по первой части, готов выслушать.&lt;/p&gt;
&lt;p&gt;[21:16] &amp;lt;Zeux&amp;gt; Правая картинка про движок для одной платформы?
&lt;br /&gt;[21:16] &amp;lt;dDIMA&amp;gt; Может быть для одной, может для нескольких
&lt;br /&gt;[21:16] &amp;lt;dDIMA&amp;gt; Для нескольких надо стараться, чтобы &amp;quot;ветки&amp;quot; дерева были максимально независимыми от платформ&lt;/p&gt;
&lt;p&gt;[21:16] &amp;lt;cppg&amp;gt; Разделение движок-игра - это только разделение на шаред/специфик код?
&lt;br /&gt;[21:17] &amp;lt;dDIMA&amp;gt; гуру, недопонял. Поясни вопрос, плз
&lt;br /&gt;[21:17] &amp;lt;cppg&amp;gt; Ну, вопрос, что ты называешь движком и что игрой?
&lt;br /&gt;[21:17] &amp;lt;dDIMA&amp;gt; движком - что-то общее, что можно выделить :)
&lt;br /&gt;[21:18] &amp;lt;cppg&amp;gt; Ага
&lt;br /&gt;[21:18] &amp;lt;_ShaMan_&amp;gt; я обычно придерживаюсь разделение по подсистемам
&lt;br /&gt;[21:18] &amp;lt;Cunter&amp;gt; Движок - графа, звук, управление, сеть, физика, аи, скрипт?
&lt;br /&gt;[21:18] &amp;lt;_ShaMan_&amp;gt; графический, игровой и т.д.
&lt;br /&gt;[21:21] &amp;lt;dDIMA&amp;gt; графика, звук (кроме процедурных примочек), управление, скрипты - это движок
&lt;br /&gt;[21:21] &amp;lt;dDIMA&amp;gt; Физика - часть безусловно системная, но очень много игровой специфики
&lt;br /&gt;[21:21] &amp;lt;dDIMA&amp;gt; да, забыл упомянуть, middleware тоже фактически представляет собой ствол
&lt;br /&gt;[21:22] &amp;lt;dDIMA&amp;gt; Причем за счет многолетней обкатанности - очень хороший ствол :)&lt;/p&gt;
&lt;p&gt;[21:17] &amp;lt;Darth&amp;gt; Вариант с готовым движком? Тут по идее и туда и туда тоже может уйти.
&lt;br /&gt;[21:17] &amp;lt;dDIMA&amp;gt; конечно
&lt;br /&gt;[21:18] &amp;lt;dDIMA&amp;gt; Darth: особенно хорошо он туда уходит, если поставляется без сорсов
&lt;br /&gt;[21:19] &amp;lt;dDIMA&amp;gt; Darth: Были примеры, когда народ правил системный код, а потом оригинальная игра начинала падать в единственном месте
&lt;br /&gt;[21:19] &amp;lt;dDIMA&amp;gt; (обнаружили через несколько месяцев)&lt;/p&gt;
&lt;p&gt;[21:18] &amp;lt;_Winnie&amp;gt; Интересно, если проекта три, и у любых двух есть пересечение, а у трёх вместе - нет...
&lt;br /&gt;[21:19] &amp;lt;dDIMA&amp;gt; Я специально на правом рисунке выделил, что необязательно все проекты юзают весь функционал движка
&lt;br /&gt;[21:20] &amp;lt;dDIMA&amp;gt; Т.е. если мы делаем сингплеер, нафиг нам сеть? ;)
&lt;br /&gt;[21:20] &amp;lt;dDIMA&amp;gt; А функционал - с ним посложнее будет :)&lt;/p&gt;
&lt;p&gt;[21:20] &amp;lt;_ShaMan_&amp;gt; ну я так понимаю что во втором подходе игра как бы собирается из кирпичиков?
&lt;br /&gt;[21:21] &amp;lt;_ShaMan_&amp;gt; т.е. берётся общая кодобаза и на ней строится игра
&lt;br /&gt;[21:22] &amp;lt;dDIMA&amp;gt; _ShaMan_: фактически да, из кирпичиков
&lt;br /&gt;[21:22] &amp;lt;dDIMA&amp;gt; То есть вариант 1 - это реконструкция имеющегося дома
&lt;br /&gt;[21:23] &amp;lt;dDIMA&amp;gt; вариант 2 - это сборка нового дома из блоков&lt;/p&gt;
&lt;p&gt;[21:21] &amp;lt;Cunter&amp;gt; Модульность позволит движку даже с ростом технологий держаться на плаву?
&lt;br /&gt;[21:23] &amp;lt;dDIMA&amp;gt; модульность позволяет держаться на плаву, и при необходимости менять отдельные &amp;quot;тяжелые&amp;quot; модули (если повезет)&lt;/p&gt;
&lt;p&gt;[21:24] &amp;lt;dDIMA&amp;gt; Я еще на 1 вопрос из привата отвечу
&lt;br /&gt;[21:24] &amp;lt;dDIMA&amp;gt; &amp;gt; Какой примерно процент успешных созданий живучего движка для нескольких игр одной компании?
&lt;br /&gt;[21:24] &amp;lt;dDIMA&amp;gt; Не все компании работают по второму варианту
&lt;br /&gt;[21:24] &amp;lt;dDIMA&amp;gt; Хотя многие пробуют создать свою технологию
&lt;br /&gt;[21:25] &amp;lt;dDIMA&amp;gt; Успешных - так сходу могу прикинуть примерно треть
&lt;br /&gt;[21:25] &amp;lt;dDIMA&amp;gt; Есть компании, которые вполне успешно работают по первому варианту&lt;/p&gt;
&lt;p&gt;[21:26] &amp;lt;dDIMA&amp;gt; продолжаем
&lt;br /&gt;[21:26] &amp;lt;dDIMA&amp;gt; Теперь про DG
&lt;br /&gt;[21:26] &amp;lt;dDIMA&amp;gt; С точки зрения организации взаимодействия объектов в игровом мире можно выделить 2 основные схемы работы:
&lt;br /&gt;[21:27] &amp;lt;dDIMA&amp;gt; 1. Если кому-то из объектов требуется обновление, он вызывает другой объект с запросом на Update()
&lt;br /&gt;[21:27] &amp;lt;dDIMA&amp;gt; 2. Система знает о порядке вызова объектов и сама вызывает им Update в требуемом порядке
&lt;br /&gt;[21:27] &amp;lt;dDIMA&amp;gt; Оба варианта проиллюстрированы на следующем рисунке
&lt;br /&gt;[21:27] &amp;lt;dDIMA&amp;gt; &lt;a href=&quot;http://www.ddima.ru/articles/v_lecture1/dep_graph.jpg&quot;&gt;http://www.ddima.ru/articles/v_lecture1/dep_graph.jpg&lt;/a&gt; (&lt;a href=&quot;http://www.gamedev.ru/files/images/?id=48037&quot;&gt;http://www.gamedev.ru/files/images/?id=48037&lt;/a&gt;)
&lt;br /&gt;[21:28] &amp;lt;dDIMA&amp;gt; Вариант 1 более подробно
&lt;br /&gt;[21:28] &amp;lt;dDIMA&amp;gt; World перед тем, как обновляться, вызывает Player.Update(), SkyBox.Update() и BackGroundSound.Update()
&lt;br /&gt;[21:28] &amp;lt;dDIMA&amp;gt; Игрок из себя вызывает WeaponMng.Update() и Camera.Update()
&lt;br /&gt;[21:28] &amp;lt;dDIMA&amp;gt; Аналогично послупают и все остальные объекты в сцене
&lt;br /&gt;[21:28] &amp;lt;dDIMA&amp;gt; Чтобы предотвратить рекурсивные вызовы, обычно делается темплейтный или базовый класс-переходник, в котором записывается счетчик кадров
&lt;br /&gt;[21:29] &amp;lt;dDIMA&amp;gt; Если на текущем кадре еще не было обновления объекта, то он будет обновляться, в противном случае ничего делаться не будет
&lt;br /&gt;[21:29] &amp;lt;dDIMA&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?rhk0dppm9tth&quot;&gt;http://www.everfall.com/paste/id.php?rhk0dppm9tth&lt;/a&gt;
&lt;br /&gt;[21:29] &amp;lt;dDIMA&amp;gt; Вариант 2 более подробно
&lt;br /&gt;[21:30] &amp;lt;dDIMA&amp;gt; Существует некоторый базовый класс (условно назовем его GameObject) с виртуальным методом virtual void Update()=0
&lt;br /&gt;[21:30] &amp;lt;dDIMA&amp;gt; Все перечисленные объекты наследуются от данного класса, переопределяют Update() и каким то образом сообщают в Update Manager, что объекты существуют, причем между ними есть такие-то зависимости
&lt;br /&gt;[21:30] &amp;lt;dDIMA&amp;gt; Update Manager на каждом фрейме вызывает обновление указанных объектов
&lt;br /&gt;[21:31] &amp;lt;dDIMA&amp;gt; Подход №1 прост и удобен для реализации
&lt;br /&gt;[21:31] &amp;lt;dDIMA&amp;gt; Все связи между объектами видны прямо в коде, отладка проста и эффективна
&lt;br /&gt;[21:31] &amp;lt;dDIMA&amp;gt; Однако этот вариант приводит к сильной связанности компонент приложения
&lt;br /&gt;[21:31] &amp;lt;dDIMA&amp;gt; Фактически он (если применяется в чистом виде) форсирует нас на создание не движка+игра, а большой кучи малы
&lt;br /&gt;[21:31] &amp;lt;dDIMA&amp;gt; см. еще раз на &lt;a href=&quot;http://www.ddima.ru/articles/v_lecture1/engine_game.jpg&quot;&gt;http://www.ddima.ru/articles/v_lecture1/engine_game.jpg&lt;/a&gt;, рисунок слева
&lt;br /&gt;[21:32] &amp;lt;dDIMA&amp;gt; Этот вариант также является более произволительным
&lt;br /&gt;[21:32] &amp;lt;dDIMA&amp;gt; так как если что-то не потребовалось апдейтить на текущем фрейме, то оно и не будет вызвано :)
&lt;br /&gt;[21:32] &amp;lt;dDIMA&amp;gt; Второй вариант более удобен для слабого связывания компонент игры и движка, но сложен как для реализации, так и для отладки
&lt;br /&gt;[21:32] &amp;lt;dDIMA&amp;gt; Нам требуется каким-то образом задавать порядок вызова объектов
&lt;br /&gt;[21:32] &amp;lt;dDIMA&amp;gt; и по шагам программу пройти очень и очень сложно
&lt;br /&gt;[21:32] &amp;lt;dDIMA&amp;gt; Тут вылезают наружу все тонкости событийно-управляемой системы и отладки таких приложений
&lt;br /&gt;[21:33] &amp;lt;dDIMA&amp;gt; На практике первая схема используется часто, а вот вторая в чистом виде используется крайне редко
&lt;br /&gt;[21:33] &amp;lt;dDIMA&amp;gt; Как правило, разработчики ищут компромисс с использованием событийной схемы,
&lt;br /&gt;[21:33] &amp;lt;dDIMA&amp;gt; а внутренности крупных сущностей самостоятельно вызывают внутренние апдейты для своих &amp;lt;детей&amp;gt;
&lt;br /&gt;[21:34] &amp;lt;dDIMA&amp;gt; То есть например Player является GameObject&apos;ом, а вот внутри него ручками вызывается обновление Inventory, Camera, WeaponMng и т.п. 
&lt;br /&gt;[21:34] &amp;lt;dDIMA&amp;gt; SoundManager является GameObject&apos;ом, а вот внутри него он сам напрямую вызывает BGSound, обновляет 3D источники и т.п.
&lt;br /&gt;[21:35] &amp;lt;dDIMA&amp;gt; Короткий комментарий по вопросам
&lt;br /&gt;[21:35] &amp;lt;dDIMA&amp;gt; приведенный пейст сделан для варианта, что Update() вызывается именно 1 раз на фрейм
&lt;br /&gt;[21:35] &amp;lt;dDIMA&amp;gt; Это как раз позволяет всем нахально вызывать DoUpdate() столько, сколько хочется
&lt;br /&gt;[21:35] &amp;lt;dDIMA&amp;gt; а реальный Update() придет только 1 раз
&lt;br /&gt;[21:36] &amp;lt;dDIMA&amp;gt; Если почему-то захотелось вызвать Update() дважды, можно сделать метод типа Invalidate()
&lt;br /&gt;[21:36] &amp;lt;dDIMA&amp;gt; Но будьте аккуратны - легко можно провалиться в бесконечную рекурсию :)
&lt;br /&gt;[21:36] &amp;lt;dDIMA&amp;gt; Возвращаясь ко второму моменту:
&lt;br /&gt;[21:36] &amp;lt;dDIMA&amp;gt; *второму варианту
&lt;br /&gt;[21:37] &amp;lt;dDIMA&amp;gt; Во второй схеме существенный нюанс - это порядок вызовов объектов
&lt;br /&gt;[21:37] &amp;lt;dDIMA&amp;gt; Его надо сохранять в правильном порядке, ибо если камера обновится раньше игрока, мы получим на экране отставание на фрейм с неприятными дрожаниями и прочими эффектами
&lt;br /&gt;[21:37] &amp;lt;dDIMA&amp;gt; Вариантов сортировки подписчиков Update() есть довольно много
&lt;br /&gt;[21:38] &amp;lt;dDIMA&amp;gt; самые популярные - это разные магические цифры, определяющие порядок
&lt;br /&gt;[21:38] &amp;lt;dDIMA&amp;gt; или задание зависимостей между классами
&lt;br /&gt;[21:38] &amp;lt;dDIMA&amp;gt; Как правило цифры удобны в комбинированной схеме, когда подписчиков Update() немного, а внутренние Update вызываются ручками
&lt;br /&gt;[21:39] &amp;lt;dDIMA&amp;gt; Там можно даже не городить огород с DoUpdate() - риск свалится в рекурсию минимальный
&lt;br /&gt;[21:39] &amp;lt;dDIMA&amp;gt; Также я еще рассмотрю подробнее организацию GameObject в виде единственного класса или группы классов
&lt;br /&gt;[21:39] &amp;lt;dDIMA&amp;gt; Недостатком общего единого GameObject является то, что он будет к концу разработки сильно перегружен различными методами
&lt;br /&gt;[21:39] &amp;lt;dDIMA&amp;gt; Основываясь на опыте работы с такими движками, можно прогнозировать цифру в 100-300 методов
&lt;br /&gt;[21:40] &amp;lt;dDIMA&amp;gt; Поэтому часто разбивают базовую сущность GameObject на несколько
&lt;br /&gt;[21:40] &amp;lt;dDIMA&amp;gt; Например что-то в таком роде: GameSystemObject, GameObject, SpriteObject и т.п.
&lt;br /&gt;[21:40] &amp;lt;dDIMA&amp;gt; Это позволяет как-то разнести интерфейсы и (тоже заодно) отсортировать порядки вызова
&lt;br /&gt;[21:40] &amp;lt;dDIMA&amp;gt; Но схема не лишена недостатков, ключевой из которых - жесткая фиксация различных типов объектов
&lt;br /&gt;[21:41] &amp;lt;dDIMA&amp;gt; То есть если появится какая-нибудь динамическая лава, которая взаимодействует с игроком, хитро светит на environment и т.п., ей может не найтись места среди заготовленных базовых классов
&lt;br /&gt;[21:41] &amp;lt;dDIMA&amp;gt; Как вы организуете иерархию объектов - ваше личное право
&lt;br /&gt;[21:41] &amp;lt;dDIMA&amp;gt; Можете сделать Hero public MoveableObject public GameObject public Object
&lt;br /&gt;[21:41] &amp;lt;dDIMA&amp;gt; Можете сделать 1 уровень интерфейса
&lt;br /&gt;[21:42] &amp;lt;dDIMA&amp;gt; Лично мне больше нравится более простая с точки зрения иерархии схема, как я писал ранее в ЖЖ, сильно хочется, чтобы компиляторы выдавали синтаксическую ошибку в том случае, если глубина наследования больше 3-4 :)
&lt;br /&gt;[21:42] &amp;lt;dDIMA&amp;gt; Мне сильнее импонирует схема наследования, когда в качестве базовых выступают не логически-игровые Game, Moveable, Sprite и прочие Objects,
&lt;br /&gt;[21:43] &amp;lt;dDIMA&amp;gt; а очевидные с точки зрения действия объекты Update, Render и т.п.
&lt;br /&gt;[21:43] &amp;lt;dDIMA&amp;gt; В данной схеме игровой цикл разворачивается в вызов обсерверов в некотором упорядоченном порядке, а конкретные объекты имплементируют те интерфейсы, которые им самим актуально требуются
&lt;br /&gt;[21:43] &amp;lt;dDIMA&amp;gt; Как водится, на практике часто применяется комбинированный вариант - с универсальными GameObject + дополнительные имплементации
&lt;br /&gt;[21:43] &amp;lt;dDIMA&amp;gt; Более подробно я займусь разделеняими на иерархии объектов чуть позже.
&lt;br /&gt;[21:44] &amp;lt;dDIMA&amp;gt; Сейчас небольшое лирическое отступление с красивыми картинками :)
&lt;br /&gt;[21:44] &amp;lt;dDIMA&amp;gt; Но еще раньше - давайте сделаем небольшой перерыв, даже перекур?
&lt;br /&gt;[21:44] &amp;lt;dDIMA&amp;gt; Пока что есть текущие вопросы?&lt;/p&gt;
&lt;p&gt;[21:44] &amp;lt;Zeux&amp;gt; Что является ключевым в первой схеме и что во второй?
&lt;br /&gt;[21:44] &amp;lt;Zeux&amp;gt; т.е. первая схема - это про то, что явный immediate вызов
&lt;br /&gt;[21:45] &amp;lt;dDIMA&amp;gt; ага
&lt;br /&gt;[21:45] &amp;lt;dDIMA&amp;gt; И как следствие - сильная связанность компонент
&lt;br /&gt;[21:45] &amp;lt;Zeux&amp;gt; точнее про то, что явный вызов или про то, что мгновенный?
&lt;br /&gt;[21:45] &amp;lt;Zeux&amp;gt; аналогично, вторая схема - про то, что есть один большой граф?
&lt;br /&gt;[21:45] &amp;lt;Zeux&amp;gt; или про что-то еще
&lt;br /&gt;[21:45] &amp;lt;dDIMA&amp;gt; Ну мгновенный и связанный - вещи одного плана
&lt;br /&gt;[21:46] &amp;lt;dDIMA&amp;gt; Я уже говорил, что за универсальность приходится платить
&lt;br /&gt;[21:46] &amp;lt;dDIMA&amp;gt; второй вариант более универсален, но соответственно, и тормознутее&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/game_orhetecture?page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2431</guid>
  <pubDate>Wed, 23 May 2007 21:34:09 GMT</pubDate>
  <title>Мини-лекция про IMGUI [лектор - Zeux]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2431</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=70277</comments>
  <description>
&lt;p&gt;&amp;lt;Zeux&amp;gt; типичное RMGUI приложение
&lt;br /&gt;&amp;lt;Zeux&amp;gt; имеет четко определенные стадии.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 1. инициализация контролов
&lt;br /&gt;&amp;lt;Zeux&amp;gt; она производится по-разному
&lt;br /&gt;&amp;lt;Zeux&amp;gt; либо в коде добавляются контролы
&lt;br /&gt;&amp;lt;Zeux&amp;gt; либо они описываются в xml файле
&lt;br /&gt;&amp;lt;Zeux&amp;gt; либо еще как
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 2. обновление и синхронизация
&lt;br /&gt;&amp;lt;Zeux&amp;gt; тут на самом деле 3 под-пункта
&lt;br /&gt;&amp;lt;Zeux&amp;gt; а. запихнуть изменившиеся данные приложения в контролы
&lt;br /&gt;&amp;lt;Zeux&amp;gt; (labels для текста, значения слайдеров, поменявшиеся по каким-то причинам, etc.)
&lt;br /&gt;&amp;lt;Zeux&amp;gt; b. вызвать какую-то мега-функцию GUI
&lt;br /&gt;&amp;lt;Zeux&amp;gt; которая отрендерит контролы и обновит состояние
&lt;br /&gt;&amp;lt;Zeux&amp;gt; обработает ввод, etc.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; c. запихнуть изменившиеся данные контролов в приложения
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 3. деинициализация контролов
&lt;br /&gt;&amp;lt;Zeux&amp;gt; замечу
&lt;br /&gt;&amp;lt;Zeux&amp;gt; что 3. часто делают автоматически
&lt;br /&gt;&amp;lt;Zeux&amp;gt; умными указателями
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 2.a. в некоторых случаях делают полуавтоматически
&lt;br /&gt;&amp;lt;Zeux&amp;gt; например, передавая при создании слайдера в него - указатель на данные
&lt;br /&gt;&amp;lt;Zeux&amp;gt; но тут варианты очень ограничены
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 2.c часто делают в 2.b
&lt;br /&gt;&amp;lt;Zeux&amp;gt; вызывая колбеки
&lt;br /&gt;&amp;lt;Zeux&amp;gt; тем не менее
&lt;br /&gt;&amp;lt;Zeux&amp;gt; все эти стадии есть&lt;/p&gt;
&lt;p&gt;&amp;lt;MiF&amp;gt; интересно минимально сформулированное отличие имгуя от рмгуя
&lt;br /&gt;&amp;lt;Zeux&amp;gt; сейчас попробую
&lt;br /&gt;&amp;lt;Zeux&amp;gt; хотя оно немного разное у всех :)&lt;/p&gt;
&lt;p&gt;&amp;lt;Zeux&amp;gt; так вот
&lt;br /&gt;&amp;lt;Zeux&amp;gt; IMGUI предлагает совсем другой подход
&lt;br /&gt;&amp;lt;Zeux&amp;gt; замечу
&lt;br /&gt;&amp;lt;Zeux&amp;gt; что в RMGUI основных проблем - 2
&lt;br /&gt;&amp;lt;Zeux&amp;gt; первая - информация о контролах разнесена
&lt;br /&gt;&amp;lt;Zeux&amp;gt; потому что 1. их нужно создавать/удалять, 2. ими нужно управлять
&lt;br /&gt;&amp;lt;Zeux&amp;gt; часто для упрощения управления даже делают id
&lt;br /&gt;&amp;lt;Zeux&amp;gt; т.е. CreateButton(ID_BUTTON1, params)
&lt;br /&gt;&amp;lt;Zeux&amp;gt; а потом оперируют с ID_BUTTON1
&lt;br /&gt;&amp;lt;Zeux&amp;gt; так сделано в DXUT
&lt;br /&gt;&amp;lt;Zeux&amp;gt; но в любом случае у вас в одном месте - информация о контролах, в другом - о том, как ей управлять
&lt;br /&gt;&amp;lt;Zeux&amp;gt; это - не хорошо и не плохо
&lt;br /&gt;&amp;lt;Zeux&amp;gt; разделение этой информации в некоторых случаях - очень во благо
&lt;br /&gt;&amp;lt;Zeux&amp;gt; например, когда над ней И ТАК работают разные люди
&lt;br /&gt;&amp;lt;Zeux&amp;gt; тогда у них ВСЕ РАВНО есть некоторый synchronization point
&lt;br /&gt;&amp;lt;Zeux&amp;gt; (дизайнер и программист договариваются, &amp;quot;ты назовешь этот слайдер Exposure&amp;quot;
&lt;br /&gt;&amp;lt;Zeux&amp;gt; etc.)
&lt;br /&gt;&amp;lt;Zeux&amp;gt; и наконец вторая проблема
&lt;br /&gt;&amp;lt;Zeux&amp;gt; контролы в подавляющем большинстве содержат информацию в себе
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в слайдере - есть float value
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в чекбоксе - bool checked
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в листбоксе - int selected_item, float scrollbar_position
&lt;br /&gt;&amp;lt;Zeux&amp;gt; и проблема заключается в том
&lt;br /&gt;&amp;lt;Zeux&amp;gt; что у вашего приложения стейты - совсем не такие
&lt;br /&gt;&amp;lt;Zeux&amp;gt; у вас есть enum HDRType
&lt;br /&gt;&amp;lt;Zeux&amp;gt; он где-то там хранится
&lt;br /&gt;&amp;lt;Zeux&amp;gt; конечно, не в листбоксе!
&lt;br /&gt;&amp;lt;Zeux&amp;gt; т.е. часть состояния дублируется
&lt;br /&gt;&amp;lt;Zeux&amp;gt; например, float scrollbar_position может быть и не дублируется. А может быть и дублируется - смотря что вам нужно сохранять при выходе из приложения или даже при закрытии/открытии окон
&lt;br /&gt;&amp;lt;Zeux&amp;gt; именно эти 2 проблемы и называются - Retained Mode
&lt;br /&gt;&amp;lt;Zeux&amp;gt; у вас 1. есть объекты (которые надо создавать/удалять/управлять), 2. в них хранится состояние
&lt;br /&gt;&amp;lt;Zeux&amp;gt; грубо говоря, чтобы не рисовать контрол - надо сделать ему setVisible(false).
&lt;br /&gt;&amp;lt;Zeux&amp;gt; IMGUI нацелен в основном на решение второй проблемы.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; т.е. основное отличие IMGUI
&lt;br /&gt;&amp;lt;Zeux&amp;gt; это - стейты контролов, не относящиеся к внутренней информации GUI - иначе говоря, стейты контролов, которыми приложение может хотеть управлять - управляются приложением
&lt;br /&gt;&amp;lt;Zeux&amp;gt; хранятся приложением
&lt;br /&gt;&amp;lt;Zeux&amp;gt; а не GUI.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; также IMGUI пытается решать первую проблему
&lt;br /&gt;&amp;lt;Zeux&amp;gt; пытается - потому что есть разные IMGUI, и не всегда ее целесообразно решать,
&lt;br /&gt;&amp;lt;Zeux&amp;gt; Итак, маленький пример.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; пусть у вас есть кнопка
&lt;br /&gt;&amp;lt;Zeux&amp;gt; и вы хотите, чтобы при нажатии на нее - приложение закрывалось.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; типичные способы сделать это в RMGUI.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 1.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; где-то в начале приложения: scoped_ptr&amp;lt;Button&amp;gt; button; где-то в инициализации: button.reset(new Button(data));
&lt;br /&gt;&amp;lt;Zeux&amp;gt; button-&amp;gt;setOnClick(&amp;MyFunc);
&lt;br /&gt;&amp;lt;Zeux&amp;gt; dialog-&amp;gt;add(button)
&lt;br /&gt;&amp;lt;Zeux&amp;gt; где-то в главном цикле:
&lt;br /&gt;&amp;lt;Zeux&amp;gt; dialog-&amp;gt;update();
&lt;br /&gt;&amp;lt;Zeux&amp;gt; где-то еще:
&lt;br /&gt;&amp;lt;Zeux&amp;gt; void MyFunc() { exit(); }
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 2.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; где-то в инициализации:
&lt;br /&gt;&amp;lt;Zeux&amp;gt; dialog.Load(&amp;quot;dialog.xml&amp;quot;);
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в dialog.xml:
&lt;br /&gt;&amp;lt;Zeux&amp;gt; &amp;lt;dialog&amp;gt;&amp;lt;button id=&amp;quot;Exit&amp;quot; caption=&amp;quot;Good bye!&amp;quot; width=120 height=60 /&amp;gt;&amp;lt;/dialog&amp;gt;
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в инициализации еще:
&lt;br /&gt;&amp;lt;Zeux&amp;gt; dialog-&amp;gt;setCallbackById(&amp;quot;Exit&amp;quot;, MyFunc);
&lt;br /&gt;&amp;lt;Zeux&amp;gt; MyFunc аналогична
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 3. где-то в инициализации
&lt;br /&gt;&amp;lt;Zeux&amp;gt; dialog-&amp;gt;addButton(EXIT_BUTTON_ID, data);
&lt;br /&gt;&amp;lt;Zeux&amp;gt; (выше где-то const unsigned int EXIT_BUTTON_ID = 1;)
&lt;br /&gt;&amp;lt;Zeux&amp;gt; dialog-&amp;gt;registerCallbackFunc(MyFunc);
&lt;br /&gt;&amp;lt;Zeux&amp;gt; где-то в главном цикле
&lt;br /&gt;&amp;lt;Zeux&amp;gt; dialog-&amp;gt;update();
&lt;br /&gt;&amp;lt;Zeux&amp;gt; где-то еще
&lt;br /&gt;&amp;lt;Zeux&amp;gt; void MyFunc(unsigned int id) { switch (id) { case EXIT_BUTTON_ID: exit(); break; } }
&lt;br /&gt;&amp;lt;Zeux&amp;gt; типичные способы сделать это в IMGUI:
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 1. в главном цикле: if (button(EXIT_BUTTON_ID, data)) { exit(); }
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 2. в главном цикле: if (button(GenerateUniqueIDSomehow(), data)) { exit(); }
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 3. в dialog.xml то, что выше
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в инициализации dialog.Load(&amp;quot;dialog.xml&amp;quot;);
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в главном цикле if (dialog.button(&amp;quot;Exit&amp;quot;)) { exit(); }
&lt;br /&gt;&amp;lt;Zeux&amp;gt; я пока ни слова не сказал про применимость, это потом
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в целом - отличия понятны?&lt;/p&gt;
&lt;p&gt;&amp;lt;Denton&amp;gt; да
&lt;br /&gt;&amp;lt;Denton&amp;gt; указывается не кудато а сразу делается то что надо. и работа идёт с данными приложения
&lt;br /&gt;&amp;lt;Zeux&amp;gt; да&lt;/p&gt;
&lt;p&gt;&amp;lt;Zeux&amp;gt; собственно
&lt;br /&gt;&amp;lt;Zeux&amp;gt; очевидно - IMGUI - далеко не silver bullet
&lt;br /&gt;&amp;lt;Zeux&amp;gt; как и RMGUI
&lt;br /&gt;&amp;lt;Zeux&amp;gt; более того!
&lt;br /&gt;&amp;lt;Zeux&amp;gt; очевидно, что вообще IM vs RM - мягко говоря не ограничено GUI
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в OpenGL есть immediate mode
&lt;br /&gt;&amp;lt;Zeux&amp;gt; glBegin(); отдать OpenGL СВОИ ДАННЫЕ; glEnd();
&lt;br /&gt;&amp;lt;Zeux&amp;gt; при этом - эти данные можно менять как угодно
&lt;br /&gt;&amp;lt;Zeux&amp;gt; если бы OpenGL в них писал - можно было бы свободно из них читать
&lt;br /&gt;&amp;lt;Zeux&amp;gt; есть и retained mode
&lt;br /&gt;&amp;lt;Zeux&amp;gt; glBufferData(ваши данные)
&lt;br /&gt;&amp;lt;Zeux&amp;gt; а потом glBindBuffer
&lt;br /&gt;&amp;lt;Zeux&amp;gt; чтобы изменить ваши данные
&lt;br /&gt;&amp;lt;Zeux&amp;gt; или прочесть их (если бы OpenGL их менял - или в случае с текстурами, ЕСЛИ он их поменял)
&lt;br /&gt;&amp;lt;Zeux&amp;gt; надо это сделать отдельно.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; ну и в дополнение
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в начале надо сделать glGenTextures
&lt;br /&gt;&amp;lt;Zeux&amp;gt; в конце - glDeleteTextures
&lt;br /&gt;&amp;lt;Zeux&amp;gt; надеюсь, я переврал меньше половины названий ф-ий.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; очевидно, что в данном конкретном случае - IM проще
&lt;br /&gt;&amp;lt;Zeux&amp;gt; очевидно также
&lt;br /&gt;&amp;lt;Zeux&amp;gt; что в случае статических данных
&lt;br /&gt;&amp;lt;Zeux&amp;gt; и в случае OpenGL
&lt;br /&gt;&amp;lt;Zeux&amp;gt; второй подход будет быстрее
&lt;br /&gt;&amp;lt;Zeux&amp;gt; по очевидным причинам.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; т.е. очевидно, что в разных ситуациях разные подходы применимы или не применимы в разной степени
&lt;br /&gt;&amp;lt;Zeux&amp;gt; итак
&lt;br /&gt;&amp;lt;Zeux&amp;gt; плюсы IMGUI - как я их вижу.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; - простые вещи делаются просто, потому что вы пишете ТУПОЙ, ПРЯМОЛИНЕЙНЫЙ код.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; потому что когда вам надо написать &amp;quot;закрыть при нажатии&amp;quot; - вы пишете if (button(...)) { закрыть }
&lt;br /&gt;&amp;lt;Zeux&amp;gt; когда вам надо сделать слайдер
&lt;br /&gt;&amp;lt;Zeux&amp;gt; с текстом под ним
&lt;br /&gt;&amp;lt;Zeux&amp;gt; который двигается со слайдером
&lt;br /&gt;&amp;lt;Zeux&amp;gt; и в котором меняется текст
&lt;br /&gt;&amp;lt;Zeux&amp;gt; вы пишете ровно это
&lt;br /&gt;&amp;lt;Zeux&amp;gt; float value = slider(data);
&lt;br /&gt;&amp;lt;Zeux&amp;gt; text(slider_pos.x + value * slider_width, slider_pos.y + someconstant, &amp;quot;Value: &amp;quot; + tostring(value), font_align_center);
&lt;br /&gt;&amp;lt;Zeux&amp;gt; вместо:
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 1. создания отдельного коллбека для слайдера
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 2. в нем поиска лейбла по ID
&lt;br /&gt;&amp;lt;Zeux&amp;gt; 3. в нем установки позиции и текста
&lt;br /&gt;&amp;lt;Zeux&amp;gt; если у вас есть пара editbox + slider, которые контролирует одно значение, то у вас не возникает проблем с синхронизацией.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; из очевидных соображений.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; потому что - НЕТ никакой синхронизации
&lt;br /&gt;&amp;lt;Zeux&amp;gt; она есть, когда данные представлены в нескольких местах
&lt;br /&gt;&amp;lt;Zeux&amp;gt; а здесь все данные - у вас.
&lt;br /&gt;&amp;lt;Zeux&amp;gt; - сложные вещи ИНОГДА делаются не сложнее, чем сама вещь
&lt;br /&gt;&amp;lt;Zeux&amp;gt; по тем же самым причинам
&lt;br /&gt;&amp;lt;Zeux&amp;gt; - не только код, использующий GUI, но и код самого GUI - прост, туп, прямолинеен. Это очень хорошо
&lt;br /&gt;&amp;lt;Zeux&amp;gt; потому что типично требования к GUI библиотеке меняются
&lt;br /&gt;&amp;lt;Zeux&amp;gt; - разделять функциональность не сложнее, чем в любом другом случае
&lt;br /&gt;&amp;lt;Zeux&amp;gt; это такой же код в конце концов
&lt;br /&gt;&amp;lt;Zeux&amp;gt; разделять - в смысле share&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2431&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/r_e_n_de_r</guid>
  <pubDate>Wed, 09 May 2007 21:10:32 GMT</pubDate>
  <title>Лекция #32. R.E.N.D.E.R.</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/r_e_n_de_r</link>
  <category>GSC</category>
  <category>render</category>
  <category>reverse engineering</category>
  <category>S.T.A.L.K.E.R.</category>
  <description>
&lt;p&gt;Disclaimer: некоторые реплики убраны, посты - передвинуты, опечатки - исправлены. &lt;a href=&quot;http://www.everfall.com/paste/id.php?y2a69dc2y3y8&quot;&gt;полный лог&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[19:59] &amp;lt;Zeux&amp;gt; Давайте начинать.
&lt;br /&gt;[19:59] &amp;lt;Zeux&amp;gt; Привет всем, спасибо, что пришли послушать.
&lt;br /&gt;[20:00] &amp;lt;Zeux&amp;gt; Сначала &lt;b&gt;вкратце о лекции и правилах проведения&lt;/b&gt;
&lt;br /&gt;[20:00] &amp;lt;Zeux&amp;gt; Лекция о том, как сделан рендер в игре STALKER
&lt;br /&gt;[20:00] &amp;lt;Zeux&amp;gt; Лекция будет преимущественно проходить в +m режиме
&lt;br /&gt;[20:00] &amp;lt;Zeux&amp;gt; т.е. говорить могу только я
&lt;br /&gt;[20:00] &amp;lt;Zeux&amp;gt; и несознательные слушатели
&lt;br /&gt;[20:00] &amp;lt;Zeux&amp;gt; которые являются опами
&lt;br /&gt;[20:00] &amp;lt;Zeux&amp;gt; будут делаться перерывы на вопросы
&lt;br /&gt;[20:01] &amp;lt;Zeux&amp;gt; наверное, 2-3
&lt;br /&gt;[20:01] &amp;lt;Zeux&amp;gt; если у вас возникают вопросы по ходу лекции - пишите мне в приват.
&lt;br /&gt;[20:01] &amp;lt;Zeux&amp;gt; Логи лекции будут доступны
&lt;br /&gt;[20:02] &amp;lt;Zeux&amp;gt; наверное, через час после окончания
&lt;br /&gt;[20:02] &amp;lt;Zeux&amp;gt; так что если надо будет через пол часа куда-то срочно бежать - особо не переживайте, вы сможете прочитать то, что пропустили :)
&lt;br /&gt;[20:02] &amp;lt;Zeux&amp;gt; Теперь таки начнем.&lt;/p&gt;
&lt;p&gt;[20:03] &amp;lt;Zeux&amp;gt; Эта лекция является своеобразным продолжением лекции про рендер в Обливионе (была примерно год назад). В начале той лекции я рассказывал, почему реверс игр возможен
&lt;br /&gt;[20:03] &amp;lt;Zeux&amp;gt; И рассказывал, как можно прореверсить большинство игр
&lt;br /&gt;[20:03] &amp;lt;Zeux&amp;gt; Повторяться я не буду.
&lt;br /&gt;[20:03] &amp;lt;Zeux&amp;gt; При анализе рендера Сталкера я использовал все тот же NV PerfHUD
&lt;br /&gt;[20:03] &amp;lt;Zeux&amp;gt; который доблестные разработчики все так же (как в Обливионе) забыли отключить в финале
&lt;br /&gt;[20:04] &amp;lt;Zeux&amp;gt; Так же были два полезных источника
&lt;br /&gt;[20:04] &amp;lt;Zeux&amp;gt; Один - исходники шейдеров Сталкера
&lt;br /&gt;[20:04] &amp;lt;Zeux&amp;gt; которые вынимаются из архивов с помощью утилиты
&lt;br /&gt;[20:04] &amp;lt;Zeux&amp;gt; STALKER Data Unpacker
&lt;br /&gt;[20:04] &amp;lt;Zeux&amp;gt; лежит где-то на ag.ru :)
&lt;br /&gt;[20:05] &amp;lt;Zeux&amp;gt; Второй - статья Олеся (программист графики Сталкера) в GPU Gems 2
&lt;br /&gt;[20:05] &amp;lt;Zeux&amp;gt; статья помогла значительно меньше (хотя и решила несколько вопросов), без исходников шейдеров - лекция появилась бы значительно позже
&lt;br /&gt;[20:05] &amp;lt;Zeux&amp;gt; и была бы менее подробной.&lt;/p&gt;
&lt;p&gt;[20:05] &amp;lt;Zeux&amp;gt; Ну и напоследок, перед тем как начать основную часть
&lt;br /&gt;[20:06] &amp;lt;Zeux&amp;gt; В сталкере есть несколько режимов рендеринга
&lt;br /&gt;[20:06] &amp;lt;Zeux&amp;gt; 3, если быть точным
&lt;br /&gt;[20:06] &amp;lt;Zeux&amp;gt; Я буду рассматривать только самый совершенный
&lt;br /&gt;[20:06] &amp;lt;Zeux&amp;gt; который использует Deferred Shading
&lt;br /&gt;[20:06] &amp;lt;Zeux&amp;gt; Поехали.&lt;/p&gt;
&lt;p&gt;[20:06] &amp;lt;Zeux&amp;gt; В Сталкере используется &lt;b&gt;технология Deferred Shading&lt;/b&gt;
&lt;br /&gt;[20:07] &amp;lt;Zeux&amp;gt; Я чуть-чуть расскажу о ней
&lt;br /&gt;[20:07] &amp;lt;Zeux&amp;gt; чтобы людям, с ней не знакомым, было проще.
&lt;br /&gt;[20:07] &amp;lt;Zeux&amp;gt; Основная идеология &amp;quot;обычного&amp;quot; (forward) рендеринга - для каждого меша
&lt;br /&gt;[20:07] &amp;lt;Zeux&amp;gt; послать его на отрисовку, и в шейдерах (вершинном и пиксельном) выполнить освещение
&lt;br /&gt;[20:08] &amp;lt;Zeux&amp;gt; Когда у вас появляются несколько источников - возникают несколько вариантов решения проблемы &amp;quot;как осветить меш не 1 источником, а 4&amp;quot;
&lt;br /&gt;[20:08] &amp;lt;Zeux&amp;gt; В Doom 3 проблема решена так - каждый меш рисуется столько раз, сколько на него влияет источников (на самом деле, вроде немного больше).
&lt;br /&gt;[20:08] &amp;lt;Zeux&amp;gt; Очевидно, с этим подходом возникают проблемы - увеличивается сложность трансформации геометрии
&lt;br /&gt;[20:08] &amp;lt;Zeux&amp;gt; (особенно в случае &amp;quot;тяжелых&amp;quot; вершинных шейдеров - скелетная анимация)
&lt;br /&gt;[20:09] &amp;lt;Zeux&amp;gt; Возрастает нагрузка на CPU
&lt;br /&gt;[20:09] &amp;lt;Zeux&amp;gt; из-за увеличенного количества вызовов API
&lt;br /&gt;[20:09] &amp;lt;Zeux&amp;gt; В Oblivion проблема решена чуть более хорошо, но все равно на каждый меш может приходиться до 4 кажется вызовов отрисовки
&lt;br /&gt;[20:09] &amp;lt;Zeux&amp;gt; что не очень здорово.
&lt;br /&gt;[20:09] &amp;lt;Zeux&amp;gt; Очевидно, если вам нужно осветить сцену большим количеством источников (50? 100?)
&lt;br /&gt;[20:10] &amp;lt;Zeux&amp;gt; то про подобные подходы сразу можно забыть.
&lt;br /&gt;[20:10] &amp;lt;Zeux&amp;gt; И еще одна проблема - проблема overdraw. Когда вы рисуете меш, и в пиксельном шейдере производите сложные вычисления, то не факт, что получившийся пиксель в итоге
&lt;br /&gt;[20:10] &amp;lt;Zeux&amp;gt; (после отрисовки всей сцены)
&lt;br /&gt;[20:10] &amp;lt;Zeux&amp;gt; будет виден на экране
&lt;br /&gt;[20:11] &amp;lt;Zeux&amp;gt; Это решают сортировкой по расстоянию, дополнительным проходом, заполняющим глубину, и прочим
&lt;br /&gt;[20:11] &amp;lt;Zeux&amp;gt; Deferred Shading предлагает другое решение обоих проблем
&lt;br /&gt;[20:11] &amp;lt;Zeux&amp;gt; Рендеринг разбивается на 2 стадии. 1 - заполнение т.н. G-buffer
&lt;br /&gt;[20:11] &amp;lt;Zeux&amp;gt; G-buffer - это одна или несколько полноэкранных текстур
&lt;br /&gt;[20:11] &amp;lt;Zeux&amp;gt; (размером с экран)
&lt;br /&gt;[20:12] &amp;lt;Zeux&amp;gt; содержащих всю информацию, которая нужна для того
&lt;br /&gt;[20:12] &amp;lt;Zeux&amp;gt; чтобы осветить сцену источником света, положить на нее тени
&lt;br /&gt;[20:12] &amp;lt;Zeux&amp;gt; и т.д.
&lt;br /&gt;[20:12] &amp;lt;Zeux&amp;gt; Например, очевидно, что если у вас есть в каждом пикселе его позиция в скажем world space
&lt;br /&gt;[20:12] &amp;lt;Zeux&amp;gt; его нормаль
&lt;br /&gt;[20:13] &amp;lt;Zeux&amp;gt; и diffuse color, взятый из диффузной текстуры
&lt;br /&gt;[20:13] &amp;lt;Zeux&amp;gt; то этой информации достаточно, чтобы в каждом пикселе посчитать освещенность по модели скажем Фонга
&lt;br /&gt;[20:13] &amp;lt;Zeux&amp;gt; Посчитать, находится ли он в тени (если используются Shadow maps, например)
&lt;br /&gt;[20:13] &amp;lt;Zeux&amp;gt; и т.д.&lt;/p&gt;
&lt;p&gt;[20:14] &amp;lt;Zeux&amp;gt; Поэтому в первой стадии вся сцена рендерится в G-buffer
&lt;br /&gt;[20:14] &amp;lt;Zeux&amp;gt; здесь происходит заполнение текстур позицией, нормалью, и прочим
&lt;br /&gt;[20:14] &amp;lt;Zeux&amp;gt; потом для каждого источника на экран рисуется примитив (для простоты - full screen quad)
&lt;br /&gt;[20:14] &amp;lt;Zeux&amp;gt; с хитрым пискельным шейдером
&lt;br /&gt;[20:15] &amp;lt;Zeux&amp;gt; пиксельный шейдер читает информацию из G-buffer (позицию, нормаль, diffuse цвет, etc.)
&lt;br /&gt;[20:15] &amp;lt;Zeux&amp;gt; и производит вычисление освещенности для данного источника
&lt;br /&gt;[20:15] &amp;lt;Zeux&amp;gt; Если отрендерить 100 квадов с разными параметрами источника с аддитивным блендом
&lt;br /&gt;[20:16] &amp;lt;Zeux&amp;gt; получится суммарная освещенность сцены от 100 источников.
&lt;br /&gt;[20:16] &amp;lt;Zeux&amp;gt; Замечу, что при этом геометрическая стоимость - практически нулевая
&lt;br /&gt;[20:16] &amp;lt;Zeux&amp;gt; (трансформировать 4 вершины на каждый источник)
&lt;br /&gt;[20:16] &amp;lt;Zeux&amp;gt; Количество вызовов - по 1 на каждый источник
&lt;br /&gt;[20:16] &amp;lt;Zeux&amp;gt; Однако, pixel cost - все еще большой
&lt;br /&gt;[20:17] &amp;lt;Zeux&amp;gt; Главная проблема - если в forward renderer вы можете балансировать нагрузку между VS и PS
&lt;br /&gt;[20:17] &amp;lt;Zeux&amp;gt; вынося часть вычислений освещенности в VS
&lt;br /&gt;[20:17] &amp;lt;Zeux&amp;gt; то здесь вам приходится делать все в PS
&lt;br /&gt;[20:17] &amp;lt;Zeux&amp;gt; с одной стороны - проблема, с другой - освещение юниформное - т.е. везде попиксельное :)
&lt;br /&gt;[20:18] &amp;lt;Zeux&amp;gt; Общее введение в DS на этом я завершу. Я не рассчитываю, что тем, кто не знает, что такое DS, стало все понятно - это не цель лекции - по DS есть набор статей и tutorial-ов
&lt;br /&gt;[20:18] &amp;lt;Zeux&amp;gt; Но надеюсь, что кто-то что-то понял. Сейчас я буду рассказывать, как DS реализован в сталкере - что-то станет более понятно (надеюсь): )&lt;/p&gt;
&lt;p&gt;[20:19] &amp;lt;Zeux&amp;gt; Итак.
&lt;br /&gt;[20:19] &amp;lt;Zeux&amp;gt; &lt;b&gt;В Сталкере G-buffer&lt;/b&gt; представлен тремя текстурами
&lt;br /&gt;[20:20] &amp;lt;Zeux&amp;gt; все три - формата A16B16G16R16F
&lt;br /&gt;[20:20] &amp;lt;Zeux&amp;gt; т.е. 4 канала, каждый канал - half (16-битный float)
&lt;br /&gt;[20:21] &amp;lt;Zeux&amp;gt; В первой текстуре находится нормаль в каналах RGB
&lt;br /&gt;[20:21] &amp;lt;Zeux&amp;gt; нормаль - в view space
&lt;br /&gt;[20:21] &amp;lt;Zeux&amp;gt; и, гм, hemi - в A
&lt;br /&gt;[20:21] &amp;lt;Zeux&amp;gt; что такое hemi я потом скажу :)
&lt;br /&gt;[20:22] &amp;lt;Zeux&amp;gt; во второй текстуре - позиция в каналах RGB
&lt;br /&gt;[20:22] &amp;lt;Zeux&amp;gt; тоже view space
&lt;br /&gt;[20:22] &amp;lt;Zeux&amp;gt; и индекс материала - в A
&lt;br /&gt;[20:22] &amp;lt;Zeux&amp;gt; значений индекса 4 штуки.
&lt;br /&gt;[20:22] &amp;lt;Zeux&amp;gt; т.е. 4 варианта материала
&lt;br /&gt;[20:22] &amp;lt;Zeux&amp;gt; в третьей текстуре в RGB находится цвет
&lt;br /&gt;[20:23] &amp;lt;Zeux&amp;gt; диффузный
&lt;br /&gt;[20:23] &amp;lt;Zeux&amp;gt; в четвертом канале - gloss коэффициент
&lt;br /&gt;[20:23] &amp;lt;Zeux&amp;gt; контролирующий количество спекуляра.
&lt;br /&gt;[20:23] &amp;lt;Zeux&amp;gt; Итак, первой задачей является - заполнить эти 3 текстуры.
&lt;br /&gt;[20:24] &amp;lt;Zeux&amp;gt; Для этого каждый видимый меш сцены рисуется в 3 текстуры с использованием MRT (из пиксельного шейдера возвращаются 3 цвета, каждый попадает в свою текстуру)&lt;/p&gt;
&lt;p&gt;[20:24] &amp;lt;Zeux&amp;gt; Теперь начинаются интересные вещи
&lt;br /&gt;[20:25] &amp;lt;Zeux&amp;gt; Вершины в мешах типично занимают 32 байта для статической геометрии
&lt;br /&gt;[20:25] &amp;lt;Zeux&amp;gt; 24 или 28 - для моделей персонажей и монстров
&lt;br /&gt;[20:25] &amp;lt;Zeux&amp;gt; что в них хранится.
&lt;br /&gt;[20:25] &amp;lt;Zeux&amp;gt; object space позиция вершины - float3 (12 байт)
&lt;br /&gt;[20:26] &amp;lt;Zeux&amp;gt; нормаль - byte4 (точнее, d3dcolor; 4 байта)
&lt;br /&gt;[20:26] &amp;lt;Zeux&amp;gt; касательная и бинормаль - так же
&lt;br /&gt;[20:26] &amp;lt;Zeux&amp;gt; 2 текстурных координаты - каждая в short2 (4 байта)
&lt;br /&gt;[20:27] &amp;lt;Zeux&amp;gt; это для статики, с монстрами потом
&lt;br /&gt;[20:27] &amp;lt;Zeux&amp;gt; первая текстурная координата используется для выборки из всех текстур, кроме лайтмапа
&lt;br /&gt;[20:27] &amp;lt;Zeux&amp;gt; вторая - для выборки из лайтмапа, в котором записано статическое освещение
&lt;br /&gt;[20:27] &amp;lt;Zeux&amp;gt; лайтмап оригинально - с их старого рендера
&lt;br /&gt;[20:28] &amp;lt;Zeux&amp;gt; который &amp;quot;статическое освещение&amp;quot; и про который рассказано не будет :)
&lt;br /&gt;[20:28] &amp;lt;Zeux&amp;gt; текстурные координаты изначально имеют range -32768..32767 (потому как short)
&lt;br /&gt;[20:28] &amp;lt;Zeux&amp;gt; для лайтмапа текс. координата просто делится на 32768
&lt;br /&gt;[20:29] &amp;lt;Zeux&amp;gt; получается значение [-1, 1] (используется реально [0,1]), этого хватает, т.к. тайлинг не нужен
&lt;br /&gt;[20:29] &amp;lt;Zeux&amp;gt; а лайтмапы - 2048х2048.
&lt;br /&gt;[20:29] &amp;lt;Zeux&amp;gt; текстурные координаты делятся на 1024
&lt;br /&gt;[20:29] &amp;lt;Zeux&amp;gt; получается значение [-32, 32]
&lt;br /&gt;[20:29] &amp;lt;Zeux&amp;gt; так вот
&lt;br /&gt;[20:30] &amp;lt;Zeux&amp;gt; как вы наверное заметили, в нормали, бинормали и касательной - остаются свободные компоненты - по 1 на вектор
&lt;br /&gt;[20:30] &amp;lt;Zeux&amp;gt; tangent.w и binormal.w - используются для повышения точности текстурных координат
&lt;br /&gt;[20:30] &amp;lt;Zeux&amp;gt; в них хранится значение [0, 1], которое прибавляется к текстурной координате перед делением на 1024.
&lt;br /&gt;[20:31] &amp;lt;Zeux&amp;gt; В свободной компоненте нормали хранится дополнительный фактор освещенности - скорее всего, статически просчитанный Ambient Occlusion&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/r_e_n_de_r?page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/blog/?id=2416</guid>
  <pubDate>Sat, 05 May 2007 20:09:53 GMT</pubDate>
  <title>R.E.N.D.E.R.</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/blog/?id=2416</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=64919</comments>
  <description>
&lt;p&gt;В среду, 9.05, в 20:00 MSK, состоится &lt;s&gt;я не верю, что пишу это!&lt;/s&gt; лекция Zeux-а &amp;quot;R.E.N.D.E.R.&amp;quot;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/blog/?id=2210</guid>
  <pubDate>Mon, 15 Jan 2007 18:08:43 GMT</pubDate>
  <title>Нам год!</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/blog/?id=2210</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=60036</comments>
  <description>
&lt;p&gt;Ну вот и прошёл первый год для Gamedev Lecture. Хоть идея казалась немного странной, было много споров и сомнений - Lecture всё-же вышла вполне удачной. Много интересного опыта было &amp;quot;разшарено&amp;quot; и увековечено в виде IRC логов.&lt;/p&gt;
&lt;p&gt;За этот год накопилось 30+ лекций. Многие из них золотые и несут огромное количество информации и экспы (кстати их большинство), некоторые короткие и познавательные; даже есть одна &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=1&quot;&gt;шутка-лекция&lt;/a&gt; :) (эх, первый опыт).&lt;/p&gt;
&lt;p&gt;Конечно эксперимент бы провалился без человека электро-веника &lt;b&gt;Zeux&lt;/b&gt;&apos;а, который проводил львиную долю суппорта и модерации. Так-же из постояльцев хочу отметить &lt;b&gt;MiF&lt;/b&gt;&apos;а, &lt;b&gt;kas&lt;/b&gt;&apos;а, &lt;b&gt;const&lt;/b&gt;&apos;а, &lt;b&gt;Rageous&lt;/b&gt;&apos;а, &lt;b&gt;Innochenti&lt;/b&gt;, &lt;b&gt;xmvlad&lt;/b&gt;&apos;a, &lt;b&gt;dotprod&lt;/b&gt;&apos;а, &lt;b&gt;DrPadawan&lt;/b&gt;&apos;а, &lt;b&gt;_ShaMan_&lt;/b&gt;&apos;а, &lt;b&gt;VoidEx&lt;/b&gt;&apos;а, &lt;b&gt;Sark7&lt;/b&gt;, &lt;b&gt;_Winnie&lt;/b&gt;, &lt;b&gt;ShTiRLiC&lt;/b&gt;&apos;а, &lt;b&gt;DaGGeR&lt;/b&gt;&apos;а, &lt;b&gt;cppguru&lt;/b&gt;, &lt;b&gt;XperienS&lt;/b&gt;&apos;а, &lt;b&gt;Joric&lt;/b&gt;&apos;а, &lt;b&gt;dRake&lt;/b&gt;&apos;а. (заранее извиняюсь если кого забыл занести в лист).&lt;/p&gt;
&lt;p&gt;Хочу так-же поблагодарить наших лекторов:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Zeux&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/resmgmt_1a&quot;&gt;&amp;quot;ресур менеджерах&amp;quot;&lt;/a&gt;, и конечно-же, за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=25&quot;&gt;технологиях рендера великого и ужасного - Oblivion&apos;а&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;xmvlad&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=5&quot;&gt;принципах ООП&lt;/a&gt;, &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=6&quot;&gt;физической водичке&lt;/a&gt;, &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=12&quot;&gt;цветовых пространствах&lt;/a&gt;, &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/sh&quot;&gt;Spherical Harmonics&lt;/a&gt;, &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/ga&quot;&gt;генетических алгоритмах&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;kas&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/landscape_lod_1&quot;&gt;GPU-unfriendly техниках LOD для ландшафта&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;IronPeter&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=10&quot;&gt;скелетной анимации&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;Sark7&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=13&quot;&gt;Atmospheric scattering&lt;/a&gt;, &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=27&quot;&gt;GUI&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;roman_p&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=14&quot;&gt;игровом AI&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;shodan&lt;/b&gt; - за &amp;quot;ревью&amp;quot; &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=15&quot;&gt;системы шейдерных материалов&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;Innochenti&lt;/b&gt; - за лекции о физике: &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=16&quot;&gt;GJK&lt;/a&gt;, &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=22&quot;&gt;физическое моделирование твердых тел с шарнирами и контактами&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;aruslan&lt;/b&gt; - за объемную лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=18&quot;&gt;паттернах&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;CEMEH&lt;/b&gt; - за объемную лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=19&quot;&gt;тенях&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;XperienS&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=20&quot;&gt;итеративных LCP-солверах&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;fd&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=23&quot;&gt;&amp;quot;LCP методом Лемке&amp;quot;&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;cppguru&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=24&quot;&gt;оптимизации геометрии (strips, vcache, VBO)&lt;/a&gt;.
&lt;br /&gt; 
&lt;br /&gt;&lt;b&gt;new&lt;/b&gt; и &lt;b&gt;Joric&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=26&quot;&gt;физике на основе интегрирования Верлета&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;Cool Ace&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=28&quot;&gt;GUI&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;Jihar&lt;/b&gt; - за &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=29&quot;&gt;постмортем игры &amp;quot;Трюкмания&amp;quot;&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;DaGGeR&lt;/b&gt; - за то что поведал нам о своём подходе к &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=33&quot;&gt;игровой механики&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;ShTiRLiC&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=34&quot;&gt;Symbian development&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;NexiliaN&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=35&quot;&gt;&amp;quot;Убер-система микрошейдеров&amp;quot;&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;korak&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=38&quot;&gt;спаривание редактора на C# с движком на С++&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;egge&lt;/b&gt; - за лекцию о &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=40&quot;&gt;встраивание интерпретатора C/С++ - CINT в игровой движок&lt;/a&gt;.
&lt;p&gt;&lt;b&gt;MiF&lt;/b&gt; &amp; &lt;b&gt;Rageous&lt;/b&gt;- за целую &lt;a href=&quot;http://www.gamedev.ru/community/oo_design/articles/&quot;&gt;книгу лекций о паттернах и архитектуре игрового движка&lt;/a&gt;.
&lt;p&gt;(Если кого пропустил из лекторов - заранее извиняюсь; говорите - исправим)
&lt;br /&gt;&amp;nbsp;  
&lt;br /&gt;Нельзя конечно забывать что лекций бы не было без слушателей. Благодарности всем тем кто слушал, интересовался, спрашивал, и вообще как-либо участвовал в процессе.&lt;/p&gt;
&lt;p&gt;Жгите дальше, больше, лучше! :)&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2204</guid>
  <pubDate>Thu, 11 Jan 2007 19:58:22 GMT</pubDate>
  <title>Лекция #31. Встраивание интерпретатора C/С++ - CINT - в движок [Лектор - egge]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2204</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=59888</comments>
  <description>
&lt;p&gt;&amp;lt;egge&amp;gt; перед тем как начать лекцию я хотел бы кой-че огласить
&lt;br /&gt;&amp;lt;egge&amp;gt; во первых пример здесь &lt;a href=&quot;http://ifolder.ru/843324&quot;&gt;http://ifolder.ru/843324&lt;/a&gt; [&lt;a href=&quot;http://www.gamedev.ru/download/?id=4833&quot;&gt;http://www.gamedev.ru/download/?id=4833&lt;/a&gt;]
&lt;br /&gt;&amp;lt;egge&amp;gt; во вторых пример только под линух
&lt;br /&gt;&amp;lt;egge&amp;gt; для компиляции понадобиться scons
&lt;br /&gt;&amp;lt;egge&amp;gt; &lt;a href=&quot;http://scons.org&quot;&gt;http://scons.org&lt;/a&gt;
&lt;br /&gt;&amp;lt;egge&amp;gt; можно откомпилить под MinGW, но только с цинтом
&lt;br /&gt;&amp;lt;egge&amp;gt; там два варианта компиляции
&lt;br /&gt;&amp;lt;egge&amp;gt; scons -Q -h подскажет
&lt;br /&gt;&amp;lt;egge&amp;gt; и еще переменная среды CINTSYSDIR должна указывать на папку с цинтом
&lt;br /&gt;&amp;lt;egge&amp;gt; кстати я счастливый обладатель плохого инета, так что если вы увидите что я зашел второй раз, значит предыдущие сообщения не читал
&lt;br /&gt;&amp;lt;egge&amp;gt; ну что приступим?
&lt;br /&gt;-----
&lt;br /&gt;&amp;lt;egge&amp;gt; итак, зачем нужны скрипты
&lt;br /&gt;&amp;lt;egge&amp;gt; скрипты нужны чтоб не все время не компилить код
&lt;br /&gt;&amp;lt;egge&amp;gt; когда их меняют каждые 5 минут дизайнеры
&lt;br /&gt;&amp;lt;egge&amp;gt; для безопастности
&lt;br /&gt;&amp;lt;egge&amp;gt; правда в случае с интерпретатором с/с++ это не совсем получаетcя
&lt;br /&gt;&amp;lt;egge&amp;gt; безопастность в основном зависит от реализации движка
&lt;br /&gt;&amp;lt;egge&amp;gt; еще один плюс в с/с++ скриптах - это возможность безобидно откомпилить код в релизе вместо его интерпретации
&lt;br /&gt;&amp;lt;egge&amp;gt; чтобы увеличить скорость работы игры
&lt;br /&gt;&amp;lt;egge&amp;gt; Принцип встраивания
&lt;br /&gt;&amp;lt;egge&amp;gt; встраивать цинт очень просто
&lt;br /&gt;&amp;lt;egge&amp;gt; берем хеадеры движка, вызываемые из скриптов
&lt;br /&gt;&amp;lt;egge&amp;gt; обромляем все нужное ( тоесть паблики ) дефайнами
&lt;br /&gt;&amp;lt;egge&amp;gt; далее прогоняем через cint
&lt;br /&gt;&amp;lt;egge&amp;gt; на выходе получаем два файла
&lt;br /&gt;&amp;lt;egge&amp;gt; *.h и *.c
&lt;br /&gt;&amp;lt;egge&amp;gt; включив их в проэкт
&lt;br /&gt;&amp;lt;egge&amp;gt; можно вызывать собсно то, что мы обромляли из хеадеров движка
&lt;br /&gt;&amp;lt;egge&amp;gt; в скриптах
&lt;br /&gt;&amp;lt;egge&amp;gt; далее просто загружаем файлы и выполняем функции
&lt;br /&gt;&amp;lt;egge&amp;gt; как в примере
&lt;br /&gt;&amp;lt;egge&amp;gt; название функций в скрипте должны быть уникальными
&lt;br /&gt;&amp;lt;egge&amp;gt; если хотите откомпилить скрипты заранее обычным компилятором
&lt;br /&gt;&amp;lt;egge&amp;gt; нужно просто экспортировать свой entry_point в скриптах как это делаеться при создании длл
&lt;br /&gt;&amp;lt;egge&amp;gt; тоесть для винды это __declspec(dllexport) перед обьявлением
&lt;br /&gt;&amp;lt;egge&amp;gt; делее загружаем как длл
&lt;br /&gt;&amp;lt;egge&amp;gt; только handle указываем на NULL, для загрузки из текущего процесса
&lt;br /&gt;&amp;lt;egge&amp;gt; получаем указатель на функцию и запускаем на выполнение
&lt;br /&gt;&amp;lt;egge&amp;gt; загрузка как длл позволяет отладить скрипты
&lt;br /&gt;&amp;lt;egge&amp;gt; если нужно
&lt;br /&gt;&amp;lt;egge&amp;gt; вопросы?
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; у меня вопрос - как быстро оно парсилось.
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; Намного ли быстрей обычных компиляторов при сборке в релизе?
&lt;br /&gt;&amp;lt;egge&amp;gt; процесс сборки сильно ускорился
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; И, ещё - на сколько оно медленней по сравнению с Debug-кодом обычных компиляторов?
&lt;br /&gt;&amp;lt;egge&amp;gt; нельзя тут точно сказать на сколько, медленей
&lt;br /&gt;&amp;lt;egge&amp;gt; а на сколько быстрей
&lt;br /&gt;&amp;lt;egge&amp;gt; в нашем проэкте
&lt;br /&gt;&amp;lt;egge&amp;gt; фпс понизился где-то на 10
&lt;br /&gt;&amp;lt;egge&amp;gt; по сравнению с комерческим аналогом ch
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; со скольких?
&lt;br /&gt;&amp;lt;egge&amp;gt; с 50 до 30
&lt;br /&gt;&amp;lt;egge&amp;gt; *между
&lt;br /&gt;&amp;lt;egge&amp;gt; почему такой маленький фпс?
&lt;br /&gt;&amp;lt;egge&amp;gt; потому в движке было очень мало оптимизаций
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; это в Debug-режиме?
&lt;br /&gt;&amp;lt;egge&amp;gt; &amp;lt;egge&amp;gt; по сравнению с комерческим аналогом ch, цинт быстрее в несколько раз
&lt;br /&gt;&amp;lt;egge&amp;gt; да
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; а не меряли, сколько скрипты отжирают в процентах от общего?
&lt;br /&gt;&amp;lt;egge&amp;gt; нет
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; ага
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; Ещё у кого-нибудь вопросы?..
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; вопросов нет :]
&lt;br /&gt;&amp;lt;egge&amp;gt; Встречаемые несовместимости
&lt;br /&gt;&amp;lt;egge&amp;gt; первая попавшаяся на глаза несовместимость с обычным компилятором - это макросы
&lt;br /&gt;&amp;lt;egge&amp;gt; цинт не позволяет делать макросы
&lt;br /&gt;&amp;lt;egge&amp;gt; тоесть можно использовать дефайты и ифдефы
&lt;br /&gt;&amp;lt;egge&amp;gt; но макросы - нет
&lt;br /&gt;&amp;lt;egge&amp;gt; далее инициализация структур
&lt;br /&gt;&amp;lt;egge&amp;gt; struct s i = { 0 }; // такое нельзя делать
&lt;br /&gt;&amp;lt;egge&amp;gt; это мс-специфик
&lt;br /&gt;&amp;lt;egge&amp;gt; цинт пропустит это не выдав никакого варнинга
&lt;br /&gt;&amp;lt;egge&amp;gt; нелзя инициализировать структуры в структурах
&lt;br /&gt;&amp;lt;egge&amp;gt; struct a { int i; };
&lt;br /&gt;&amp;lt;egge&amp;gt; struct b { int j; };
&lt;br /&gt;&amp;lt;egge&amp;gt; struct c{ struct a z; struct b x; } m;
&lt;br /&gt;&amp;lt;egge&amp;gt; m = { {0}, {0} }; //такое не поймент цинт
&lt;br /&gt;&amp;lt;egge&amp;gt; m = { 0, 0 }; //такое не поймент мс-компилер
&lt;br /&gt;&amp;lt;egge&amp;gt; итак выводы
&lt;br /&gt;&amp;lt;egge&amp;gt; можно почти без изменений встраивать функции для вызова из скриптов
&lt;br /&gt;&amp;lt;egge&amp;gt; увеличение скорости компиляции и линковки
&lt;br /&gt;&amp;lt;egge&amp;gt; при изменении кода не надо его постоянно компилить
&lt;br /&gt;&amp;lt;egge&amp;gt; можно вбилдить в код скрипты по релизу проэкта, для увеличения скорости выполнения
&lt;br /&gt;&amp;lt;egge&amp;gt; минусы:
&lt;br /&gt;&amp;lt;egge&amp;gt; безопастность кода очень низкая и зависить напрямую от интерфейса движка
&lt;br /&gt;&amp;lt;egge&amp;gt; некоторые несовместимости с компиляторами
&lt;br /&gt;&amp;lt;egge&amp;gt; вопросы есть?
&lt;br /&gt;&amp;lt;Juster&amp;gt; в каких проектах использовали?
&lt;br /&gt;&amp;lt;egge&amp;gt; использовалась для детской аркадной игры, которая еще вышла
&lt;br /&gt;&amp;lt;KASiak&amp;gt; не вышла?
&lt;br /&gt;&amp;lt;egge&amp;gt; нет
&lt;br /&gt;&amp;lt;egge&amp;gt; кстати извиняюсь что лекция может прошла может не очень интересно
&lt;br /&gt;&amp;lt;egge&amp;gt; это первый выход мой в свет&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2182</guid>
  <pubDate>Sun, 24 Dec 2006 20:14:42 GMT</pubDate>
  <title>Лекция #30. Спаривание редактора на C# с движком на С++ [Лектор - korak]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2182</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=59233</comments>
  <description>
&lt;p&gt;[21:17:41] korak: для начала пара слов о выборе .Net и С#.
&lt;br /&gt;[21:18:34] korak: поднималось много тем что лучше для редактора. какой язык, какая библиотека... спор штука бесполезная. поэтому просто приведу аргументы своего выбора:
&lt;br /&gt;[21:19:31] korak: * использование одной и той же среды разработки без дополнительных зависимостей. т.е. везде где есть студия есть .Net framework
&lt;br /&gt;[21:20:03] korak: * низки порог вхождения. как для C# так и для WinForms в целом
&lt;br /&gt;[21:20:23] korak: * большое комьюнити в фриварными контролами. 
&lt;br /&gt;[21:20:44] korak: * наличие механизма рефлекшена
&lt;br /&gt;[21:21:02] korak: вот основные причины. вопросы?
&lt;br /&gt;[21:21:36] Reystlin: что такое рефлекшен?
&lt;br /&gt;[21:23:34] korak: &lt;a href=&quot;http://en.wikipedia.org/wiki/Reflection_&quot; rel=&quot;nofollow&quot;&gt;http://en.wikipedia.org/wiki/Reflection_&lt;/a&gt;(computer_science)
&lt;br /&gt;[21:23:47] Reystlin: сенкс
&lt;br /&gt;[21:24:29] korak: своими словами: это механизм посредством которого можно узнать информацию о типах которые содержит программа(модуль). 
&lt;br /&gt;[21:24:45] korak: т.е. какие есть классы, какие у классов методы и т.д.
&lt;br /&gt;[21:25:33] Reystlin: понятно
&lt;br /&gt;[21:26:39] korak: ок. продолжаю.
&lt;br /&gt;[21:28:07] korak: первый блин использования .Net вышел комом. 
&lt;br /&gt;[21:28:59] korak: причина была в движке. у него не было четкого порядка инициализации, т.к. какждый модуль был оформлен в виде сингельтона.
&lt;br /&gt;[21:30:51] korak: другая причина - попытка сделать &amp;quot;быстрее&amp;quot;. было принять решение писать редактор &amp;quot;быстро&amp;quot; на CLI C++. и через 2 дня сглючил форм дизайнер. продолжать разработку на CLI C++ прекратили.
&lt;br /&gt;[21:32:33] korak: CLI C++ не глюкавый сам по себе. но MS решила не делать из него нормальный инструмент для написания оконных приложений. поэтому код получается совершенной ужасным + дизайнер форм работает медленно и периодически случаются глюки.
&lt;br /&gt;[21:34:51] korak: после этого грабли кончились :)
&lt;br /&gt;[21:36:13] korak: решили не &amp;quot;халявить&amp;quot;. за 2 дня был написан прототип редактора который работал с движком через адаптер - .Net C++ CLI dll.
&lt;br /&gt;[21:37:39] korak: дальше буду расказывать о том хорошем что получили от .Net и С# и какие сложности предолели. если есть вопросы лучше задать.
&lt;br /&gt;[21:38:53] korak: ок. вопросов нет :)
&lt;br /&gt;[21:38:59] korak: есть.
&lt;br /&gt;[21:40:20] korak: egge: вы экспортили классы в длл? 
&lt;br /&gt;[21:41:12] korak: в C# классы не экспортили. для классов писалась обвязка на CLI C++ - обвязка являлась .Net объектом и с ней уже&amp;nbsp; работал редактор. 
&lt;br /&gt;[21:42:44] korak: egge: тоесть вы начали писать только после того как у вас движок был полностью написан? 
&lt;br /&gt;[21:43:23] korak: нет, движок полностью написан не был. но базовые классы и механизмы движка уже были в стабильной стадии.
&lt;br /&gt;[21:44:51] korak: продолжаю. 
&lt;br /&gt;[21:48:06] korak: манаджед языки имеют ограничения на создания найтив типов 
&lt;br /&gt;[21:50:44] korak: очень полезным ресурсом по вопросам связанным с .Net оказался rsdn.ru
&lt;br /&gt;[21:52:08] korak: Но как часто бывает решения &amp;quot;наших&amp;quot; проблем там не было. писались классе хендлеры для оборачивания Boost::shared_ptr&amp;lt;&amp;gt; на игровые объекты, хелперные классы для перехвата лога движка и пр. 
&lt;br /&gt;[21:54:34] korak: к сожалению из-за предновогодней суеты я не успел подготовить исходники по этим проблемам. исправлю это упущение в ближайшее время.
&lt;br /&gt;[21:58:08] korak: далее шли только &amp;quot;плюшки&amp;quot; от .Net. на codeproject была найдена библиотека контролов с поддержкой докинга и сохранением раскаладки, так была решена проблема кастомизации редактора под нужны программистов и артистов. там же был найдет и вставлен за пару часов контрол изменения цвета. 
&lt;br /&gt;[21:58:46] korak: общая архитектура системы этот момент была такая:
&lt;br /&gt;[22:01:05] korak: создавался редактор. он передвал хэндл на окно для рендера в метод создания движка. движок грузил данные прописанные в &amp;quot;стартовом&amp;quot; xml файле
&lt;br /&gt;[22:01:40] korak: редактор узнавал об добавлении\\удалении объектов сцены через&amp;nbsp; callback 
&lt;br /&gt;[22:03:07] korak: главный цикл крутился в редакторе, где и вызывались engine::tick и engine::render
&lt;br /&gt;[22:04:53] korak: изначально были написаны обвязки только для базовых типов движка. по мере необходимости дописались wrapperы для остальных типов. написание 1 врапера занимало &amp;lt;= 1 час.
&lt;br /&gt;[22:06:44] korak: выделив объект в списке объектов сцены, можно было редактировать его паблик совойства в property grid редактора.
&lt;br /&gt;[22:10:36] korak: список объектов сцены содержал только объекты базового типа. и этого было достаточно для работы механизмов выделения и редактирования св-в через property grid контрол.
&lt;br /&gt;[22:13:49] korak: кастомизация работы с контретными типами достигалась за счет использования RTTI - проверялся тип выбранного объекта и если он приводился, например к типу AnimatedObject, то создавалось окно со списком анимаций.
&lt;br /&gt;[22:16:19] korak: так же в врапперной DLL использовались 2 класса атрибутов. которыми помечались методы класса, для представления их в виде кнопочек редактора, один атрибут отвечал за кнопочки на toolbar другой - на tab panel объекта. параметрами атрибутов были: отображаемый текст, текст тултипа, имя файла с картинкой.
&lt;br /&gt;[22:17:50] korak: так же с помощью атрибутов превратили в кнопочки сервисные методы движка, как, например, перезагрузка всех текстур.
&lt;br /&gt;[22:18:14] korak: вопросы и закругляюсь.
&lt;br /&gt;[22:22:13] korak: egge: сколько было потраченно времени и стоит ли оно того? я имею ввиду вобще написание редактора 
&lt;br /&gt;[22:22:32] korak: базовая версия была написана за неделю. потом только расширялась, причем другими людьми. впрочем об этом будет подробней в заключении.
&lt;br /&gt;[22:28:21] korak: xmvlad: как происходила сериализация и миграция данных между движком и редактором? то есть добавили пачку новых свойств как преобразовывались старые данные редактора? 
&lt;br /&gt;[22:28:28] korak: что значит старые данные? 
&lt;br /&gt;[22:28:48] korak: xmvlad: ну наклепали часть сцены. потом добавились новые свойства материалов например.
&lt;br /&gt;[22:29:27] korak: а причем тут редактор? загрузку он только делегирует движку. поддержка и расширения формата данных движка - тема, вероятно, другой лекции. причем не моей :)
&lt;br /&gt;[22:30:14] korak: заключение:
&lt;br /&gt;[22:31:23] korak: базовая версия редактора с 0 была написана где-то за 1 неделю. включая враперную DLL и редактирования базовых св-в игровых объектов, как то цвет, позиция, имя, т.д.
&lt;br /&gt;[22:36:01] korak: все цели которые ставились написанием редактора были достигнуты. основные проблемы были связанны с изначальной непродуманностью архитекторы движка в целом.
&lt;br /&gt;[22:36:12] korak: *архитектуры.
&lt;br /&gt;[22:36:58] kas: вот у меня вопрос - делали undo/redo? врапер не станет ли толстым слишком изза етого?
&lt;br /&gt;[22:37:24] korak: экспорт утилитарных методов в редактор занимал меньше времени чем тоже самое на ingame gui
&lt;br /&gt;[22:39:09] kas: ну, по опыту написания остального, тяжело было бы внедрить?
&lt;br /&gt;[22:39:34] kas: на что следует обращать внимание при написании движка, чтобы потом можно было безболезненно оборачивать?
&lt;br /&gt;[22:39:45] korak: нет. тут бы и проявился один из основных плюсов врапера - то что логика редактора никак не влияет на движок.
&lt;br /&gt;[22:40:34] korak: kas, класические советы. ничего более.
&lt;br /&gt;[22:40:45] viv_: nothing more
&lt;br /&gt;[22:40:52] korak: просто код должен быть кодом а не помойкой :)
&lt;br /&gt;[22:40:55] kas: ага. понимать. ещё раз спасибо :)
&lt;br /&gt;[22:41:23] viv_: Это можно подискусировать? /me счетает если код помойка - то это просто кажеццо
&lt;br /&gt;[22:41:32] egge: а что насчет функционала?
&lt;br /&gt;[22:42:06] kas: насамом деле приятно конечно, пропертигрид пропертя автоматом показывает, вынес во врапер всякого и радуйся...
&lt;br /&gt;[22:42:12] korak: очень лично меня радовало что разный крап связанный с логикой редактирования никак не добавлял мусора и багов&amp;nbsp; в движок :)
&lt;br /&gt;[22:44:04] ** *kas понял что его основная ошибка была с++/cli*&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=2182&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=816</guid>
  <pubDate>Wed, 28 Jun 2006 20:43:39 GMT</pubDate>
  <title>Лекция #29. Убер-система микрошейдеров [Лектор - NexiliaN]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=816</link>
  <description>
&lt;p&gt;Disclaimer: некоторые опечатки поправлены, некоторые реплики передвинуты. &lt;a href=&quot;http://www.everfall.com/paste/id.php?ggtu9bh6ysfu&quot;&gt;полный лог &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[22:59] &amp;lt;_NexiliaN_&amp;gt; речь в общем о довольно простой вещи - незнаю почему такая шумиха
&lt;br /&gt;[22:59] &amp;lt;_NexiliaN_&amp;gt; и так.
&lt;br /&gt;[22:59] &amp;lt;_NexiliaN_&amp;gt; Здравствуйте товарищи! )
&lt;br /&gt;[22:59] &amp;lt;_NexiliaN_&amp;gt; и так начинаем наш сказ про убер микро шОйдеры.
&lt;br /&gt;[22:59] &amp;lt;_NexiliaN_&amp;gt; Пролог:
&lt;br /&gt;[22:59] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp;  1.&amp;nbsp; Убер-система микрошейдыров&amp;nbsp; за это название спасибо Zeux.
&lt;br /&gt;[22:59] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; a.&amp;nbsp; Убер-Шаудеры это очень толстые монстры с тонной #if/def 
&lt;br /&gt;[22:59] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  это из другой оперы в общем.
&lt;br /&gt;[22:59] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; b.&amp;nbsp; Речь же идёт о microshaders
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp;  2.&amp;nbsp; система microshaders собирает код из фрагментов.
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; 3.&amp;nbsp; Фрагмент ( микро-шадер ) - код на asm или на языке высокого
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; уровня( от реализаций ) с входными/выходными данными,
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; требованиями и профилем.
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; 4.&amp;nbsp; лекция идёт as-is, то есть обвинять лектора в обкуренности
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; не стоит.&lt;/p&gt;
&lt;p&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; далее немного поиграю в q.a;)&lt;/p&gt;
&lt;p&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; q. &lt;b&gt;что такое микро шадеры&lt;/b&gt; и чем они лучше убершадеров?
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; a. Убер-шадеры явно фиксированные(#if/def)&amp;nbsp; могут помочь
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; сгенерировать несколько вариаций, но в пределах максимально
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; заложенных возможностей *препроцессор рулит . Микро шадеры от
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; данного недостатка избавлены и могут свободно комбинироваться c
&lt;br /&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; заранее неизвестными.&lt;/p&gt;
&lt;p&gt;[23:00] &amp;lt;_NexiliaN_&amp;gt; q. &lt;b&gt;зачем это надо? Как это отразится на материалах?&lt;/b&gt;
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; a. в общем-то со стороны материала мало что меняется. Это скорее
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; более тонкие возможности.
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp;  Пример: в материале обычно есть модификатор diffuse&amp;nbsp; он
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; отвечает за diffuse(цвет точки без затенения)
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp;  например: color = sample2D(diffise,&amp;nbsp; uv) + sample2D(noise ,
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; uv + time * 2) * sample(mask, uv). =))
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp;  и такой эффект скажем, встречается крайне редко.
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp;  Что нам теперь делать описывать все вариаций shadera или
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; очередной uber-shader для света, кожинга и т.д.? ;)
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp;  А в случай с microshaders эта проблема отпадает.
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp;  Для этого примера мы просто создаём материал, указываем
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; модификатор и создаём новый microshader который и делает
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; указанную операцию.&lt;/p&gt;
&lt;p&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; q. &lt;b&gt;что такое модификатор?&lt;/b&gt;
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; a. модификатор это система управление определёнными группами
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; microshaderев. *Модификаторов столько, сколько и систем.
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp;  К Примеру: diffuse, lightmap, light, posteffect и т.д. Они
&lt;br /&gt;[23:01] &amp;lt;_NexiliaN_&amp;gt; зависимы и расположены иерархически. Вернёмся к ним позднее.&lt;/p&gt;
&lt;p&gt;[23:02] &amp;lt;_NexiliaN_&amp;gt; q. то есть если просто к материалу прицепит модификатор?
&lt;br /&gt;[23:02] &amp;lt;_NexiliaN_&amp;gt; skinning, shader автоматически скомпилируется?
&lt;br /&gt;[23:02] &amp;lt;_NexiliaN_&amp;gt; a. да. Только не к материалу, а непосредственно к объекту/render
&lt;br /&gt;[23:02] &amp;lt;_NexiliaN_&amp;gt; actorу. (меш если хотите)
&lt;br /&gt;[23:02] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp;  К примеру: есть на просторах, новой Зеландий, меш травы
&lt;br /&gt;[23:02] &amp;lt;_NexiliaN_&amp;gt; (конопли, если хотите)
&lt;br /&gt;[23:02] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; мы к этому объекту просто прицепляем глобальный
&lt;br /&gt;[23:02] &amp;lt;_NexiliaN_&amp;gt; модификатор Vegetation waves.
&lt;br /&gt;[23:02] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp;  Разумеется, веса должны хранится в потоке vb.&lt;/p&gt;
&lt;p&gt;[23:02] &amp;lt;_NexiliaN_&amp;gt; &lt;b&gt;Лекция:&amp;nbsp; begin: часть 1&lt;/b&gt;
&lt;br /&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; Система microshaderев представляем из себя набор и фрагментов
&lt;br /&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; на любом языке дружественный для GPU.
&lt;br /&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; Позволяет собирать из них полноценные программы для GPU
&lt;br /&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; (shaders).
&lt;br /&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; Формирует RenderGraph (точнее его узел). - Выходной сценарий
&lt;br /&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; обрисовки.- Последовательность установки буферов, shaderов и
&lt;br /&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; т.д.
&lt;br /&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; Я предпочёл asm в своё время (точнее свой скрипт).&amp;nbsp; это
&lt;br /&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; позволило более точно оценивать длину фрагмента и точнее
&lt;br /&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; профилировать( hlsl такого на компилит порой ). ;)&lt;/p&gt;
&lt;p&gt;[23:03] &amp;lt;_NexiliaN_&amp;gt; &lt;b&gt;MicroShader и методы&lt;/b&gt; ( в дальнейшем microshader == ms )
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp;  1.&amp;nbsp; Method&amp;nbsp; это непосредственно код GPU и все параметры
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; необходимые для того объекта.
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; a.&amp;nbsp; Описывается как тип method программы (может быть 
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  ps/vs/psva/any в будущем сложнее).
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; i.&amp;nbsp; Пример: &amp;lt; method type=&amp;quot;any&amp;quot; name=&amp;quot;Normalize&amp;quot; template_name =
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;quot;vector3&amp;quot; &amp;gt;
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1.&amp;nbsp; type&amp;nbsp; тип программы
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt; 2.&amp;nbsp; name&amp;nbsp; имя
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt; 3.&amp;nbsp; template_name&amp;nbsp; имя для другим программ. ( реализация =] )
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; b.&amp;nbsp; Link&amp;nbsp; указывает явные зависимости программ.
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; i.&amp;nbsp; К Примеру: пиксельная программа ссылается на нужную для неё
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; vs программу.
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1.&amp;nbsp; Например:&amp;nbsp; &amp;lt;link type=vs name=baryCentricCoord&amp;gt;
&lt;br /&gt;[23:05] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  a.&amp;nbsp; Именно это устанавливает связку программ.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;
&lt;br /&gt;[23:06] &amp;lt;_NexiliaN_&amp;gt; korak : для какого АПИ была реализована система?
&lt;br /&gt;[23:07] &amp;lt;_NexiliaN_&amp;gt; апи значение иметь небудет если вы позаботитесь о собственном скрипте
&lt;br /&gt;&lt;/i&gt;
&lt;p&gt;[23:07] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; c.&amp;nbsp; Include&amp;nbsp; тоже что и #include в cpp&amp;nbsp; целые ms
&lt;br /&gt;[23:07] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; i.&amp;nbsp; Пример: &amp;lt;include name = &amp;quot;Normalize&amp;quot;/&amp;gt;
&lt;br /&gt;[23:07] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; d.&amp;nbsp; Common&amp;nbsp; указывается необходимый общий ms до этого ms.
&lt;br /&gt;[23:07] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; i.&amp;nbsp; Пример: в случай со светом
&lt;br /&gt;[23:07] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1.&amp;nbsp; &amp;lt;common name = ReflectVector/&amp;gt;
&lt;br /&gt;[23:07] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  a.&amp;nbsp; этот объект встанет выше последнего просившего.&amp;nbsp; хотя его
&lt;br /&gt;[23:07] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; также можно запросить в IO.
&lt;br /&gt;[23:07] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  i.&amp;nbsp; Применяется в частных случаях.
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; e.&amp;nbsp; IO&amp;nbsp; входящий и выходящие параметры (сроковыми именами)
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; i.&amp;nbsp; К Примеру: &amp;lt;IO input = &amp;quot;vector3&amp;quot; var = &amp;quot;invec&amp;quot; proxy = any
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; params =/&amp;gt;
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  a.&amp;nbsp; input&amp;nbsp; создает переменную IO для фрагмента. Где явно
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; указывает, с чем работаем. Это может быть строковое имя.
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  i.&amp;nbsp; Например, явное указание:&amp;nbsp; в место vector3&amp;nbsp; normal3 (что
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  потребует до этого фрагмента нормаль). Не в этом случай.
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 2.&amp;nbsp; var&amp;nbsp; имя как будет называться в нутрии фрагмента эта IO
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  переменная.
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 3.&amp;nbsp; proxy&amp;nbsp; явные Тип. (например, что это anyFloat3).
&lt;br /&gt;[23:08] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 4.&amp;nbsp; params&amp;nbsp; доп. Параметры.
&lt;br /&gt;[23:09] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ii. К Примеру: &amp;lt;IO output = &amp;quot;vector3&amp;quot; var = &amp;quot;outvec&amp;quot; proxy=any
&lt;br /&gt;[23:09] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; params=/&amp;gt;
&lt;br /&gt;[23:11] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; f.&amp;nbsp; Далее описывается: порядок параметров&amp;nbsp; необходимо
&lt;br /&gt;[23:11] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  использование линковки в телах других фрагментов.
&lt;br /&gt;[23:11] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; i.&amp;nbsp; К Примеру: &amp;lt;func_order&amp;gt; &amp;lt;order name = &amp;quot;outvec&amp;quot;/&amp;gt; &amp;lt;order name
&lt;br /&gt;[23:11] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; = &amp;quot;invec&amp;quot;/&amp;gt; &amp;lt;/func_order&amp;gt;.
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  ii. Обязательно только для библиотечных ms как эта.
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; g.&amp;nbsp; Requare&amp;nbsp; описание требований (констант или текстур и т.д.)
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; i.&amp;nbsp; Пример: &amp;lt;require texLookUp = &amp;quot;normalizeCubeMap&amp;quot; var =
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;quot;nrmLookUp&amp;quot;/&amp;gt; - $к этому примеру не относится.
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1.&amp;nbsp; сто соответственно запросит самплер normalizeCubeMap 
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;  переменная nrmLookUp - $к этому примеру не относится.
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ii. Пример: &amp;lt;require global_constant = adaptiveBias, var =
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; bias/&amp;gt; - $к этому примеру не относится.
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; iii.Пример: &amp;lt;require interpolator = diffuse_uv, var = bias/&amp;gt;
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - и т.д. - $к этому примеру не относится.
&lt;br /&gt;[23:12] &amp;lt;_NexiliaN_&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1.&amp;nbsp; diffuse_uv равна общей uv.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=816&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/blog/?id=807</guid>
  <pubDate>Sun, 25 Jun 2006 09:39:55 GMT</pubDate>
  <title>Убер-система микрошейдеров</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/blog/?id=807</link>
  <description>
&lt;p&gt;В среду, 28.06, в 23:00 MSK, состоится лекция &lt;b&gt;NexiliaN&lt;/b&gt;-а &amp;quot;Убер-система микрошейдеров.&amp;quot;&lt;/p&gt;
&lt;p&gt;Также выложены &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=34&quot;&gt;логи прошедшей лекции&lt;/a&gt; Symbian development (лектор - &lt;b&gt;ShTiRLiC&lt;/b&gt;).&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=806</guid>
  <pubDate>Sat, 24 Jun 2006 20:40:09 GMT</pubDate>
  <title>Лекция #28. Symbian development [Лектор - ShTiRLiC]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=806</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=1271</comments>
  <description>
&lt;p&gt;Disclaimer: некоторые опечатки поправлены, некоторые реплики передвинуты. &lt;a href=&quot;http://www.everfall.com/paste/id.php?5unzv6q8h390&quot;&gt;полный лог&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[21:01] &amp;lt;ShTiRLiC&amp;gt; &lt;b&gt;Итак, что же такое Symbian OS?&lt;/b&gt; Это полноценная 32-битная операционная система, многозадачная, с разделением времени процессов
&lt;br /&gt;[21:02] &amp;lt;ShTiRLiC&amp;gt; Работает она на смартфонах и некоторых КПК
&lt;br /&gt;[21:02] &amp;lt;ShTiRLiC&amp;gt; В основном, Симбиан ставится на смартфоны Nokia, также Ericsson
&lt;br /&gt;[21:02] &amp;lt;ShTiRLiC&amp;gt; Симбиан на рынке смартфонов охватывает порядка 60-70% рынка
&lt;br /&gt;[21:02] &amp;lt;ShTiRLiC&amp;gt; Для сравнения, WinMobile - 20%
&lt;br /&gt;[21:03] &amp;lt;ShTiRLiC&amp;gt; Собственно, я в лекции не буду рассматривать подробно создание UI
&lt;br /&gt;[21:03] &amp;lt;ShTiRLiC&amp;gt; Потому что в играх он все равно графический&lt;/p&gt;
&lt;p&gt;[21:03] &amp;lt;ShTiRLiC&amp;gt; &lt;b&gt;Немного про SDK&lt;/b&gt;
&lt;br /&gt;[21:03] &amp;lt;ShTiRLiC&amp;gt; Его можно скачать на сайте &lt;a href=&quot;http://forum.nokia.com&quot;&gt;http://forum.nokia.com&lt;/a&gt;, весит 145 метров
&lt;br /&gt;[21:04] &amp;lt;ShTiRLiC&amp;gt; да, у меня Nokia 6630, и именно отталкиваясь от поддерживаемого им Симбиана я буду отталкиваться
&lt;br /&gt;[21:04] &amp;lt;ShTiRLiC&amp;gt; У меня стоит Symbian 8.0a, на довольно известных Nokia N-Gage - Symbian 6
&lt;br /&gt;[21:04] &amp;lt;ShTiRLiC&amp;gt; Между ними на устройствах Symbian 7.0s
&lt;br /&gt;[21:04] &amp;lt;ShTiRLiC&amp;gt; Еще замечу, что связь у меня не очень стабильная, и я могу вылетать
&lt;br /&gt;[21:05] &amp;lt;ShTiRLiC&amp;gt; Так, значит про SDK
&lt;br /&gt;[21:05] &amp;lt;ShTiRLiC&amp;gt; Он реализован в виде огромной системы классов
&lt;br /&gt;[21:05] &amp;lt;ShTiRLiC&amp;gt; Совсем непривычно, да?
&lt;br /&gt;[21:05] &amp;lt;ShTiRLiC&amp;gt; В знакомых большинству системах SDK - всего лишь набор функций в C-стиле
&lt;br /&gt;[21:05] &amp;lt;ShTiRLiC&amp;gt; Отсюда специфика разработки приложений под Symbian&lt;/p&gt;
&lt;p&gt;[21:06] &amp;lt;ShTiRLiC&amp;gt; Начнем с &lt;b&gt;первого типа программ - EXE&lt;/b&gt;
&lt;br /&gt;[21:06] &amp;lt;ShTiRLiC&amp;gt; Эти программы все консольные, то есть работают в текстовом режиме
&lt;br /&gt;[21:06] &amp;lt;ShTiRLiC&amp;gt; На эмуляторе их легко создавать, т.к. там по сути то же самое, что и в программах на C - одна главная функция и операторы вывода в консоль
&lt;br /&gt;[21:08] &amp;lt;ShTiRLiC&amp;gt; Примеры будут преимущественно из SDK
&lt;br /&gt;[21:08] &amp;lt;ShTiRLiC&amp;gt; Итак, Hello World для консоли
&lt;br /&gt;[21:08] &amp;lt;ShTiRLiC&amp;gt; Вас, возможно, удивит его вид, т.к. отличия от DOS найти сложно
&lt;br /&gt;[21:09] &amp;lt;ShTiRLiC&amp;gt; Ну и вообще от консоли
&lt;br /&gt;[21:09] &amp;lt;ShTiRLiC&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?fedt6qjtyovi&quot;&gt;http://www.everfall.com/paste/id.php?fedt6qjtyovi&lt;/a&gt;
&lt;br /&gt;[21:09] &amp;lt;ShTiRLiC&amp;gt; Вот так всё примитивно
&lt;br /&gt;[21:09] &amp;lt;ShTiRLiC&amp;gt; Однако, запустить такую программу на телефоне весьма затруднительно
&lt;br /&gt;[21:09] &amp;lt;ShTiRLiC&amp;gt; По крайней мере, у меня ничего не вышло =)
&lt;br /&gt;[21:10] &amp;lt;ShTiRLiC&amp;gt; Дело в том, что в формате EXE обычно создаются сервисы - не имеющие интерфейса (UI имею в виду), работающие в фоне
&lt;br /&gt;[21:10] &amp;lt;ShTiRLiC&amp;gt; В загруженной ОСи, в которой еще ничего не запущено, работает порядка 64 процессов
&lt;br /&gt;[21:10] &amp;lt;ShTiRLiC&amp;gt; Почти все эти программы - консольные
&lt;br /&gt;[21:10] &amp;lt;ShTiRLiC&amp;gt; Нас они не очень интересуют, т.к. игры там писать довольно сложно =)&lt;/p&gt;
&lt;p&gt;[21:11] &amp;lt;ShTiRLiC&amp;gt; Поэтому закроем эту тему и перейдем к &lt;b&gt;более интересному виду приложения - .APP&lt;/b&gt;
&lt;br /&gt;[21:11] &amp;lt;ShTiRLiC&amp;gt; Аппы - это визуальные приложения
&lt;br /&gt;[21:11] &amp;lt;ShTiRLiC&amp;gt; На самом деле, они не являются истинно исполняемыми файлами, т.к. банально не имеют точки входа =)
&lt;br /&gt;[21:12] &amp;lt;ShTiRLiC&amp;gt; APP - это DLL
&lt;br /&gt;[21:12] &amp;lt;ShTiRLiC&amp;gt; UI фреймворк симбиана вызывает определенные экспортированные функции из этой DLL, получая в ответ необходимые &lt;u&gt;объекты&lt;/u&gt;
&lt;br /&gt;[21:13] &amp;lt;ShTiRLiC&amp;gt; Повторю, что в симбиане вся работа приложения построена на объектах, никто не даст вам вызвать какие-либо функции напрямую
&lt;br /&gt;[21:13] &amp;lt;ShTiRLiC&amp;gt; Минимальная APP-программа (далее - просто программа) состоит из 4-х классов
&lt;br /&gt;[21:14] &amp;lt;ShTiRLiC&amp;gt; И вообще, вся система работы симбиан-программы построена по концепции UI-Документ-Вид
&lt;br /&gt;[21:14] &amp;lt;ShTiRLiC&amp;gt; Собственно, это три основные класса
&lt;br /&gt;[21:14] &amp;lt;ShTiRLiC&amp;gt; Еще один класс - это т.н. ядро (я называю его так)
&lt;br /&gt;[21:14] &amp;lt;ShTiRLiC&amp;gt; Ядро создает &lt;u&gt;документ&lt;/u&gt;
&lt;br /&gt;[21:14] &amp;lt;ShTiRLiC&amp;gt; В ядре должны содержаться 4 функции
&lt;br /&gt;[21:15] &amp;lt;ShTiRLiC&amp;gt; (кстати, минимальная программа легко создается визардом нового приложения, так что вам не придется писать эту рутину руками)
&lt;br /&gt;[21:15] &amp;lt;ShTiRLiC&amp;gt; Кратенько перечислю, что они делают, без названий
&lt;br /&gt;[21:16] &amp;lt;ShTiRLiC&amp;gt; Также ща закину исходник на everfall
&lt;br /&gt;[21:16] &amp;lt;ShTiRLiC&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?worqeq998ob6&quot;&gt;http://www.everfall.com/paste/id.php?worqeq998ob6&lt;/a&gt;
&lt;br /&gt;[21:16] &amp;lt;ShTiRLiC&amp;gt; Пожалуйста, следите за исходником
&lt;br /&gt;[21:17] &amp;lt;ShTiRLiC&amp;gt; Метод AppDllUid должен вернуть UID приложения
&lt;br /&gt;[21:17] &amp;lt;ShTiRLiC&amp;gt; UID - это уникальный номер, который есть у каждой программы
&lt;br /&gt;[21:17] &amp;lt;ShTiRLiC&amp;gt; Собственно, в целях тестирования можно вбить что-нибудь, не входящее в диапазоны системных UID&apos;ов
&lt;br /&gt;[21:18] &amp;lt;ShTiRLiC&amp;gt; Но при релизе необходимо бесплатно запросить у Symbian Ltd. уникальный UID (соответственно его названию =))
&lt;br /&gt;[21:18] &amp;lt;ShTiRLiC&amp;gt; Дают обычно пачками, сразу 10-20 штук
&lt;br /&gt;[21:18] &amp;lt;ShTiRLiC&amp;gt; Просто если в системе будет более одного UID&apos;а, возникнут проблемы
&lt;br /&gt;[21:18] &amp;lt;ShTiRLiC&amp;gt; Далее
&lt;br /&gt;[21:19] &amp;lt;ShTiRLiC&amp;gt; CreateDocumentL() - этот метод вызывается фреймворком Symbian
&lt;br /&gt;[21:19] &amp;lt;ShTiRLiC&amp;gt; Приложение должно создать и вернуть в ответ указатель на документ приложения
&lt;br /&gt;[21:19] &amp;lt;ShTiRLiC&amp;gt; Так, вкратце про документы
&lt;br /&gt;[21:19] &amp;lt;ShTiRLiC&amp;gt; Документ - объект хранения данных, например, сейвов или действительно документов
&lt;br /&gt;[21:20] &amp;lt;ShTiRLiC&amp;gt; В принципе, в наших целях он использоваться не будет
&lt;br /&gt;[21:20] &amp;lt;ShTiRLiC&amp;gt; Все данные лучше грузить руками через сервер файловой системы
&lt;br /&gt;[21:20] &amp;lt;ShTiRLiC&amp;gt; Еще сразу объясню, что такое CSymbianPrjDocument::NewL()
&lt;br /&gt;[21:20] &amp;lt;ShTiRLiC&amp;gt; Ну, как видно из названия, это статический метод создания
&lt;br /&gt;[21:21] &amp;lt;ShTiRLiC&amp;gt; Буква L означает, что функция может вызвать исключение (например, если нет памяти)
&lt;br /&gt;[21:21] &amp;lt;ShTiRLiC&amp;gt; Но исключения тут называются &amp;quot;ливами&amp;quot; (Leave)
&lt;br /&gt;[21:21] &amp;lt;ShTiRLiC&amp;gt; Просто стандартные эксепшны С++ оказались очень прожорливыми до памяти, и был придуман другой, экономичный механизм
&lt;br /&gt;[21:21] &amp;lt;ShTiRLiC&amp;gt; Хотя и более кривой =)
&lt;br /&gt;[21:22] &amp;lt;ShTiRLiC&amp;gt; Но об этом попозже
&lt;br /&gt;[21:22] &amp;lt;ShTiRLiC&amp;gt; В качестве параметра передается указатель на объект приложения
&lt;br /&gt;[21:22] &amp;lt;ShTiRLiC&amp;gt; Стоит отметить, что в предыдущих двух методах мы работали с классом CSymbianPrjApp
&lt;br /&gt;[21:23] &amp;lt;ShTiRLiC&amp;gt; Однако его еще надо создать
&lt;br /&gt;[21:23] &amp;lt;ShTiRLiC&amp;gt; Функция NewApplication(), которая, как видно из префикса, является экспортируемой, вызывается фреймворком
&lt;br /&gt;[21:23] &amp;lt;ShTiRLiC&amp;gt; В ответ приложение создает класс ядра (т.н. мной) и отдает фреймворку
&lt;br /&gt;[21:24] &amp;lt;ShTiRLiC&amp;gt; В принципе, функция NewApplication() является единственной явно экспортируемой из нашей DLL (APP)
&lt;br /&gt;[21:24] &amp;lt;ShTiRLiC&amp;gt; Дальше объекты создаются по цепочке
&lt;br /&gt;[21:24] &amp;lt;ShTiRLiC&amp;gt; Так, ну и последняя функция E32Dll()
&lt;br /&gt;[21:25] &amp;lt;ShTiRLiC&amp;gt; Она должна вернуть код ошибки, всегда возвращает KErrNone
&lt;br /&gt;[21:25] &amp;lt;ShTiRLiC&amp;gt; Хм, ну она тоже экспортируемая =)
&lt;br /&gt;[21:25] &amp;lt;ShTiRLiC&amp;gt; Итак, у нас создан документ
&lt;br /&gt;[21:25] &amp;lt;ShTiRLiC&amp;gt; Ща закину исходник класса документа
&lt;br /&gt;[21:26] &amp;lt;ShTiRLiC&amp;gt; Кстати, .h закидывать надо для понимания, от чего унаследованы эти мои классы?
&lt;br /&gt;[21:26] &amp;lt;ShTiRLiC&amp;gt; Хм
&lt;br /&gt;[21:27] &amp;lt;ShTiRLiC&amp;gt; Ну ладно, потом
&lt;br /&gt;[21:27] &amp;lt;ShTiRLiC&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?zh0qslssrncl&quot;&gt;http://www.everfall.com/paste/id.php?zh0qslssrncl&lt;/a&gt;
&lt;br /&gt;[21:27] &amp;lt;ShTiRLiC&amp;gt; Тут расписан класс документа
&lt;br /&gt;[21:27] &amp;lt;ShTiRLiC&amp;gt; Он практически пуст, за исключением двухстадийного конструктора
&lt;br /&gt;[21:27] &amp;lt;ShTiRLiC&amp;gt; Поступила просьба выложить хедеры
&lt;br /&gt;[21:27] &amp;lt;ShTiRLiC&amp;gt; Ща объясню про конструктор и выложу&lt;/p&gt;
&lt;p&gt;[21:28] &amp;lt;ShTiRLiC&amp;gt; Итак, в симбиане многое сделано не по-человечески
&lt;br /&gt;[21:28] &amp;lt;ShTiRLiC&amp;gt; В силу ограниченной оперативной памяти (у меня, к примеру, 10 Мб всего, из них 2 заняты системой)
&lt;br /&gt;[21:28] &amp;lt;ShTiRLiC&amp;gt; Хотя может там и больше RAM
&lt;br /&gt;[21:29] &amp;lt;ShTiRLiC&amp;gt; Неважно
&lt;br /&gt;[21:29] &amp;lt;ShTiRLiC&amp;gt; Стек на каждый поток - всего 8 Кб
&lt;br /&gt;[21:29] &amp;lt;ShTiRLiC&amp;gt; Так что на локальных переменных стоит экономить
&lt;br /&gt;[21:29] &amp;lt;ShTiRLiC&amp;gt; По этим причинам создание любого объекта происходит в две стадии
&lt;br /&gt;[21:30] &amp;lt;ShTiRLiC&amp;gt; Товарищи замечают, что в j2me 300 Кбайт за счастье
&lt;br /&gt;[21:30] &amp;lt;ShTiRLiC&amp;gt; Объясняю, что в симбиане весь код нативный, да и объектов зачастую побольше
&lt;br /&gt;[21:30] &amp;lt;ShTiRLiC&amp;gt; Но в общем-то запустить 2-3 массивных проги вполне реально
&lt;br /&gt;[21:31] &amp;lt;ShTiRLiC&amp;gt; Ну что ж, я все-таки попробую объяснить про двухстадийные конструкторы =)
&lt;br /&gt;[21:31] &amp;lt;ShTiRLiC&amp;gt; Для создания объектов в Симбиане не принято использовать new, т.к. все объекты должны наследовать от CBase и иметь дефолтный конструктор приватным
&lt;br /&gt;[21:32] &amp;lt;ShTiRLiC&amp;gt; Для создания используется фабрика NewL (или NewLC, разницу поясню позже)
&lt;br /&gt;[21:32] &amp;lt;ShTiRLiC&amp;gt; Смотрим в код, читаем мое пояснение
&lt;br /&gt;[21:32] &amp;lt;ShTiRLiC&amp;gt; У нас мало памяти, и её всегда может не хватить для создания нового объекта
&lt;br /&gt;[21:32] &amp;lt;ShTiRLiC&amp;gt; Это неминуемо вызовет Leave (далее лив), т.е. исключение
&lt;br /&gt;[21:33] &amp;lt;ShTiRLiC&amp;gt; Для перехвата ливов можно ставить трапы (аналог catch) или ловушки
&lt;br /&gt;[21:33] &amp;lt;ShTiRLiC&amp;gt; Но я с этим не работал, честно говоря
&lt;br /&gt;[21:33] &amp;lt;ShTiRLiC&amp;gt; Итак, на первой стадии двухфазного конструктора мы создаем объект простым new
&lt;br /&gt;[21:34] &amp;lt;ShTiRLiC&amp;gt; Поступил вопрос, что же я там такое создам в 8 метрах
&lt;br /&gt;[21:34] &amp;lt;ShTiRLiC&amp;gt; Что ж, мы рассматриваем исключительно игры, так что игровые объекты могут быть больших размеров
&lt;br /&gt;[21:35] &amp;lt;ShTiRLiC&amp;gt; То есть, я может быть захочу создать большой массив, инициализированный нулями
&lt;br /&gt;[21:35] &amp;lt;ShTiRLiC&amp;gt; Или создам класс-контейнер с заранее выделенной памятью
&lt;br /&gt;[21:35] &amp;lt;ShTiRLiC&amp;gt; Статический массив, грубо говоря&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=806&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/blog/?id=804</guid>
  <pubDate>Fri, 23 Jun 2006 19:16:21 GMT</pubDate>
  <title>Symbian development</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/blog/?id=804</link>
  <description>
&lt;p&gt;В субботу, 24.06.06, в 21:00 MSK состоится лекция &lt;b&gt;ShTiRLiC&lt;/b&gt;-а, посвященная разработке под платформу Symbian.&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=799</guid>
  <pubDate>Fri, 16 Jun 2006 20:51:13 GMT</pubDate>
  <title>Лекция #27. &quot;Треп Даггера про игровую механику&quot; Организация игровой механики (Не лекция) [Лектор - DaGGeR]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=799</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=1238</comments>
  <description>
&lt;p&gt;Disclaimer: некоторые опечатки поправлены, некоторые реплики передвинуты.&lt;/p&gt;
&lt;p&gt;&amp;lt;DaGGeR&amp;gt; Значит как я это делаю. На уберправильность не претендую, но работает хорошо.
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; Два основных понятия в игровой логике это Мир и Актор.
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; Мир представляет собой класс который как ни странно менеджит игровой мир.
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; Он умеет: 1. создавать акторов через фабрики
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; 2. Апдейтиться через deltatime изменяя свои параметры (там гравитацию поменять, и т.д)
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; 3. Апдейтить Акторов
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; 4. Убивать Акторов&lt;/p&gt;
&lt;p&gt;&amp;lt;DaGGeR&amp;gt; Теперь про акторов
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; Актор это базовый класс от которого наследуются все объекты в игровом мире.
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; Актор может быть создан только миром через фабрику
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; Актор умеет:
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; 1. Апдейтиться по прошествию deltatime
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; 2. Сообщать о своем состоянии миру
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; Например в актора попала ракета.
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; Он убит и должен исчезнуть.
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; Он выставляет у себя cпециальный параметр LifeTime=0
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; и мир в следующий проход удаляет его
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; Конечно можно сделать чтобы мир сам при обработке столкновения актора с ракетой обработал это событие и удалил актора
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; но при этом теряется гибкость.
&lt;br /&gt;&amp;lt;Cote-Duke&amp;gt; Должен согласиться с Дагом.
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; С другой стороны в моей реализации актор обязан знать что с ним столкнулось и как на это реагировать
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; но все решается дефолтной реакцией + расширения на акторов, на которых он должен както особенно реагировать&lt;/p&gt;
&lt;p&gt;&amp;lt;DaGGeR&amp;gt; Так вот
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; как это сейчас реализовано.
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; щас псевдокод набросаю
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; пока можно вопросы если вдруг есть
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; :))
&lt;br /&gt;&amp;lt;Cote-Duke&amp;gt; Могу сказать что это классика. В своей версии я ещё добавил workgroups для акторов (entity) что-бы они могли апдейтиться в разные промежутки времени с разной частотой. (fixed time step)&lt;/p&gt;
&lt;p&gt;&amp;lt;kas&amp;gt; раскрой тему разного апдейта
&lt;br /&gt;&amp;lt;ShTiRLiC&amp;gt; Что-то мне как-то примитивной схема показалась...
&lt;br /&gt;&amp;lt;ShTiRLiC&amp;gt; Обычно сложнее описывают
&lt;br /&gt;&amp;lt;Cote-Duke&amp;gt; Simplicty the genius.
&lt;br /&gt;&amp;lt;ShTiRLiC&amp;gt; Или я путаю логику игры со структурой движка?..
&lt;br /&gt;&amp;lt;ShTiRLiC&amp;gt; Не, ну это понятно
&lt;br /&gt;&amp;lt;_ShaMan_&amp;gt; это в общих чертах
&lt;br /&gt;&amp;lt;kas&amp;gt; я видать пропустил
&lt;br /&gt;&amp;lt;kas&amp;gt; но ето для какого жанра?
&lt;br /&gt;&amp;lt;Cote-Duke&amp;gt; Я думаю почти для любого.
&lt;br /&gt;&amp;lt;ShTiRLiC&amp;gt; В данном случае не рассмотрена подробная классификация акторов
&lt;br /&gt;&amp;lt;kas&amp;gt; ну, чем ето лучше чем скажем саморегаца в мире и из какихнить скриптов там создаваться
&lt;br /&gt;&amp;lt;ShTiRLiC&amp;gt; Поэтому такое базовое деление - да, для любого
&lt;br /&gt;&amp;lt;kas&amp;gt; или ешё чего
&lt;br /&gt;# kas нивидит мегобонуса&lt;/p&gt;
&lt;p&gt;&amp;lt;kas&amp;gt; подробная класификация не интересна, ибо ето личный конкретный случай
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; кас
&lt;br /&gt;&amp;lt;kas&amp;gt; ась
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; это ты пытаешся скатиться к единичным случаям
&lt;br /&gt;&amp;lt;kas&amp;gt; м?
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; а я говорю о базовой концепции
&lt;br /&gt;&amp;lt;kas&amp;gt; не понял про единичные случаи
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; скриптовый актор у меня наследуется от базового и хорошо живет
&lt;br /&gt;&amp;lt;kas&amp;gt; ну, тогда определено надо какихто подробностей&lt;/p&gt;
&lt;p&gt;&amp;lt;DaGGeR&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?5qqh3r51n9fp&quot;&gt;http://www.everfall.com/paste/id.php?5qqh3r51n9fp&lt;/a&gt;
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; вот так примерно выглядит основной функционал мира
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?wbf9tz9kdust&quot;&gt;http://www.everfall.com/paste/id.php?wbf9tz9kdust&lt;/a&gt;
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; а вот так - актор
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; есть несколько тонких моментов
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; например если програмер решил удалить актора в ручную а не выставлять ему лайфтайм
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; в таком случае у меня актор в деструкторе сам сообщает миру, что &amp;quot;не жди меня мама...&amp;quot;
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; и мир вычеркивает его из списка живых не дожидаясь следующего тика&lt;/p&gt;
&lt;p&gt;&amp;lt;DaGGeR&amp;gt; сейчас как временная мера реализована саморегистрация приблудных акторов в конструкторе
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; не зря же там World* передается
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; но я потихоньку от таких беспризорников избавляюсь&lt;/p&gt;
&lt;p&gt;&amp;lt;DaGGeR&amp;gt; вот собственно и все
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; абстрактно но работоспособно хоть в 2д аркаде хоть в гоночном симуляторе
&lt;br /&gt;&amp;lt;DaGGeR&amp;gt; я уложился в 15 минут? :)&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/sh</guid>
  <pubDate>Tue, 13 Jun 2006 21:50:37 GMT</pubDate>
  <title>Лекция #26. Spherical Harmonics [Лектор - xmvlad]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/sh</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=1245</comments>
  <description>
&lt;p&gt;оригинальный лог:&amp;nbsp; &lt;a href=&quot;http://www.everfall.com/paste/id.php?20f4zp1hf2y9&quot;&gt;http://www.everfall.com/paste/id.php?20f4zp1hf2y9&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;MiF&amp;gt; давай 
&lt;br /&gt;&amp;lt;MiF&amp;gt; вещай уже
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; надо тогда дисклеймер хотя бы написать чтоб касег не волновался..
&lt;br /&gt;&amp;lt;Zeux&amp;gt; пиши свой дисклеймер
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; ладно в общем :) данное повествование является разжовыванием теоретических основ SH для тех кто как и 
&lt;br /&gt;&amp;nbsp; я пропускал матан, в достаточно мере что бы их не знать :)
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; 1. линейное пространство
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; в общем линейным пространством является все что угодно удовлетворяющее следующим аксиомам: 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; &lt;a href=&quot;http://en.wikipedia.org/wiki/Vector_space&quot; rel=&quot;nofollow&quot;&gt;http://en.wikipedia.org/wiki/Vector_space&lt;/a&gt;
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; 1. ассоциативность сложения векторов то есть (a + b) + c = a + (b + c)
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; 2. коммутативность a + b = b + a
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; 3. существования нуля, то есть для каждого элемента v принадлежащему V (векторному пространству) 
&lt;br /&gt;&amp;nbsp; существует элемент z такой что v + z = v
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; и т.д далее для жаждущих ссылка в википедию 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; суть в следующим: одним из примеров линейного пространства может являтся функциональное пространство
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; то есть если мы возьмем множество векторных функций f(x), g(x)... Fi(x), то они так же будут являтся линейным пространством
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; &lt;a href=&quot;http://en.wikipedia.org/wiki/Functional_space&quot; rel=&quot;nofollow&quot;&gt;http://en.wikipedia.org/wiki/Functional_space&lt;/a&gt;
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; теперь вводим в данном линейном пространстве скалярное произведение
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; аксиомы скалярного произведения &lt;a href=&quot;http://en.wikipedia.org/wiki/Inner_product_space&quot; rel=&quot;nofollow&quot;&gt;http://en.wikipedia.org/wiki/Inner_product_space&lt;/a&gt;, то есть проще говоря 
&lt;br /&gt;&amp;nbsp; это обобщение &amp;quot;геометрического&amp;quot; dot product для линейных пространств
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; по просьбе cppg: &lt;a href=&quot;http://ru.wikipedia.org/wiki/Линейное_пространство&quot; rel=&quot;nofollow&quot;&gt;http://ru.wikipedia.org/wiki/Линейное_пространство&lt;/a&gt;
&lt;br /&gt;&amp;lt;cppg&amp;gt; добавлю, перевод: &lt;a href=&quot;http://ru.wikipedia.org/wiki/Векторное_пространство&quot; rel=&quot;nofollow&quot;&gt;http://ru.wikipedia.org/wiki/Векторное_пространство&lt;/a&gt;
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; &lt;a href=&quot;http://ru.wikipedia.org/wiki/Скалярное_произведение&quot; rel=&quot;nofollow&quot;&gt;http://ru.wikipedia.org/wiki/Скалярное_произведение&lt;/a&gt;
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; теперь, одна теорема которая нам нужна
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; Пусть S подпространство в эвклидовом пространстве V, и (e1, ..., ei) ортонормированный базис для S. Если x принадлежит V, тогда элемент s = sum(i = 1, n) (x, ei) * ei - проекция x на S
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; значит такая теорема: проекция x на S ближе к x (ближе в смысле нормы), чем любой другой элемент принадлежащий S 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; все, с мутью покончили 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; значит берем функциональнольно пространство и вводим в нем следующее скалярное произведение:
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; (f, g) = integral f(x) * g(x) dx 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; как можно убедится удовлетворяет всем аксиомам для скалярного произведения 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; базисом этого функционального пространства могут являтся - сферические гармоники
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; сферические гармоники принадлежат к семейству ортогональных полиномов 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; то есть, (f, g) = 0 если f != g, и (f, f) = 1 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; SH(spherical harmonics) задаются на поверхности сферы, то есть x = f(a, b), где a,b - сферические 
&lt;br /&gt;&amp;nbsp; координаты некоторой точки на поверхности сферы
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; тогда, любую функцию заданную на поверхности сферы мы можем задать линейной комбинацией базисных 
&lt;br /&gt;&amp;nbsp; функций, то есть
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; f_aprox(a, b) = s0 * y1 + s1 * y1 + s2 * y2 + .. + si * yi
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; если мы берем конечное число гармоник, то есть &amp;quot;обрезаем&amp;quot; высокие частоты мы получаем лишь некоторую 
&lt;br /&gt;&amp;nbsp; апроксимацию 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; наша f_aprox и будет проекцией f (элемента функционального пространства) в базис SH
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; при этом в соответствии с теоремой, эта проекция является наилучшим приближением f в базисе SH
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; проще говоря, что нам надо - посчитать s0.. si, для этого в соответсвии с определением проецируем f на 
&lt;br /&gt;&amp;nbsp; базис SH, то есть считаем si = (f, yi)&amp;nbsp; для i = 0..n
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; или по нашему определению скалярного умножения si = интеграл по поверхности сферы (f(s) * yi(s)) ds
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; зная si, мы можем восстановить нашу функцию f, некоторую апроксимацию, выше написана формула
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; но это не главное
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; если у нас есть две функции f и g, которые мы спроецировали в базис SH тогда 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; в силу ортогональности базисных функций то есть все термы i != g равны 0, остальные i = i, 1 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; интеграл по поверхности сферы f(s) * g(s) ds = fs0 * gs0 + fs1 * gs1 + .. + fsi * gsi
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; то есть просто дот продукт коэффициентов
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; как это обычно используют
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; возьмем меш, зададим вокруг каждой вершины функцию f(s), если c направления s - приходит лучик, f(s) 
&lt;br /&gt;&amp;nbsp; == 1 если нет f(s) == 0
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; то есть задаем для каждой вершины объекта oclussion для всех возможных направлений (поверхность сферы)
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; вторая функция, g, задает &amp;quot;источник освещения&amp;quot;, то же самое только для каждого направления s g(s) == 1 
&lt;br /&gt;&amp;nbsp; есть лучик g(s)== 0 нет лучика
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; теперь если взять интеграл по поверхности сферы произведения этих двух функий f и g, получим 
&lt;br /&gt;&amp;nbsp; количество освещения достигающего вершину
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; а интеграл это всего лишь дот продукт как было выше расписано
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; таким образом считаем во время препроцессинга повершинно f
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; раз в кадр считаем проекцию освещения в SH базис - g, а затем в шейдере - дот продукт - количестов 
&lt;br /&gt;&amp;nbsp; освещения (интеграл по поверхности сферы)

&lt;li&gt;DobroKOT всё про разложение понял, дальше как это применяется для освещения втыкает.&lt;/li&gt;
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; xmvlad, что такое f?
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; каким освещением рисовать пиксель на экране?

&lt;li&gt;DobroKOT тупит, наверное...&lt;/li&gt;
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; воть хочу блинна, например...
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; сорри, away, метро закрывается в час.
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; DobroKOT: f - освещение
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; то есть если хочется цветного их должно быть три штуки :)
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; DobroKOT: освещение повершинное
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; учитывается только диффузная составляющая (интеграл по поверхности сферы) без спекуляра
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; но суть в том что f - можно поретрейсить и закодить туда self-shadowing от объекта
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; xmvlad, я что-то не понимаю.
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; да что я забыл сказать, там где было про проецирование в базис, интеграл, можно посчитать и аналитически (если функция простая) или при помощи монте-карло (рейтрейсинг по сцене)
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; DobroKOT: говори что %)
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; почему нельзя в offline тупо посчитать освещённость?
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; каждой вершины?
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; тупо lightmap ?
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; что дают SH ?
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; смотри
&lt;br /&gt;&amp;lt;Zeux&amp;gt; DobroKOT, освещенность относительно статического источника?
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; если &amp;quot;учитывается только диффузная составляющая&amp;quot;
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; одну часть f - мы считаем в офлайне повершинно - это локальный occlusion или вобще что угодно
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; вторую часть g - мы можем посчитать покадрово, освещение то есть
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; а затем в шейдере уже посчитать интеграл по поверхности сферы произведения этих функций - дот продуктом
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; при этом g у нас будет не повершинно а для всего объекта
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; что такое oclusion для уровня типа quake1 ? ведь любая точка в этом уровне - внутри уровня? 
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; f - это что?

&lt;li&gt;dR|drunk is now known as dR|phone&lt;/li&gt;
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; DobrKOT: occlusion для некоторого объекта :)
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; f - это функция на поверхности сферы, то есть проекция в SH
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; что такое f?
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; если считать что гармоник нет, (бесконечная точность и тп) как она используется для освещения?
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; DobroKOT: функция заданная на поверхности сферы, occlusion то есть
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; повершинно 
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; на выпуклом объекте oclusion везде будет - полусфера?
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; точнее, сфера с одним полушарием - 1, и вторым - 0 ?
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; DobroKOT: ага
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; а это же дико разрывная функция.
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; она хорошо приближается гармониками?
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; но с оклюжен это простейший случай, можно закодировать что угодно, любую функцию освещения %)
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; DobroKOT: ну дык будут &amp;quot;мягкие тени&amp;quot; =) вобще нужен препроцессинг, вроде размытия гаусом
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; как полагается считать f для замкнутого уровня типа кваки?
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; не, я имеле ввиду, что считать надо для объекта какого-нить 
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; то есть для области внутри которой не будет источника света
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; хорошо, умеем считать интеграл в шейдере быстро и приближённо.
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; а как задаётся g ?
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; вообще как задаются источнки света в этом методе?
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; а g как хочеш считай =) но суть в том что это опять же функция на поверхности сферы
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; ну вот пусть два точечных источника...
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; ага, в каждой вершине можно задать как dot(n, l1) + dot(n, l2) ...
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; DobroKOT: нет :)
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; а как?
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; мы сразу все освещение проецируем в базис SH
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; g - одна на все вершины?
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; ага
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; и поэтому фейк :)
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; ага, тогда n можно подставить как точку сферы.

&lt;li&gt;DobroKOT не понимает, как метод который не может осветить кубическую комнату с одним точечным источником света является супер-методом.&lt;/li&gt;
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; а почему он крутой?
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; что он позволяет?
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; DobroKOT: да он говно, просто этого никто не знает =)
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; неее!
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; сначала скажи почему хороший.
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; вот я туплю и не понимаю, для чего его применять.
&lt;br /&gt;&amp;lt;DobroKOT&amp;gt; а, типа g можно сделать&amp;nbsp; сложной, да?
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; DobroKOT: да
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; да для любого динамического освещения только фейковым оно будет
&lt;br /&gt;&amp;lt;xmvlad&amp;gt; то есть вопрос в том - на сколько это будет фейково&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/sh?page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/blog/?id=776</guid>
  <pubDate>Thu, 01 Jun 2006 21:15:04 GMT</pubDate>
  <title>Постмортем игры &quot;Трюкмания&quot;.</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/blog/?id=776</link>
  <description>
&lt;p&gt;Выложен лог прошедшей лекции &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=29&quot;&gt;Постмортем игры &amp;quot;Трюкмания&amp;quot;&lt;/a&gt; (лектор - &lt;b&gt;Jihar&lt;/b&gt;).&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=775</guid>
  <pubDate>Thu, 01 Jun 2006 20:57:07 GMT</pubDate>
  <title>Лекция #25. Постмортем игры &quot;Трюкмания&quot; [Лектор - Jihar]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=775</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=1199</comments>
  <description>
&lt;p&gt;Disclaimer: некоторые опечатки поправлены, некоторые реплики передвинуты. &lt;a href=&quot;http://www.everfall.com/paste/id.php?jefbf12tw82s&quot;&gt;полный лог&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[21:40] &amp;lt;Jihar_&amp;gt; ок. меня кличут Жихарь, работаю в фирме KVision
&lt;br /&gt;[21:40] &amp;lt;Jihar_&amp;gt; не так давно мы закончили свой первый проект - Трюкмания : гонки экстремалов, издатель Акелла
&lt;br /&gt;[21:41] &amp;lt;Jihar_&amp;gt; игра - аркадные гонки в абстрактном городе
&lt;br /&gt;[21:41] &amp;lt;Jihar_&amp;gt; разработка велась примерно 3 года, из них почти 2 с моим участием
&lt;br /&gt;[21:42] &amp;lt;Jihar_&amp;gt; движок - свой, написанный можно сказать с нуля
&lt;br /&gt;[21:42] &amp;lt;Jihar_&amp;gt; когда я пришел работать в фирму, костяк уже был готов
&lt;br /&gt;[21:42] &amp;lt;Jihar_&amp;gt; я думаю интересно будет именно программная часть?
&lt;br /&gt;[21:43] &amp;lt;Jihar_&amp;gt; ошибок у нас было много, первый проект все таки...&lt;/p&gt;
&lt;p&gt;[21:43] &amp;lt;Jihar_&amp;gt; итак, самое главное
&lt;br /&gt;[21:43] &amp;lt;Jihar_&amp;gt; постановка задач. это примерно 90% успеха и от этого зависит скорость разработки
&lt;br /&gt;[21:44] &amp;lt;Jihar_&amp;gt; приведу пример - была у меня задача, написать утилитку для артистов, аля артист менеджер для удобной работы
&lt;br /&gt;[21:44] &amp;lt;Jihar_&amp;gt; те чтобы она могда выгрузить модель\статику в наш формат, сконвертить текстуры, также конвертить пачку моделей\миров
&lt;br /&gt;[21:45] &amp;lt;Jihar_&amp;gt; затем стали добавляться фичи - проверки текстур например (есть ли одинаковые текстуры с разными именами, миррор\скейл)
&lt;br /&gt;[21:46] &amp;lt;Jihar_&amp;gt; таких фич захотелось очень много, в результате сейчас эта утилита хоть и работает, но улучшать ее очень сложно
&lt;br /&gt;[21:46] &amp;lt;Jihar_&amp;gt; надеюсь мысль понятна - когда пишешь для себя, сроки разработки не сильно волнуют
&lt;br /&gt;[21:47] &amp;lt;Jihar_&amp;gt; когда пишешь с учетом сроков - лучше периодически (когда еще не поздно) тратить время на рефакторинг, это время очень быстро окупится
&lt;br /&gt;[21:47] &amp;lt;Jihar_&amp;gt; прописные истины, да. но как всегда про такие истины и забывают...&lt;/p&gt;
&lt;p&gt;[21:50] &amp;lt;Jihar_&amp;gt; проект на самом деле очень технологичный. изначально в игре было больше фич (фичекат подлый), и сейчас база очень солидная
&lt;br /&gt;[21:50] &amp;lt;Jihar_&amp;gt; процесс достаточно обычно у нас построен - есть база (в трюкмании ВСС, сейчас свн)
&lt;br /&gt;[21:50] &amp;lt;Jihar_&amp;gt; коменты - доксиген стайл, свой стиль кодирования
&lt;br /&gt;[21:51] &amp;lt;Jihar_&amp;gt; пробовали кучу различных таск трекеров, баг трекеров итд, до сих пор находимся в поиске идеального решения&lt;/p&gt;
&lt;p&gt;[21:53] &amp;lt;xmvlad&amp;gt; тулсет свой был или в максе?
&lt;br /&gt;[21:53] &amp;lt;Jihar_&amp;gt; тулсет на самом деле достаточно разнообразный
&lt;br /&gt;[21:54] &amp;lt;Jihar_&amp;gt; например расставить модельки в мире - можно их расставить в максе, при выгрузке плагин выцепит модельки отдельно. можно расстаивть модельки в движке&lt;/p&gt;
&lt;p&gt;[21:54] &amp;lt;kas&amp;gt; можешь про арт пайплайн рассказать, коль уж о тулсете заговорили?
&lt;br /&gt;[21:54] &amp;lt;kas&amp;gt; т.е. путь от набота триуглов в максе до модельки в игре
&lt;br /&gt;[21:54] &amp;lt;Jihar_&amp;gt; осноной пакет - 3ds max
&lt;br /&gt;[21:55] &amp;lt;Jihar_&amp;gt; есть возможность юзать и майю
&lt;br /&gt;[21:55] &amp;lt;Jihar_&amp;gt; значит модели, миры проходят через плагины к этим программам. сейчас это практически монстры - встроено большое количество проверок геометрии
&lt;br /&gt;[21:56] &amp;lt;Jihar_&amp;gt; миры после выгрузки из DCC проходят доп обработку - расчет лайтмепов
&lt;br /&gt;[21:56] &amp;lt;Jihar_&amp;gt; эту доп обработку можно запустить и при выгрзуке из DCC
&lt;br /&gt;[21:57] &amp;lt;Jihar_&amp;gt; ну те старались все автоматизировать, чтобы не сильно напрягать моделлеров. в том числе и проверки для этого - достаточно просто артисты находят различные ошибки в геометрии, некоторые советы по оптимизации моделей
&lt;br /&gt;[21:58] &amp;lt;Jihar_&amp;gt; для своих форматов есть различные утилиты - например для моделей редактор моделей - отредактить какие-то свойства, поиграться с цветами итд итп (это же можно делать и в плагине для DCC)&lt;/p&gt;
&lt;p&gt;[21:58] &amp;lt;kas&amp;gt; ето один мегаридактор? или несколько маленьких?
&lt;br /&gt;[21:59] &amp;lt;Jihar_&amp;gt; можно сказать это сборная солянка - т.е. часть возможностей есть и в виде отдельных утилит, они же доступны из плагиноы
&lt;br /&gt;[21:59] &amp;lt;Jihar_&amp;gt; те артист настраивает модельку, она ушла в производство. чтобы затем изменить какие-то игровые свой-ва не надо ее выгружать заново
&lt;br /&gt;[22:00] &amp;lt;Jihar_&amp;gt; в том же редакторе моделей настраиваются машины. с физикой куча наворотов конечно. например расчет экспериментов - после настройки можно посмотреть графики (начиная с бангальных разгон до 100 км\ч)
&lt;br /&gt;[22:01] &amp;lt;Jihar_&amp;gt; есть те же тесты физики - их куча на самом деле, проверяющих различные параметры. те разгон до 100 км\ч - берем значение теоретическое, ставим машину на землю и смотрим за сколько она реально разгоняется. сравниваем.. так тестятся почти все параметры физики (а их у нас много:))&lt;/p&gt;
&lt;p&gt;[22:01] &amp;lt;kas&amp;gt; физика своя?
&lt;br /&gt;[22:01] &amp;lt;Jihar_&amp;gt; физика полностью своя, да&lt;/p&gt;
&lt;p&gt;[22:02] &amp;lt;Jihar_&amp;gt; редаткора миров своего нету (те возможность создания геометрии в своей тулзе)
&lt;br /&gt;[22:03] &amp;lt;Jihar_&amp;gt; но есть различные вспомогательные утилиты - для расстановки моделей например, редактирования карт АИ&lt;/p&gt;
&lt;p&gt;[22:02] &amp;lt;kas&amp;gt; а сколько кодеров было и как они распределены были?
&lt;br /&gt;[22:03] &amp;lt;Jihar_&amp;gt; кодеров - по разному в разное время
&lt;br /&gt;[22:03] &amp;lt;Jihar_&amp;gt; закончили проект - нас было трое, один на физике и рендере в основном, второй на аи, и третий я :)&lt;/p&gt;
&lt;p&gt;[22:04] &amp;lt;kas&amp;gt; а гейдизайнеров/дизайнеров?
&lt;br /&gt;[22:04] &amp;lt;Jihar_&amp;gt; геймдизайнер один, артистов до 20 человек было
&lt;br /&gt;[22:05] &amp;lt;Jihar_&amp;gt; текучка артистов большая была, т.к. найти профи в твери сложновато (да и програмеров тоже, как и всех остальных)
&lt;br /&gt;[22:05] &amp;lt;Jihar_&amp;gt; поэтому артистов учили по несколько месяцев, смотрели что получается ну итд
&lt;br /&gt;[22:05] &amp;lt;Jihar_&amp;gt; некоторые артисты работают сейчас в москве :)&lt;/p&gt;
&lt;p&gt;[22:06] &amp;lt;kas&amp;gt; расскажи про интероп
&lt;br /&gt;[22:07] &amp;lt;kas&amp;gt; ну, т.е. как от гейдизайнера доходило до простого негра, процесс
&lt;br /&gt;[22:08] &amp;lt;Jihar_&amp;gt; ну это итеративный процесс
&lt;br /&gt;[22:08] &amp;lt;Jihar_&amp;gt; есть задание - делаем трек, такие-то параметры
&lt;br /&gt;[22:08] &amp;lt;Jihar_&amp;gt; сначала делается чертеж трека с дорогами, зданиями итд
&lt;br /&gt;[22:08] &amp;lt;Jihar_&amp;gt; после нескольких итераций этот чертеж утверждается, попадает в разработку моделлеру
&lt;br /&gt;[22:09] &amp;lt;Jihar_&amp;gt; моделлер собсно моделит статику - те дороги, здания
&lt;br /&gt;[22:09] &amp;lt;Jihar_&amp;gt; затем этот тре подвергается заселению моделями
&lt;br /&gt;[22:10] &amp;lt;Jihar_&amp;gt; на всех этапах само собой есть влияние геймдизайнера - те что надо поправить, что не так
&lt;br /&gt;[22:10] &amp;lt;Jihar_&amp;gt; где не удобно гонять к примеру
&lt;br /&gt;[22:10] &amp;lt;Jihar_&amp;gt; несколько треков (на мой взгляд интереных) не попали в игру - сложно гонять на них было, обычному игроку не понравилось бы
&lt;br /&gt;[22:11] &amp;lt;Jihar_&amp;gt; по трекам создавались списки нужных зданий\моделей само собой, на этом этапе мог подключаться другой моделлер
&lt;br /&gt;[22:11] &amp;lt;Jihar_&amp;gt; практиковали разработку треков по кускам - те один делает этот кусок, другой этот
&lt;br /&gt;[22:11] &amp;lt;Jihar_&amp;gt; но очень сложно - различается все-таки стиль, не просто потом это объединять, в текущем проекте один трек делает один артист практически на 100%&lt;/p&gt;
&lt;p&gt;[22:11] &amp;lt;kas&amp;gt; а как ето всё разруливалось?
&lt;br /&gt;[22:11] &amp;lt;kas&amp;gt; т.е. не было генерального плана у каждого на весь проект?
&lt;br /&gt;[22:11] &amp;lt;kas&amp;gt; а по мере необходимости?
&lt;br /&gt;[22:12] &amp;lt;Jihar_&amp;gt; про генеральный план артистов сложно сказать, думаю он часто корректировался :)
&lt;br /&gt;[22:12] &amp;lt;Jihar_&amp;gt; появлялись затыки само собой перидически, переброска людей на узкие места итд
&lt;br /&gt;[22:13] &amp;lt;Jihar_&amp;gt; разруливолась не так просто как кажется конечно... количество арта у нас было очень большое
&lt;br /&gt;[22:13] &amp;lt;Jihar_&amp;gt; и с каждым днем все больше :)
&lt;br /&gt;[22:14] &amp;lt;Jihar_&amp;gt; были люди, которые отвечали за арт. не за его создание, а за его обработку
&lt;br /&gt;[22:14] &amp;lt;Jihar_&amp;gt; они можно сказать одобряли арт с технической точки зрения и поддерживали общую базу арта в нужном виде&lt;/p&gt;
&lt;p&gt;[22:14] &amp;lt;kas&amp;gt; а очень большое ето сколько? икак контролировали? под вершионингом лежало?
&lt;br /&gt;[22:15] &amp;lt;Jihar_&amp;gt; под вершионингом не лежало, артисты мутили это сами (сейчас пытаемся научить черепахе)
&lt;br /&gt;[22:15] &amp;lt;Jihar_&amp;gt; очень большое - несколько тысяч моделей, несколько тысяч текстур
&lt;br /&gt;[22:15] &amp;lt;Jihar_&amp;gt; больше десяти :)&lt;/p&gt;
&lt;p&gt;[22:15] &amp;lt;neteraser&amp;gt; Jihar: какие были нововведения в девпроцессе и чем обусловлены?
&lt;br /&gt;[22:16] &amp;lt;Jihar_&amp;gt; нововведения периодически появлялись, да. в основном подстройка под людей
&lt;br /&gt;[22:15] &amp;lt;Jihar_&amp;gt; те изначальная схема была слишком строгой, ее постоянно ослабляли для комфорта людей&lt;/p&gt;
&lt;p&gt;[22:15] &amp;lt;neteraser&amp;gt; Jihar: физика чисто игровая ?
&lt;br /&gt;[22:16] &amp;lt;Jihar_&amp;gt; физика - что значит чисто игровая?
&lt;br /&gt;[22:17] &amp;lt;Jihar_&amp;gt; физика машины у нас проработана почти до болтиков&lt;/p&gt;
&lt;p&gt;[22:17] &amp;lt;neteraser&amp;gt; сколько у вас кода ушло? будете выкидывать или мигрировать?
&lt;br /&gt;[22:18] &amp;lt;Jihar_&amp;gt; кода чисто специфичного не так уж и много
&lt;br /&gt;[22:18] &amp;lt;Jihar_&amp;gt; специфичного м\именно для трюкмании, а не для гонок
&lt;br /&gt;[22:18] &amp;lt;Jihar_&amp;gt; сейчас как раз глобальный рефакторинг у нас
&lt;br /&gt;[22:19] &amp;lt;Jihar_&amp;gt; некоторые системы не будутзатрагиваться (например рендер), некоторые с нуля переписаны, некоторые разбиты на части
&lt;br /&gt;[22:19] &amp;lt;Jihar_&amp;gt; например класс СМашина у нас очень толстый
&lt;br /&gt;[22:19] &amp;lt;neteraser&amp;gt; а CCamera?
&lt;br /&gt;[22:21] &amp;lt;Jihar_&amp;gt; классы камер разбиты достаточно хорошо
&lt;br /&gt;[22:21] &amp;lt;Jihar_&amp;gt; тем более различных камер куча
&lt;br /&gt;[22:21] &amp;lt;Jihar_&amp;gt; разные камеры в движке (аля полетать), в встроенных утилитах, камера машины другая
&lt;br /&gt;[22:21] &amp;lt;Jihar_&amp;gt; динаические камеры на треках - тоже другие&lt;/p&gt;
&lt;p&gt;[22:19] &amp;lt;neteraser&amp;gt; сколько всего кода в мб и миллионовстрок?
&lt;br /&gt;[22:20] &amp;lt;Jihar_&amp;gt; код в метрах щас померю
&lt;br /&gt;[22:20] &amp;lt;Jihar_&amp;gt; всего 14 метров чисто игрового кода
&lt;br /&gt;[22:20] &amp;lt;Jihar_&amp;gt; без учета утилит
&lt;br /&gt;[22:21] &amp;lt;neteraser&amp;gt; немало&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=775&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=761</guid>
  <pubDate>Sat, 13 May 2006 17:01:21 GMT</pubDate>
  <title>Лекция #24. GUI Revisited. Подробная лекция. [Лектор - Cool Ace]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=761</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=128676</comments>
  <description>
&lt;p&gt;Disclaimer: некоторые опечатки поправлены. &lt;a href=&quot;http://www.everfall.com/paste/id.php?dtxqn5vywyrb&quot;&gt;полный лог&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[23:04:58] &amp;lt;coolace&amp;gt; значит захотелось как то раз GUI сделать 1 раз и так чтобы его юзать везде
&lt;br /&gt;[23:05:52] &amp;lt;coolace&amp;gt; для этого нужно было придумать как например не париться с внедрением новых контролов в редактор будующий
&lt;br /&gt;[23:06:42] &amp;lt;coolace&amp;gt; вобщем нужен был рефлекшн новых контролов
&lt;br /&gt;[23:07:33] &amp;lt;coolace&amp;gt; для этого сделана была система свойств, с которыми контрол работет и может предоставлять их полный список
&lt;br /&gt;[23:08:18] &amp;lt;coolace&amp;gt; с именами и типами чтобы в редакторе автоматически заполнять панель редактирования выбранного контрола
&lt;br /&gt;[23:09:10] &amp;lt;coolace&amp;gt; причем сам контрол для своих вычислений использует те же самые свойства
&lt;br /&gt;[23:09:55] &amp;lt;coolace&amp;gt; свойства добавляются динамически в вектор и потом по имени можно его получить
&lt;br /&gt;[23:10:49] &amp;lt;coolace&amp;gt; не особо это хорошо можно переделать, но пока так суть в том чтобы все свойства контрола 
&lt;br /&gt;[23:11:32] &amp;lt;coolace&amp;gt; не какие то промежуточные состояния а именно то что однозначное его инициализирует рефлектилось
&lt;br /&gt;[23:13:03] &amp;lt;coolace&amp;gt; значит так же сделаны обработчики событий, те их список тоже можно получить и к каждому привязать пользовательский обработчик
&lt;br /&gt;[23:14:18] &amp;lt;coolace&amp;gt; пользовательский обработчик это функтор(в макросы обернутый для простоты), который регистрируется в системе и при надобности получается его копия 
&lt;br /&gt;[23:14:44] &amp;lt;coolace&amp;gt; к ней биндятся параметры если они нужны и исполнятся
&lt;br /&gt;[23:15:39] &amp;lt;coolace&amp;gt; обработка сообщений(событий) состороны контрола состоит из 3х этапов
&lt;br /&gt;[23:16:00] &amp;lt;coolace&amp;gt; а не рано еще про это :)
&lt;br /&gt;[23:17:04] &amp;lt;coolace&amp;gt; терминологии не много которую я буду использовать
&lt;br /&gt;[23:18:16] &amp;lt;coolace&amp;gt; процессор сообщения - функция которая обрабатывает сообщение на низком уровне
&lt;br /&gt;[23:18:54] &amp;lt;coolace&amp;gt; пример: ProcessClick()
&lt;br /&gt;[23:20:21] &amp;lt;coolace&amp;gt; обработчик - вирт функция которую можно переопределить если нужно в потомке изменять некие промежуточные данные
&lt;br /&gt;[23:20:41] &amp;lt;coolace&amp;gt; пример OnClick
&lt;br /&gt;[23:21:24] &amp;lt;coolace&amp;gt; пользовательский обработчик - то что рулит игрой или тем чем нужно
&lt;br /&gt;[23:22:11] &amp;lt;coolace&amp;gt; вот значит в принципе промежуточный кровень можно убрать, но иногда удобным оказалось
&lt;br /&gt;[23:22:23] &amp;lt;coolace&amp;gt; например в кнопках
&lt;br /&gt;[23:22:39] &amp;lt;coolace&amp;gt; те менять текстуру принаведении
&lt;br /&gt;[23:23:38] &amp;lt;coolace&amp;gt; процессоры сообщений регистрируются в классе и биндятся к определенным типам сообщений
&lt;br /&gt;[23:24:29] &amp;lt;coolace&amp;gt; извлекают из них параметры и параметры эти передают пользовательскому и системному обработчику
&lt;br /&gt;[23:24:55] &amp;lt;coolace&amp;gt; здесь же проводится валидация этих параметров
&lt;br /&gt;[23:25:09] &amp;lt;coolace&amp;gt; все понятно пока?&lt;/p&gt;
&lt;p&gt;[23:25:39] &amp;lt;coolace&amp;gt; значит как приходят сообщения....
&lt;br /&gt;[23:26:00] &amp;lt;R|lecture&amp;gt; можешь пример простой менюшки (контрола) и обработчика в коде изобразить? было бы понятнее глядя на код, я думаю
&lt;br /&gt;[23:26:08] &amp;lt;R|lecture&amp;gt; извини, что перебиваю
&lt;br /&gt;[23:26:27] &amp;lt;coolace&amp;gt; могу щас
&lt;br /&gt;[23:27:21] &amp;lt;coolace&amp;gt; void DefaultAction::Execute()
&lt;br /&gt;[23:27:21] &amp;lt;coolace&amp;gt; {
&lt;br /&gt;[23:27:21] &amp;lt;coolace&amp;gt;&amp;nbsp;  ActionParameters::action_parameters_list::const_iterator i;
&lt;br /&gt;[23:27:21] &amp;lt;coolace&amp;gt;&amp;nbsp;  for(i = input_parameters.GetParameters().begin(); i != input_parameters.GetParameters().end(); ++i)
&lt;br /&gt;[23:27:21] &amp;lt;coolace&amp;gt;&amp;nbsp;  {
&lt;br /&gt;[23:27:22] &amp;lt;coolace&amp;gt;&amp;nbsp; &amp;nbsp;  if (i-&amp;gt;name == &amp;quot;action_name&amp;quot;) 
&lt;br /&gt;[23:27:24] &amp;lt;coolace&amp;gt;&amp;nbsp; &amp;nbsp;  {
&lt;br /&gt;[23:27:26] &amp;lt;coolace&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;  std::string report_string = &amp;quot;Не найден обработчик с именем: &amp;quot; + boost::get&amp;lt;std::string&amp;gt;(i-&amp;gt;value);
&lt;br /&gt;[23:27:28] &amp;lt;coolace&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;  GUI_LOG_2(&amp;quot;DefaultAction::Execute(): &amp;quot;, report_string);
&lt;br /&gt;[23:27:30] &amp;lt;coolace&amp;gt;&amp;nbsp; &amp;nbsp;  }
&lt;br /&gt;[23:27:32] &amp;lt;coolace&amp;gt;&amp;nbsp;  }
&lt;br /&gt;[23:27:34] &amp;lt;coolace&amp;gt; }
&lt;br /&gt;[23:27:38] &amp;lt;R|lecture&amp;gt; лучше было, конечно, в everfall.com/paste
&lt;br /&gt;[23:27:49] &amp;lt;coolace&amp;gt; понимаю :)
&lt;br /&gt;[23:27:57] &amp;lt;coolace&amp;gt; щас
&lt;br /&gt;[23:30:37] &amp;lt;coolace&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?iq2qece9qm09&quot;&gt;http://www.everfall.com/paste/id.php?iq2qece9qm09&lt;/a&gt;
&lt;br /&gt;[23:30:46] &amp;lt;coolace&amp;gt; во разобрался
&lt;br /&gt;[23:32:17] &amp;lt;coolace&amp;gt; значит там лежит код пользовательского обработчика типа открывающего окно, он нигде не используется ибо код устарел но выглядит это именно так
&lt;br /&gt;[23:32:57] &amp;lt;coolace&amp;gt; в качестве тела такой вещи пишется любой пользовательский код вобщем
&lt;br /&gt;[23:33:13] &amp;lt;coolace&amp;gt; все это оформляем в макрос
&lt;br /&gt;[23:33:36] &amp;lt;coolace&amp;gt; для компактности так сказать
&lt;br /&gt;[23:34:24] &amp;lt;coolace&amp;gt; вот на чем я остановился
&lt;br /&gt;[23:36:12] &amp;lt;coolace&amp;gt; так вот приходят сообщения
&lt;br /&gt;[23:37:04] &amp;lt;coolace&amp;gt; раньше они передавались по дереву контролов пока не будут обработаны и всплавали
&lt;br /&gt;[23:37:30] &amp;lt;coolace&amp;gt; контролы организованы как composite
&lt;br /&gt;[23:37:54] &amp;lt;coolace&amp;gt; пришел к выводу что такой метод передачи лажа полная
&lt;br /&gt;[23:38:59] &amp;lt;coolace&amp;gt; сейчас все по другому, в случае пользовательского сообщения мы его отправляем по имени либо по указателю
&lt;br /&gt;[23:39:15] &amp;lt;coolace&amp;gt; имена могут быть не уникальны
&lt;br /&gt;[23:39:51] &amp;lt;coolace&amp;gt; поэтому иногда лучше по указателю, хотя это доступно только на низком уровне
&lt;br /&gt;[23:40:21] &amp;lt;coolace&amp;gt; в случае с инпутом все интереснее
&lt;br /&gt;[23:40:39] &amp;lt;coolace&amp;gt; мы их отправляем &amp;quot;по координатам&amp;quot; :)
&lt;br /&gt;[23:41:25] &amp;lt;coolace&amp;gt; конечно не прямо так, а находим самый верхний приемщик инпута и ему по указателю флем сообщение
&lt;br /&gt;[23:42:16] &amp;lt;coolace&amp;gt; это можно кешировать так что время приема сообщения именно тем кто его должет принять станет константным
&lt;br /&gt;[23:43:10] &amp;lt;coolace&amp;gt; раньше сообщения были асинхронными те складывались в очередь а потом вся очередь обрабатывалась
&lt;br /&gt;[23:43:38] &amp;lt;coolace&amp;gt; опыт показал что лажа это... 
&lt;br /&gt;[23:44:05] &amp;lt;coolace&amp;gt; непонятно откуда пришло битое сообщение например
&lt;br /&gt;[23:44:30] &amp;lt;coolace&amp;gt; вот теперь сообщения синхронны
&lt;br /&gt;[23:44:48] &amp;lt;coolace&amp;gt; обрабатывается сразу после закрытия
&lt;br /&gt;[23:45:27] &amp;lt;coolace&amp;gt; и записывать их можно а потом проигрывать
&lt;br /&gt;[23:45:36] &amp;lt;coolace&amp;gt; так же как и раньше
&lt;br /&gt;[23:46:18] &amp;lt;coolace&amp;gt; + временные задержки равномерно распределены а не так что пришло 1000 сообщений и игра подвисла
&lt;br /&gt;[23:46:35] &amp;lt;coolace&amp;gt; только из за цикла :)&lt;/p&gt;
&lt;p&gt;[23:47:23] &amp;lt;coolace&amp;gt; вопросы по поводу сообщений есть? я щас код покажу
&lt;br /&gt;[23:49:53] &amp;lt;coolace&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?6o6fceispxkz&quot;&gt;http://www.everfall.com/paste/id.php?6o6fceispxkz&lt;/a&gt;
&lt;br /&gt;[23:49:57] &amp;lt;coolace&amp;gt; вот пример
&lt;br /&gt;[23:51:43] &amp;lt;coolace&amp;gt; это на самом деле обернутое сообщение на изменение свойств
&lt;br /&gt;[23:52:02] &amp;lt;coolace&amp;gt; но смысл всегда такой же
&lt;br /&gt;[23:52:43] &amp;lt;coolace&amp;gt; те открыли сообщение - набили его параметрами - закрыли сообщение
&lt;br /&gt;[23:53:18] &amp;lt;coolace&amp;gt; в момент закрытия оно обрабатывается
&lt;br /&gt;[23:54:11] &amp;lt;coolace&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?kw5zqcvfw11b&quot;&gt;http://www.everfall.com/paste/id.php?kw5zqcvfw11b&lt;/a&gt;
&lt;br /&gt;[23:54:27] &amp;lt;coolace&amp;gt; это сообщение от мыши в чистом виде
&lt;br /&gt;[23:55:20] &amp;lt;coolace&amp;gt; пауза 3 мин перекур, дальше про свойства подробно&lt;/p&gt;
&lt;p&gt;[23:55:44] &amp;lt;Zeux&amp;gt; вопросы, пожелания
&lt;br /&gt;[23:58:05] &amp;lt;coolace&amp;gt; ну если нет вопосов то продолжаем
&lt;br /&gt;[23:59:30] &amp;lt;coolace&amp;gt; свойства содержит в себе значение, имя, и связи с другими свойствами других контролов
&lt;br /&gt;[00:00:30] &amp;lt;coolace&amp;gt; с именем и значением все понятно, а вот зачем нужны связи и динамическое добавление совйств хотябы в редакторе рассморю подробно
&lt;br /&gt;[23:57:14] &amp;lt;coolace&amp;gt; значит классическая проблема всех систем с которыми я работал до этого (3 штуки)
&lt;br /&gt;[23:57:58] &amp;lt;coolace&amp;gt; это то что программисту игровому нужно знать тип контрола и метод для задания того или иного параметра
&lt;br /&gt;[23:59:16] &amp;lt;coolace&amp;gt; а это значит тесное переплетение вобщем то низкоуровнего кода GUI в стиле FindContol(&amp;quot;label_armor&amp;quot;)-&amp;gt;SetCaption(armor)
&lt;br /&gt;[23:59:40] &amp;lt;coolace&amp;gt; с игровым
&lt;br /&gt;[00:00:07] &amp;lt;coolace&amp;gt; вот чтобы решить проблему сделал так
&lt;br /&gt;[00:00:40] &amp;lt;coolace&amp;gt; в данном примере еще и имя окна надо знать
&lt;br /&gt;[00:02:24] &amp;lt;coolace&amp;gt; в моем случае тоже имя окна и имя свойства которое представляет собой игровой термин добавляется и связывается с низкоуровневым именетм свойства конкретного контрола ужее в редакторе
&lt;br /&gt;[00:03:21] &amp;lt;coolace&amp;gt; можно написать его описание и генерить документацию и код полной поддержки окна останется только параметры передать и все
&lt;br /&gt;[00:04:23] &amp;lt;coolace&amp;gt; они сами попадут куда нужно, а куда нужно может меняться часто и меняет это сборщик окон без какого бы то нибыло вмешательства программиста
&lt;br /&gt;[00:04:43] &amp;lt;coolace&amp;gt; главное чтобы имена и типы совпадали
&lt;br /&gt;[00:05:13] &amp;lt;coolace&amp;gt; хотя типы могут и не совпадать а связь идти через какой либо фильтрл
&lt;br /&gt;[00:07:20] &amp;lt;coolace&amp;gt; вот пример сгенереного кода
&lt;br /&gt;[00:07:21] &amp;lt;coolace&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?015r8okp7m88&quot;&gt;http://www.everfall.com/paste/id.php?015r8okp7m88&lt;/a&gt;
&lt;br /&gt;[00:08:21] &amp;lt;coolace&amp;gt; это облегчило жизнь просто охренеть как если честно
&lt;br /&gt;[00:08:56] &amp;lt;coolace&amp;gt; еще больше облегчило жизнь когда это заработало в связке с шаблонами
&lt;br /&gt;[00:09:27] &amp;lt;coolace&amp;gt; шаблон - готовая сборка компонент которая много где используется
&lt;br /&gt;[00:10:05] &amp;lt;coolace&amp;gt; те у шаблона есть связанные свойства с его внутренними компонентами, которые тоже могут быть шаблонами
&lt;br /&gt;[00:10:26] &amp;lt;coolace&amp;gt; и свзь может быть с из связанными свойствами :)
&lt;br /&gt;[00:10:56] &amp;lt;coolace&amp;gt; все это в конечном итоге выводится в свойства окна
&lt;br /&gt;[00:11:43] &amp;lt;coolace&amp;gt; про шаблоны интересно послушать или и так все ясно?
&lt;br /&gt;[00:13:36] &amp;lt;coolace&amp;gt; ладно пока расскажу про абстрагирование от движка и локализацию, потом про шаблоны если кого заинтересует
&lt;br /&gt;[00:14:56] &amp;lt;coolace&amp;gt; значит абстрагирование это нужно понятно зачем... вобщем хотел вытянуть из прошлого проекта некий код гуя и понял что это невозможно из за дикого переплетения
&lt;br /&gt;[00:15:13] &amp;lt;coolace&amp;gt; его с низкоуровневым кодом рендера и инпута
&lt;br /&gt;[00:15:38] &amp;lt;coolace&amp;gt; значит абстрагироваться решил так..
&lt;br /&gt;[00:15:52] &amp;lt;coolace&amp;gt; паттерн bridge
&lt;br /&gt;[00:16:35] &amp;lt;coolace&amp;gt; + пустые реализации интерфейсов задаваемые по умолчанию
&lt;br /&gt;[00:17:07] &amp;lt;coolace&amp;gt; для того чтобы если вдруг нету звуковой реализации то подсовывалать пустышка&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=761&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/blog/?id=736</guid>
  <pubDate>Wed, 26 Apr 2006 13:32:26 GMT</pubDate>
  <title>Прошедшие лекции</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/blog/?id=736</link>
  <description>
&lt;p&gt;Выложены логи двух прошедших недавно лекций.&lt;/p&gt;
&lt;p&gt;* &lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=26&quot;&gt;Реализация физики на основе интегрирования Верлета&lt;/a&gt; (Лекторы - &lt;b&gt;new&lt;/b&gt;, &lt;b&gt;Joric&lt;/b&gt;)

&lt;li&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=27&quot;&gt;GUI&lt;/a&gt; (Лектор - &lt;b&gt;Sark7&lt;/b&gt;)&lt;/p&gt;&lt;/li&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=735</guid>
  <pubDate>Wed, 26 Apr 2006 13:28:49 GMT</pubDate>
  <title>Лекция #23. GUI [Лектор - Sark7]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=735</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=1154</comments>
  <description>
&lt;p&gt;Disclaimer: некоторые опечатки поправлены, некоторые реплики передвинуты. &lt;a href=&quot;http://www.everfall.com/paste/id.php?6vj3j70yuki0&quot;&gt;полный лог&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[13:42] &amp;lt;Sark7&amp;gt; значецо, хотим мы гуи
&lt;br /&gt;[13:43] &amp;lt;Sark7&amp;gt; и чтобы ексендабельный был
&lt;br /&gt;[13:43] &amp;lt;Sark7&amp;gt; и чтобы по возможности как можно более кроссплатформенный/апи
&lt;br /&gt;[13:43] &amp;lt;Sark7&amp;gt; не в смысле работать на всех платформах, а уменьшить зависимость от апи/системы
&lt;br /&gt;[13:43] &amp;lt;Sark7&amp;gt; первое что приходит в голову
&lt;br /&gt;[13:44] &amp;lt;Sark7&amp;gt; это html
&lt;br /&gt;[13:44] &amp;lt;Sark7&amp;gt; ну и xml в той же степени
&lt;br /&gt;[13:44] &amp;lt;Sark7&amp;gt; на самом деле, это единственно реальный вариант
&lt;br /&gt;[13:44] &amp;lt;Sark7&amp;gt; и адобе, и мозилла, и мс это понимают, поэтому предложили свои варианты gui markup langs
&lt;br /&gt;[13:45] &amp;lt;Sark7&amp;gt; причина этого
&lt;br /&gt;[13:45] &amp;lt;Sark7&amp;gt; что абсолютный (ручной) лайоут контролов - зло
&lt;br /&gt;[13:45] &amp;lt;Sark7&amp;gt; абсолютное
&lt;br /&gt;[13:45] &amp;lt;Sark7&amp;gt; слишком многое надо учесть чтобы такой лайоут нормально работал на всех разрешениях, dpi, шрифтах итд
&lt;br /&gt;[13:46] &amp;lt;Sark7&amp;gt; мне вот лично очень понравился SWT
&lt;br /&gt;[13:46] &amp;lt;Sark7&amp;gt; это такая gui библиотека для явы в eclipse
&lt;br /&gt;[13:46] &amp;lt;Sark7&amp;gt; я брал ее за основу
&lt;br /&gt;[13:46] &amp;lt;Sark7&amp;gt; итак
&lt;br /&gt;[13:46] &amp;lt;Sark7&amp;gt; есть контрол
&lt;br /&gt;[13:47] &amp;lt;Sark7&amp;gt; у него есть методы Layout() и Draw(UIRenderer&amp; renderer)
&lt;br /&gt;[13:47] &amp;lt;Sark7&amp;gt; события рассмотрим позже
&lt;br /&gt;[13:47] &amp;lt;Sark7&amp;gt; в контроле Layout() ничего не делает
&lt;br /&gt;[13:47] &amp;lt;Sark7&amp;gt; как и Draw
&lt;br /&gt;[13:48] &amp;lt;Sark7&amp;gt; есть контейнер
&lt;br /&gt;[13:48] &amp;lt;Sark7&amp;gt; наследуется от контрола, и их хранит
&lt;br /&gt;[13:48] &amp;lt;Sark7&amp;gt; у него Layout() выполняет работу по расстановке контролов
&lt;br /&gt;[13:49] &amp;lt;Sark7&amp;gt; это так сказать база
&lt;br /&gt;[13:49] &amp;lt;Sark7&amp;gt; что такое UIRenderer
&lt;br /&gt;[13:50] &amp;lt;Sark7&amp;gt; у него есть методы по отрисовке основных виджетов и графических примитивов
&lt;br /&gt;[13:50] &amp;lt;Sark7&amp;gt; чтобы когда мы захотели поменять стиль контролов, нам пришлось бы только сменить рендерер
&lt;br /&gt;[13:50] &amp;lt;Sark7&amp;gt; есть Window который наследуется от контейнера
&lt;br /&gt;[13:51] &amp;lt;Sark7&amp;gt; он как раз и выполняет основную работу
&lt;br /&gt;[13:51] &amp;lt;Sark7&amp;gt; и посылает нужным контролам сообщения
&lt;br /&gt;[13:52] &amp;lt;Sark7&amp;gt; идеальная модель для сообщений - это event sinking/bubbling
&lt;br /&gt;[13:52] &amp;lt;Sark7&amp;gt; т.е. сначала событие как бы тонет
&lt;br /&gt;[13:52] &amp;lt;Sark7&amp;gt; т.е. идет от парента к чайлду
&lt;br /&gt;[13:53] &amp;lt;Sark7&amp;gt; на этом этапе парент может обработать его и далее оно тонуть не будет
&lt;br /&gt;[13:53] &amp;lt;Sark7&amp;gt; после того как событие достигло дна
&lt;br /&gt;[13:53] &amp;lt;Sark7&amp;gt; т.е. собственно таргет контрола для которого событие предназначалось
&lt;br /&gt;[13:53] &amp;lt;Sark7&amp;gt; оно начинает всплывать
&lt;br /&gt;[13:54] &amp;lt;Sark7&amp;gt; и идет от чайлда к паренту
&lt;br /&gt;[13:54] &amp;lt;Sark7&amp;gt; на этом этапе, если событие пришло к паренту, он знает, что никакой из чайлдов его не обработал
&lt;br /&gt;[13:55] &amp;lt;Sark7&amp;gt; и может действовать соответственно
&lt;br /&gt;[13:55] &amp;lt;Sark7&amp;gt; сообщения я лично разделил на три категории
&lt;br /&gt;[13:56] &amp;lt;Sark7&amp;gt; MouseEvent, KeyEvent и CommandEvent
&lt;br /&gt;[13:56] &amp;lt;Sark7&amp;gt; ну из названий понятно что они делают )
&lt;br /&gt;[13:56] &amp;lt;Sark7&amp;gt; соотв. в контроле имеется три методы on(MouseEvent&amp;), on(KeyEvent)&amp;, on(CommandEvent&amp;)
&lt;br /&gt;[13:56] &amp;lt;Sark7&amp;gt; это базисные
&lt;br /&gt;[13:57] &amp;lt;Sark7&amp;gt; ладно, может кто чо спросить хочет )&lt;/p&gt;
&lt;p&gt;[13:58] &amp;lt;Anubis|tea&amp;gt; про евенты понятно... не понял самое начало правда
&lt;br /&gt;[13:58] &amp;lt;Anubis|tea&amp;gt; про маркап
&lt;br /&gt;[13:58] &amp;lt;Anubis|tea&amp;gt; чем он помогает от ручного лэйаута... и какой он тогда, если не ручной
&lt;br /&gt;[13:59] &amp;lt;Sark7&amp;gt; он автоматический&lt;/p&gt;
&lt;p&gt;[13:58] &amp;lt;Sark7&amp;gt; такая модель гуи легко переносится на data-driven
&lt;br /&gt;[13:59] &amp;lt;Sark7&amp;gt; в этом пойнт&lt;/p&gt;
&lt;p&gt;[13:59] &amp;lt;cppg&amp;gt; да, кто контролы двигает?
&lt;br /&gt;[13:59] &amp;lt;Sark7&amp;gt; у контролов есть стиль
&lt;br /&gt;[13:59] &amp;lt;Sark7&amp;gt; это как css стиль у элемента в html
&lt;br /&gt;[13:59] &amp;lt;Sark7&amp;gt; он определяет как контрол будет позиционироваться в контейнере
&lt;br /&gt;[14:00] &amp;lt;Sark7&amp;gt; и вообще его внешний вид
&lt;br /&gt;[14:00] &amp;lt;Sark7&amp;gt; т.е. его align, font-size, overflow... практически весь css&lt;/p&gt;
&lt;p&gt;[14:00] &amp;lt;Anubis|tea&amp;gt; а, то есть есть набор контролов, и аффтаматам, как в броузере, определяеццо как он рисоваццо будет?&lt;/p&gt;
&lt;p&gt;[14:01] &amp;lt;Anubis|tea&amp;gt; гм... а речь о гуи для игр? там ведь дизайнер хочет контролировать все на свете, как, где, что и зачем, каким цветом рисуецца
&lt;br /&gt;[14:01] &amp;lt;Sark7&amp;gt; что именно ненравицо?
&lt;br /&gt;[14:01] &amp;lt;Anubis|tea&amp;gt; с точностью до пикселей как будет нарисовано.. или нет?
&lt;br /&gt;[14:01] &amp;lt;Sark7&amp;gt; веб-дизайнеры все прекрасно контролируют с помощью html/css
&lt;br /&gt;[14:02] &amp;lt;Zeux&amp;gt; у веб дизайнеров есть опции алигнмента по позиции
&lt;br /&gt;[14:02] &amp;lt;Zeux&amp;gt; в том самом html/css
&lt;br /&gt;[14:03] &amp;lt;Sark7&amp;gt; что еще за алигнмент по позиции? )
&lt;br /&gt;[14:03] &amp;lt;Zeux&amp;gt; ну, хочу текст в позиции 100, 100
&lt;br /&gt;[14:03] &amp;lt;Sark7&amp;gt; ну, есть абсолютное позиционирование конечно
&lt;br /&gt;[14:03] &amp;lt;Zeux&amp;gt; то что ты называешь абсолютным лейаутом
&lt;br /&gt;[14:03] &amp;lt;Sark7&amp;gt; и у меня )
&lt;br /&gt;[14:03] &amp;lt;Sark7&amp;gt; будет тоже, да
&lt;br /&gt;[14:04] &amp;lt;Zeux&amp;gt; вопрос в том
&lt;br /&gt;[14:04] &amp;lt;Zeux&amp;gt; как будет авто лейаут
&lt;br /&gt;[14:04] &amp;lt;Zeux&amp;gt; сочетаться с абсолютным лейаутом
&lt;br /&gt;[14:04] &amp;lt;Zeux&amp;gt; и не съедет ли все
&lt;br /&gt;[14:04] &amp;lt;Sark7&amp;gt; замечательно
&lt;br /&gt;[14:04] &amp;lt;Sark7&amp;gt; как он в html сочетается
&lt;br /&gt;[14:05] &amp;lt;Sark7&amp;gt; на самом деле абсолютное позиционирование контрола нужно в очень редких случаях
&lt;br /&gt;[14:05] &amp;lt;Sark7&amp;gt; лого там нарисовать чтобы висело на месте итд
&lt;br /&gt;[14:05] &amp;lt;Zeux&amp;gt; в html он сочетается так
&lt;br /&gt;[14:05] &amp;lt;Zeux&amp;gt; что страницы во всех браузерах выглядят по-разному&lt;/p&gt;
&lt;p&gt;[14:04] &amp;lt;_Anubis_&amp;gt; ну ладно, проехали :) надо обдумать.. просто я не вижу, почему дизайнерам самим все не расставить на экране. и дать им возможность подрисовать для разных разрешений если где что некрасиво смотрицца.
&lt;br /&gt;[14:04] &amp;lt;cppg&amp;gt; патамушта разные разрешения надо
&lt;br /&gt;[14:04] &amp;lt;cppg&amp;gt; любые размеры окна, скажем
&lt;br /&gt;[14:05] &amp;lt;cppg&amp;gt; имхо надо всё указывать в координатах float 0.0...1.0 и не париться с размерами окон и пикселями
&lt;br /&gt;[14:05] &amp;lt;_Anubis_&amp;gt; цппг - разрешения вполней фиксированые ведь.. их не много и чаще фсего с фиксированым аспектом
&lt;br /&gt;[14:05] &amp;lt;Sark7&amp;gt; _Anubis_, размеры окон
&lt;br /&gt;[14:06] &amp;lt;cppg&amp;gt; _Anubis_, их много во-первых, во-вторых незачем делать десять раз то, что можно сделать один раз
&lt;br /&gt;[14:06] &amp;lt;_Anubis_&amp;gt; цппг - так я так и имел ввиду, блин
&lt;br /&gt;[14:06] &amp;lt;_Anubis_&amp;gt; просто при некоторых может там ченить съехать
&lt;br /&gt;[14:07] &amp;lt;cppg&amp;gt; АА вруби и не сьедет
&lt;br /&gt;[14:07] &amp;lt;Sark7&amp;gt; как бы оно не сьехало, оно нормально будет выглядеть
&lt;br /&gt;[14:07] &amp;lt;Sark7&amp;gt; в отличие от ручного лайоута
&lt;br /&gt;[14:06] &amp;lt;_Anubis_&amp;gt; я имел ввиду дать возможность подправить руками там где не нравицца&lt;/p&gt;
&lt;p&gt;[14:07] &amp;lt;Zeux&amp;gt; координаты от 0 до 1 - это здорово
&lt;br /&gt;[14:07] &amp;lt;Zeux&amp;gt; но шрифты масштабировать не стоит
&lt;br /&gt;[14:07] &amp;lt;Zeux&amp;gt; так что все равно делать кучу шрифтов
&lt;br /&gt;[14:07] &amp;lt;Zeux&amp;gt; под разные разрешения
&lt;br /&gt;[14:07] &amp;lt;cppg&amp;gt; текстурные шрифты отлично ложаццо на это
&lt;br /&gt;[14:07] &amp;lt;Zeux&amp;gt; cppg, если рисовать крупные надписи - ложатся
&lt;br /&gt;[14:07] &amp;lt;Zeux&amp;gt; если мелкие - нет
&lt;br /&gt;[14:07] &amp;lt;cppg&amp;gt; ну вруби trilinear?
&lt;br /&gt;[14:08] &amp;lt;Zeux&amp;gt; ага, и будет все размыто
&lt;br /&gt;[14:08] &amp;lt;Zeux&amp;gt; т.е. если есть фиксированный размер шрифта
&lt;br /&gt;[14:08] &amp;lt;Zeux&amp;gt; то можно аккуратно попадать тексель в пиксель
&lt;br /&gt;[14:08] &amp;lt;Zeux&amp;gt; и делать чтобы можно было читать
&lt;br /&gt;[14:08] &amp;lt;cppg&amp;gt; ну вапще да
&lt;br /&gt;[14:08] &amp;lt;cppg&amp;gt; ну для мелких надо отдельный фонт делать, да&lt;/p&gt;
&lt;p&gt;[14:08] &amp;lt;Sark7&amp;gt; шрифтами управляет UIRenderer... он и выбирает нужный шрифт в зависимости от
&lt;br /&gt;[14:08] &amp;lt;Sark7&amp;gt; или масштабирует какой есть если нету нужного&lt;/p&gt;
&lt;p&gt;[14:08] &amp;lt;_Anubis_&amp;gt; не зря же консольный шрифт в кваке той же меняецца по размеру на экране в зависимости от разрешения&lt;/p&gt;
&lt;p&gt;[14:08] &amp;lt;Zeux&amp;gt; но вообще конечно для каждого разрешения делать раскладку контролов по экрану - это об стену
&lt;br /&gt;[14:08] &amp;lt;Zeux&amp;gt; правда (!)
&lt;br /&gt;[14:08] &amp;lt;Zeux&amp;gt; об стену дизайнерам, а не программистам :)&lt;/p&gt;
&lt;p&gt;[14:09] &amp;lt;Sark7&amp;gt; так
&lt;br /&gt;[14:09] &amp;lt;Sark7&amp;gt; как происходит собственно отправка событий в Window
&lt;br /&gt;[14:09] &amp;lt;Sark7&amp;gt; Window приходит сообщение (от WindowManager, я про него позже расскажу)
&lt;br /&gt;[14:10] &amp;lt;Sark7&amp;gt; для MouseEvent
&lt;br /&gt;[14:10] &amp;lt;Sark7&amp;gt; Window находит контрол в котором находится мышь
&lt;br /&gt;[14:11] &amp;lt;Sark7&amp;gt; и отправляет сначала parent2child затем child2parent
&lt;br /&gt;[14:11] &amp;lt;Sark7&amp;gt; на самом деле немного сложнее, потому что есть еще leave/enter события, но в принципе одинаково
&lt;br /&gt;[14:11] &amp;lt;Sark7&amp;gt; для KeyEvent
&lt;br /&gt;[14:12] &amp;lt;Sark7&amp;gt; Window держит фокусный контрол
&lt;br /&gt;[14:12] &amp;lt;Sark7&amp;gt; которому и шлет событие от клавиатуры
&lt;br /&gt;[14:12] &amp;lt;Sark7&amp;gt; Command вообще тривиально и зависит от
&lt;br /&gt;[14:12] &amp;lt;Sark7&amp;gt; так, расскажу про UIRenderer
&lt;br /&gt;[14:13] &amp;lt;Sark7&amp;gt; он и обеспечивает некий промежуточный слой между рендер-апи и собственно гуи
&lt;br /&gt;[14:13] &amp;lt;Sark7&amp;gt; у него есть методы для отрисовки основных виджетов
&lt;br /&gt;[14:13] &amp;lt;Sark7&amp;gt; типа DrawSlider, DrawCheckbox итд
&lt;br /&gt;[14:13] &amp;lt;Sark7&amp;gt; на самом деле это необязательно, но нужно если мы хотим total theming
&lt;br /&gt;[14:14] &amp;lt;Sark7&amp;gt; и методы для отрисовки примитивов - квады, треугольники, текст
&lt;br /&gt;[14:14] &amp;lt;Sark7&amp;gt; контрол передает в эти методы _желаемые_ параметры вывода
&lt;br /&gt;[14:14] &amp;lt;Sark7&amp;gt; UIRenderer выбирает актуальные
&lt;br /&gt;[14:14] &amp;lt;Sark7&amp;gt; и рисует
&lt;br /&gt;[14:15] &amp;lt;Sark7&amp;gt; например
&lt;br /&gt;[14:15] &amp;lt;Sark7&amp;gt; текстуры тоже абстрагированы
&lt;br /&gt;[14:16] &amp;lt;Sark7&amp;gt; контрол передает в методы UIRenderer имя текстуры/хендл
&lt;br /&gt;[14:16] &amp;lt;Sark7&amp;gt; это нужно например, если у нас атласинг для гуи
&lt;br /&gt;[14:16] &amp;lt;Sark7&amp;gt; и текстуры виртуализированы )
&lt;br /&gt;[14:17] &amp;lt;Sark7&amp;gt; про WindowManager
&lt;br /&gt;[14:17] &amp;lt;Sark7&amp;gt; он управляет собственно окнами
&lt;br /&gt;[14:17] &amp;lt;Sark7&amp;gt; есть список окон
&lt;br /&gt;[14:17] &amp;lt;Sark7&amp;gt; наверху этого списка - модальное окно
&lt;br /&gt;[14:17] &amp;lt;Sark7&amp;gt; т.е. сообщения посылаются лишь одному окну, первому в списке
&lt;br /&gt;[14:18] &amp;lt;Sark7&amp;gt; мультиоконность реализуется через MultiWindow
&lt;br /&gt;[14:18] &amp;lt;Sark7&amp;gt; которое собственно наследуется он окна, но управляет несколькими окнами в себе&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=735&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
<item>
  <guid isPermaLink="true">http://www.gamedev.ru/community/gamedev_lecture/articles/?id=720</guid>
  <pubDate>Thu, 20 Apr 2006 20:54:29 GMT</pubDate>
  <title>Лекция #22. Реализация физики на основе интегрирования Верлета. [Лекторы - new, Joric]</title>
  <link>http://www.gamedev.ru/community/gamedev_lecture/articles/?id=720</link>
  <comments>http://www.gamedev.ru/community/gamedev_lecture/forum/?id=1146</comments>
  <description>
&lt;p&gt;Disclaimer: некоторые опечатки поправлены, некоторые реплики передвинуты.&lt;/p&gt;
&lt;p&gt;[23:04:11] &amp;lt;new&amp;gt; В общем сразу скажу, что лекция в большенстве своего объёма построена на материалах статьи Advanced Character Physics
&lt;br /&gt;[23:04:29] &amp;lt;new&amp;gt; автор Thomas Jakobsen (&lt;a href=&quot;http://www.gamasutra.com/resource_guide/20030121/jacobson_01.shtml&quot;&gt;http://www.gamasutra.com/resource_guide/20030121/jacobson_01.shtml&lt;/a&gt;)
&lt;br /&gt;[23:04:57] &amp;lt;new&amp;gt; её перевод может быть найден в формате DOC здесь &lt;a href=&quot;http://www.l1f.nm.ru/download/AdvancedCharacterPhysics.rar&quot;&gt;http://www.l1f.nm.ru/download/AdvancedCharacterPhysics.rar&lt;/a&gt;
&lt;br /&gt;[23:05:09] &amp;lt;new&amp;gt; автор перевода Антон Ткачёв
&lt;br /&gt;[23:05:23] &amp;lt;new&amp;gt; остальные ссылки в конце лекции
&lt;br /&gt;[23:05:51] &amp;lt;new&amp;gt; Цель лекции рассказать основы бодробнее, чем в оригинальной статье
&lt;br /&gt;[23:06:44] &amp;lt;new&amp;gt; приобщить &amp;quot;новичков&amp;quot; к физике на основе этого метода и показать что физика может быть проста в реализации&lt;/p&gt;
&lt;p&gt;
&lt;br /&gt;[23:07:41] &amp;lt;new&amp;gt; Основой структуры данного метода является система частиц
&lt;br /&gt;[23:08:20] &amp;lt;new&amp;gt; в привычной формулировке для каждой частицы системы хранится её текущее положение и скорость
&lt;br /&gt;[23:08:33] &amp;lt;new&amp;gt; pos_new = pos + vel*dt
&lt;br /&gt;[23:08:33] &amp;lt;new&amp;gt; vel_new = vel + accel*dt
&lt;br /&gt;[23:08:33] &amp;lt;new&amp;gt; Это простое объединение Эйлера
&lt;br /&gt;[23:10:14] &amp;lt;new&amp;gt; таким образом считается положение и скорость на новом шаге(pos_new и vel_new) через предыдущий (pos и vel)
&lt;br /&gt;[23:10:50] &amp;lt;new&amp;gt; Метод с использованием интегрирования Верлющей, т.е.
&lt;br /&gt;[23:10:57] &amp;lt;new&amp;gt; pos_new = 2*pos - pos_last + a*dt*dt
&lt;br /&gt;[23:10:57] &amp;lt;new&amp;gt; pos_last = pos
&lt;br /&gt;[23:12:18] &amp;lt;new&amp;gt; где (pos_last-pos) является аналогом скорости при постоянном времени шага
&lt;br /&gt;[23:14:09] &amp;lt;new&amp;gt; то-есть pos + (pos-pos_last)*1(ед. времета предпологает хранение предыдущей и текущей координаты для получения следуени) + a*dt*dt
&lt;br /&gt;[23:15:36] &amp;lt;new&amp;gt; таким образом система не зависит от явного значения скорости и становится более стабильной
&lt;br /&gt;[23:16:07] &amp;lt;new&amp;gt; уже исходя из написанного выше можно написать простую систему частиц
&lt;br /&gt;[23:16:13] &amp;lt;new&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?8nblk7hk1mhg&quot;&gt;http://www.everfall.com/paste/id.php?8nblk7hk1mhg&lt;/a&gt;
&lt;br /&gt;[23:18:22] &amp;lt;new&amp;gt; функция AccumulateForces накапливает силовые состовляющие для каждой частицы, пока что это действует только сила гравитации
&lt;br /&gt;[23:18:56] &amp;lt;new&amp;gt; функция Verlet() делает то, что описано выше
&lt;br /&gt;[23:19:06] &amp;lt;new&amp;gt; сразу упомяну об оптимизации
&lt;br /&gt;[23:21:11] &amp;lt;new&amp;gt; здесь можно использовать 3 массива (pos_new, pos и pos_last) и не менять местами значения в массивах, а менять местами сами массивы
&lt;br /&gt;[23:24:37] &amp;lt;new&amp;gt; Сразу же можно собрать и посмотреть в действии простую систему частиц, добавив несколько частиц с разными положениями и предыдущими положениями (pos_last = pos-vel), где vel - желаемая вами скорость частицы
&lt;br /&gt;[23:28:01] &amp;lt;new&amp;gt; и ограничив координаты частиц кубом &lt;a href=&quot;http://www.everfall.com/paste/id.php?dcvzxmlkhad2&quot;&gt;http://www.everfall.com/paste/id.php?dcvzxmlkhad2&lt;/a&gt;
&lt;br /&gt;[23:29:41] &amp;lt;new&amp;gt; теперь запустив систему мы должны увидеть как частицы летят по параболе и при ударе в стенку вооброжаемого куба перестают перемещаться в сторону норамали
&lt;br /&gt;[23:30:04] &amp;lt;new&amp;gt; причём не отменяя перемещения в остальных направлениях
&lt;br /&gt;[23:32:00] &amp;lt;new&amp;gt; Теперь добавим связь между частицами.
&lt;br /&gt;[23:34:21] &amp;lt;new&amp;gt; Под связью будем понимать обсолютно нерастяжимый стержень с определённой длиной
&lt;br /&gt;[23:36:31] &amp;lt;new&amp;gt; То-есть если &amp;quot;связаны&amp;quot; 2 частицы, то условием связи будет |part1.pos-part2.pos| = constrain.length
&lt;br /&gt;[23:40:00] &amp;lt;new&amp;gt; таким образом необходимо будет найти длину вектора, отнять её от длины связи
&lt;br /&gt;[23:40:33] &amp;lt;new&amp;gt; (длину вектора (part1.pos-part2.pos) )
&lt;br /&gt;[23:41:47] &amp;lt;new&amp;gt; получим расстояние, на которое надо переместить партиклы на встречу друг к другу (или друг от друга)
&lt;br /&gt;[23:42:38] &amp;lt;new&amp;gt; делим это расстояние на длину вектора - получаем какая это часть от исходного вектора
&lt;br /&gt;[23:44:21] &amp;lt;new&amp;gt; если это найденное значение =diff, а сам вектор delta, то партиклы нужно переместить на +0.5*delta*diff и -0.5*delta*diff
&lt;br /&gt;[23:46:52] &amp;lt;new&amp;gt; &lt;a href=&quot;http://www.everfall.com/paste/id.php?kg654bsepuy5&quot;&gt;http://www.everfall.com/paste/id.php?kg654bsepuy5&lt;/a&gt;
&lt;br /&gt;[23:48:03] &amp;lt;new&amp;gt; для нахождения длины вектора необходимо находить квадратный корень
&lt;br /&gt;[23:49:33] &amp;lt;new&amp;gt; Даже при не большой точности вычисления квадратного корня система не выйдет из равновесия
&lt;br /&gt;[23:49:46] &amp;lt;new&amp;gt; из-за не явного хранения скорости
&lt;br /&gt;[23:51:21] &amp;lt;new&amp;gt; используя формулу Тейлора (находим только функцию 1-го порядка ряда)
&lt;br /&gt;[23:53:03] &amp;lt;new&amp;gt; можно упростить всё выражение &lt;a href=&quot;http://www.everfall.com/paste/id.php?45hmot1k5g80&quot;&gt;http://www.everfall.com/paste/id.php?45hmot1k5g80&lt;/a&gt;
&lt;br /&gt;[23:54:17] &amp;lt;new&amp;gt; restlength нам известна заранее, по этому можно кешировать значение restlength*restlength&lt;/p&gt;
&lt;p&gt;
&lt;br /&gt;[23:54:36] &amp;lt;_Winnie&amp;gt; а где-то можно будет увидеть программу-демонстрашку целиком ? с примитивным выводом на GLUT или даже может быть вообще без графики, которую легко самому прилепить?
&lt;br /&gt;[23:55:02] &amp;lt;new&amp;gt; да, в конце лекции будут полезные ссылки
&lt;br /&gt;[23:55:15] &amp;lt;new&amp;gt; хотя давайте сейчас
&lt;br /&gt;[23:55:35] &amp;lt;new&amp;gt; я покурить схожу - вы пока посмотрите, ато нудно как-то получается...&lt;/p&gt;
&lt;p&gt;
&lt;br /&gt;[23:55:50] &amp;lt;new&amp;gt; &lt;b&gt;Полезные ссылки:&lt;/b&gt;
&lt;br /&gt;[23:55:50] &amp;lt;new&amp;gt; &amp;quot;Advanced Character Physics&amp;quot; (Thomas Jakobsen) &lt;a href=&quot;http://www.gamasutra.com/resource_guide/20030121/jacobson_01.shtml&quot;&gt;http://www.gamasutra.com/resource_guide/20030121/jacobson_01.shtml&lt;/a&gt;
&lt;br /&gt;[23:55:50] &amp;lt;new&amp;gt; &amp;quot;Продвинутая физика персонажей&amp;quot; перевод предыдущей (Антон Ткачёв) &amp;lt;в DOC формате&amp;gt; &lt;a href=&quot;http://www.l1f.nm.ru/download/AdvancedCharacterPhysics.rar&quot;&gt;http://www.l1f.nm.ru/download/AdvancedCharacterPhysics.rar&lt;/a&gt;
&lt;br /&gt;[23:55:50] &amp;lt;new&amp;gt; &amp;quot;Простой метод Верлетной интеграции с поправкой времени&amp;quot; (Джонатан &amp;quot;одинокий носок&amp;quot; Даммер) &lt;a href=&quot;http://1wd.ru/ru/fm/translat/tcv-rus.htm&quot;&gt;http://1wd.ru/ru/fm/translat/tcv-rus.htm&lt;/a&gt;
&lt;br /&gt;[23:55:50] &amp;lt;new&amp;gt; Демки с исходниками &lt;a href=&quot;http://www.members.lycos.co.uk/olivierrenault/&quot;&gt;http://www.members.lycos.co.uk/olivierrenault/&lt;/a&gt;
&lt;br /&gt;[23:55:50] &amp;lt;new&amp;gt; Convex hull (физика со схожими принцыпами) &lt;a href=&quot;http://www.rowlhouse.co.uk/jiggle/&quot;&gt;http://www.rowlhouse.co.uk/jiggle/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
&lt;br /&gt;[23:56:03] &amp;lt;_Winnie&amp;gt; new а то что ты сказал - это только для стержня или может быть применено для произвольной системы между частицами?
&lt;br /&gt;[23:56:22] &amp;lt;_Winnie&amp;gt; *произвольной системы связей между 
&lt;br /&gt;[23:57:05] &amp;lt;new&amp;gt; То, что написано выше, приминимо только для нерастяжимых стержней
&lt;br /&gt;[23:57:07] &amp;lt;Innochenti&amp;gt; э, стоп. В Jiggle совершенно другой подход.
&lt;br /&gt;[23:58:04] &amp;lt;new&amp;gt; Innochenti там схожий принцып в том смысле, что выпуклые объекты выталкиваются из объектов, в которые они попали
&lt;br /&gt;[23:58:07] &amp;lt;Innochenti&amp;gt; там физика по след. документу Eran Guendelman - Nonconvex Rigid Bodies with Stacking.pdf
&lt;br /&gt;[23:58:12] &amp;lt;new&amp;gt; и только в том
&lt;br /&gt;[23:58:44] &amp;lt;new&amp;gt; ну да, не пояснил
&lt;br /&gt;[23:59:19] &amp;lt;new&amp;gt; _Winnie но система легко расширяется для реализации любых связей&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://www.gamedev.ru/community/gamedev_lecture/articles/?id=720&amp;amp;page=2&quot;&gt;Продолжение&lt;/a&gt;&lt;/p&gt;</description>
</item>
</channel>
</rss>
