Blender по-русски
Panda3D по-русски

четверг, 29 января 2009 г.

Новый сайт по Panda3D

Появился еще один сайт по Panda3D в рунете!
Его адрес http://panda3d.org.ru/
Поздравляю с открытием!

суббота, 24 января 2009 г.

Импорт файлов из Blender

В данный момент существует два пути получения данных из Blender в Panda3D.

Вариант 1: Файлы формата X
Существует бесплатный плагин для Blender, который может экспортировать в "Х" (родной DirectX) формат файла. Сохраните файл из Blender как X файл, а затем загрузите его прямо в Panda3D, который может читать файлы формата X. В качестве альтернативы, если файл будет грузиться слишком долго и вам это не нравится, вы можете сконвертировать файл из X формата в Egg или Bam формат с помощью программ конвертирования, поставляемых с Panda3D (x2egg, egg2bam).

Так как вы сохранили модель в неродном формате, вы возможно зададитесь вопросом: "а поддерживает ли этот формат все, что мне нужно?". Например, когда вы сохраняете модель в формате 3DS, вы автоматически теряете все узлы и данные анимации, так как формат файла 3DS не содержит узлы и данные анимации. В случае X формата вы будете приятно удивлены: это достаточно мощный формат, поддерживающий вершины, полигоны, узлы и анимации.

Однако надо отметить, когда анимированный X файл конвертируется в egg, то результирующий egg файл проигрывает только ключевые кадры, но не те, что содержаться между ними. Например анимация, содержащая 200 фреймов может снизится до 40 кадров и воспроизведение будет выглядеть дрожащим (шатким). Эта шаткость случается потому, что X формат поддерживает концепцию ключевых кадров с неявными структурами, которые интерполируются между собой. Формат egg файла является явным. egg файл должен содержать все фреймы анимации, даже фреймы между ключевыми кадрами.

Поэтому, при конвертировании X файла с помощью x2egg будет опущено множество фреймов между ключевыми, и будет создана "шаткая" анимация. Единственное решение это убедиться что X файлы сгенерированы со всеми фреймами. Может потребоваться тестирование различных экспортеров в X из Blender.

Далее, родной формат Panda - egg поддерживает некоторые "эзотерические" вещи. Например он поддерживает blend targets (анимации морфа) и кривые путей движения, которые не поддерживаются в формате X.

Предостережение: недавно было обнаружено, что имеется два фага в парсере X-файлов panda. Один - это чувствительность к регистру, а его не должно быть. Второй - он не обрабатывает дефисы в идентификаторах некорректно. Эти два бага будут исправлены в следующей версии Panda3D. Для временного решения и обхода этих проблем, поищите на информацию форумах.

Вариант 2: Egg плагин-экспортер для Blender
Существует несколько плагинов Blender, разработанных пользователями Panda3D.

Плагин Chicken это наиболее обновляемый, документированный и функционально-законченный. Он поддерживает статические меши и анимацию арматуры, материалы, цвета вершин, альфа текстуры, тэги, типы объектов и т.д. Он также имеет продвинутые функции автоматического вызова инструментов Panda (egg2bam, egg-optchar и pview) и Motion Extraction. Вы можете найти плагин на http://chicken-export.sf.net

EggX - другой экспортер, который работает с материалами, не-процедурными текстурами, анимацией арматуры, статическими мешами. Его можно найти на http://www.wickwack.com/panda

Еще один экспортер с поддержкой только статических мешей можно найти по адресу http://xoomer.virgilio.it/glabro1/panda.html

Основные операции

Общие операции

Обобщение
Эта страница содержит список наиболее употребляемых оперций над 3D моделью. Эта страница просто быстрый обзор, детальная документация по этим операциям изложена в этом мануале позже.

Быстрый обзор операций.

Две наиболее употребляемые операции это смена положения и ориентации.

myNodePath.setPos(X,Y,Z)

По-умолчанию в Panda3D ось X направлена вправо, ось Y — вперед, а ось Z вверх. Вращение объекта обычно описывается с помощью углов Эйлера называемых Heading, Pitch и Roll (иногда называемых Yaw, Pitch и Roll в других пакетах) — они указывают углы вращения в градусах. (если вам больше нравится использовать не градусы а радианты то используйте setQuat() метод)

Вы можете изменить размер объекта, как по всем осям так и по отдельности (x,y или z).

myNodePath.setScale(uniform)

Иногда нужно работать индивидуально с каждой осью:

