﻿<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja">
	<id>https://wiki.blender.jp/index.php?action=history&amp;feed=atom&amp;title=Dev%3APy%2FScripts%2FCookbook%2FCode_snippets%2FBlender_add-ons</id>
	<title>Dev:Py/Scripts/Cookbook/Code snippets/Blender add-ons - 版の履歴</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.blender.jp/index.php?action=history&amp;feed=atom&amp;title=Dev%3APy%2FScripts%2FCookbook%2FCode_snippets%2FBlender_add-ons"/>
	<link rel="alternate" type="text/html" href="https://wiki.blender.jp/index.php?title=Dev:Py/Scripts/Cookbook/Code_snippets/Blender_add-ons&amp;action=history"/>
	<updated>2026-07-30T05:54:21Z</updated>
	<subtitle>このウィキのこのページに関する変更履歴</subtitle>
	<generator>MediaWiki 1.31.0</generator>
	<entry>
		<id>https://wiki.blender.jp/index.php?title=Dev:Py/Scripts/Cookbook/Code_snippets/Blender_add-ons&amp;diff=104795&amp;oldid=prev</id>
		<title>Yamyam: 1版 をインポートしました</title>
		<link rel="alternate" type="text/html" href="https://wiki.blender.jp/index.php?title=Dev:Py/Scripts/Cookbook/Code_snippets/Blender_add-ons&amp;diff=104795&amp;oldid=prev"/>
		<updated>2018-06-28T19:43:25Z</updated>

		<summary type="html">&lt;p&gt;1版 をインポートしました&lt;/p&gt;
&lt;table class=&quot;diff diff-contentalign-left&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;ja&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #222; text-align: center;&quot;&gt;← 古い版&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #222; text-align: center;&quot;&gt;2018年6月28日 (木) 19:43時点における版&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;ja&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(相違点なし)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Yamyam</name></author>
		
	</entry>
	<entry>
		<id>https://wiki.blender.jp/index.php?title=Dev:Py/Scripts/Cookbook/Code_snippets/Blender_add-ons&amp;diff=104794&amp;oldid=prev</id>
		<title>wiki&gt;Brecht: moved Dev:2.5/Py/Scripts/Cookbook/Code snippets/Blender add-ons to Dev:Py/Scripts/Cookbook/Code snippets/Blender add-ons: remove version namespace</title>
		<link rel="alternate" type="text/html" href="https://wiki.blender.jp/index.php?title=Dev:Py/Scripts/Cookbook/Code_snippets/Blender_add-ons&amp;diff=104794&amp;oldid=prev"/>
		<updated>2015-12-27T19:24:32Z</updated>

		<summary type="html">&lt;p&gt;moved &lt;a href=&quot;/Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Blender_add-ons&quot; class=&quot;mw-redirect&quot; title=&quot;Dev:2.5/Py/Scripts/Cookbook/Code snippets/Blender add-ons&quot;&gt;Dev:2.5/Py/Scripts/Cookbook/Code snippets/Blender add-ons&lt;/a&gt; to &lt;a href=&quot;/Dev:Py/Scripts/Cookbook/Code_snippets/Blender_add-ons&quot; title=&quot;Dev:Py/Scripts/Cookbook/Code snippets/Blender add-ons&quot;&gt;Dev:Py/Scripts/Cookbook/Code snippets/Blender add-ons&lt;/a&gt;: remove version namespace&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新規ページ&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{Page/Header|2.5x|Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Interface|Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Multi-File_packages}}&lt;br /&gt;
