Dev:IT/2.5/Py/Scripts/Cookbook/Code snippets/Properties

提供: wiki
移動先: 案内検索

Proprietà

Proprietà RNA vs proprietà ID

In Blender ci sono due differenti tipi di proprietà: proprietà ID e proprietà RNA. Una proprietà RNA estende la definizione data di struttura dati. Deve essere dichiarata prima dell'uso.

bpy.types.Object.myRnaInt = bpy.props.IntProperty(
    name = "RNA int",
    min = -100,
    max = 100,
    default = 33)

Una volta che è stata dichiarata, le proprietà RNA sono accessibili con la sintassi punto:

cube.myRnaInt = -99

Poiche la dichiarazione della proprietà RNA myRnaInt estende la definizione della struttura dei dati, ogni oggetto avrà questa proprietà.

Una proprietà ID è aggiunta a un singolo datablock, senza agire sugli altri dati dello stesso tipo. Non serve nessuna dichiarazione, ma è automaticamente definita quando è impostata, per es.

cube.data["MyIdInt"] = 4711

Le proprietà ID possono essere solo di tipo intero, float, e stringa, altri tipi saranno convertiti automaticamente. Quindi la linea

cube.data["MyIdBool"] = True

definisce una proprietà ID di tipo intero e non una di tipo Booleana.

Le proprietà sono memorizzate all'interno del file .blend, ma non la dichiarazione delle proprietà.

Questo è uno script che crea tre mesh, assegna varie proprietà e stampa i loro valori nella console.

#----------------------------------------------------------
# File properties.py
#----------------------------------------------------------
import bpy
from bpy.props import *

# Clean the scene and create some objects
bpy.ops.object.select_by_type(type='MESH')
bpy.ops.object.delete()
bpy.ops.mesh.primitive_cube_add(location=(-3,0,0))
cube = bpy.context.object
bpy.ops.mesh.primitive_cylinder_add(location=(0,0,0))
cyl = bpy.context.object
bpy.ops.mesh.primitive_uv_sphere_add(location=(3,0,0))
sphere = bpy.context.object

# Define RNA props for every object
bpy.types.Object.myRnaInt = IntProperty(
    name = "RNA int", 
    min = -100, max = 100,
    default = 33)

bpy.types.Object.myRnaFloat = FloatProperty(
    name = "RNA float", 
    default = 12.345,
    min = 1, max = 20)

bpy.types.Object.myRnaString = StringProperty(
    name = "RNA string", 
    default = "Ribonucleic acid")

bpy.types.Object.myRnaBool = BoolProperty(
    name = "RNA bool")

bpy.types.Object.myRnaEnum = EnumProperty(
    items = [('one', 'eins', 'un'), 
            ('two', 'zwei', 'deux'), 
            ('three', 'drei', 'trois')],
    name = "RNA enum")

# Set the cube's RNA props
cube.myRnaInt = -99
cube.myRnaFloat = -1
cube.myRnaString = "I am an RNA prop"
cube.myRnaBool = True
cube.myRnaEnum = 'three'

# Create ID props fore cube mesh by setting them.
cube.data["MyIdInt"] = 4711
cube.data["MyIdFloat"] = 666.777
cube.data["MyIdString"] = "I am an ID prop"
cube.data["MyIdBool"] = True

# Print all properties
def printProp(rna, path):
    try:
        print('    %s%s =' % (rna.name, path), eval("rna"+path))
    except:
        print('    %s%s does not exist' % (rna.name, path))

for ob in [cube, cyl, sphere]:
    print("%s RNA properties" % ob)
    printProp(ob, ".myRnaInt")
    printProp(ob, ".myRnaFloat")
    printProp(ob, ".myRnaString")
    printProp(ob, ".myRnaBool")
    printProp(ob, ".myRnaEnum")
    print("%s ID properties" % ob.data)
    printProp(ob.data, '["MyIdInt"]')
    printProp(ob.data, '["MyIdFloat"]')
    printProp(ob.data, '["MyIdString"]')
    printProp(ob.data, '["MyIdBool"]')

Lo script stampa il seguente testo nella console:

<bpy_struct, Object("Cube")> RNA properties
    Cube.myRnaInt = -99
    Cube.myRnaFloat = 1.0
    Cube.myRnaString = I am an RNA prop
    Cube.myRnaBool = True
    Cube.myRnaEnum = three