myNodePath.setX(X)
myNodePath.setY(Y)
myNodePath.setZ(Z)
myNodePath.setH(H)
myNodePath.setP(P)
myNodePath.setR(R)
myNodePath.setSx(SX)
myNodePath.setSy(SY)
myNodePath.setSz(SZ)

Или сразу со всеми параметрами

myNodePath.setPosHprScale(X,Y,Z,H,P,R,SX,SY,SZ)

Вы также можете запросить текущие параметры трансформации:

myNodePath.getPos()
myNodePath.getX()
myNodePath.getY()
myNodePath.getZ()

Также с помощью функций setTag() и getTag() вы можете хранить собственную информацию в виде пар ключ-значение. Например:

myNodePath.setTag('Key', 'Value')

Более продвинутая возможность — вы можете также установить или считать положение (или любое из свойств трансформации) отдельного NodePath по отношению к другому. Чтобы сделать это, укажите относительный NodePath в качестве первого параметра:

myNodePath.setPos(otherNodePath,X,Y,Z)
myNodePath.getPos(otherNodePath)

указывая NodePath в качестве первого параметра в любых операциях трансформации выполняется относительная операция. Вышеуказанная операция setPos() означает установить myNodePath в положение (X,Y,Z) относительно otherNodePath — это значит положение myNodePath будет там, где был бы дочерний узел для otherNodePath и его положение было бы установлено в (X,Y,Z). getPos() возвращает положение myNodePath где бы он был если бы был дочерним узлом otherNodePath.

Также важно помнить что вы можете использовать NodePath сам по себе для относительных преобразований. Это может быть полезно в ситуациях когда вы работаете с дистанцией. Например:

# переместить myNodePath на 3 единицы прямо по оси x
myNodePath.setPos(myNodePath,3,0,0)

Относительные преобразования — очень мощная возможность Panda графов сцены, но иногда вы можете получить не тот результат, что ожидали.

Метод lookAt() поворачивает модель «лицом» к другому объекту, это значит, что ось +Y одного объекта будет совпадать с осью другого. Помните, что у модели ось +Y при создании может не совпадать с реальным «лицом», как бы хотели вы и поэтому метод lookAt() может не сработать правильно.

MyNodePath.lookAt(otherObject)

Изменение цвета — еще одна возможность изменений. Значения цветов — числа с плавающей точкой от 0 до 1, 0 — черный 1 — белый.

MyNodePath.setColor(R,G,B,A)

Если у модели есть текстуры, то они могут отображаться не так как задумано или даже отображаться с другим цветом. Устанавливая цвет в белый может восстановить видимость текстуры, но лучше всего просто убрать (отчистить) настройки цвета.

MyNodePath.clearColor()

Запомните четвертый параметр цвета — альфа. Он обычно используется для указывания прозрачности и обычно равен 1.0 чтобы указать, что объект не прозрачный. Если вы устанавливаете альфа между 0 и 1 вы можете сделать объект невидимым. Чтобы использовать прозрачность ее надо активировать:

myNodePath.setTransparency(TransparencyAttrib.MAlpha)

Параметр для setTransparency() это обычно TransparencyAttrib.MAlpha — это прозрачность. Вы можете также выключить прозрачность с помощью параметра TransparencyAttrib.MNone. (Возможны и другие режимы но об этом в другой раз. В старом коде можно передавать 0 или 1 в этом параметре, но лучше использовать имена режимов) Если вы сначала не активируете прозрачность, то альфа компонент цвета может игнорироваться. Не используйте прозрачность без нужды, так как это влияет на требования рендеринга и требует дополнительные аппаратные ресурсы.

Установка цвета для объекта заменяет все цвета вершин. Если вы создали модель и раскрасили ее вершины по разному то предпочтете модулировать цвет объекта без потери цветов вершин. Для этого есть метод setColorScale(), который умножает цвет вершин на указанный существующий цвет вершин:

myNodePath.setColorScale(R,G,B,A)

одно из применений setColorScale() это использование его на вершине графа сцены (render) чтобы затемнить всю сцену одновременно, например реализовать эффект перехода в темноту.

Так как альфа также важна, есть также метод для изменения его без влияния на компоненты цветов:

myNodePath.setAlphaScale(SA)

Чтобы временно скрыть объект на всех камерах испольуйте hide() и show():

myNodePath.hide()
myNodePath.show()

если вы хотите скрыть объект на одной камере но оставить на другой вы можете использовать команды hide() и show() вместе с функцией camera.setCameraMask():