&lt;br /&gt;
=Blender add-ons=&lt;br /&gt;
Until now we have only considered stand-alone scripts, which are executed from the {{Format/Literal|Text Editor}} window. For an end user it is more convenient if the script is a Blender add-on, which can be enabled from the {{Format/Literal|User Preferences}} window. It is also possible to auto-load a script every time Blender starts.&lt;br /&gt;
&lt;br /&gt;
In order for a script to be an add-on, it must be written in a special way. There must be a &amp;lt;code&amp;gt;bl_info&amp;lt;/code&amp;gt; structure in the beginning of the file, and &amp;lt;code&amp;gt;register&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;unregister&amp;lt;/code&amp;gt; functions must be defined at the end. Moreover, the script must be placed at a location where Blender looks for add-ons on upstart. This includes the &amp;lt;code&amp;gt;addons&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;addons-contrib&amp;lt;/code&amp;gt; folders, which are located under the &amp;lt;code&amp;gt;2.57/scripts&amp;lt;/code&amp;gt; subdirectory of the directory where Blender is located.&lt;br /&gt;
&lt;br /&gt;
==Shapekey pinning==&lt;br /&gt;
This script can be executed from the {{Format/Literal|Text Editor}} window as usual. However, it can also be accessed as a Blender add-on. The add-on info is specified in the &amp;lt;code&amp;gt;bl_info&amp;lt;/code&amp;gt; dictonary in the beginning of the file.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
bl_info = {&lt;br /&gt;
    'name': 'Shapekey pinning',&lt;br /&gt;
    'author': 'Thomas Larsson',&lt;br /&gt;
    'version': (0, 1, 2),&lt;br /&gt;
    'blender': (2, 57, 0),&lt;br /&gt;
    'location': 'View3D &amp;gt; UI panel &amp;gt; Shapekey pinning',&lt;br /&gt;
    'description': 'Pin and key the shapekeys of a mesh',&lt;br /&gt;
    'warning': '',&lt;br /&gt;
    'wiki_url': 'http://blenderartists.org/forum/showthread.php?193908',&lt;br /&gt;
    'tracker_url': '',&lt;br /&gt;
    'support': 'COMMUNITY',&lt;br /&gt;
    'category': '3D View'}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The meaning of most slots in this dictionary is self-evident.&lt;br /&gt;
