-
Campbell Barton authoredCampbell Barton authored
cubester.py 34.33 KiB
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# Original Author = Jacob Morris
# URL = blendingjacob.blogspot.com
# Note: scene properties are moved into __init__ together with the 3 update functions
# for properties search for the name patterns adv_obj and advanced_objects
bl_info = {
"name": "CubeSter",
"author": "Jacob Morris",
"version": (0, 7, 1),
"blender": (2, 78, 0),
"location": "View 3D > Toolbar > CubeSter",
"description": "Takes image, image sequence, or audio file and converts it "
"into a height map based on pixel color and alpha values",
"category": "Add Mesh"
}
import bpy
import bmesh
from bpy.types import (
Operator,
Panel,
)
import timeit
from random import uniform
from math import radians
from os import (
path,
listdir,
)
# create block at center position x, y with block width 2 * hx and 2 * hy and height of h
def create_block(x, y, hw, h, verts: list, faces: list):
if bpy.context.scene.advanced_objects.cubester_block_style == "size":
z = 0.0
else:
z = h
h = 2 * hw
p = len(verts)
verts += [(x - hw, y - hw, z), (x + hw, y - hw, z), (x + hw, y + hw, z), (x - hw, y + hw, z)]
verts += [(x - hw, y - hw, z + h), (x + hw, y - hw, z + h),
(x + hw, y + hw, z + h), (x - hw, y + hw, z + h)]
faces += [(p, p + 1, p + 5, p + 4), (p + 1, p + 2, p + 6, p + 5),
(p + 2, p + 3, p + 7, p + 6), (p, p + 4, p + 7, p + 3),
(p + 4, p + 5, p + 6, p + 7), (p, p + 3, p + 2, p + 1)]
# go through all frames in len(frames), adjusting values at frames[x][y]
def create_f_curves(mesh, frames, frame_step_size, style):
# use data to animate mesh
action = bpy.data.actions.new("CubeSterAnimation")
mesh.animation_data_create()
mesh.animation_data.action = action
data_path = "vertices[%d].co"
vert_index = 4 if style == "blocks" else 0 # index of first vertex
# loop for every face height value
for frame_start_vert in range(len(frames[0])):
# only go once if plane, otherwise do all four vertices that are in top plane if blocks
end_point = frame_start_vert + 4 if style == "blocks" else frame_start_vert + 1
# loop through to get the four vertices that compose the face
for frame_vert in range(frame_start_vert, end_point):
# fcurves for x, y, z
fcurves = [action.fcurves.new(data_path % vert_index, i) for i in range(3)]
frame_counter = 0 # go through each frame and add position
temp_v = mesh.vertices[vert_index].co
# loop through frames
for frame in frames:
# new x, y, z positions
vals = [temp_v[0], temp_v[1], frame[frame_start_vert]]
for i in range(3): # for each x, y, z set each corresponding fcurve
fcurves[i].keyframe_points.insert(frame_counter, vals[i], {'FAST'})
frame_counter += frame_step_size # skip frames for smoother animation
vert_index += 1
# only skip vertices if made of blocks
if style == "blocks":
vert_index += 4
# create material with given name, apply to object
def create_material(scene, ob, name):
mat = bpy.data.materials.new("CubeSter_" + name)
adv_obj = scene.advanced_objects
image = None
# image
if not adv_obj.cubester_use_image_color and adv_obj.cubester_color_image in bpy.data.images:
try:
image = bpy.data.images[adv_obj.cubester_color_image]
except:
pass
else:
try:
image = bpy.data.images[adv_obj.cubester_image]
except:
pass
if scene.render.engine == "CYCLES":
mat.use_nodes = True
nodes = mat.node_tree.nodes
att = nodes.new("ShaderNodeAttribute")
att.attribute_name = "Col"
att.location = (-200, 300)
att = nodes.new("ShaderNodeTexImage")
if image:
att.image = image
if adv_obj.cubester_load_type == "multiple":
att.image.source = "SEQUENCE"
att.location = (-200, 700)
att = nodes.new("ShaderNodeTexCoord")
att.location = (-450, 600)
if adv_obj.cubester_materials == "image":
mat.node_tree.links.new(
nodes["Image Texture"].outputs[0],
nodes["Diffuse BSDF"].inputs[0]
)
mat.node_tree.links.new(
nodes["Texture Coordinate"].outputs[2],
nodes["Image Texture"].inputs[0]
)
else:
mat.node_tree.links.new(
nodes["Attribute"].outputs[0],
nodes["Diffuse BSDF"].inputs[0]
)
else:
if adv_obj.cubester_materials == "image" or scene.render.engine != "BLENDER_RENDER":
tex = bpy.data.textures.new("CubeSter_" + name, "IMAGE")
if image:
tex.image = image
slot = mat.texture_slots.add()
slot.texture = tex
else:
mat.use_vertex_color_paint = True
ob.data.materials.append(mat)
# generate mesh from audio
def create_mesh_from_audio(self, scene, verts, faces):
adv_obj = scene.advanced_objects
audio_filepath = adv_obj.cubester_audio_path
width = adv_obj.cubester_audio_width_blocks
length = adv_obj.cubester_audio_length_blocks
size_per_hundred = adv_obj.cubester_size_per_hundred_pixels
size = size_per_hundred / 100
# create all blocks
y = -(width / 2) * size + (size / 2)
for r in range(width):
x = -(length / 2) * size + (size / 2)
for c in range(length):
create_block(x, y, size / 2, 1, verts, faces)
x += size
y += size
# create object
mesh = bpy.data.meshes.new("cubed")
mesh.from_pydata(verts, [], faces)
ob = bpy.data.objects.new("cubed", mesh)
bpy.context.scene.objects.link(ob)
bpy.context.scene.objects.active = ob
ob.select = True
# inital vertex colors
if adv_obj.cubester_materials == "image" and adv_obj.cubester_color_image != "":
picture = bpy.data.images[adv_obj.cubester_color_image]
pixels = list(picture.pixels)
vert_colors = []
skip_y = int(picture.size[1] / width)
skip_x = int(picture.size[0] / length)
for row in range(0, picture.size[1], skip_y + 1):
# go through each column, step by appropriate amount
for column in range(0, picture.size[0] * 4, 4 + skip_x * 4):
r, g, b, a = get_pixel_values(picture, pixels, row, column)
vert_colors += [(r, g, b) for i in range(24)]
bpy.ops.mesh.vertex_color_add()
i = 0
vert_colors_size = len(vert_colors)
for c in ob.data.vertex_colors[0].data:
if i < vert_colors_size:
c.color = vert_colors[i]
i += 1
# image sequence handling
if adv_obj.cubester_load_type == "multiple":
images = find_sequence_images(self, bpy.context)
frames_vert_colors = []
max_images = adv_obj.cubester_max_images + 1 if \
len(images[0]) > adv_obj.cubester_max_images else len(images[0])
# goes through and for each image for each block finds new height
for image_index in range(0, max_images, adv_obj.cubester_skip_images):
filepath = images[0][image_index]
name = images[1][image_index]
picture = fetch_image(self, name, filepath)
pixels = list(picture.pixels)
frame_colors = []
for row in range(0, picture.size[1], skip_y + 1):
for column in range(0, picture.size[0] * 4, 4 + skip_x * 4):
r, g, b, a = get_pixel_values(picture, pixels, row, column)
frame_colors += [(r, g, b) for i in range(24)]
frames_vert_colors.append(frame_colors)
adv_obj.cubester_vertex_colors[ob.name] = \
{"type": "vertex", "frames": frames_vert_colors,
"frame_skip": adv_obj.cubester_frame_step,
"total_images": max_images}
# either add material or create
if ("CubeSter_" + "Vertex") in bpy.data.materials:
ob.data.materials.append(bpy.data.materials["CubeSter_" + "Vertex"])
else:
create_material(scene, ob, "Vertex")
# set keyframe for each object as initial point
frame = [1 for i in range(int(len(verts) / 8))]
frames = [frame]
area = bpy.context.area
old_type = area.type
area.type = "GRAPH_EDITOR"
scene.frame_current = 0
create_f_curves(mesh, frames, 1, "blocks")
# deselect all fcurves
fcurves = ob.data.animation_data.action.fcurves.data.fcurves
for i in fcurves:
i.select = False
max_images = adv_obj.cubester_audio_max_freq
min_freq = adv_obj.cubester_audio_min_freq
freq_frame = adv_obj.cubester_audio_offset_type
freq_step = (max_images - min_freq) / length
freq_sub_step = freq_step / width
frame_step = adv_obj.cubester_audio_frame_offset
# animate each block with a portion of the frequency
for c in range(length):
frame_off = 0
for r in range(width):
if freq_frame == "frame":
scene.frame_current = frame_off
l = c * freq_step
h = (c + 1) * freq_step
frame_off += frame_step
else:
l = c * freq_step + (r * freq_sub_step)
h = c * freq_step + ((r + 1) * freq_sub_step)
pos = c + (r * length) # block number
index = pos * 4 # first index for vertex
# select curves
for i in range(index, index + 4):
curve = i * 3 + 2 # fcurve location
fcurves[curve].select = True
try:
bpy.ops.graph.sound_bake(filepath=bpy.path.abspath(audio_filepath), low=l, high=h)
except:
pass
# deselect curves
for i in range(index, index + 4):
curve = i * 3 + 2 # fcurve location
fcurves[curve].select = False
area.type = old_type
# UV unwrap
create_uv_map(bpy.context, width, length)
# if radial apply needed modifiers
if adv_obj.cubester_audio_block_layout == "radial":
# add bezier curve of correct width
bpy.ops.curve.primitive_bezier_circle_add()
curve = bpy.context.object
# slope determined off of collected data
curve_size = (0.319 * (width * (size * 100)) - 0.0169) / 100
curve.dimensions = (curve_size, curve_size, 0.0)
# correct for z height
curve.scale = (curve.scale[0], curve.scale[0], curve.scale[0])
ob.select = True
curve.select = False
scene.objects.active = ob
# data was collected and then multi-variable regression was done in Excel
# influence of width and length
width_infl, length_infl, intercept = -0.159125, 0.49996, 0.007637
x_offset = ((width * (size * 100) * width_infl) +
(length * (size * 100) * length_infl) + intercept) / 100
ob.location = (ob.location[0] + x_offset, ob.location[1], ob.location[2])
ob.rotation_euler = (radians(-90), 0.0, 0.0)
bpy.ops.object.modifier_add(type="CURVE")
ob.modifiers["Curve"].object = curve
ob.modifiers["Curve"].deform_axis = "POS_Z"
# generate mesh from image(s)
def create_mesh_from_image(self, scene, verts, faces):
context = bpy.context
adv_obj = scene.advanced_objects
picture = bpy.data.images[adv_obj.cubester_image]
pixels = list(picture.pixels)
x_pixels = picture.size[0] / (adv_obj.cubester_skip_pixels + 1)
y_pixels = picture.size[1] / (adv_obj.cubester_skip_pixels + 1)
width = x_pixels / 100 * adv_obj.cubester_size_per_hundred_pixels
height = y_pixels / 100 * adv_obj.cubester_size_per_hundred_pixels
step = width / x_pixels
half_width = step / 2
y = -height / 2 + half_width
vert_colors = []
weights = [uniform(0.0, 1.0) for i in range(4)] # random weights
rows = 0
# go through each row of pixels stepping by adv_obj.cubester_skip_pixels + 1
for row in range(0, picture.size[1], adv_obj.cubester_skip_pixels + 1):
rows += 1
x = -width / 2 + half_width # reset to left edge of mesh
# go through each column, step by appropriate amount
for column in range(0, picture.size[0] * 4, 4 + adv_obj.cubester_skip_pixels * 4):
r, g, b, a = get_pixel_values(picture, pixels, row, column)
h = find_point_height(r, g, b, a, scene)
# if not transparent
if h != -1:
if adv_obj.cubester_mesh_style == "blocks":
create_block(x, y, half_width, h, verts, faces)
vert_colors += [(r, g, b) for i in range(24)]
else:
verts += [(x, y, h)]
vert_colors += [(r, g, b) for i in range(4)]
x += step
y += step
# if plane not blocks, then remove last 4 items from vertex_colors
# as the faces have already wrapped around
if adv_obj.cubester_mesh_style == "plane":
del vert_colors[len(vert_colors) - 4:len(vert_colors)]
# create faces if plane based and not block based
if adv_obj.cubester_mesh_style == "plane":
off = int(len(verts) / rows)
for r in range(rows - 1):
for c in range(off - 1):
faces += [(r * off + c, r * off + c + 1, (r + 1) * off + c + 1, (r + 1) * off + c)]
mesh = bpy.data.meshes.new("cubed")
mesh.from_pydata(verts, [], faces)
ob = bpy.data.objects.new("cubed", mesh)
context.scene.objects.link(ob)
context.scene.objects.active = ob
ob.select = True
# uv unwrap
if adv_obj.cubester_mesh_style == "blocks":
create_uv_map(context, rows, int(len(faces) / 6 / rows))
else:
create_uv_map(context, rows - 1, int(len(faces) / (rows - 1)))
# material
# determine name and if already created
if adv_obj.cubester_materials == "vertex": # vertex color
image_name = "Vertex"
elif not adv_obj.cubester_use_image_color and \
adv_obj.cubester_color_image in bpy.data.images and \
adv_obj.cubester_materials == "image": # replaced image
image_name = adv_obj.cubester_color_image
else: # normal image
image_name = adv_obj.cubester_image
# either add material or create
if ("CubeSter_" + image_name) in bpy.data.materials:
ob.data.materials.append(bpy.data.materials["CubeSter_" + image_name])
# create material
else:
create_material(scene, ob, image_name)
# vertex colors
bpy.ops.mesh.vertex_color_add()
i = 0
for c in ob.data.vertex_colors[0].data:
c.color = vert_colors[i]
i += 1
frames = []
# image sequence handling
if adv_obj.cubester_load_type == "multiple":
images = find_sequence_images(self, context)
frames_vert_colors = []
max_images = adv_obj.cubester_max_images + 1 if \
len(images[0]) > adv_obj.cubester_max_images else len(images[0])
# goes through and for each image for each block finds new height
for image_index in range(0, max_images, adv_obj.cubester_skip_images):
filepath = images[0][image_index]
name = images[1][image_index]
picture = fetch_image(self, name, filepath)
pixels = list(picture.pixels)
frame_heights = []
frame_colors = []
for row in range(0, picture.size[1], adv_obj.cubester_skip_pixels + 1):
for column in range(0, picture.size[0] * 4, 4 + adv_obj.cubester_skip_pixels * 4):
r, g, b, a = get_pixel_values(picture, pixels, row, column)
h = find_point_height(r, g, b, a, scene)
if h != -1:
frame_heights.append(h)
if adv_obj.cubester_mesh_style == "blocks":
frame_colors += [(r, g, b) for i in range(24)]
else:
frame_colors += [(r, g, b) for i in range(4)]
if adv_obj.cubester_mesh_style == "plane":
del vert_colors[len(vert_colors) - 4:len(vert_colors)]
frames.append(frame_heights)
frames_vert_colors.append(frame_colors)
# determine what data to use
if adv_obj.cubester_materials == "vertex" or scene.render.engine == "BLENDER_ENGINE":
adv_obj.cubester_vertex_colors[ob.name] = {
"type": "vertex", "frames": frames_vert_colors,
"frame_skip": adv_obj.cubester_frame_step,
"total_images": max_images
}
else:
adv_obj.cubester_vertex_colors[ob.name] = {
"type": "image", "frame_skip": scene.cubester_frame_step,
"total_images": max_images
}
att = get_image_node(ob.data.materials[0])
att.image_user.frame_duration = len(frames) * adv_obj.cubester_frame_step
# animate mesh
create_f_curves(
mesh, frames,
adv_obj.cubester_frame_step,
adv_obj.cubester_mesh_style
)
# generate uv map for object
def create_uv_map(context, rows, columns):
adv_obj = context.scene.advanced_objects
mesh = context.object.data
mesh.uv_textures.new("cubester")
bm = bmesh.new()
bm.from_mesh(mesh)
uv_layer = bm.loops.layers.uv[0]
bm.faces.ensure_lookup_table()
x_scale = 1 / columns
y_scale = 1 / rows
y_pos = 0.0
x_pos = 0.0
count = columns - 1 # hold current count to compare to if need to go to next row
# if blocks
if adv_obj.cubester_mesh_style == "blocks":
for fa in range(int(len(bm.faces) / 6)):
for i in range(6):
pos = (fa * 6) + i
bm.faces[pos].loops[0][uv_layer].uv = (x_pos, y_pos)
bm.faces[pos].loops[1][uv_layer].uv = (x_pos + x_scale, y_pos)
bm.faces[pos].loops[2][uv_layer].uv = (x_pos + x_scale, y_pos + y_scale)
bm.faces[pos].loops[3][uv_layer].uv = (x_pos, y_pos + y_scale)
x_pos += x_scale
if fa >= count:
y_pos += y_scale
x_pos = 0.0
count += columns
# if planes
else:
for fa in range(len(bm.faces)):
bm.faces[fa].loops[0][uv_layer].uv = (x_pos, y_pos)
bm.faces[fa].loops[1][uv_layer].uv = (x_pos + x_scale, y_pos)
bm.faces[fa].loops[2][uv_layer].uv = (x_pos + x_scale, y_pos + y_scale)
bm.faces[fa].loops[3][uv_layer].uv = (x_pos, y_pos + y_scale)
x_pos += x_scale
if fa >= count:
y_pos += y_scale
x_pos = 0.0
count += columns
bm.to_mesh(mesh)
# if already loaded return image, else load and return
def fetch_image(self, name, load_path):
if name in bpy.data.images:
return bpy.data.images[name]
else:
try:
image = bpy.data.images.load(load_path)
return image
except RuntimeError:
self.report({"ERROR"}, "CubeSter: '{}' could not be loaded".format(load_path))
return None
# find height for point
def find_point_height(r, g, b, a, scene):
adv_obj = scene.advanced_objects
if a: # if not completely transparent
normalize = 1
# channel weighting
if not adv_obj.cubester_advanced:
composed = 0.25 * r + 0.25 * g + 0.25 * b + 0.25 * a
else:
# user defined weighting
if not adv_obj.cubester_random_weights:
composed = adv_obj.cubester_weight_r * r + adv_obj.cubester_weight_g * g + \
adv_obj.cubester_weight_b * b + adv_obj.cubester_weight_a * a
total = adv_obj.cubester_weight_r + adv_obj.cubester_weight_g + adv_obj.cubester_weight_b + \
adv_obj.cubester_weight_a
normalize = 1 / total
# random weighting
else:
weights = [uniform(0.0, 1.0) for i in range(4)]
composed = weights[0] * r + weights[1] * g + weights[2] * b + weights[3] * a
total = weights[0] + weights[1] + weights[2] + weights[3]
normalize = 1 / total
if adv_obj.cubester_invert:
h = (1 - composed) * adv_obj.cubester_height_scale * normalize
else:
h = composed * adv_obj.cubester_height_scale * normalize
return h
else:
return -1
# find all images that would belong to sequence
def find_sequence_images(self, context):
scene = context.scene
images = [[], []]
if scene.advanced_objects.cubester_image in bpy.data.images:
image = bpy.data.images[scene.advanced_objects.cubester_image]
main = image.name.split(".")[0]
# first part of name to check against other files
length = len(main)
keep_going = True
for i in range(length - 1, -1, -1):
if main[i].isdigit() and keep_going:
length -= 1
else:
keep_going = not keep_going
name = main[0:length]
dir_name = path.dirname(bpy.path.abspath(image.filepath))
try:
for file in listdir(dir_name):
if path.isfile(path.join(dir_name, file)) and file.startswith(name):
images[0].append(path.join(dir_name, file))
images[1].append(file)
except FileNotFoundError:
self.report({"ERROR"}, "CubeSter: '{}' directory not found".format(dir_name))
return images
# get image node
def get_image_node(mat):
nodes = mat.node_tree.nodes
att = nodes["Image Texture"]
return att
# get the RGBA values from pixel
def get_pixel_values(picture, pixels, row, column):
# determine i position to start at based on row and column position
i = (row * picture.size[0] * 4) + column
pixs = pixels[i: i + 4]
r = pixs[0]
g = pixs[1]
b = pixs[2]
a = pixs[3]
return r, g, b, a
# frame change handler for materials
def material_frame_handler(scene):
frame = scene.frame_current
adv_obj = scene.advanced_objects
keys = list(adv_obj.cubester_vertex_colors.keys())
# get keys and see if object is still in scene
for i in keys:
# if object is in scene then update information
if i in bpy.data.objects:
ob = bpy.data.objects[i]
data = adv_obj.advanced_objects.cubester_vertex_colors[ob.name]
skip_frames = data["frame_skip"]
# update materials using vertex colors
if data['type'] == "vertex":
colors = data["frames"]
if frame % skip_frames == 0 and 0 <= frame < (data['total_images'] - 1) * skip_frames:
use_frame = int(frame / skip_frames)
color = colors[use_frame]
i = 0
for c in ob.data.vertex_colors[0].data:
c.color = color[i]
i += 1
else:
att = get_image_node(ob.data.materials[0])
offset = frame - int(frame / skip_frames)
att.image_user.frame_offset = -offset
# if the object is no longer in the scene then delete then entry
else:
del adv_obj.advanced_objects.cubester_vertex_colors[i]
class CubeSterPanel(Panel):
bl_idname = "OBJECT_PT_cubester"
bl_label = "CubeSter"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_category = "Create"
bl_options = {"DEFAULT_CLOSED"}
bl_context = "objectmode"
def draw(self, context):
layout = self.layout.box()
scene = bpy.context.scene
adv_obj = scene.advanced_objects
images_found = 0
rows = 0
columns = 0
layout.prop(adv_obj, "cubester_audio_image")
if adv_obj.cubester_audio_image == "image":
box = layout.box()
box.prop(adv_obj, "cubester_load_type")
box.label("Image To Convert:")
box.prop_search(adv_obj, "cubester_image", bpy.data, "images")
box.prop(adv_obj, "cubester_load_image")
# find number of approriate images if sequence
if adv_obj.cubester_load_type == "multiple":
box = layout.box()
# display number of images found there
images = find_sequence_images(self, context)
images_found = len(images[0]) if len(images[0]) <= adv_obj.cubester_max_images \
else adv_obj.cubester_max_images
if len(images[0]):
box.label(str(len(images[0])) + " Images Found", icon="PACKAGE")
box.prop(adv_obj, "cubester_max_images")
box.prop(adv_obj, "cubester_skip_images")
box.prop(adv_obj, "cubester_frame_step")
box = layout.box()
col = box.column(align=True)
col.prop(adv_obj, "cubester_skip_pixels")
col.prop(adv_obj, "cubester_size_per_hundred_pixels")
col.prop(adv_obj, "cubester_height_scale")
box.prop(adv_obj, "cubester_invert", icon="FILE_REFRESH")
box = layout.box()
box.prop(adv_obj, "cubester_mesh_style", icon="MESH_GRID")
if adv_obj.cubester_mesh_style == "blocks":
box.prop(adv_obj, "cubester_block_style")
else:
# audio file
layout.prop(adv_obj, "cubester_audio_path")
box = layout.box()
col = box.column(align=True)
col.prop(adv_obj, "cubester_audio_min_freq")
col.prop(adv_obj, "cubester_audio_max_freq")
box.separator()
box.prop(adv_obj, "cubester_audio_offset_type")
if adv_obj.cubester_audio_offset_type == "frame":
box.prop(adv_obj, "cubester_audio_frame_offset")
box.prop(adv_obj, "cubester_audio_block_layout")
box.separator()
col = box.column(align=True)
col.prop(adv_obj, "cubester_audio_width_blocks")
col.prop(adv_obj, "cubester_audio_length_blocks")
rows = adv_obj.cubester_audio_width_blocks
columns = adv_obj.cubester_audio_length_blocks
col.prop(adv_obj, "cubester_size_per_hundred_pixels")
# materials
box = layout.box()
box.prop(adv_obj, "cubester_materials", icon="MATERIAL")
if adv_obj.cubester_materials == "image":
box.prop(adv_obj, "cubester_load_type")
# find number of approriate images if sequence
if adv_obj.cubester_load_type == "multiple":
# display number of images found there
images = find_sequence_images(self, context)
images_found = len(images[0]) if len(images[0]) <= adv_obj.cubester_max_images \
else adv_obj.cubester_max_images
if len(images[0]):
box.label(str(len(images[0])) + " Images Found", icon="PACKAGE")
box.prop(adv_obj, "cubester_max_images")
box.prop(adv_obj, "cubester_skip_images")
box.prop(adv_obj, "cubester_frame_step")
box.separator()
if adv_obj.cubester_audio_image == "image":
box.prop(adv_obj, "cubester_use_image_color", icon="COLOR")
if not adv_obj.cubester_use_image_color or adv_obj.cubester_audio_image == "audio":
box.label("Image To Use For Colors:")
box.prop_search(adv_obj, "cubester_color_image", bpy.data, "images")
box.prop(adv_obj, "cubester_load_color_image")
if adv_obj.cubester_image in bpy.data.images:
rows = int(bpy.data.images[adv_obj.cubester_image].size[1] /
(adv_obj.cubester_skip_pixels + 1))
columns = int(bpy.data.images[adv_obj.cubester_image].size[0] /
(adv_obj.cubester_skip_pixels + 1))
box = layout.box()
if adv_obj.cubester_mesh_style == "blocks":
box.label("Approximate Cube Count: " + str(rows * columns))
box.label("Expected Verts/Faces: " + str(rows * columns * 8) + " / " + str(rows * columns * 6))
else:
box.label("Approximate Point Count: " + str(rows * columns))
box.label("Expected Verts/Faces: " + str(rows * columns) + " / " + str(rows * (columns - 1)))
# blocks and plane generation time values
if adv_obj.cubester_mesh_style == "blocks":
slope = 0.0000876958
intercept = 0.02501
block_infl, frame_infl, intercept2 = 0.0025934, 0.38507, -0.5840189
else:
slope = 0.000017753
intercept = 0.04201
block_infl, frame_infl, intercept2 = 0.000619, 0.344636, -0.272759
# if creating image based mesh
points = rows * columns
if adv_obj.cubester_audio_image == "image":
if adv_obj.cubester_load_type == "single":
time = rows * columns * slope + intercept # approximate time count for mesh
else:
time = (points * slope) + intercept + (points * block_infl) + \
(images_found / adv_obj.cubester_skip_images * frame_infl) + intercept2
box.label("Images To Be Used: " + str(int(images_found / adv_obj.cubester_skip_images)))
else:
# audio based mesh
box.label("Audio Track Length: " + str(adv_obj.cubester_audio_file_length) + " frames")
block_infl, frame_infl, intercept = 0.0948, 0.0687566, -25.85985
time = (points * block_infl) + (adv_obj.cubester_audio_file_length * frame_infl) + intercept
if time < 0.0: # usually no audio loaded
time = 0.0
time_mod = "s"
if time > 60: # convert to minutes if needed
time /= 60
time_mod = "min"
time = round(time, 3)
box.label("Expected Time: " + str(time) + " " + time_mod)
# advanced
if adv_obj.cubester_audio_image == "image":
icon_1 = "TRIA_DOWN" if adv_obj.cubester_advanced else "TRIA_RIGHT"
# layout.separator()
box = layout.box()
box.prop(adv_obj, "cubester_advanced", icon=icon_1)
if adv_obj.cubester_advanced:
box.prop(adv_obj, "cubester_random_weights", icon="RNDCURVE")
if not adv_obj.cubester_random_weights:
box.label("RGBA Channel Weights", icon="COLOR")
col = box.column(align=True)
col.prop(adv_obj, "cubester_weight_r")
col.prop(adv_obj, "cubester_weight_g")
col.prop(adv_obj, "cubester_weight_b")
col.prop(adv_obj, "cubester_weight_a")
# generate mesh
layout.operator("mesh.cubester", icon="OBJECT_DATA")
class CubeSter(Operator):
bl_idname = "mesh.cubester"
bl_label = "Generate Mesh"
bl_description = "Generate a mesh from an Image or Sound File"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
verts, faces = [], []
start = timeit.default_timer()
scene = bpy.context.scene
adv_obj = scene.advanced_objects
if adv_obj.cubester_audio_image == "image":
if adv_obj.cubester_image != "":
create_mesh_from_image(self, scene, verts, faces)
frames = find_sequence_images(self, context)
created = len(frames[0])
else:
self.report({'WARNING'},
"Please add an Image for Object generation. Operation Cancelled")
return {"CANCELLED"}
else:
if (adv_obj.cubester_audio_path != "" and
path.isfile(adv_obj.cubester_audio_path) and adv_obj.cubester_check_audio is True):
create_mesh_from_audio(self, scene, verts, faces)
created = adv_obj.cubester_audio_file_length
else:
self.report({'WARNING'},
"Please add an Sound File for Object generation. Operation Cancelled")
return {"CANCELLED"}
stop = timeit.default_timer()
if adv_obj.cubester_mesh_style == "blocks" or adv_obj.cubester_audio_image == "audio":
self.report({"INFO"},
"CubeSter: {} blocks and {} frame(s) "
"in {}s".format(str(int(len(verts) / 8)),
str(created),
str(round(stop - start, 4)))
)
else:
self.report({"INFO"},
"CubeSter: {} points and {} frame(s) "
"in {}s" .format(str(len(verts)),
str(created),
str(round(stop - start, 4)))
)
return {"FINISHED"}
def register():
bpy.utils.register_module(__name__)
bpy.app.handlers.frame_change_pre.append(material_frame_handler)
def unregister():
bpy.utils.unregister_module(__name__)
bpy.app.handlers.frame_change_pre.remove(material_frame_handler)
if __name__ == "__main__":
register()