camera1.node().setCameraMask(BitMask32.bit(0))
camera2.node().setCameraMask(BitMask32.bit(1))
myNodePath.show(BitMask32.bit(1)) # объект будет показан только на камере 2
Пожалуйста, запомните, что использование hide/show без аргументов будет работать только для hide/show без аргументов, то есть если вы скрыли объект с помощью hide() то не покажите его с помощью show(bit)) Чтобы скрыть объект со всех камер лучше использовать nodepath.hide(BitMask32.allOn()) Чтобы установить маску камеры для камеры по-умолчанию используйте base.cam а не base.camera. Детально будет описано в секции по камерам.

Если к скрытому объекту были прикреплены дочерние узлы, то они тоже скроются.

Если будут проблемы с размещением, масштабом или вращением ваших узлов вы можете использовать функцию place() чтобы появлялся небольшой интерфейс GUI который поможет вам. Чтобы его использовать нужно установить TkInter.

MyNodePath.place()

Управление графом сцены

Графы сцены по-умолчанию

По-умолчанию автоматически создается два различных графа сцены, когда вы стартуете Panda3D. Эти графы имеют каждый свой корневой узел — render и render2d.
Чаще всего вы используете render — это вершина отдельной 3D сцены. Когда вы помещаете объект в игровой мир вам нужно сделать его потомком render (или другого узла, который все равно имеет своим предком render).
Вы будете использовать render2d для создания 2D элементов интерфейса (GUI), таких как текст или кнопки, которые вы захотите отображать на экране, например заголовок. Все что размещено в дереве render2d будет отрисовываться поверх 3D сцены, так как если бы рисовалось прямо на стекле экрана.
Координатная система render2d устанавливается так, что совпадает с вводом с мыши, нижний левый угол экран имеет координаты (-1,0,-1) а верхний правый (1,0,1). Так как это квадратная система координат, а экран обычно не квадратный, объекты прикрепленные к render2d могут отображаться растянутыми. По этой причине Panda3D также определяет дочерний узел для render2d, который называется aspect2d, который применяет масштабирование для корректировки неквадратного вывода render2d. Чаще всего вы будете прикреплять GUI элементы к aspect2d а не к render2d.

Координатная система aspect2d по-умолчанию масштабируется так, что ось x имеет диапазон [-ratio,ratio], а y имеет диапазон [-1,1], где ratio это размер_экрана_по_оси_х поделенное на размер_экрана_по_оси_y (в обычном случае ширина экрана больше его высоты).

В конце вы можете увидеть ссылки на еще один из высокоуровневых узлов называемый hidden. Это просто одиночный узел, который не имеет никаких свойств отображения и все объекты, прикрепленные к этому узлу также не будут отображаться. Старый Panda3D код использует этот узел, чтобы удалить узел из графа сцены render. Однако в новых версиях это больше не нужно и не рекомендуется использовать его для новых программ, лучший путь для удаления узла из графа render это вызвать nodePath.detachNode().

Загрузка моделей
Вы можете загрузить модель из файла, используя Panda синтаксис для имени файла, загрузить egg или bam файл. Во многих примерах расширение файла не указано — в этом случае Panda будет искать файл с расширением .egg или .bam.

myNodePath = loader.loadModel('my/path/to/models/myMode.egg')

Когда вы первый раз вызываете loadModel() для отдельного узла, эта модель считывается и сохраняется в таблице памяти и при следующих вызовах просто копируется из таблицы вместо повторного чтения из файла.

Вышеуказанный метод применяется для загрузки статических моделей, для анимированных моделей смотрите главу Загрузка Актеров и Анимаций.

Смена родителей для узлов и моделей
Одна из наиболее частых действий с графом сцены это смена родительских узлов для выбранных. Вам нужно будет сделать это по-крайней мере один раз после загрузки модели, чтобы вставить ее в render для просмотра:

myModel.reparentTo(render)

А чтобы удалить его:

myModel.detachNode()

Чтобы полностью удалить nodePath из графа сцены и памяти надо вызвать removeNode, это действие освобождает память и удаляет узел, освобождая место в памяти. Используйте это действие только когда вам больше действительно не нужен этот узел:

myNodePath.removeNode()

Когда вы станете более опытным с операциями над графом, вы заметите что можете создавать все более и более продвинутые графы сцены и можете манипулировать моделью по вашему желанию. Иногда может понадобится создавать пустые узлы для этого, например для группировки нескольких моделей вместе.
dummyNode = render.attachNewNode('Dummy Node Name')
myModel.reparentTo(dummyNode)
myOtherModel.reparentTo(dummyNode)

Так как узел наследует свое положение в пространстве от родительского узла, то когда вы прикрепляете его к другому родителю графа мы можете нечаяно изменить его положение в игровом мире. Если вам нужно избежать этой ситуации вы можете использовать специальные варианты reparentTo():

myModel.wrtReparentTo(newParent)

Префикс wrt означает «with respect to» (с уважением к). Это специальный метод работает как reparentTo(), за исключением того, что он автоматически пересчитывает его локальные транформации над myModel для компенсирования изменений при преобразовании к новому родителю, так чтобы узел оказался в той же позиции относительно игрового мира.

Помните, что расчет преобразования, который делает wrtReparentTo() выполняется над числами с плавающей точкой и может иметь погрешность. Это значит, что если вы будете использовать wrtReparentTo() непрерывно, тысячу раз над одним и тем же узлом, то эта погрешность может аккумулироваться и вместо 1 у вас будет например 0.99999.
Начинающие слишком часто используют этот метод, не следует использовать wrtReparentTo() пока для этого не будет значимой причины.

среда, 21 января 2009 г.

Программирование в Panda3D. Часть A. Граф сцены.

Граф сцены : Дерево узлов (Nodes).
Множество простых игровых 3D движков используют список 3D моделей при рендеринге каждого фрейма (кадра). В этих простых движках надо создать 3D модель (или загрузить с диска) и затем вставить ее в список моделей для рендеринга. Модель не видима для рендеринга до тех пор, пока не вставлена в этот список.
Panda3D немного сложнее. Вместо представления списка объектов рендеру она представляет дерево объектов. Объект не видим рендеру пока он не вставлен в дерево.
Дерево состоит из объектов класса PandaNode. Это основной суперкласс для всех остальных классов:ModelNode, GeomNode, LightNode и т.д. В этом мануале мы будем обращаться к объектам как к простым узлам. Корневой (root) узел дерева это узел называемый рендер (render). (Примечание: могут быть дополнительные корневые узлы для специального назначения, как например render2d для 2D объектов)
Дерево таких объектов в Panda3D называется граф сцены (scene graph).

Что надо знать об иерархии графа сцены.
Вот наиболее важные вещи, которые надо знать об иерархической структуре графа сцены:
1. Вы должны контролировать, где находится и где появится ваш объект. Когда вы вставляете объект в дерево, вы указываете куда его вставить. Вы можете перемещаться по дереву. Вы можете создать как очень "ветвистое" дерево там и очень простое.
2. Положение объектов указывается относительно их родительских узлов в дереве. Например, если у вас есть модель шляпы, вам может понадобиться указать что она всегда находится на пять юнитов над 3D моделью головы. Вставляйте шляпу как дочерний узел головы и устанавливайте положение шляпы в (0,0,5).
3. Когда модели выстроены в дерево, любые атрибуты рендеринга, которые вы присвоили узлу будут распостранятся на его дочерние элементы-узлы. Например, если вы укажите что указанный узел надо отображать в тумане, то его дочерние узлы также будут отображены в тумане пока вы отдельно вручную не измените это на дочернем узле.
4. Panda3D создает границы-боксы для каждого узла в дереве. Хорошо организованная иерархия может значительно увеличить скорость работы игры и избежать ошибок. Если границы узла дерева не пересекаются с другими, то нет нужды проверять это у его дочерних элементов.
Новички обычно создают свои деревья полностью плоскими - все вставляется прямо за узлом рендера. Это нормально для начального изучения. Когда-нибудь у вас появится причина чтобы добавить немного больше глубины вашей иерархии. Однако не стоит этим злоупотреблять, если для этого нет достаточных причин.

NodePaths

Есть класс-помощник NodePath - это очень маленький объект, содержащий указатель-ссылку на узел и некоторую административную информацию. Сейчас вы можете игнорировать эту информацию, она будет объяснена позже в мануале. Проектировщики задумывали NodePath как обработчик для узла. Любые функции, которые создают узел возвращают NodePath, который ссылается на новый узел.
NodePath не просто указатель-ссылка на узел; он "обрабатывает" узел. Концептуально различий нет. Однако есть определенные функции API, которые ожидают, что вы передадите им NodePath, а есть другие функции, которым надо представлять указатель на узел. В этом и есть небольшое отличие и вы должны его запомнить.
Вы можете преобразовать NodePath в обычный указатель в любое время с помощью nodePath.node(). Однако нет никакого однозначного способа для обратного преобразования. Это важно: иногда вам нужен будет NodePath, а не указатель. Когда вы передаете параметры, следует по-возможности использовать NodePath, а не обычные указатели. В вызываемой функции всегда можно преобразовать NodePath, если понадобится.

