Книга: Написание скриптов для Blender 2.49

Пользовательский интерфейс

Пользовательский интерфейс

Наш скрипт будет использоваться не только как скриптсвязь, связанная с объектом, но он также будет использоваться автономно (по нажатию Alt + P в текстовом редакторе, например), чтобы обеспечить пользователя средствами для идентификации цели, которая создаст отпечаток, чтобы очищать кеш, и, чтобы ассоциировать скриптсвязь с активным объектом. При использовании таким образом, он обеспечивает конечного пользователя несколькими управляющими меню, показанными на скриншотах. Первый показывает возможные действия:


Второй скриншот показывает всплывающее меню с предложением выбрать объект из списка Меш-объектов, из которого пользователь может выбрать, чем создавать отпечаток:


Мы сначала определяем вспомогательную функцию, которая будет использована выпадающим меню, обеспечивающим пользователя выбором Меш-объектов, для использования в качестве цели при создании отпечатка. getmeshobjects() принимает аргумент scene и возвращает список имен всех Меш-объектов. Как показано на скриншоте, список объектов-целей включает в том числе исходный объект. Хотя это законно, но вряд ли очень полезно:

def getmeshobjects(scene):
   return [ob.name for ob in scene.objects if
           ob.type=='Mesh']

Само меню осуществляется функцией  targetmenu(), определенной следующим образом:

def targetmenu(ob):
   meshobjects=getmeshobjects(Blender.Scene.GetCurrent())
   menu='Select target%t|'+ "|".join(meshobjects)
   ret = Blender.Draw.PupMenu(menu)
   if ret>0:
      try:
         p = ob.getProperty(impresstarget)
         p.setData(meshobjects[ret-1])
      except:
         ob.addProperty(impresstarget,meshobjects[ret-1])

Она выбирает список из всех Меш-объектов в сцене и представляет этот список на выбор пользователю, используя функцию Блендера Draw.PupMenu(). Если пользователь выбирает один из пунктов меню (возвращённая величина будет больше нуля, смотри выделенную строку предыдущего кода), будет загружено имя этого Меш-объекта  как свойство, связанное с нашим объектом. Константа impresstarget определяется в другом месте в качестве имени для свойства. Сначала, программа независимо проверяет, есть ли там уже такое свойство, связанное с объектом, вызывая метод getProperty(), и присваивает данные свойству, если есть. Если метод getProperty() вызывает исключение, поскольку свойство еще не существует, тогда мы добавляем новое свойство к объекту и назначаем ему данные с помощью единственного вызова addProperty().

Основной интерфейс пользователя определяется на верхнем уровне скрипта. Он проверяет, что не был запущен как скриптсвязь, затем предоставляет пользователю несколько действий на выбор:

if not Blender.bylink:
   ret = Blender.Draw.PupMenu('Impress scriptlink%t|'+
                              'Add/Replace scriptlink|'+
                              'Clear cache|Remove ' + 
                              'all|New Target')
   active = Blender.Scene.GetCurrent().objects.active
   if ret > 0:
      clearcache(active)
   if ret== 1:
      active.clearScriptLinks([scriptname])
      active.addScriptLink(scriptname,'FrameChanged')
      targetmenu(active)
   elif ret== 2:
      pass
   elif ret== 3:
      active.removeProperty(meshcache)
      active.clearScriptLinks([scriptname])
   elif ret== 4:
      targetmenu(active)

Любой правильный выбор очистит кеш (выделено), и в последующих проверках выполняются необходимые действия, связанные каждым индивидуальным выбором:  Add/Replace scriptlink удалит скриптсвязь, если она уже присутствует, чтобы предотвратить появление дубликатов и, затем, добавит её к активному объекту. Затем будет представлено меню целей, чтобы выбрать Меш-объект для использования при создании отпечатка. Так как мы уже очистили кеш, то второй выбор, Clear cache, не делает ничего специфического, так что здесь у нас просто оператор pass (пропустить). Remove All попытается удалить кеш и отсоединить себя как скриптсвязь, и, наконец, меню New target представит меню выбора целей, чтобы дать возможность пользователю выбрать новый целевой объект, не удаляя никаких кешированных результатов.

Если скрипт выполняется как скриптсвязь, мы сначала проверяем, что мы действуем при событии FrameChanged, затем пытаемся извлечь любые сохраненные координаты вершин для текущего кадра (выделено в следующем коде). Если нет ранее загруженных данных, мы должны вычислить эффекты от целевого объекта для этого кадра. Следовательно, мы  получаем список целевых объектов для рассматриваемого объекта, вызывая вспомогательную функцию gettargetobjects() (на данный момент будет возвращен список только из одного объекта), и для каждого объекта мы вычисляем эффект для нашего меша с помощью вызова impress(). Затем, мы сохраняем эти, возможно изменённые, координаты вершин и корректируем дисплейный список, чтобы графический интерфейс пользователя Блендера знал, как отображать наш измененный меш:

elif Blender.event == 'FrameChanged':
   try:
      retrievemesh(Blender.link,Blender.Get('curframe'))
   except Exception as e: # мы ловим что-нибудь
      objects = gettargetobjects(Blender.link)
      for ob in objects:
         impress(Blender.link,ob)
      storemesh(Blender.link,Blender.Get('curframe'))
   Blender.link.makeDisplayList()

Теперь нам осталось фактическое вычисление отпечатка целевого объекта в нашем меше.

Оглавление книги


Генерация: 0.084. Запросов К БД/Cache: 2 / 0
поделиться
Вверх Вниз