<bpy_struct, Mesh("Cube.001")> ID properties
    Cube.001["MyIdInt"] = 4711
    Cube.001["MyIdFloat"] = 666.777
    Cube.001["MyIdString"] = I am an ID prop
    Cube.001["MyIdBool"] = 1
<bpy_struct, Object("Cylinder")> RNA properties
    Cylinder.myRnaInt = 33
    Cylinder.myRnaFloat = 12.345000267028809
    Cylinder.myRnaString = Ribonucleic acid
    Cylinder.myRnaBool = False
    Cylinder.myRnaEnum = one
<bpy_struct, Mesh("Cylinder")> ID properties
    Cylinder["MyIdInt"] does not exist
    Cylinder["MyIdFloat"] does not exist
    Cylinder["MyIdString"] does not exist
    Cylinder["MyIdBool"] does not exist
<bpy_struct, Object("Sphere")> RNA properties
    Sphere.myRnaInt = 33
    Sphere.myRnaFloat = 12.345000267028809
    Sphere.myRnaString = Ribonucleic acid
    Sphere.myRnaBool = False
    Sphere.myRnaEnum = one
<bpy_struct, Mesh("Sphere")> ID properties
    Sphere["MyIdInt"] does not exist
    Sphere["MyIdFloat"] does not exist
    Sphere["MyIdString"] does not exist
    Sphere["MyIdBool"] does not exist

Code Snippets PropsCube.png Tutti e tre gli oggetti hanno proprietà RNA, perché sono un'estensione dei tipi di dati dell'oggetto. Le proprietà RNA del cubo hanno il valore assegnato dal programma ad eccezione della proprietà myRnaFloat il cui valore non può essere più piccolo di 1. Nessuna proprietà è stata impostata per il cilindro e per la sfera, ma hanno comunque proprietà RNA con valori di default.

La mesh cubo ha le proprietà ID impostate dal programma. Nota che la proprietà MyIdBool è un intero con valore 1 anziché una booleana con valore True.

Le proprietà dell'oggetto sono mostrate nell'interfaccia nel pannello sotto Properties, e anche nel contesto dell' oggetto. Le proprietà della mesh possono essere trovate nel contesto della mesh.


Code Snippets PropsSphere.png Come abbiamo visto, possiamo accedere alle proprietà RNA dell'oggetto sfera, tuttavia, non sono mostrate nell'interfaccia utente. A quanto pare solo le proprietà impostate sono memorizzate nel datablock dell'oggetto. Possiamo usare una proprietà RNA che non è stata impostata nello script, prende il valore di default. Al contrario, se proviamo ad accedere a una proprietà ID non acora impostata, sarà generato un errore.


Code Snippets PropsLinkedCube.png Le proprietà sono compatibili con il collegamento del file. Salva il file e collega il cubo a un nuovo file. Sia le proprietà RNA che quelle ID sono presenti nel nuovo file, ma sono in grigio, perché non sono accessibili attraverso il collegamento del file.


Code Snippets PropsProxyCube.png Se rendiamo proxy il cubo collegato, le proprietà dell'oggetto appartengono al datablock dell'oggetto proxy, e può essere modificato nel file collegato; al contrario, le proprietà della mesh appartengono al datablock della mesh e non possono esere cambiate.


Code Snippets PropsBlenderRestarted.png Come detto prima, le proprietà sono memorizzate all'interno del file, ma la dichiarazione no. Esci, riavvia Blender, e apri il file che abbiamo precedentemente salvato. Le proprietà myRnaBool e myRnaEnum, sono state convertite a interi. Loro sono infatti memorizzate sempre come interi, ma saranno mostrate come booleane ed enumeratori, a causa della dichiarazione della proprietà memorizzata nel tipo di Object datamyRnaEnum.

Per avere conferma del fatto che le proprietà RNA si trasformano in proprietà Id esegui lo script seguente.

#----------------------------------------------------------
# File print_props.py
#----------------------------------------------------------
import bpy

def printProp(rna, path):
    try:
        print('    %s%s =' % (rna.name, path), eval("rna"+path))
    except:
        print('    %s%s does not exist' % (rna.name, path))