Методы NodePath и методы узлов (Node).
Есть множество методов, которые используют NodePath, которые можно применять к узлам любого типа. Специальные типы узлов, такие как LODNodes и камеры Cameras (например) представляют дополнительные методы, которые доступны только для узлов этого типа, которые можно использовать только с узлами этого типа. Вот несколько примеров:
# NODEPATH METHODS:
myNodePath.setPos(x,y,z)
myNodePath.setColor(banana)

# LODNODE METHODS:
myNodePath.node().addSwitch(1000, 100)
myNodePath.node().setCenter(Point3(0, 5, 0))

# CAMERA NODE METHODS:
myNodePath.node().setLens(PerspectiveLens())
myNodePath.node().getCameraMask()


Всегда помните: когда вы вызываете методы NodePath, вы на самом деле исполняете операцию над узлом, на который ссылается NodePath.
В примере выше мы вызываем метод узла сначала конвертируя NodePath в узел, а затем уже вызываем метод узла. Это рекомендуемый стиль.

Общая информация о Panda3D

Panda3D это 3D движок: библиотека подпрограмм для 3D рендеринга и разработки игр. Библиотека написана на С++ с набором Python расширений. Разработка игры с помощью Panda3D обычно состоит из написания Python или C++ кода программы, которая контролирует библиотека Panda3D.
Panda была создана для коммерческой разработки игр и ее основные пользователи это все еще коммерческие разработчики. Поэтому Panda должна быть мощной, быстрой, законченной и толерантной к ошибкам. Каждый знает что такое мощь и скорость. А вот законченность и «терпимость» ошибок нуждается в некотором пояснении.
Законченность означает то, что Panda3D содержит множество инструментов: обозреватель графа сцены, мониторинг производительности, оптимизатор анимации и так далее. Такие инструменты могут быть не приятны в разработке и как результат, open-source проекты часто не имеют их. Но когда вы хотите сделать серьезную работу, не просто поиграть, эти инструменты должны быть обязательно.
Толерантность к ошибкам нужна потому что все разработчики игр совершают ошибки в коде. Когда вы совершаете ошибку вы хотите чтобы движок дал вам простое сообщение и помог найти ошибку. Большинство игровых движков просто аварийно завершится если вы передадите неверное значение функции. Panda3D почти никогда не завершается аварийно и большинство кода позволяет отследить и изолировать ошибки.

Вернемся к мощности и скорости: лучший путь увидеть возможности Panda3D это взглянуть на примеры программ. Это небольшие программы которые демонстрируют примеры. На скриншотах в верхнем правом углу есть частота кадров, взятая с видеокарты Radeon X700.

Panda3D была разработана Disney для ее огромной многопользовательской онлайн-игры, Toontown. Библиотека стала бесплатной в 2002 году. Panda3D сейчас разрабатывается совместно Disney и университетом Карнеги Меллона — центром развлекательных технологий.

Вы можете прочитать больше о возможностях Panda3D по адресу http://panda3d.org/features.php

Panda3D это не инструмент для новичков или игрушка.
Для успешного использования Panda3D вы должны быть опытным программистом. Если вы не знаете, что такое API или не понимаете что такое «дерево» вы найдете Panda3D совершенно непонятной. Это не инструмент для простого создания игр типа кликай-и-указывай: это инструмент для профессионалов.
Некоторые люди посмотрели скриншоты игр для детей написанных на Panda3D и решили что графика Panda ограничена. Это не так. Разработчики игр для детей часто не используют шейдеры или другие продвинутые графические элементы, так как дети часто имеют старый далеко не мощный компьютер. А Panda поддерживает полный спектр возможностей современных движков: normal mapping, gloss mapping, HDR, cartoon shading и inking, bloom и другие возможности. Она также позволяет вам писать собственные шейдеры. Одна из таких возможностей в данное время это то, что динамические тени не обрабатываются автоматически: для использования динамических теней вам придется написать собственные шейдеры. Скоро это изменится.

Люди иногда ошибочно представляют что Panda3D написан на python, что сделает его очень медленным. Но Panda3D не написан на python — он написан на С++. Python нужен только для скриптов, часто разработчики пишут особо-производительные куски кода на С++.

пятница, 16 января 2009 г.

Стартовое сообщение

Этот блог о Panda3D. Почти нет информации о нем в сети по-русски. Я решил немного изменить эту ситуацию.
Первая задача - перевод мануала с сайта Panda3D.org
Как говорится - по дороге и научимся, а там видно будет.