* &amp;lt;code&amp;gt;name&amp;lt;/code&amp;gt;: The name of the add-on.&lt;br /&gt;
* &amp;lt;code&amp;gt;author&amp;lt;/code&amp;gt;: The author's name.&lt;br /&gt;
* &amp;lt;code&amp;gt;version&amp;lt;/code&amp;gt;: The script version.&lt;br /&gt;
* &amp;lt;code&amp;gt;blender&amp;lt;/code&amp;gt;: Blender version.&lt;br /&gt;
* &amp;lt;code&amp;gt;location&amp;lt;/code&amp;gt;: Where to find the buttons.&lt;br /&gt;
* &amp;lt;code&amp;gt;description&amp;lt;/code&amp;gt;: A description displayed as a tooltip and in documentation.&lt;br /&gt;
* &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt;: A warning message. If not empty, a little warning sign will show up in the user preference window.&lt;br /&gt;
* &amp;lt;code&amp;gt; wiki_url&amp;lt;/code&amp;gt;: Link to the script's wiki page. Should really be on the Blender site, but here we are linking to a thread at blenderartists.org.&lt;br /&gt;
* &amp;lt;code&amp;gt;tracker_url&amp;lt;/code&amp;gt;: Link to the scripts bug  tracker.&lt;br /&gt;
* &amp;lt;code&amp;gt;support&amp;lt;/code&amp;gt;: Official or community&lt;br /&gt;
* &amp;lt;code&amp;gt;category&amp;lt;/code&amp;gt;: Script category, e.g. {{Format/Literal|3D View}}, {{Format/Literal|Import-Export}}, {{Format/Literal|Add Mesh}}, or{{Format/Literal|Rigging}}. Correspond to categories in the {{Format/Literal|User Preferences}}  window.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Notes:&amp;lt;/b&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;blender&amp;lt;/code&amp;gt;: The version number tuple is comprised of 3 integers, &amp;lt;code&amp;gt;(major, minor, sub)&amp;lt;/code&amp;gt;, for instance &amp;lt;code&amp;gt;(2, 70, 0)&amp;lt;/code&amp;gt; for v2.70 (sub 0), not &amp;lt;strike&amp;gt;&amp;lt;code&amp;gt;(2, 7, 0)&amp;lt;/code&amp;gt;&amp;lt;/strike&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;api&amp;lt;/code&amp;gt;: Deprecated attribute, do not use (Blender never tested it against revision number).&lt;br /&gt;
&lt;br /&gt;
Many of the items can simply be omitted, as we will see in other examples below.&lt;br /&gt;
&lt;br /&gt;
The second requirement on an add-on is that it defines &amp;lt;code&amp;gt;register()&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;unregister()&amp;lt;/code&amp;gt; functions, which usually are placed at the end of the file. &amp;lt;code&amp;gt;register()&amp;lt;/code&amp;gt; normally makes a call to &amp;lt;code&amp;gt;bpy.utils.register_module(__name__)&amp;lt;/code&amp;gt;, which registers all classes defined in the file. It can also contain some custom initialization tasks. The present script also declares a custom RNA property. As we saw in subsection [[Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Properties#RNA_properties_versus_ID_properties|RNA properties versus ID properties]], declaration is necessary here because the bool property would appear as an integer otherwise.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
def register():&lt;br /&gt;
    initialize()&lt;br /&gt;
    bpy.utils.register_module(__name__)&lt;br /&gt;
&lt;br /&gt;
def unregister():&lt;br /&gt;
    bpy.utils.unregister_module(__name__)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    register()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Unregistration is analogous to registration. The last lines makes it possible to run the script in stand-alone mode from the {{Format/Literal|Text Editor}} window. Even if the end user will never run the script from the editor, it is useful to have this possibility when debugging.&lt;br /&gt;
&lt;br /&gt;
Copy the file to a location where Blender looks for add-ons. Restart Blender. Open the {{Format/Literal|User Preferences}} window from the {{Menu|File|User Preferences}} menu, and navigate to the Add-ons tab. Our script can be found at the bottom of the 3D View section.&lt;br /&gt;
&lt;br /&gt;
[[File:Code_Snippets_UserPref.png|640px]]&lt;br /&gt;
&lt;br /&gt;
We recognize the fields in the &amp;lt;code&amp;gt;bl_info&amp;lt;/code&amp;gt; dictionary. Enable the script by pressing the checkbox in the upper-right corner. If you want the add-on to load every time you start Blender, press the {{Button|Save As Default}} button at the bottom of the window.&lt;br /&gt;
&lt;br /&gt;
After the add-on has been enabled, it appears in the UI panel.&lt;br /&gt;
&lt;br /&gt;
[[File:Code_Snippets_Addon-enabled.png|640px]]&lt;br /&gt;
&lt;br /&gt;
The script itself displays the shapekeys of the active object in the UI panel. The default cube does not have any shapekeys. Instead we import a MakeHuman character which has a lot of facial expressions that are implemented as shapekeys. [http://www.makehuman.org MakeHuman] is a application which easily allows you to design a character. A fully rigged and textured character can then be exported to Blender using the MHX (MakeHuman eXchange) format. MHX files can be imported into Blender with the MHX importer, which is an add-on which is distributed with Blender.&lt;br /&gt;
&lt;br /&gt;
What matters for the present example is that the MakeHuman mesh has a lot of shapekeys. If you press the Pin button right to the shapekey value, the shapekey is pinned, i.e. its value is set to one whereas the values of all other shapekeys are zero. If Autokey button in the timeline is set, a key is set for the shapekey value. If furthermore the Key all option in selected, keys are set for every shapekey in the mesh.&lt;br /&gt;
&lt;br /&gt;
[[File:Code_Snippets_Shapepin.png|640px]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#----------------------------------------------------------&lt;br /&gt;
# File shapekey_pin.py&lt;br /&gt;
#----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
bl_info = {&lt;br /&gt;
    'name': 'Shapekey pinning',&lt;br /&gt;
    'author': 'Thomas Larsson',&lt;br /&gt;
    'version': (0, 1, 2),&lt;br /&gt;
    'blender': (2, 57, 0),&lt;br /&gt;
    'location': 'View3D &amp;gt; UI panel &amp;gt; Shapekey pinning',&lt;br /&gt;
    'description': 'Pin and key the shapekeys of a mesh',&lt;br /&gt;
    'warning': '',&lt;br /&gt;
    'wiki_url': 'http://blenderartists.org/forum/showthread.php?193908',&lt;br /&gt;
    'tracker_url': '',&lt;br /&gt;
    'support': 'COMMUNITY',&lt;br /&gt;
    'category': '3D View'}&lt;br /&gt;
&lt;br /&gt;
import bpy&lt;br /&gt;
from bpy.props import *&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    class VIEW3D_OT_ResetExpressionsButton(bpy.types.Operator):&lt;br /&gt;
#&lt;br /&gt;
class VIEW3D_OT_ResetExpressionsButton(bpy.types.Operator):&lt;br /&gt;
    bl_idname = &amp;quot;shapepin.reset_expressions&amp;quot;&lt;br /&gt;
    bl_label = &amp;quot;Reset expressions&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    def execute(self, context):&lt;br /&gt;
        keys = context.object.data.shape_keys&lt;br /&gt;
        if keys:&lt;br /&gt;
            for shape in keys.keys:&lt;br /&gt;
                shape.value = 0.0&lt;br /&gt;
        return{'FINISHED'}    &lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    class VIEW3D_OT_PinExpressionButton(bpy.types.Operator):&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class VIEW3D_OT_PinExpressionButton(bpy.types.Operator):&lt;br /&gt;
    bl_idname = &amp;quot;shapepin.pin_expression&amp;quot;&lt;br /&gt;
    bl_label = &amp;quot;Pin&amp;quot;&lt;br /&gt;
    expression = bpy.props.StringProperty()&lt;br /&gt;
&lt;br /&gt;
    def execute(self, context):&lt;br /&gt;
        skeys = context.object.data.shape_keys&lt;br /&gt;
        if skeys:&lt;br /&gt;
            frame = context.scene.frame_current&lt;br /&gt;
            for block in skeys.key_blocks:            &lt;br /&gt;
                oldvalue = block.value&lt;br /&gt;
                block.value = 1.0 if block.name == self.expression else 0.0&lt;br /&gt;
                if (context.tool_settings.use_keyframe_insert_auto and &lt;br /&gt;
                    (context.scene.key_all or &lt;br /&gt;
                    (block.value &amp;gt; 0.01) or &lt;br /&gt;
                    (abs(block.value-oldvalue) &amp;gt; 0.01))):&lt;br /&gt;
                    block.keyframe_insert(&amp;quot;value&amp;quot;, index=-1, frame=frame)&lt;br /&gt;
        return{'FINISHED'}    &lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    class ExpressionsPanel(bpy.types.Panel):&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class ExpressionsPanel(bpy.types.Panel):&lt;br /&gt;
    bl_label = &amp;quot;Pin shapekeys&amp;quot;&lt;br /&gt;
    bl_space_type = &amp;quot;VIEW_3D&amp;quot;&lt;br /&gt;
    bl_region_type = &amp;quot;UI&amp;quot;&lt;br /&gt;
    &lt;br /&gt;
    @classmethod&lt;br /&gt;
    def poll(cls, context):&lt;br /&gt;
        return context.object and (context.object.type == 'MESH')&lt;br /&gt;
&lt;br /&gt;
    def draw(self, context):&lt;br /&gt;
        layout = self.layout&lt;br /&gt;
        layout.operator(&amp;quot;shapepin.reset_expressions&amp;quot;)&lt;br /&gt;
        layout.prop(context.scene, &amp;quot;key_all&amp;quot;)&lt;br /&gt;
        skeys = context.object.data.shape_keys&lt;br /&gt;
        if skeys:&lt;br /&gt;
            for block in skeys.key_blocks:            &lt;br /&gt;
                row = layout.split(0.75)&lt;br /&gt;
                row.prop(block, 'value', text=block.name)&lt;br /&gt;
                row.operator(&amp;quot;shapepin.pin_expression&amp;quot;, &lt;br /&gt;
                    text=&amp;quot;Pin&amp;quot;).expression = block.name&lt;br /&gt;
        return&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    initialize and register&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def initialize():&lt;br /&gt;
    bpy.types.Scene.key_all = BoolProperty(&lt;br /&gt;
        name=&amp;quot;Key all&amp;quot;,&lt;br /&gt;
        description=&amp;quot;Set keys for all shapes&amp;quot;,&lt;br /&gt;
        default=False)&lt;br /&gt;
&lt;br /&gt;
def register():&lt;br /&gt;
    initialize()&lt;br /&gt;
    bpy.utils.register_module(__name__)&lt;br /&gt;
&lt;br /&gt;
def unregister():&lt;br /&gt;
    bpy.utils.unregister_module(__name__)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    register()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Simple BVH import==&lt;br /&gt;
The BVH format is commonly used to transfer character animation, e.g. from mocap data. This program is a simple BVH importer, which builds a skeleton with the action described &lt;br /&gt;
by the BVH file. It is implemented as a Blender add-on, which a &amp;lt;code&amp;gt;bl_info&amp;lt;/code&amp;gt; dictionary at the top of the file and registration code at the bottom.&lt;br /&gt;
&lt;br /&gt;
Once the script below has been executed, or enabled as an add-on, the simple BVH importer can be invoked from user interface panel ({{Shortcut|Ctrl|N}}). There are two options: a boolean choice to rotate the mesh 90 degrees (to make Z up), and a scale.&lt;br /&gt;
&lt;br /&gt;
This program also illustrates how to invoke a file selector by pushing a button in a panel. The Load BVH button class inherits both from the &amp;lt;code&amp;gt;bpy.types.Operator&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ImportHelper&amp;lt;/code&amp;gt; base classes.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class OBJECT_OT_LoadBvhButton(bpy.types.Operator, ImportHelper):&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
The (possibly undocumented) &amp;lt;code&amp;gt;ImportHelper&amp;lt;/code&amp;gt; class defines some attributes which are used to filter the files visible in the file selector.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
filename_ext = &amp;quot;.bvh&amp;quot;&lt;br /&gt;
filter_glob = bpy.props.StringProperty(default=&amp;quot;*.bvh&amp;quot;, options={'HIDDEN'})&lt;br /&gt;
filepath = bpy.props.StringProperty(name=&amp;quot;File Path&amp;quot;,&lt;br /&gt;
    maxlen=1024, default=&amp;quot;&amp;quot;)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
There is an analogous &amp;lt;code&amp;gt;ExportHelper&amp;lt;/code&amp;gt; class which limits the available choices in an export file selector.&lt;br /&gt;
&lt;br /&gt;
[[File:Code_Snippets_Bvh-load.png|640px]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#----------------------------------------------------------&lt;br /&gt;
# File simple_bvh_import.py&lt;br /&gt;
# Simple bvh importer&lt;br /&gt;
#----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
bl_info = {&lt;br /&gt;
    'name': 'Simple BVH importer (.bvh)',&lt;br /&gt;
    'author': 'Thomas Larsson',&lt;br /&gt;
    'version': (1, 0, 0),&lt;br /&gt;
    'blender': (2, 57, 0),&lt;br /&gt;
    'location': 'File &amp;gt; Import',&lt;br /&gt;
    'description': 'Simple import of Biovision bvh',&lt;br /&gt;
    'category': 'Import-Export'}&lt;br /&gt;
&lt;br /&gt;
import bpy, os, math, mathutils, time&lt;br /&gt;
from mathutils import Vector, Matrix&lt;br /&gt;
from bpy_extras.io_utils import ImportHelper&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    class CNode:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class CNode:&lt;br /&gt;
    def __init__(self, words, parent):&lt;br /&gt;
        name = words[1]&lt;br /&gt;
        for word in words[2:]:&lt;br /&gt;
            name += ' '+word&lt;br /&gt;
        &lt;br /&gt;
        self.name = name&lt;br /&gt;
        self.parent = parent&lt;br /&gt;
        self.children = []&lt;br /&gt;
        self.head = Vector((0,0,0))&lt;br /&gt;
        self.offset = Vector((0,0,0))&lt;br /&gt;
        if parent:&lt;br /&gt;
            parent.children.append(self)&lt;br /&gt;
        self.channels = []&lt;br /&gt;
        self.matrix = None&lt;br /&gt;
        self.inverse = None&lt;br /&gt;
        return&lt;br /&gt;
&lt;br /&gt;
    def __repr__(self):&lt;br /&gt;
        return &amp;quot;CNode %s&amp;quot; % (self.name)&lt;br /&gt;
&lt;br /&gt;
    def display(self, pad):&lt;br /&gt;
        vec = self.offset&lt;br /&gt;
        if vec.length &amp;lt; Epsilon:&lt;br /&gt;
            c = '*'&lt;br /&gt;
        else:&lt;br /&gt;
            c = ' '&lt;br /&gt;
        print(&amp;quot;%s%s%10s (%8.3f %8.3f %8.3f)&amp;quot; % &lt;br /&gt;
            (c, pad, self.name, vec[0], vec[1], vec[2]))&lt;br /&gt;
        for child in self.children:&lt;br /&gt;
            child.display(pad+&amp;quot;  &amp;quot;)&lt;br /&gt;
        return&lt;br /&gt;
&lt;br /&gt;
    def build(self, amt, orig, parent):&lt;br /&gt;
        self.head = orig + self.offset&lt;br /&gt;
        if not self.children:&lt;br /&gt;
            return self.head&lt;br /&gt;
        &lt;br /&gt;
        zero = (self.offset.length &amp;lt; Epsilon)&lt;br /&gt;
        eb = amt.edit_bones.new(self.name)        &lt;br /&gt;
        if parent:&lt;br /&gt;
            eb.parent = parent&lt;br /&gt;
        eb.head = self.head&lt;br /&gt;
        tails = Vector((0,0,0))&lt;br /&gt;
        for child in self.children:&lt;br /&gt;
            tails += child.build(amt, self.head, eb)&lt;br /&gt;
        n = len(self.children)&lt;br /&gt;
        eb.tail = tails/n&lt;br /&gt;
        (trans,quat,scale) = eb.matrix.decompose()&lt;br /&gt;
        self.matrix = quat.to_matrix()&lt;br /&gt;
        self.inverse = self.matrix.copy()&lt;br /&gt;
        self.inverse.invert()&lt;br /&gt;
        if zero:&lt;br /&gt;
            return eb.tail&lt;br /&gt;
        else:        &lt;br /&gt;
            return eb.head&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    readBvhFile(context, filepath, rot90, scale):&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
Location = 1&lt;br /&gt;
Rotation = 2&lt;br /&gt;
Hierarchy = 1&lt;br /&gt;
Motion = 2&lt;br /&gt;
Frames = 3&lt;br /&gt;
&lt;br /&gt;
Deg2Rad = math.pi/180&lt;br /&gt;
Epsilon = 1e-5&lt;br /&gt;
&lt;br /&gt;
def readBvhFile(context, filepath, rot90, scale):&lt;br /&gt;
    fileName = os.path.realpath(os.path.expanduser(filepath))&lt;br /&gt;
    (shortName, ext) = os.path.splitext(fileName)&lt;br /&gt;
    if ext.lower() != &amp;quot;.bvh&amp;quot;:&lt;br /&gt;
        raise NameError(&amp;quot;Not a bvh file: &amp;quot; + fileName)&lt;br /&gt;
    print( &amp;quot;Loading BVH file &amp;quot;+ fileName )&lt;br /&gt;
&lt;br /&gt;
    time1 = time.clock()&lt;br /&gt;
    level = 0&lt;br /&gt;
    nErrors = 0&lt;br /&gt;
    scn = context.scene&lt;br /&gt;
            &lt;br /&gt;
    fp = open(fileName, &amp;quot;rU&amp;quot;)&lt;br /&gt;
    print( &amp;quot;Reading skeleton&amp;quot; )&lt;br /&gt;
    lineNo = 0&lt;br /&gt;
    for line in fp: &lt;br /&gt;
        words= line.split()&lt;br /&gt;
        lineNo += 1&lt;br /&gt;
        if len(words) == 0:&lt;br /&gt;
            continue&lt;br /&gt;
        key = words[0].upper()&lt;br /&gt;
        if key == 'HIERARCHY':&lt;br /&gt;
            status = Hierarchy&lt;br /&gt;
        elif key == 'MOTION':&lt;br /&gt;
            if level != 0:&lt;br /&gt;
                raise NameError(&amp;quot;Tokenizer out of kilter %d&amp;quot; % level)    &lt;br /&gt;
            amt = bpy.data.armatures.new(&amp;quot;BvhAmt&amp;quot;)&lt;br /&gt;
            rig = bpy.data.objects.new(&amp;quot;BvhRig&amp;quot;, amt)&lt;br /&gt;
            scn.objects.link(rig)&lt;br /&gt;
            scn.objects.active = rig&lt;br /&gt;
            bpy.ops.object.mode_set(mode='EDIT')&lt;br /&gt;
            root.build(amt, Vector((0,0,0)), None)&lt;br /&gt;
            #root.display('')&lt;br /&gt;
            bpy.ops.object.mode_set(mode='OBJECT')&lt;br /&gt;
            status = Motion&lt;br /&gt;
        elif status == Hierarchy:&lt;br /&gt;
            if key == 'ROOT':    &lt;br /&gt;
                node = CNode(words, None)&lt;br /&gt;
                root = node&lt;br /&gt;
                nodes = [root]&lt;br /&gt;
            elif key == 'JOINT':&lt;br /&gt;
                node = CNode(words, node)&lt;br /&gt;
                nodes.append(node)&lt;br /&gt;
            elif key == 'OFFSET':&lt;br /&gt;
                (x,y,z) = (float(words[1]), float(words[2]), float(words[3]))&lt;br /&gt;
                if rot90:                    &lt;br /&gt;
                    node.offset = scale*Vector((x,-z,y))&lt;br /&gt;
                else:&lt;br /&gt;
                    node.offset = scale*Vector((x,y,z))&lt;br /&gt;
            elif key == 'END':&lt;br /&gt;
                node = CNode(words, node)&lt;br /&gt;
            elif key == 'CHANNELS':&lt;br /&gt;
                oldmode = None&lt;br /&gt;
                for word in words[2:]:&lt;br /&gt;
                    if rot90:&lt;br /&gt;
                        (index, mode, sign) = channelZup(word)&lt;br /&gt;
                    else:&lt;br /&gt;
                        (index, mode, sign) = channelYup(word)&lt;br /&gt;
                    if mode != oldmode:&lt;br /&gt;
                        indices = []&lt;br /&gt;
                        node.channels.append((mode, indices))&lt;br /&gt;
                        oldmode = mode&lt;br /&gt;
                    indices.append((index, sign))&lt;br /&gt;
            elif key == '{':&lt;br /&gt;
                level += 1&lt;br /&gt;
            elif key == '}':&lt;br /&gt;
                level -= 1&lt;br /&gt;
                node = node.parent&lt;br /&gt;
            else:&lt;br /&gt;
                raise NameError(&amp;quot;Did not expect %s&amp;quot; % words[0])&lt;br /&gt;
        elif status == Motion:&lt;br /&gt;
            if key == 'FRAMES:':&lt;br /&gt;
                nFrames = int(words[1])&lt;br /&gt;
            elif key == 'FRAME' and words[1].upper() == 'TIME:':&lt;br /&gt;
                frameTime = float(words[2])&lt;br /&gt;
                frameTime = 1&lt;br /&gt;
                status = Frames&lt;br /&gt;
                frame = 0&lt;br /&gt;
                t = 0&lt;br /&gt;
                bpy.ops.object.mode_set(mode='POSE')&lt;br /&gt;
                pbones = rig.pose.bones&lt;br /&gt;
                for pb in pbones:&lt;br /&gt;
                    pb.rotation_mode = 'QUATERNION'&lt;br /&gt;
        elif status == Frames:&lt;br /&gt;
            addFrame(words, frame, nodes, pbones, scale)&lt;br /&gt;
            t += frameTime&lt;br /&gt;
            frame += 1&lt;br /&gt;
&lt;br /&gt;
    fp.close()&lt;br /&gt;
    time2 = time.clock()&lt;br /&gt;
    print(&amp;quot;Bvh file loaded in %.3f s&amp;quot; % (time2-time1))&lt;br /&gt;
    return rig&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    channelYup(word):&lt;br /&gt;
#    channelZup(word):&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def channelYup(word):&lt;br /&gt;
    if word == 'Xrotation':&lt;br /&gt;
        return ('X', Rotation, +1)&lt;br /&gt;
    elif word == 'Yrotation':&lt;br /&gt;
        return ('Y', Rotation, +1)&lt;br /&gt;
    elif word == 'Zrotation':&lt;br /&gt;
        return ('Z', Rotation, +1)&lt;br /&gt;
    elif word == 'Xposition':&lt;br /&gt;
        return (0, Location, +1)&lt;br /&gt;
    elif word == 'Yposition':&lt;br /&gt;
        return (1, Location, +1)&lt;br /&gt;
    elif word == 'Zposition':&lt;br /&gt;
        return (2, Location, +1)&lt;br /&gt;
&lt;br /&gt;
def channelZup(word):&lt;br /&gt;
    if word == 'Xrotation':&lt;br /&gt;
        return ('X', Rotation, +1)&lt;br /&gt;
    elif word == 'Yrotation':&lt;br /&gt;
        return ('Z', Rotation, +1)&lt;br /&gt;
    elif word == 'Zrotation':&lt;br /&gt;
        return ('Y', Rotation, -1)&lt;br /&gt;
    elif word == 'Xposition':&lt;br /&gt;
        return (0, Location, +1)&lt;br /&gt;
    elif word == 'Yposition':&lt;br /&gt;
        return (2, Location, +1)&lt;br /&gt;
    elif word == 'Zposition':&lt;br /&gt;
        return (1, Location, -1)&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    addFrame(words, frame, nodes, pbones, scale):&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def addFrame(words, frame, nodes, pbones, scale):&lt;br /&gt;
    m = 0&lt;br /&gt;
    for node in nodes:&lt;br /&gt;
        name = node.name&lt;br /&gt;
        try:&lt;br /&gt;
            pb = pbones[name]&lt;br /&gt;
        except:&lt;br /&gt;
            pb = None&lt;br /&gt;
        if pb:&lt;br /&gt;
            for (mode, indices) in node.channels:&lt;br /&gt;
                if mode == Location:&lt;br /&gt;
                    vec = Vector((0,0,0))&lt;br /&gt;
                    for (index, sign) in indices:&lt;br /&gt;
                        vec[index] = sign*float(words[m])&lt;br /&gt;
                        m += 1&lt;br /&gt;
                    pb.location = (scale * vec  - node.head) * node.inverse&lt;br /&gt;
                    for n in range(3):&lt;br /&gt;
                        pb.keyframe_insert('location', index=n, frame=frame, group=name)&lt;br /&gt;
                elif mode == Rotation:&lt;br /&gt;
                    mats = []&lt;br /&gt;
                    for (axis, sign) in indices:&lt;br /&gt;
                        angle = sign*float(words[m])*Deg2Rad&lt;br /&gt;
                        mats.append(Matrix.Rotation(angle, 3, axis))&lt;br /&gt;
                        m += 1&lt;br /&gt;
                    mat = node.inverse * mats[0] * mats[1] * mats[2] * node.matrix&lt;br /&gt;
                    pb.rotation_quaternion = mat.to_quaternion()&lt;br /&gt;
                    for n in range(4):&lt;br /&gt;
                        pb.keyframe_insert('rotation_quaternion',&lt;br /&gt;
                                           index=n, frame=frame, group=name)&lt;br /&gt;
    return&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    initSceneProperties(scn):&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def initSceneProperties(scn):&lt;br /&gt;
    bpy.types.Scene.MyBvhRot90 = bpy.props.BoolProperty(&lt;br /&gt;
        name=&amp;quot;Rotate 90 degrees&amp;quot;, &lt;br /&gt;
        description=&amp;quot;Rotate the armature to make Z point up&amp;quot;)&lt;br /&gt;
    scn['MyBvhRot90'] = True&lt;br /&gt;
&lt;br /&gt;
    bpy.types.Scene.MyBvhScale = bpy.props.FloatProperty(&lt;br /&gt;
        name=&amp;quot;Scale&amp;quot;, &lt;br /&gt;
        default = 1.0,&lt;br /&gt;
        min = 0.01,&lt;br /&gt;
        max = 100)&lt;br /&gt;
    scn['MyBvhScale'] = 1.0&lt;br /&gt;
&lt;br /&gt;
initSceneProperties(bpy.context.scene)&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    class BvhImportPanel(bpy.types.Panel):&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class BvhImportPanel(bpy.types.Panel):&lt;br /&gt;
    bl_label = &amp;quot;BVH import&amp;quot;&lt;br /&gt;
    bl_space_type = &amp;quot;VIEW_3D&amp;quot;&lt;br /&gt;
    bl_region_type = &amp;quot;UI&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    def draw(self, context):&lt;br /&gt;
        self.layout.prop(context.scene, &amp;quot;MyBvhRot90&amp;quot;)&lt;br /&gt;
        self.layout.prop(context.scene, &amp;quot;MyBvhScale&amp;quot;)&lt;br /&gt;
        self.layout.operator(&amp;quot;simple_bvh.load&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    class OBJECT_OT_LoadBvhButton(bpy.types.Operator, ImportHelper):&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class OBJECT_OT_LoadBvhButton(bpy.types.Operator, ImportHelper):&lt;br /&gt;
    bl_idname = &amp;quot;simple_bvh.load&amp;quot;&lt;br /&gt;
    bl_label = &amp;quot;Load BVH file (.bvh)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    # From ImportHelper. Filter filenames.&lt;br /&gt;
    filename_ext = &amp;quot;.bvh&amp;quot;&lt;br /&gt;
    filter_glob = bpy.props.StringProperty(default=&amp;quot;*.bvh&amp;quot;, options={'HIDDEN'})&lt;br /&gt;
&lt;br /&gt;
    filepath = bpy.props.StringProperty(name=&amp;quot;File Path&amp;quot;, &lt;br /&gt;
        maxlen=1024, default=&amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    def execute(self, context):&lt;br /&gt;
        import bpy, os&lt;br /&gt;
        readBvhFile(context, self.properties.filepath, &lt;br /&gt;
            context.scene.MyBvhRot90, context.scene.MyBvhScale)&lt;br /&gt;
        return{'FINISHED'}    &lt;br /&gt;
&lt;br /&gt;
    def invoke(self, context, event):&lt;br /&gt;
        context.window_manager.fileselect_add(self)&lt;br /&gt;
        return {'RUNNING_MODAL'}    &lt;br /&gt;
&lt;br /&gt;
#&lt;br /&gt;
#    Registration&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def menu_func(self, context):&lt;br /&gt;
    self.layout.operator(&amp;quot;simple_bvh.load&amp;quot;, text=&amp;quot;Simple BVH (.bvh)...&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
def register():&lt;br /&gt;
    bpy.utils.register_module(__name__)&lt;br /&gt;
    bpy.types.INFO_MT_file_import.append(menu_func)&lt;br /&gt;
&lt;br /&gt;
def unregister():&lt;br /&gt;
    bpy.utils.unregister_module(__name__)&lt;br /&gt;
    bpy.types.INFO_MT_file_import.remove(menu_func)&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    try:&lt;br /&gt;
        unregister()&lt;br /&gt;
    except:&lt;br /&gt;
        pass&lt;br /&gt;
    register()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
{{Page/Footer|Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Interface|Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Multi-File_packages}}&lt;/div&gt;</summary>
		<author><name>wiki&gt;Brecht</name></author>
		
	</entry>
</feed>