Блоґ одного кібера

Історія хвороби контуженого інформаційним вибухом

Скриптуємо Блендер (частина 1)

leave a comment »

Це кусочок з моєї майбутньої класної книжки про програмування ігор – Давайте пограємо зі змією. І звичайно я планую вставити його в курсову. Жаль не встиг завершити сьогодні.

Внизу заодно скореговані плани на завтра. (Виявляється я як сова зранку не здатен до мислення, тому вирішив подумати зарані).

Привіт світ Блендер!

Скрипти можна писати як у вбудованому редакторі Блендера, так і в зовнішньому. Вбудований може бути незручним для вас, якщо ви звикли до певних комбінацій клавіш. Наприклад, щоб копіювати та вставити текст з буфера обміну, доведеться користуватись комбінаціями CTR+SHIFT-C та CTR+SHIFT+V відповідно.

Скрипти зберігаються в каталозі ~/.blender/scripts у лінуксі, та там де ви встановили блендер\.blender\scripts у windows. Тепер створимо там маленький скрипт. Якось його називаємо. Наприклад hello.py.

#!BPY

"""
Name: 'Hello'
Blender: 244
Group: 'Export'
Tooltip: 'Our test script'
"""
import Blender
import bpy

def write(filename):
    out = file(filename, "w")
    sce= bpy.data.scenes.active
    for ob in sce.objects:
        out.write(ob.type + ": " + ob.name + "\n")
    out.close()

Blender.Window.FileSelector(write, "Export")

Тепер повертаємось до вікна скриптів, і в його меню Scripts вибираємо пункт Update Menus. Після чого шукаємо hello в Scripts -> Export. Натискаємо. У вікні скриптів з’являється вікно вибору файлу. Вводимо якусь назву, і натиснувши Export отримаємо там текстовий файл з приблизно таким вмістом:

 Mesh: Cube
 Lamp: Lamp
 Camera: Camera

Якщо звісно ми нічого не додавали на нашу сцену.

Як воно працює?

Розглянемо наш скрипт рядок за рядком:

 #!BPY

Перший рядок каже блендеру, що це скрипт блендера, і що його треба додати в меню скануючи папки зі скриптами. Далі йде багаторядкова документація. Вона складається з чотирьох рядків

 Name: 'Hello'
 Blender: 244
 Group: 'Export'
 Tooltip: 'Our test script'

які допомагають блендеру правильно розмістити скрипт в меню. Name – так буде називатись пункт меню. Group – він буде поміщений в таке меню. Tooltip – підказка що буде з’являтись при затримці курсора над пунктом меню. Ну, а Blender – номер версії для якої написаний скрипт.

Далі завантажуються два модулі:

 import Blender
 import bpy

Перший модуль є основним для написання скриптів, другий загалом повторює його функціональність, та поки що є експериментальним. Він мав би надавати зручніший доступ до даних та функцій блендера, та поки що його вміст часто змінюють. Модуль Blender поки що задокументований краще.

Далі ми створюємо функцію, яка пише щось у файл:

 def write(filename):
    out = file(filename, "w")

Це просто. Далі цікавіше:

 sce= bpy.data.scenes.active
   for ob in sce.objects:
       out.write(ob.type + ": " + ob.name + "\n")

Дані три рядки беруть поточну сцену, і для всіх об’єктів сцени виводять у файл тип об’єкта, та через дві крапки його ім’я. Потім файл закривається і функція закінчується.

А остання функція:

 Blender.Window.FileSelector(write, "Export")

Відображає вікно вибору файла, з кнопкою “Export”. Після того як її натиснуть викликає функцію write передавши їй ім’я файлу.

Взагалі то, цей скрипт майже нічого не робить, зате демонструє нам загальний принцип роботи розширень Блендера.

Експорт мешу

Щоб розібратись з форматом трикутного мешу у Блендері, найкраще було б написати скрипт, яка виписує дані мешу у зовнішній файл. Наприклад можна написати програму, що генерує код OpenGL який малює наш об’єкт. Для цього треба замінити три основні рядки в попередньому скрипті.

Спочатку знайти вибраний об’єкт:

	sce = bpy.data.scenes.active
	ob = sce.objects.active

Потім отримати його меш:

	mesh = ob.getData(mesh=1)

Хоча ми могли і отримати не меш. Якщо наприклад вибраним об’єктом було джерело світла. А воно не має ніякої трикутної сітки. Тому, в коді що піде далі варто ловити виключення. Якось так:

	try:
		for face in mesh.faces:
			out.write("glBegin(GL_POLYGON);\n")
			for vert in face.v:
				c=mesh.verts[vert.index].co
				out.write("glVertex3f(%f,%f,%f);\n" % (c.x,c.y,c.z) )
			out.write("glEnd();\n\n")		
	except:
		print "Selected something without mesh. Nothing exported."

