bebraw
4/11/2012 - 3:18 PM

Just some custom voxel shiz in Blender 2.62

Just some custom voxel shiz in Blender 2.62

from functools import partial
from math import hypot
import itertools

import bpy

# http://blenderpythonscripts.wordpress.com/2011/04/24/cursor-control-0-6-0/
def space():
    area = None
    for area in bpy.data.window_managers[0].windows[0].screen.areas:
        if area.type == 'VIEW_3D':
            break
    if area.type != 'VIEW_3D':
        return None
    for space in area.spaces:
        if space.type == 'VIEW_3D':
            break
    if space.type != 'VIEW_3D':
        return None
    return space

def set_cursor(*coordinates):
    space().cursor_location = coordinates

def get_cursor():
    return space().cursor_location

def get_selected():
    return bpy.context.selected_editable_objects

def cube():
    bpy.ops.mesh.primitive_cube_add()
    return get_selected()[0]

def material(n, o=None):
    if o:
        o.active_material = material(n)
        return

    return bpy.data.materials[n]

def toggle(o):
    if o.active_material is None or o.active_material.name == 'led_on':
        material('led_off', o)
    else:
        material('led_on', o)

def ob(n):
    return [a for a in bpy.context.selectable_objects if a.name == n][0]

def toggle_led(i):
    toggle(ob('led_' + str(i)))

def toggle_z(i):
    offset = i * 8
    [toggle_led(j) for j in range(offset, offset + 8)]

def leds():
    prefix = 'led'
    n = 8
    for i in range(n * n * n):
        yield prefix + '_' + str(i)

def led_obs():
    for l in leds():
        yield ob(l)

# TODO: make this use leds() generator
def generate_leds():
    prefix = 'led'
    n = 8
    s = 0.01
    r = [i / (n - 1) for i in range(n)]
    i = 0
    for i, axes in enumerate(itertools.product(r, r, r)):
        o = cube()
        o.name = prefix + '_' + str(i)
        o.location = axes
        o.scale = (s, s, s)
        material('led_off', o)

def turn_off(o):
    material('led_off', o)

def turn_on(o):
    material('led_on', o)

def clear():
    for led_ob in led_obs():
        turn_off(led_ob)

def sdist(a, b):
    # likely really slow!!!
    return a * a + b * b

def voxelize(o, is_set=None):
    is_set = is_set or turn_on
    delta = 0.2
    imat = o.matrix_world.inverted()
    dverts = o.data.vertices

    for led_ob in led_obs():
        loc = imat * led_ob.location
        for e in o.data.edges.values():
            verts = e.vertices
            v1 = imat * dverts[verts[0]].co
            v2 = imat * dverts[verts[1]].co

            # TODO: try vec ops instead (compare vec rots)
            if sdist(v1, loc) + sdist(v2, loc) < sdist(v1, v2) + delta:
            #if hypot(v1[0], loc[0]) + hypot(v2[0], loc[0]) < hypot(v1[0], v2[0]) < delta:
            #    if hypot(v1[1], loc[1]) + hypot(v2[1], loc[1]) < hypot(v1[1], v2[1]) + delta:
                is_set(led_ob)
                break

# TODO: use this to generate actual c code
def animate(o):
    clear()
    
    scn = bpy.data.scenes[0]

    for i in range(scn.frame_start, scn.frame_end):
        scn.frame_current = i
        voxelize(o)
        
        #bpy.ops.object.select_all( action = 'DESELECT' )
        for led_ob in led_obs():
            pass
            #led_ob.select = True
            # TODO: figure out how to anim diffuse color
            #led_ob.keyframe_insert('diffuse')

# run only once :)
#generate_leds()

# toggle tests
#toggle_led(13)
#toggle_z(3)

def update(states, ctx):
    #scn = bpy.data.scenes[0]

    #state = states[scn.frame_current - scn.frame_start]
    
    clear()
    c = ob('Cube')
    voxelize(c) # cache here instead???
    #[turn_on(o) for o in state]

def generate_states(o):
    generate_states.ret = []
    scn = bpy.data.scenes[0]

    def is_set(led_ob):
        generate_states.ret[-1].append(led_ob)

    for i in range(scn.frame_start, scn.frame_end):
        scn.frame_current = i
        # TODO: figure out how refresh properly
        
        print('Caching frame', scn.frame_current)

        generate_states.ret.append([])        
        voxelize(o, is_set)

    generate_states.ret.append([])

    return generate_states.ret

while len(bpy.app.handlers.frame_change_pre):
    bpy.app.handlers.frame_change_pre.pop()

#c = ob('Cube')
#clear()
#voxelize(c)
states = [] #generate_states(c)
bpy.app.handlers.frame_change_pre.append(partial(update, states))