Halloween Costume ideas 2015

PYTHON / Group Basic

In many scripts we wrote so far, we may have been creating a bunch of objects without thinking about how we could access them again in the future for further processing. It is my bad, I should have thought about that earlier.

Although we may have named the objects nicely like: Object.1, Object.2, Object.3, etc OR Object.001, Object.002, Object.003, etc, and we could probably select the objects again by name or by pattern, maybe it is a good idea to start to put them in Group.

I think, there is probably a more Pythonic way to store Group that can be accessed later (even after the file is closed), but I think Blender Group is a nice place to internally store list of objects.

We all know Blender has quite a nice Group system that will work between Blender scenes.

Objects linked to the same Group is also easily selectable whenever we do Select by the Same Group. I usually select an object and then Shift+G and select Group:


Grouped objects are also easily seen as list from the Outliner:


Let's take a quick look on how we can group objects and some basic Python way to group and link objects.

BEFORE CHECKING GROUP... LET'S CREATE AN ANIMATION

I am going to do a quick step by step exercise on keyframing and animation again. In previous post, I think I have been going too fast with Blender Python and keyframing.

I always start with Blender default scene, so you can follow along. Understand every steps so that you know which block of codes you will need next time if you want to copy paste or if you want to undo and re-run part of codes.

For step 005 for example, you can choose the one you like.


import bpy
import random

# 001 Hide default Camera and Lamp

bpy.data.objects['Camera'].layers[1] = True

bpy.data.objects['Lamp'].layers[1] = True

bpy.data.objects['Camera'].layers[0] = False
bpy.data.objects['Lamp'].layers[0] = False

# 002 Select and delete default Cube
bpy.data.objects['Cube'].select = True
bpy.ops.object.delete(use_global=False)



# Create a single material that respect Object Color
mat = bpy.data.materials.new('MyMaterial')

# 003 Create a bunch of new Cubes (should we give them material? yes, let's give one material to all)
totalCube = 25
cubeSet = [] 

for number in range(totalCube):
    bpy.ops.mesh.primitive_cube_add(location = [0, 0, number])
    selectedObject = bpy.context.selected_objects
    mesh = selectedObject[0]
    mesh.name = 'MyCube.%s' % number
    mesh.scale = 0.45, 0.45, 0.45
    
    # Keep our newly created cubes in Set
    cubeSet.append(selectedObject[0])
    
    # Apply our special Material
    bpy.context.object.data.materials.append(mat)


# 004 Set keyframes for Position XYZ value at Frame 1 and 10 (to hold position) for every cubes
for cube in cubeSet:
    cube.keyframe_insert('location', frame=1)
    cube.keyframe_insert('location', frame=10)

# 005 A Move our Cubes to new position (5 unit in positive Y) at frame 20 and set keyframes

bpy.context.scene.frame_current = 20

for cube in cubeSet:
    cube.location[1] += 5
    cube.keyframe_insert('location', frame=20)


# OFFSET BY FRAME
# 005 B If we like to offset each frame slightly

frameTarget = 20
frameOffset = 3
bpy.context.scene.frame_current = frameTarget

for cube in cubeSet:
    cube.location[1] += 20
    cube.keyframe_insert('location', frame=frameTarget)
    frameTarget += frameOffset
   

OFFSET BY FRAME BY RANDOM
# 005 C If we like to offset by random

frameTarget = 30
bpy.context.scene.frame_current = frameTarget

for cube in cubeSet:
    frameOffset = random.randrange(-10,10)
    cube.location[1] += 20
    frameTargetWithOffset = frameTarget + frameOffset
    cube.keyframe_insert('location', frame=frameTargetWithOffset)


GROUPING STUFF

OK, now we have something to group on. We have not actually group any of objects we have created.

But, within the Python script above, we have also put our newly created objects in a LIST, called "cubeSet". Since we already do that, we just pass on the List and tell Blender to link to new Group.

Reference:
http://blenderartists.org/forum/showthread.php?218394-Python-Grouping-objects

import bpy

''' APPEND SCRIPT BELOW AT THE VERY BOTTOM TO GROUP STUFF'''

objects_to_group = cubeSet

for item in objects_to_group:
    item.select = True
    bpy.context.scene.objects.active = item
    bpy.ops.object.group_link(group="myGroup")



RE-SELECTING GROUP
Whenever we like to select our objects again in the future, we simply do something like below.