ob = bpy.context.object
print("%s RNA properties" % ob)
printProp(ob, ".myRnaInt")
printProp(ob, ".myRnaFloat")
printProp(ob, ".myRnaString")
printProp(ob, ".myRnaBool")
printProp(ob, ".myRnaEnum")
print("%s ID properties" % ob)
printProp(ob, '["myRnaInt"]')
printProp(ob, '["myRnaFloat"]')
printProp(ob, '["myRnaString"]')
printProp(ob, '["myRnaBool"]')
printProp(ob, '["myRnaEnum"]')
print("%s ID properties" % ob.data)
printProp(ob.data, '["MyIdInt"]')
printProp(ob.data, '["MyIdFloat"]')
printProp(ob.data, '["MyIdString"]')
printProp(ob.data, '["MyIdBool"]')

Lo script stampa il seguente testo nella console.

 RNA properties
    Cube.myRnaInt does not exist
    Cube.myRnaFloat does not exist
    Cube.myRnaString does not exist
    Cube.myRnaBool does not exist
    Cube.myRnaEnum does not exist
<bpy_struct, Object("Cube")> ID properties
    Cube["myRnaInt"] = -99
    Cube["myRnaFloat"] = 1.0
    Cube["myRnaString"] = I am an RNA prop
    Cube["myRnaBool"] = 1
    Cube["myRnaEnum"] = 2
<bpy_struct, Mesh("Cube.001")> ID properties
    Cube.001["MyIdInt"] = 4711
    Cube.001["MyIdFloat"] = 666.777
    Cube.001["MyIdString"] = I am an ID prop
    Cube.001["MyIdBool"] = 1

Se ripristiniamo le dichiarazioni di proprietà, le proprietà ID saranno convertite di nuovo in proprietà RNA.

Bone roll

Questo programma si aspetta, come oggetto attivo, un'armatura. Memorizizza l'angolo di rotazione di ogni editbone come proprietà del corrispondente osso, e infine stampa i valori delle proprietà nella console. Quando eseguito con l'armatura dell'immagine, il risultato nella console sarà il seguente.

    Head    3.1416
    Arm_L   1.5708
    Leg_R  -2.7646
    Leg_L   2.7646
    Arm_R  -1.5708
    Torso   3.1416

Nota che i valori della proprietà sono in radianti. Gli angoli nella view port sono mostrati in gradi, ma quando ci accedi da Python, sono espressi in radianti. Tuttavia la proprietà Roll è solo una proprietà float, e Blender non sa che è considerato un angolo. Per trovare la proprietà nell'interfaccia utente, ci serve selezionare l'osso in Pose Mode e quindi andare in Edit Mode, come mostrato nella figura. Code Snippets BoneRoll.png Questo codice, in realtà è piuttosto utile per uno script che retargets i dati provenienti da un motion capture. Per farlo in maniera adeguata, abbiamo bisogno di conoscere l'angolo di rotazione. Tuttavia non possiamo trovarlo se l'armatura è stata collegata in un altro file e reso reso proxy. Per accedere all'angolo di rotatazione rig.data.edit_bones[name].roll, l'armatura deve essere in Edit Mode, cosa, che non è possibile se è collegata. Ma, se lo script è esegito nel file dove l'armatura è definita, la proprietà Roll può essere accessibile dal file collegato come rig.pose.bones[name].bone["Roll"].

#----------------------------------------------------------
# File bone_roll.py
#----------------------------------------------------------
import bpy

def createBoneRollProps(rig):
    if rig.type != 'ARMATURE':
        raise NameError("Object not an armature")
    bpy.context.scene.objects.active = rig
    try:
        bpy.ops.object.mode_set(mode='EDIT')    
        editable = (len(rig.data.edit_bones) > 0)
    except:
        editable = False

    rolls = {}
    if editable:
        for eb in rig.data.edit_bones:
            rolls[eb.name] = eb.roll
        bpy.ops.object.mode_set(mode='POSE')    
        for pb in rig.pose.bones:
            pb.bone["Roll"] = rolls[pb.name]
    else:
        try:
            bpy.ops.object.mode_set(mode='POSE')    
        except:
            raise NameError("Armature is not posable. Create proxy")
        for pb in rig.pose.bones:
            try:
                rolls[pb.name] = pb.bone["Roll"]
            except:
                raise NameError("Create roll props in asset file")
    return rolls

rolls = createBoneRollProps(bpy.context.object)
for (bname, roll) in rolls.items():
        print("  %16s %8.4f" % (bname, roll))