This script builds a 3-digit, 7-segment red LED display and cycles through 0-315 in steps of 45. But it doesn't quite work.
When changing the first digit to "EDIT" mode in order to change the material of each face (according to the digit pattern) I get an error I don't understand.
NOTE: Set 3D viewport shading to "Rendered" before running script.
This is what it should look like after it finishes running.
ERROR MESSAGE
Traceback (most recent call last): File "/Users/david914/Documents/Blender/BlenderPython/Fishing/3D text writing/text writing 7-seg digital counter v03.blend/Animate 7-segment", line 225, in File "/Applications/blender.app/Contents/MacOS/../Resources/2.74/scripts/modules/bpy/ops.py", line 189, in call ret = op_call(self.idname_py(), None, kw) RuntimeError: Operator bpy.ops.object.mode_set.poll() failed, context is incorrect Error: Python script fail, look in the console for now...
def make_LED_mat(mat_name, color_transp=None, color_emit=None,
emit_strength=None, frac=None):
# modified from HERE: http://blender.stackexchange.com/a/32162/5334
# and HERE: http://blender.stackexchange.com/q/34609/5334
LED_mat = bpy.data.materials.new(mat_name)
LED_mat.use_nodes = True
tree = LED_mat.node_tree
nodes = LED_mat.node_tree.nodes
for node in nodes:
tree.nodes.remove(node) # clean it up, start fresh
out = nodes.new(type='ShaderNodeOutputMaterial')
mix = nodes.new(type='ShaderNodeMixShader')
emit = nodes.new(type='ShaderNodeEmission')
transp = nodes.new(type='ShaderNodeBsdfTransparent')
out.location = 300, 0
mix.location = 0, 0
transp.location = -200, 50
emit.location = -200, -100
# link mix_shader to material output
a = mix.outputs['Shader']
b = out.inputs['Surface']
tree.links.new(a, b)
# link transp to mix
a = transp.outputs['BSDF']
b = mix.inputs[1] # 'Shader' is used twice, so you access via index.
tree.links.new(a, b)
# link emissive to mix
a = emit.outputs['Emission']
b = mix.inputs[2]
tree.links.new(a, b)
if color_transp == None:
color_diff = [0.8, 0.8, 0.8, 1.0]
if color_emit == None:
color_emit = [1.0, 0.2, 0.2, 1.0]
if frac == None:
frac = 0.5
if emit_strength == None:
emit_strength = 2.0
mix.inputs[0].default_value = frac # factor
transp.inputs['Color'].default_value = color_transp
emit.inputs['Color'].default_value = color_emit
emit.inputs['Strength'].default_value = emit_strength
return LED_mat
def make_7_seg(hw, hl, gapxy, slant_factor):
xnom = np.array([-hl, -hl+hw, hl-hw, hl, hl-hw, -hl+hw])
ynom = np.array([0.0, -hw, -hw, 0.0, hw, hw])
znom = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
xoffs = (hl+gapxy) * np.array([0, 1, 1, 0, -1, -1, 0])
yoffs = (hl+gapxy) * np.array([2, 1, -1, -2, -1, 1, 0])
rots = 0.5 * np.pi * np.array([0, 1, 1, 0, 1, 1, 0])
sinrot, cosrot = np.sin(rots), np.cos(rots)
X = cosrot[:,None]*xnom[None,:] - sinrot[:,None]*ynom[None,:] + xoffs[:,None]
Y = sinrot[:,None]*xnom[None,:] + cosrot[:,None]*ynom[None,:] + yoffs[:,None]
Z = np.zeros_like(X, dtype='float')
X = X + slant_factor*Y
# help from here:http://blender.stackexchange.com/a/35362/5334
# question from here: http://blender.stackexchange.com/questions/35360/having-problems-with-python-int-types-specifying-mesh-faces-again
faces = np.arange(7*6).reshape(7,6).tolist()
verts = [ thing for thing in zip(X.flatten(), Y.flatten(), Z.flatten())]
me = bpy.data.meshes.new('digit')
ob = bpy.data.objects.new('digit', me)
bpy.context.scene.objects.link(ob)
me.from_pydata(verts, [], faces)
return ob
def segit_dictionary():
#
# ---A---
# | |
# F B
# | |
# ---G---
# | |
# E C
# | |
# ---D---
#
# A B C D E F G
# "0" X X X X X X -
# "1" - X X - - - -
# "2" X X - X X - X
# "3" X X X X - - X
# "4" - X X - - X X
# "5" X - X X - X X
# "6" X - X X X X X
# "7" X X X - - - -
# "8" X X X X X X X
# "9" X X X X - X X
# " *ALTERNATES* "
# "9*" X X X - - X X
# "7*" X X X - - X -
# "6*" - - X X X X X
# "1*" - - - - X X -
#
#
segit = dict()
segit[0] = [1,1,1,1,1,1,0]
segit[1] = [0,1,1,0,0,0,0]
segit[2] = [1,1,0,1,1,0,1]
segit[3] = [1,1,1,1,0,0,1]
segit[4] = [0,1,1,0,0,1,1]
segit[5] = [1,0,1,1,0,1,1]
segit[6] = [1,0,1,1,1,1,1]
segit[7] = [1,1,1,0,0,0,0]
segit[8] = [1,1,1,1,1,1,1]
segit[9] = [1,1,1,1,0,1,1]
digits = [thing for thing in segit]
for digit in digits:
segit[str(digit)] = segit[digit] # text is OK too
for thing in ['blank', 'BLANK', 'dark', 'DARK', 'null', 'NULL']:
segit[thing] = [0,0,0,0,0,0,0]
return segit
import bpy
import bmesh
import numpy as np
import time
# MAKE MATERIALS
ON_mat = make_LED_mat("ON", color_transp= (0.8, 0.8, 0.8, 1.0),
color_emit = (1.0, 0.0, 0.0, 1.0),
emit_strength =1.0, frac=1.0)
OFF_mat = make_LED_mat("OFF", color_transp= (0.8, 0.8, 0.8, 1.0),
color_emit = (1.0, 0.0, 0.0, 1.0),
emit_strength =1.0, frac=0.0)
# MAKE DISPLAY
# MAKE DIGITS
ones_digit = make_7_seg(0.5, 2.0, 0.15, 0.20)
tens_digit = make_7_seg(0.5, 2.0, 0.15, 0.20)
hundreds_digit = make_7_seg(0.5, 2.0, 0.15, 0.20)
ones_digit.name = "ones_digit"
tens_digit.name = "tens_digit"
hundreds_digit.name = "hundreds_digit"
digits = [hundreds_digit, tens_digit, ones_digit]
# PLACE THEM UPRIGHT
for i, digit in enumerate(digits):
digit.rotation_euler = ((0.5*np.pi, 0.0, 0.0))
digit.location = ((7.0*(i-1), 0, 5.0))
digit.data.materials.append(OFF_mat) # material index 0
digit.data.materials.append(ON_mat) # material index 1
#digit.active_material = ON_mat # turn everything on first
# GET DICTIONARY
S = segit_dictionary()
# later we'll put SUZANNE behind the semi-transparent LEDs and rotate her by these angles
angles_deg = list(range(0, 350, 45))
angles = [thing*np.pi/180.0 for thing in angles_deg]
# try to animate the 3D window
# setup some stuff first
# from HERE: https://gist.github.com/zeffii/a422d4d7dc04ed023a57#file-proof2-py
context = bpy.context
for area in context.screen.areas:
if area.type == "VIEW_3D":
ctx = { "window": context.window, "area": area, "region":None}
break
US = lambda: bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
# if ready to go:
if 1 == 1:
#bpy.context.space_data.viewport_shade = 'RENDERED'
for a, adeg in zip(angles, angles_deg):
astr = str(adeg+1000)[1:]
# hundreds:
if astr[0] == "0":
p_hundreds = S['blank'] # leading zero suppresion
else:
p_hundreds = S[astr[0]]
# tens:
if astr[1] == "0" and astr[0] == "0": # leading zero suppresion
p_tens = S['blank']
else:
p_tens = S[astr[1]]
# ones:
p_ones = S[astr[2]]
patterns = [p_hundreds, p_tens, p_ones]
if 1 == 1:
print(adeg, " ", astr)
print(p_hundreds)
print(p_tens)
print(p_ones)
print(" ")
if 1 == 1:
for dig, pat in zip(digits, patterns):
bpy.ops.object.select_all(action='DESELECT')
dig.select = True
bpy.ops.object.mode_set(mode='EDIT')
bm = bmesh.from_edit_mesh(dig.data)
for f, p in zip(bm.faces, pat): # each face coresponds to one value in pattern list
f.material_index = p # index 0 or 1
dig.data.update()
bpy.ops.object.mode_set(mode='OBJECT')
US()
time.sleep(1.0)