import bpy


groupname = 'myGroup'
for object in bpy.data.groups[groupname].objects:
    object.select = True


We then just need to worry about the SORTING of objects by name.

MODIFYING FURTHER
Once we are able to re-select our objects, we can continue further and 

import bpy

frameOrigin = 40
frameTarget = 60
frameOffset = 3

groupname = 'myGroup'

for object in bpy.data.groups[groupname].objects:

    # set origin keyframe
    bpy.context.scene.frame_current = 40
    object.keyframe_insert('scale', frame=frameOrigin)
    frameOrigin += frameOffset

    # set target keyframe
    
    bpy.context.scene.frame_current = frameTarget
    object.scale[1] *= 10
    object.keyframe_insert('scale', frame=frameTarget)
    frameTarget += frameOffset


What we have been doing so far with Blender Python is kind of Animation with Offset. We simply applying same animation to every object and then offset the keyframe for each animation.

I am actually curious on how we can achieve this using other mean, such as using Action Curve or maybe Drivers.

RANDOM ARRANGEMENT
Things get a little bit more interesting if you add RANDOM here and there. Not everything need to be aligned and move and stop at the same time. Whether you are using the default Python Random module or other means (noise, perlin, etc). Maybe we look into this in near future.

I think the whole procedural animation thing is a little bit like controlled movement. Maybe like ballet or other dance performance or airplane airshow, we can carefully plan every formation of movement in a mathematical kind of way.

The best example for this is Beijing Olympic 2008. It was an extravagant performance by Chinese military and martial artist and dancer. Don't know exactly how they can do that, but I think they plan the whole performance using computer program of some sort.

Thinking about this further, we could have the same setup and simulation using Blender Particle system, actually. We could Keyframe Particle, tell it to move in random kind of way using Particle Boids, make them move and affected by Force, etc.

At some point, we also probably want to take consideration of manual animation curve as INPUT. That will be a lot more interesting.

BONUS: RANDOM MOVEMENT OF CUBE WITH RANDOM HSB COLOR

Below will be the exact same example like above, but I am applying a random HSB Color to each cube as Object Color.


import bpy
import random
import colorsys

# 001 Hide default Camera and Lamp
bpy.data.objects['Camera'].layers[1] = True
bpy.data.objects['Lamp'].layers[1] = True

bpy.data.objects['Camera'].layers[0] = False
bpy.data.objects['Lamp'].layers[0] = False

# 002 Select and delete default Cube
bpy.data.objects['Cube'].select = True
bpy.ops.object.delete(use_global=False)

# Create a single material that respect Object Color
mat = bpy.data.materials.new('MyMaterial')
mat.use_object_color = True

# 003 Create a bunch of new Cubes (should we give them material? yes, let's give one material to all)
totalCube = 25
cubeSet = [] 

for number in range(totalCube):
                    
    bpy.ops.mesh.primitive_cube_add(location = [0, 0, number])
    selectedObject = bpy.context.selected_objects
    mesh = selectedObject[0]
    mesh.name = 'MyCube.%s' % number
    mesh.scale = 0.45, 0.45, 0.45
    
    
    # Rainbow Spectrum Color HSB
    
    randomHueValue = random.uniform(0.0,1)
    
    convertedRGBvalue = colorsys.hsv_to_rgb(randomHueValue, .6, 1.0)
    
    # This will return Tuple of (R,G,B), you need to extract them using Index
    
    alphaValue = 1.0
    
    mesh.color = (
                    convertedRGBvalue[0], 
                    convertedRGBvalue[1], 
                    convertedRGBvalue[2] , 
                    alphaValue)
    
    # Keep our newly created cubes in Set
    cubeSet.append(selectedObject[0])
    
    # Apply our special Material
    bpy.context.object.data.materials.append(mat)


# 004 Set keyframes for Position XYZ value at Frame 1 and 10 (to hold position) for every cubes
for cube in cubeSet:
    cube.keyframe_insert('location', frame=1)
    cube.keyframe_insert('location', frame=10)


# OFFSET BY FRAME BY RANDOM
# 005 C If we like to offset by random

frameTarget = 30
bpy.context.scene.frame_current = frameTarget

for cube in cubeSet:
    frameOffset = random.randrange(-10,10)
    cube.location[1] += 20
    frameTargetWithOffset = frameTarget + frameOffset
    cube.keyframe_insert('location', frame=frameTargetWithOffset)




ANIMATE SCALE?
How about another example, and this time we animate the SCALE:

import bpy
import random
import colorsys

# 001 Hide default Camera and Lamp
bpy.data.objects['Camera'].layers[1] = True
bpy.data.objects['Lamp'].layers[1] = True

bpy.data.objects['Camera'].layers[0] = False
bpy.data.objects['Lamp'].layers[0] = False

# 002 Select and delete default Cube
bpy.data.objects['Cube'].select = True
bpy.ops.object.delete(use_global=False)

# Create a single material that respect Object Color
mat = bpy.data.materials.new('MyMaterial')
mat.use_object_color = True

# 003 Create a bunch of new Cubes (should we give them material? yes, let's give one material to all)
totalCube = 25
cubeSet = [] 

for number in range(totalCube):
                    
    bpy.ops.mesh.primitive_cube_add(location = [0, 0, number])
    selectedObject = bpy.context.selected_objects
    mesh = selectedObject[0]
    mesh.name = 'MyCube.%s' % number
    mesh.scale = 0.45, 0.45, 0.45
    
    
    # Rainbow Spectrum Color HSB
    
    randomHueValue = random.uniform(0.0,1)
    
    convertedRGBvalue = colorsys.hsv_to_rgb(randomHueValue, .6, 1.0)
    
    # This will return Tuple of (R,G,B), you need to extract them using Index
    
    alphaValue = 1.0
    
    mesh.color = (
                    convertedRGBvalue[0], 
                    convertedRGBvalue[1], 
                    convertedRGBvalue[2] , 
                    alphaValue)
    
    # Keep our newly created cubes in Set
    cubeSet.append(selectedObject[0])
    
    # Apply our special Material
    bpy.context.object.data.materials.append(mat)


# 004 Set keyframes for Position XYZ value at Frame 1 and 10 (to hold position) for every cubes
for cube in cubeSet:
    cube.keyframe_insert('scale', frame=1)
    cube.keyframe_insert('scale', frame=10)


# ANIMATE SCALE

    
frameOrigin = 40
frameTarget = 60
frameOffset = 3

for cube in cubeSet:

    # set origin keyframe
    bpy.context.scene.frame_current = 40
    cube.keyframe_insert('scale', frame=frameOrigin)
    frameOrigin += frameOffset

    # set target keyframe
    
    bpy.context.scene.frame_current = frameTarget
    cube.scale[1] *= 10
    cube.keyframe_insert('scale', frame=frameTarget)
    frameTarget += frameOffset


What if we want the color to be more organized like Rainbow Spectrum color? Let's modify the script again slightly (by normalizing the Hue color):

import bpy
import random
import colorsys

# 001 Hide default Camera and Lamp
bpy.data.objects['Camera'].layers[1] = True
bpy.data.objects['Lamp'].layers[1] = True

bpy.data.objects['Camera'].layers[0] = False
bpy.data.objects['Lamp'].layers[0] = False

# 002 Select and delete default Cube
bpy.data.objects['Cube'].select = True
bpy.ops.object.delete(use_global=False)

# Create a single material that respect Object Color
mat = bpy.data.materials.new('MyMaterial')
mat.use_object_color = True

# 003 Create a bunch of new Cubes (should we give them material? yes, let's give one material to all)
totalCube = 25
cubeSet = [] 

for number in range(totalCube):
                    
    bpy.ops.mesh.primitive_cube_add(location = [0, 0, number])
    selectedObject = bpy.context.selected_objects
    mesh = selectedObject[0]
    mesh.name = 'MyCube.%s' % number
    mesh.scale = 0.45, 0.45, 0.45
    
    
    # Rainbow Spectrum Color HSB
    
    rainbowHueValue = number/totalCube
    
    convertedRGBvalue = colorsys.hsv_to_rgb(rainbowHueValue, .6, 1.0)
    
    # This will return Tuple of (R,G,B), you need to extract them using Index
    
    alphaValue = 1.0
    
    mesh.color = (
                    convertedRGBvalue[0], 
                    convertedRGBvalue[1], 
                    convertedRGBvalue[2] , 
                    alphaValue)
    
    # Keep our newly created cubes in Set
    cubeSet.append(selectedObject[0])
    
    # Apply our special Material
    bpy.context.object.data.materials.append(mat)


# 004 Set keyframes for Position XYZ value at Frame 1 and 10 (to hold position) for every cubes
for cube in cubeSet:
    cube.keyframe_insert('scale', frame=1)
    cube.keyframe_insert('scale', frame=10)


# ANIMATE SCALE

frameOrigin = 40
frameTarget = 60
frameOffset = 3

for cube in cubeSet:

    # set origin keyframe
    bpy.context.scene.frame_current = 40
    cube.keyframe_insert('scale', frame=frameOrigin)
    frameOrigin += frameOffset

    # set target keyframe
    
    bpy.context.scene.frame_current = frameTarget
    cube.scale[1] *= 10
    cube.keyframe_insert('scale', frame=frameTarget)
    frameTarget += frameOffset


ADD ROTATION?
One more experiment. How about we also animation the rotation? Let's give that a try. We have never do anything with Rotation after all. For rotation, looks like we need to import Math Module because the rotation needs to be in RADIAN instead of DEGREE.

A bit of Math refreshment (I found by Google-ing)
  • degrees = radians * 180 / math.pi
  • radians = degrees * math.pi /180

import bpy
import random
import colorsys
import math

# 001 Hide default Camera and Lamp
bpy.data.objects['Camera'].layers[1] = True
bpy.data.objects['Lamp'].layers[1] = True

bpy.data.objects['Camera'].layers[0] = False
bpy.data.objects['Lamp'].layers[0] = False

# 002 Select and delete default Cube
bpy.data.objects['Cube'].select = True
bpy.ops.object.delete(use_global=False)

# Create a single material that respect Object Color
mat = bpy.data.materials.new('MyMaterial')
mat.use_object_color = True

# 003 Create a bunch of new Cubes (should we give them material? yes, let's give one material to all)
totalCube = 25
cubeSet = [] 

for number in range(totalCube):
                    
    bpy.ops.mesh.primitive_cube_add(location = [0, 0, number])
    selectedObject = bpy.context.selected_objects
    mesh = selectedObject[0]
    mesh.name = 'MyCube.%s' % number
    mesh.scale = 0.45, 0.45, 0.45
    
    
    # Rainbow Spectrum Color HSB
    
    rainbowHueValue = number/totalCube
    
    convertedRGBvalue = colorsys.hsv_to_rgb(rainbowHueValue, .6, 1.0)
    
    # This will return Tuple of (R,G,B), you need to extract them using Index
    
    alphaValue = 1.0
    
    mesh.color = (
                    convertedRGBvalue[0], 
                    convertedRGBvalue[1], 
                    convertedRGBvalue[2] , 
                    alphaValue)
    
    # Keep our newly created cubes in Set
    cubeSet.append(selectedObject[0])
    
    # Apply our special Material
    bpy.context.object.data.materials.append(mat)


# 004 Set keyframes for Position XYZ value at Frame 1 and 10 (to hold position) for every cubes
for cube in cubeSet:
    cube.keyframe_insert('scale', frame=1)
    cube.keyframe_insert('scale', frame=10)


# ANIMATE SCALE

frameOrigin = 40
frameTarget = 60
frameOffset = 3

for cube in cubeSet:

    # set origin keyframe
    bpy.context.scene.frame_current = 40
    cube.keyframe_insert('scale', frame=frameOrigin)
    frameOrigin += frameOffset

    # set target keyframe
    
    bpy.context.scene.frame_current = frameTarget
    cube.scale[1] *= 10
    cube.keyframe_insert('scale', frame=frameTarget)
    frameTarget += frameOffset
    
    
# KEYFRAME ROTATION ORIGIN
for cube in cubeSet:
    cube.keyframe_insert('rotation_euler', frame=150)

# ANIMATE ROTATION AND KEYFRAME

frameOrigin = 150
frameTarget = 250
frameOffset = 3

for cube in cubeSet:

    # set origin keyframe
    bpy.context.scene.frame_current = 40
    cube.keyframe_insert('rotation_euler', frame=frameOrigin)
    frameOrigin += frameOffset

    # set target keyframe
    
    bpy.context.scene.frame_current = frameTarget
    cube.rotation_euler[2] = 360 * math.pi /180
    cube.keyframe_insert('rotation_euler', frame=frameTarget)
    frameTarget += frameOffset







Post a Comment

MKRdezign

Contact Form

Name

Email *

Message *

Powered by Blogger.
Javascript DisablePlease Enable Javascript To See All Widget