Тобто від пробує виконати код в секції try, а якщо не виходить, то жаліється в консоль. Варто зауважити, що при тестуванні скриптів до блендера, бажано щоб він був запущений з консолі, тоді в ній будуть з’являтись повідомлення про помилки. Він вам прямо так і скаже, але не скаже де ту консоль шукати, тому вам варто знати самим.

Тепер по коду. mesh.faces як вже можна було здогадатись – список граней нашої моделі. Кожна грань має список своїх вершин – атрибут v. Кожна вершина списку має атрибут .index, в якому зберігається індекс цієї вершини – її номер в загальному списку вершин. (Очевидно що одна вершина зазвичай входить в більш ніж одну грань, тому зберігати її координати по кілька раз – неефективно.

Ну, а mesh.verts – список вершин. Основні атрибути в вершини це co – координати, та no – нормаль. Що цікаво, нормалі також є і у кожної грані. Які з них впливають на затінення – визначається кнопками set smooth та set solid на панелі кнопок у вкладці Editing -> Link and materials. Але туди лізти поки що не варто.

Генерація свого мешу

Трикутник

Тепер давайте намалюємо свій меш. Що небудь попростіше. Найпростіше – трикутник, з нього і почнемо. Ось функція яка його створює:

def createtriangle():
	obj=NMesh.GetRaw()

	v1=NMesh.Vert(0,10,0)
	v2=NMesh.Vert(-1,0,0)
	v3=NMesh.Vert(1,0,0)

	obj.verts.append(v1)
	obj.verts.append(v2)
	obj.verts.append(v3)

	f=NMesh.Face()
	f.v.append(obj.verts[0])
	f.v.append(obj.verts[1])
	f.v.append(obj.verts[2])
	
	obj.faces.append(f)

	NMesh.PutRaw(obj,"Triangle",1)

А тепер по порядку. Спочатку ми створюємо базовий об’єкт, з чистим мешем:

obj=NMesh.GetRaw()

Якщо цій функції передати параметром ім’я якогось існуючого об’єкта, то меш того об’єкта буде взятий за основу. Тобто побудова почнеться не з нуля. Тільки варто переконатись що такий об’єкт існує. Далі створимо якісь три вершини. Будь-які, основне – аби їх було не менше трьох, бо інакше ми не отримаємо жодної грані.

v1=NMesh.Vert(0,10,0)
v2=NMesh.Vert(-1,0,0)
v3=NMesh.Vert(1,0,0)

Потім додамо ці вершини у об’єкт.

obj.verts.append(v1)
obj.verts.append(v2)
obj.verts.append(v3)

Коли вершини створено, можна створювати грані. Починають з порожньої грані.

f=NMesh.Face()

А потім в неї додають потрібні вершини. З об’єкта. (Щоб він міг розібратись з індексами). Десь ось так:

f.v.append(obj.verts[0])
f.v.append(obj.verts[1])
f.v.append(obj.verts[2])

Після того як грань буде готова додаємо її в об’єкт.

obj.faces.append(f)

А так як наш об’єкт – трикутник, то цього достатньо. Залишилось тільки зробити так, щоб він появився у вікні блендера.

NMesh.PutRaw(obj,"Triangle",1)

Першим параметром передається об’єкт, що буде вставлятись в сцену, другим – його ім’я. Якщо ім’я унікальне – створиться новий об’єкт. Якщо ні – то той об’єкт що носив це ім’я раніше заміниться на наш новий. Тому, будьте обережні. Третій параметр – прапор, що вказує блендеру, про необхідність обчислення нормалей. Нуль – ми задали нормалі. Інакше – обчислити їх.

Вуаля - ось і результат наших старань (кубик був там завжди)

Вуаля - ось і результат наших старань (кубик був там завжди)

План курсової на завтра

  1. Згенерувати таки карту висот (нумераціями кантора, і всіма прибамбасами).
  2. Навчитись писати графічний інтерфейс до таких скриптів
  3. Реалізувати алгоритм маршируючих квадратів.
  4. Опублікувати відповідні артефакти.

Віхи етапів самі собою зрозумілі. Загалом все йде майже за планом.

Ніхто до речі не підкине мені посилання на гарний зразок оформлення курсової? Цікаво глянути як же виглядає “науковий” стиль, бо в мене є підозра, що мій від згаданого дуже далекий.

Advertisements

Written by bunyk

Травень 4, 2010 at 23:41

Залишити відповідь

Заповніть поля нижче або авторизуйтесь клікнувши по іконці

Лого WordPress.com

Ви коментуєте, використовуючи свій обліковий запис WordPress.com. Log Out / Змінити )

Twitter picture

Ви коментуєте, використовуючи свій обліковий запис Twitter. Log Out / Змінити )

Facebook photo

Ви коментуєте, використовуючи свій обліковий запис Facebook. Log Out / Змінити )

Google+ photo

Ви коментуєте, використовуючи свій обліковий запис Google+. Log Out / Змінити )

З’єднання з %s

%d блогерам подобається це: