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

Panda3D: Работа с текстом и изображениями

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

Описание начну с работы с текстом.  По умолчанию в установочном пакете Panda3D представлена библиотека "Freetype", которая позволяет установить любой шрифт для отображения в рендер-окне. Данный код позволяет выполнить данную задачу:

font = loader.loadFont('arial.ttf')

Как не трудно догадаться для параметра "font", которым в данном случае выступает отображаемый текст задается шрифт "arial" с помощью функции "loadfont" и класса "loader". Также произвольно можно задать и путь к файлу шрифта. (ВАЖНО: путь указывать при синтаксисе "C:/font").

Также возможно создать шрифт для Panda3D с помощью утилиты "egg-mkfont", поставляющейся с пакетом движка. После конвертации будет создан .egg файл, который будет является уже текстурным файлом, но  используемый в качестве шрифта. Для использования утилиты и конвертации шрифта в командной строке необходимо прописать:

egg-mkfont -o arial.egg arial.ttf

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

font = loader.loadFont('arial.egg')

Основные преимущества использования конвертированных шрифтов:

1. Конвертированный шрифт (.egg) может использоваться в версии Panda3D, которая не поддерживает 'freetype'

2. Можно применять некоторые базовые эффекты к сгенерированной текстуре используя 2d редактор (photoshop и др.)

Для отображения текста в рендер-окне мы будем использовать класс "OnscreenText". Самый простой код скрипта с использованием данного класса можно представить так:

from direct.gui.OnscreenText import OnscreenText

textObject = OnscreenText(text = 'my text string', pos = (-0.5, 0.02), scale = 0.07)

run()

Думаю здесь все понятно. Сначала создаем поддержку класса при импортировании, затем для объекта "textObject" задаем параметры отображения (отображаемый текст, позиция относительно координат x,y, размер шрифта). Кроме данных параметров существует еще ряд плезных значений, например:

"fg" - генерирует цвет текста. Цвет определяют 4 параметра задания цвета (красный, зеленый, голубой, номер комбинации).
"bg" - цвет заднего фона текста. Также задается 4мя параметрами.
"shadow" - создает тень за текстом с цветом, цвет которого задается 4мя параметрами. 
"frame" - создание рамки вокруг текста с заданным цветом и порядковым номером. 

Как пример для всего вышеприведенного используем наглядный код:

#importing part
import direct.directbase.DirectStart
from direct.gui.DirectGui import *



#text
text = OnscreenText(text = 'Demo Render', pos = (-1.15, 0.9), scale = 0.065, fg=(1,1,0,1), shadow=(1,1,0,1), frame=(4,4,4,1))



#Programm run
run()

Результат:

Работа с классом "OnscreenImage" аналогична. Единственное отличие что вместо текста отображается изображение. 

Единственное что хотел бы здесь добавить. Создание прозрачного изображения:

В сегмент импорта добавим строку:

from pandac.PandaModules import TransparencyAttrib


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

self.myImage=OnscreenImage(image = 'panda.png', pos = (0, 0, 0))
self.myImage.setTransparency(TransparencyAttrib.MAlpha)

Особых пояснений, думаю, делать не стоит :) Кроме одного: так как движок не поддерживает формат файлов ".gif" для прозрачных изображений следует использовать файлы ".png" и ".tga".

С уважением, Dredd

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

Python: Первые шаги

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

Фактически программировать в Python возможно в режимах : интерактивном (использование встроенного интерпритатора) и посредством IDE, то есть среды разработки (файлам, созданным в них присвоен термин "скрипт"). Для себя я выбрал IDE  под названием Notepad++. Если вы разделяете мой выбор, то его можно скачать здесь: http://sourceforge.net/project/downloading.php?group_id=95717&use_mirror=puzzle&filename=npp.5.1.3.Installer.exe&31868935

Существует множество других весьма удобных IDE: PyPE, PSPad, Geany, Crimson Editor и т.д.

Главный нюанс при работе с данными редакторами это указать с файлом какого типа вы работаете (установка синстаксиса). Кто не в курсе расширение и формат файлов питона: *.py, *.pyw.

Итак, вы выбрали редактор по душе, приступаем.

По мере продвижения по статье будет представлен код для создания скрипта и отдельны "строки" для работы в интерпритаторе.

 Для тех кто устанавливал пакет Python отдеально можно запустить через Пуск-Программы-Python, для пользователей из директории движка Panda3D (к которым отношусь и я,  по умолчанию C:\Panda3D\python\) .

Запустим интерпритатор (python.exe) и выбранную IDE. Интерпритатор встрчает на мигающим курсором и ">>>". 

Как и при изучении всех языков программирования мы начнем с оператора отображения текста :) - "print".

Введем выражение:

print "Hello there!"

и нажмем Enter. Интерпритатор отобразит введенную строку для отображения. В IDE необходимо все то навсего сохранить данный документ и запустить, используя python.exe- ничего сверхъестественного :)

ЕЩЕ РАЗ ОБРАЩАЮ ВНИМАНИЕ НА СОБЛЮДЕНИЕ РЕГИСТРА: print и Print НЕ ОДНО И ТО ЖЕ!!!

К начальной стадии обучения питону я бы отнес использование возможностей калькулятора. Введем выражение:

print 6 + 5

На выходе получим сумму чисел: 11. То есть здесь применимы все элементарные арифметические действия. Здесь есть только один ньюанс. Если вы зададите выражение:

print 5/2

То получите значение 2. Это все потому что Python воспринял исходную информацию целым числом (integer). Для уточнения результат нужно просто подставить значение с дробной частью, т.е. 2.0 или 3.0. И тогда ответ будет верным. Дробное число определяется как "float".  Операцию возведения в степень можно представить так:

print 2**3 - результат 8.

Теперь рассмотри оператор расчета остатка "modulus". Все очень просто:

print 6%5

Принцип таков: мы делим 6 на 5, получаем 6 целых и 1/6. Вот 1 как раз и отображает. Другими словами данный оператор показывает значение величины которая осталась после деления одного числа на друго. Поэксперементируйте с данными, сами поймете если еще не поняли :) . 

Мы можем задавать значения определенных величин. Например нам надо купить рыбу (fish), воду(water) и .... скажем мясо (meat) :). Но черт побери, в магазине принимают только доллары. Создаем скрипт:

# Prices 
fish=32
bread=3.
water=4.

# Money to pay in $s :)
price = (fish+bread+water)/5.
print "I need to pay for meal", price, "dollars"

Результатом расчетов будет фраза: "I need to pay for meal 7.8 dollars". Я придумал этот просто пример чтобы наглядно скомбинировать калькулятор и оператор отобажения. Я думаю, вы уже поняли что запятая при выводе результата попросту указывает оператору дальнейшее прочтение кода, а не конец выполнения операции при закрытии кавычек. 

При написании данного кода я столкнулся с интересным моментом. В то время как интерпритатор спокойно отображает символы кириллицы, некоторые IDE выдают ошибку при запуске програмы. На это тоже стоит обращать внимание.

Python: Описание, установка, возможности

Данная статья является исключительно ознакомительным материалом для понимания с ЧЕМ мы имеем дело в процессе разработки приложений.

Так как нам рано или поздно придется столкнутся с необходимостью программирования на Python`e, то пошаговое его изучения для человка, желающего изучить Panda3D, становится некой догмой :). Итак что же такое Python и что он из себя представляет?

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

Python портируем и работает почти на всех известных платформах — от КПК до мейнфреймов. Существуют порты под Microsoft Windows, все варианты UNIX (включая FreeBSD и GNU/Linux), Plan 9, Mac OS и Mac OS X, Palm OS, OS/2, Amiga, AS/400 и даже OS/390 и Symbian.

По мере устаревания платформы ее поддержка в основной ветви языка прекращается. Например, с серии 2.6 прекращена поддержка Windows 95, Windows 98 и Windows ME.[7] Однако на этих платформах можно использовать предыдущие версии Python — на данный момент сообщество активно поддерживает версии Python начиная от 2.3 (для них выходят исправления).

При этом, в отличие от многих портируемых систем, для всех основных платформ Python имеет поддержку характерных для данной платформы технологий (например, Microsoft COM/DCOM). Более того, существует специальная версия Питона для виртуальной машины Java — Jython, что позволяет интерпретатору выполняться на любой системе, поддерживающей Java, при этом классы Java могут непосредственно использоваться из Питона и даже быть написанными на Питоне. Также несколько проектов обеспечивают интеграцию с платформой Microsoft .NET, основные из которых — IronPython и Python.Net.

К основным возможностям языка относят:

 - Классы являются одновременно объектами со всеми ниже приведёнными возможностями
 - Наследование, в том числе множественное.
 - Полиморфизм (все функции виртуальные).
 - Инкапсуляция (два уровня — общедоступные и скрытые методы и поля).
 - Специальные методы, управляющие жизненным циклом объекта: конструкторы, деструкторы, распределители памяти.
 - Перегрузка операторов (всех, кроме is, '.', '=' и символьных логических).
 - Свойства (имитация поля с помощью функций).
 - Управление доступа к полям (эмуляция полей и методов, частичный доступ, и т. п.).
 - Методы для управления наиболее распространёнными операциями (истинностное значение, len(), глубокое копирование, сериализация, итерация по объекту, …)
 - Метапрограммирование (управление созданием классов, триггеры на создание классов, и др.)
 - Классовые и статические методы, классовые поля.
 - Классы, вложенные в функции и классы.

Программное обеспечение (приложение или библиотека) на Питоне оформляется в виде модулей, которые в свою очередь могут быть собраны в пакеты. Модули могут располагаться как в папках так и в ZIP архивах. Модули могут быть двух типов по своему происхождению: модули, написанные на «чистом» Питоне, и модули расширения (extension modules), написанные на других языках программирования. Например, в стандартной библиотеке есть «чистый» модуль pickle и его аналог на Си: cPickle. Модуль оформляется в виде отдельного файла, а пакет — в виде отдельного каталога. Подключение модуля к программе осуществляется оператором import. После импорта модуль представлен отдельным объектом, дающим доступ к пространству имён модуля. В ходе выполнения программы модуль можно перезагрузить функцией reload().

Теперь, думаю, каждому будет понятно что из себя представляет инструмент для реализации наших идей и соображений.

Теперь что касается установки. Здесь есть несколько вариантов использования Python`a. В пакете движка Panda3D уже поставляется дистрибутив, но также можно скачать Python отдельным пакетом: Скачать Python 2.5.4

Почему именно 2.5.4, ведь уже есть новые версии? Так как последняя сборка движка базируется на Python 2.5 и чтобы не "ломать" совместимость версий, рекомендуется использовать версию 2.5. 

С уважением, Dredd

Пример 1.4: Динамическая непрерывная анимация, использование интервалов

В этом примере мы рассмотрим перемещение панды по отображаемой сцене с помощью интервалов. Интервалы это задача по изменению значения параметра за определенный промежуток времени. При старте интервала запускается "закулисный :)" процесс, который преобразует значение параметра за опр. временной промежуток. Теперь разберем нововведения в коде программы.

Добавим в сегмент импорта библиотек и классов следующие строки:

from pandac.PandaModules import *

from direct.interval.IntervalGlobal import *

Здесь мы импортируем все доступные классы и методы из вышеприведенных модулей для применения интервалов.

Код импорта:

#importing part
import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.actor import Actor
from direct.task import Task
from direct.interval.IntervalGlobal import *
import math

Теперь добавим непосредственные изменения в код. Для этого после строки "panda.loop("walk")" добавляем:

#Create the four lerp intervals needed to walk back and forth
pandaPosInterval1= panda.posInterval(13,Point3(0,-10,0), startPos=Point3(0,10,0))
pandaPosInterval2= panda.posInterval(13,Point3(0,10,0), startPos=Point3(0,-10,0))
pandaHprInterval1= panda.hprInterval(3,Point3(180,0,0), startHpr=Point3(0,0,0))
pandaHprInterval2= panda.hprInterval(3,Point3(0,0,0), startHpr=Point3(180,0,0))

#Create and play the sequence that coordinates the intervals
pandaPace = Sequence(pandaPosInterval1, pandaHprInterval1,
  pandaPosInterval2, pandaHprInterval2, name = "pandaPace")
pandaPace.loop()

В первом фрагмене кода с помощью параметров "pandaPosInterval" мы определяем точки старта и конца отрезка для движения панды, а также точки поворота и ее возврата в исходное положение. Теперь немного конкретизирую. 

В первой строка показана скорость движения панды по оси Y( начальное значение (0,10,0) и конечное (0,-10,0)) - 13 сек. Вторая же строка проводить обратную по логике операцию, то бишь возвращает панду "домой" :).

Третья и четвертая строка определяют с помоцью функции panda.hprInterval() вращение модели на определенный угол (в данном случаем полный поворот - 180 градусов, вокруг оси Х с интервалом в 3 сек).

Второй сегмент нового кода задает "последовательность" поведения операций. По логике тут все наглядно что за чем будет следовать :). Но все таки распишу : pandaPosInterval1, pandaHprInterval1, pandaPosInterval2, pandaHprInterval2 имя данной последовательности припишем "pandaPace". Внимательно прочитав предидущие примеры не трудно понять что последняя строка кода отвечает за непрерывное выполнение данной последовательности.

Исходный код всей программы:

#importing part
import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.actor import Actor
from direct.task import Task
from direct.interval.IntervalGlobal import *
import math


#Load the first environment model
envirom = loader.loadModel("models/environment")
envirom.reparentTo(render)
envirom.setScale(0.25,0.25,0.25)
envirom.setPos(-8,42,0)

#Task to move the camera
def SpinCameraTask(task):
  angledegrees = task.time * 6.0
  angleradians = angledegrees * (math.pi / 180.0)
  base.camera.setPos(20*math.sin(angleradians),-20.0*math.cos(angleradians),3)
  base.camera.setHpr(angledegrees, 0, 0)
  return Task.cont

taskMgr.add(SpinCameraTask, "SpinCameraTask")

#Import Panda and its animation
panda = Actor.Actor("models/panda-model",{"walk":"models/panda-walk4"})
panda.setScale(0.005,0.005,0.005)
panda.reparentTo(render)
panda.loop("walk")

#Create the four lerp intervals needed to walk back and forth
pandaPosInterval1= panda.posInterval(13,Point3(0,-10,0), startPos=Point3(0,10,0))
pandaPosInterval2= panda.posInterval(13,Point3(0,10,0), startPos=Point3(0,-10,0))
pandaHprInterval1= panda.hprInterval(3,Point3(180,0,0), startHpr=Point3(0,0,0))
pandaHprInterval2= panda.hprInterval(3,Point3(0,0,0), startHpr=Point3(180,0,0))

#Create and play the sequence that coordinates the intervals
pandaPace = Sequence(pandaPosInterval1, pandaHprInterval1,
  pandaPosInterval2, pandaHprInterval2, name = "pandaPace")
pandaPace.loop()


#Run the tutorial
run()

На этом заканчивает первый, приведенный мной, пример по основам работы в Panda3D. Какового его практическое применение (а оно всегда должно быть)? Конечно же это "презентация" чего - либо в трехмерном пространстве. Как вы видите, не так уж и сложно творить, главное только научиться применять для этого инструменты. В дальнейших примерах я постараюсь вместе с вами постигать постепенно Python и Panda3D в их отдельных элементах разработки. 

С уважением, Dredd.

Пример 1.3: Загрузка модели и ее непрерывная анимация

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

Для начала в строку импортирования библиотек добавим строку:

from direct.actor import Actor

Тем самым мы добавили класс "Actor", который отвечает за создание на сцене персонажа, манипулирование им, а также его анимацию. Результирующий код импорта:

#importing part
import direct.directbase.DirectStart
from direct.actor import Actor
from direct.task import Task
import math


После строки: "taskMgr.add(SpinCameraTask, "SpinCameraTask")" добавляем код:

#Import Panda and its animation
panda = Actor.Actor("models/panda-model",{"walk":"models/panda-walk4"})
panda.setScale(0.005,0.005,0.005)
panda.reparentTo(render)
panda.loop("walk")

Первая строка как и полагается - комментарии к даннобу блоку кода.

Следующие строки отвечают за приминение класса "Actor" для рендера на сцене модели панды Actor.Actor("models/panda-model". Код {"walk":"models/panda-walk4"} отвечает за использование анимации для модели. 

Если помните, в первом примере для создания сцены мы использовали команду loader.loadModel. Разница состоит в том, что класс "Actor" применяется для динамических объектов, а класс "Loader" - статических.

Строка panda.setScale(0.005,0.005,0.005) задает параметры отображения модели. К примеру, изменив значения параметра по оси х до 0.015 мы получим "черепахоподобную" панду :).

Значение 3й строки вы уже должна знать (см. пример 1.1), а четвертая попросту отвечает за непрерывное выполнение анимации модели.

В конечном итога в окне рендера должно быть что то похожее на этот скриншот :


Исходный код всей программы:

#importing part
import direct.directbase.DirectStart
from direct.actor import Actor
from direct.task import Task
import math


#Load the first environment model
envirom = loader.loadModel("models/environment")
envirom.reparentTo(render)
envirom.setScale(0.25,0.25,0.25)
envirom.setPos(-8,42,0)

#Task to move the camera
def SpinCameraTask(task):
  angledegrees = task.time * 6.0
  angleradians = angledegrees * (math.pi / 180.0)
  base.camera.setPos(20*math.sin(angleradians),-20.0*math.cos(angleradians),3)
  base.camera.setHpr(angledegrees, 0, 0)
  return Task.cont

taskMgr.add(SpinCameraTask, "SpinCameraTask")

#Import Panda and its animation
panda = Actor.Actor("models/panda-model",{"walk":"models/panda-walk4"})
panda.setScale(0.005,0.005,0.005)
panda.reparentTo(render)
panda.loop("walk")


#Run the tutorial
run()