lib/glitch3d/bpy/helpers.py in glitch3d-0.2.4.0 vs lib/glitch3d/bpy/helpers.py in glitch3d-0.5.0.0

- old
+ new

@@ -1,299 +1,217 @@ -REFLECTOR_SCALE = random.uniform(5, 8) -REFLECTOR_STRENGTH = random.uniform(10, 15) -REFLECTOR_LOCATION_PADDING = random.uniform(10, 12) -WIREFRAME_THICKNESS = random.uniform(0.0004, 0.002) -DISPLACEMENT_AMPLITUDE = random.uniform(0.02, 0.1) -REPLACE_TARGET = str(random.uniform(0, 9)) -REPLACEMENT = str(random.uniform(0, 9)) -ORIGIN = (0,0,2) -NUMBER_OF_FRAMES = 100 -SCATTER_INTENSITY = 0.015 -ABSORPTION_INTENSITY = 0.25 -DISPLAY_SCALE = (2, 2, 2) -PRIMITIVES = ['PYRAMID', 'CUBE'] -props = [] -YELLOW = (1, 0.7, 0.1, 1) -GREY = (0.2, 0.2, 0.2 ,1) -BLUE = (0.1, 0.1, 0.8, 0.4) -PINK = (0.8, 0.2, 0.7, 1.0) -WORDS = string.ascii_lowercase -RENDER_OUTPUT_PATHS = [] -NORMALS_RENDERING = False #(random.randint(0, 1) == 1) -MATERIALS_NAMES = [] +import sys, code, random, os, math, bpy, numpy, uuid, mathutils -def pry(): - code.interact(local=dict(globals(), **locals())) +def pry(globs=globals(), locs=locals()): + import sys + code.interact(local=dict(globs, **locs)) sys.exit("Aborting execution") -def fetch_material(material_name): - new_material = bpy.data.materials[material_name].copy() - return new_material +def chunk_it(seq, num): + avg = len(seq) / float(num) + out = [] + last = 0.0 + while last < len(seq): + out.append(seq[int(last):int(last + avg)]) + last += avg + return out -def apply_displacement(obj): - subdivide(obj, 6) +def add_frame(collection, data_paths): + for obj in collection: + for path in data_paths: + obj.keyframe_insert(data_path=path, index=-1) + +# Hashmap with proba in values +def rand_proba(hashmap): + return numpy.random.choice( + list(hashmap.keys()), + 1, + p=list(map(lambda x: x/sum(hashmap.values()), hashmap.values())) + )[0] + +def apply_displacement(obj, height_map_folder, strength = 0.2, subdivisions = 2): + subdivide(obj, subdivisions) subsurf = obj.modifiers.new(name='subsurf', type='SUBSURF') subsurf.levels = 2 subsurf.render_levels = 2 displace = obj.modifiers.new(name='displace', type='DISPLACE') new_texture = bpy.data.textures.new(name='texture', type='IMAGE') - new_texture.image = random_height_map() + new_texture.image = random_height_map(height_map_folder, low = True) displace.texture = new_texture + displace.strength = strength def look_at(obj): location_camera = CAMERA.matrix_world.to_translation() location_object = obj.matrix_world.to_translation() direction = location_object - location_camera rot_quat = direction.to_track_quat('-Z', 'Y') CAMERA.rotation_euler = rot_quat.to_euler() def shoot(filepath): - print('Camera now at location: ' + camera_location_string(CAMERA) + ' / rotation: ' + camera_rotation_string(CAMERA)) - SCENE.render.filepath = filepath + print('Camera now at location: ' + str(CAMERA.location) + ' / rotation: ' + str(CAMERA.rotation_euler)) + bpy.context.scene.render.filepath = filepath if animate: bpy.ops.render.render(animation=animate, write_still=True) else: RENDER_OUTPUT_PATHS.append(filepath) bpy.ops.render.render(write_still=True) def output_name(model_path, index = 0): - if animate: - return './renders/' + os.path.splitext(model_path)[0].split('/')[-1] + '_' + str(index) + '_' + str(datetime.date.today()) + '_' + str(mode) + '.avi' - else: - return './renders/' + os.path.splitext(model_path)[0].split('/')[-1] + '_' + str(index) + '_' + str(datetime.date.today()) + '_' + str(mode) + '.png' + return './renders/' + os.path.splitext(model_path)[0].split('/')[-1] + '_' + str(index) + '_' + str(datetime.date.today()) + '_' + str(mode) + ('.avi' if animate else '.png') -def rotate(model_object, index): - model_object.rotation_euler.z = math.radians(index * (360.0 / shots_number)) - # RGB 0 -> 1 def rand_color_value(): return random.uniform(0, 255) / 255 -def rand_location(): - return (rand_location_value(), rand_location_value(), rand_location_value()) +def rand_location(boundary): + return (random.uniform(-boundary, boundary), random.uniform(-boundary, boundary), random.uniform(-boundary, boundary)) def rand_rotation(): - return (rand_rotation_value(), rand_rotation_value(), rand_rotation_value()) + return (math.radians(random.uniform(0, 360)), math.radians(random.uniform(0, 360)), math.radians(random.uniform(0, 360))) -def rand_rotation_value(): - return round(math.radians(random.uniform(0, 60), 10)) - -def rand_rotation(): - return (random.uniform(0, 20), random.uniform(0, 20), random.uniform(0, 20)) - -def rand_location_value(): - return round(random.uniform(-4, 4), 10) - -def rand_color(): - return random.choice(COLORS) - -def rand_scale(): - return round(random.uniform(0, 0.2), 10) - -def rand_scale_vector(): - scale = rand_scale() - return(scale, scale, scale) - def unwrap_model(obj): if obj.name.startswith('Camera') or obj.name.startswith('Text') or obj.name.startswith('Cube'): return False - SCENE.objects.active = obj + bpy.context.scene.objects.active = obj bpy.ops.object.mode_set(mode='EDIT') bpy.ops.uv.unwrap() bpy.ops.object.mode_set(mode='OBJECT') -def camera_rotation_string(camera): - return str(int(camera.rotation_euler.x)) + ' ' + str(int(camera.rotation_euler.y)) + ' ' + str(int(camera.rotation_euler.z)) +############# +# <materials> +############# -def camera_location_string(camera): - return str(int(camera.location.x)) + ' ' + str(int(camera.location.y)) + ' ' + str(int(camera.location.z)) +# create material and load .osl file from fixtures +def load_osl_materials(osl_path): + for f in os.listdir(osl_path): + if f.endswith('.osl'): + material = create_cycles_material('osl_' + f[0:-4] + '_', True) + script_node = material.node_tree.nodes.new('ShaderNodeScript') + material.node_tree.nodes.new('ShaderNodeOutputMaterial') + script_node.mode = 'EXTERNAL' + script_node.filepath = osl_path + f + assign_node_to_output(material, script_node) +def fetch_material(material_name): + new_material = bpy.data.materials[material_name].copy() + return new_material + def assign_material(obj, material): flush_materials(obj.data.materials) if len(obj.data.materials) == 0: obj.data.materials.append(material) else: obj.data.materials[0] = material return material +def random_material(materials_list): + return fetch_material(random.choice(materials_list)) + # Returns a new Cycles material with default DiffuseBsdf node linked to output -def create_cycles_material(name = 'Object Material - ', clean=False): +def create_cycles_material(name = 'object_material_', clean=False): material = bpy.data.materials.new(name + str(uuid.uuid1())) material.use_nodes = True if clean: flush_nodes(material) return material -def random_texture(): - texture_path = TEXTURE_FOLDER_PATH + random.choice(os.listdir(TEXTURE_FOLDER_PATH)) +def random_texture(texture_folder_path): + texture_path = texture_folder_path + random.choice(os.listdir(texture_folder_path)) print("LOADING TEXTURE -> " + texture_path) return bpy.data.images.load(texture_path) -def random_height_map(): - path = HEIGHT_MAP_FOLDER_PATH + random.choice(os.listdir(HEIGHT_MAP_FOLDER_PATH)) +def random_height_map(height_map_folder, low = False): + if low: + path = height_map_folder + 'low.png' + else: + path = height_map_folder + random.choice(os.listdir(height_map_folder)) print("LOADING HEIGHT MAP -> " + path) return bpy.data.images.load(path) -def random_material(blacklist=[]): - return fetch_material(random.choice(MATERIALS_NAMES)) - def assign_texture_to_material(material, texture): assert material.use_nodes == True texture_node = material.node_tree.nodes.new('ShaderNodeTexImage') - emission_node = material.node_tree.nodes.new('ShaderNodeEmission') - material.node_tree.links.new(texture_node.outputs['Color'], emission_node.inputs['Color']) + node = material.node_tree.nodes.new('ShaderNodeBsdfGlossy') + material.node_tree.links.new(texture_node.outputs['Color'], node.inputs['Color']) texture_node.image = texture - assign_node_to_output(material, emission_node) + assign_node_to_output(material, node) def assign_node_to_output(material, new_node): assert material.use_nodes == True output_node = material.node_tree.nodes['Material Output'] material.node_tree.links.new(new_node.outputs[0], output_node.inputs['Surface']) -def mix_nodes(material, node1, node2): - mix = material.node_tree.nodes.new('ShaderNodeMixShader') - material.node_tree.links.new(mix.inputs[1], node1.outputs[0]) - material.node_tree.links.new(mix.inputs[2], node2.outputs[0]) - assign_node_to_output(material, mix) +def make_object_reflector(obj, color, reflector_scale, reflector_strength): + obj.scale = (reflector_scale, reflector_scale, reflector_scale) + make_object_emitter(obj, color, reflector_strength) -def make_object_glossy(obj, color = (PINK), roughness = 0.2): - material = create_cycles_material('Glossy Material - ') - glossy_node = material.node_tree.nodes.new('ShaderNodeBsdfGlossy') - glossy_node.inputs[0].default_value = color - glossy_node.inputs[1].default_value = roughness - assign_node_to_output(material, glossy_node) - assign_material(obj, material) - -def make_object_reflector(obj): - obj.scale = (REFLECTOR_SCALE, REFLECTOR_SCALE, REFLECTOR_SCALE) - make_object_emitter(obj, REFLECTOR_STRENGTH) - -def make_texture_object_transparent(obj, color = (1,1,1,0.5), intensity = 0.25): - material = obj.data.materials[-1] - emission_node = material.node_tree.nodes['Emission'] - trans = material.node_tree.nodes.new('ShaderNodeBsdfTransparent') - add = material.node_tree.nodes.new('ShaderNodeMixShader') - material.node_tree.links.new(emission_node.outputs[0], add.inputs[0]) - material.node_tree.links.new(trans.outputs[0], add.inputs[1]) - material.node_tree.links.new(emission_node.outputs[0], add.inputs[0]) - add.inputs[0].default_value = intensity - trans.inputs[0].default_value = color - -def make_object_transparent(obj): - material = create_cycles_material('Transparent Material - ') - trans = material.node_tree.nodes.new('ShaderNodeBsdfTransparent') - trans.inputs[0].default_value = rand_color() - assign_node_to_output(material, trans) - assign_material(obj, material) - -def make_object_emitter(obj, emission_strength = 1): +def make_object_emitter(obj, color, emission_strength = 1): emissive_material = assign_material(obj, fetch_material('emission')) emission_node = emissive_material.node_tree.nodes['Emission'] - emission_node.inputs[0].default_value = rand_color() + emission_node.inputs[0].default_value = color emission_node.inputs[1].default_value = emission_strength return emission_node def make_object_gradient_fabulous(obj, color1, color2): material = assign_material(obj, fetch_material('gradient_fabulous')) - mixer_node = material.node_tree.nodes.new('ShaderNodeMixRGB') - gradient_node = material.node_tree.nodes.new('ShaderNodeTexGradient') - gradient_node.gradient_type = 'SPHERICAL' - bsdf_node = material.node_tree.nodes.new('ShaderNodeBsdfDiffuse') - material.node_tree.links.new(gradient_node.outputs['Fac'], mixer_node.inputs['Fac']) - material.node_tree.links.new(mixer_node.outputs[0], bsdf_node.inputs['Color']) - assign_node_to_output(material, bsdf_node) + mixer_node = material.node_tree.nodes['Mix'] mixer_node.inputs['Color1'].default_value = color1 mixer_node.inputs['Color2'].default_value = color2 -def voronoize(obj, scale = 5.0): - material = obj.data.materials[-1] - texture_node = material.node_tree.nodes.new('ShaderNodeTexVoronoi') - material.node_tree.links.new(texture_node.outputs['Color'], material.node_tree.nodes['Glossy BSDF'].inputs['Color']) - texture_node.coloring = 'CELLS' - texture_node.inputs[1].default_value = scale - VORONOIED.append(obj) - -def texture_object(obj): +def texture_object(obj, texture_folder_path): new_material = create_cycles_material() - assign_texture_to_material(new_material, random_texture()) + assign_texture_to_material(new_material, random_texture(texture_folder_path)) assign_material(obj, new_material) -def duplicate_object(obj): - new_object = obj.copy() - new_object.data = obj.data.copy() - SCENE.objects.link(new_object) - return new_object +############# +# </material> +############# -def random_text(): - global WORDS - return random.choice(WORDS) - -def create_mesh(name, verts, faces, location, edges=[]): - mesh_data = bpy.data.meshes.new("mesh_data") - mesh_data.from_pydata(verts, edges, faces) - mesh_data.update() - obj = bpy.data.objects.new(name, mesh_data) - obj.location = location - SCENE.objects.link(obj) - return obj - -def spawn_text(): +def spawn_text(text_file_path, text = None): identifier = str(uuid.uuid1()) - new_curve = bpy.data.curves.new(type="FONT",name="Curve - " + identifier) + new_curve = bpy.data.curves.new(type="FONT",name="text_curve_" + identifier) new_curve.extrude = 0.11 - new_text = bpy.data.objects.new("Text - " + identifier, new_curve) - new_text.data.body = random_text() - SCENE.objects.link(new_text) + content = text if text else random_text(text_file_path) + new_text = bpy.data.objects.new("text_" + content, new_curve) + new_text.data.body = content + bpy.context.scene.objects.link(new_text) return new_text -def wireframize(obj, emission_strength = 1): - SCENE.objects.active = obj +def wireframize(obj, color, emission_strength = 1, thickness = random.uniform(0.0004, 0.001)): + bpy.context.scene.objects.active = obj + assert obj.type == 'MESH' obj.modifiers.new(name = 'wireframe', type='WIREFRAME') - obj.modifiers['wireframe'].thickness = WIREFRAME_THICKNESS - make_object_emitter(obj, emission_strength) + obj.modifiers['wireframe'].thickness = thickness + make_object_emitter(obj, color, emission_strength) return obj -def shuffle(obj): - obj.location = rand_location() - obj.scale = rand_scale_vector() +# randomize location and rotation of an object +def shuffle(obj, boundary): + obj.location = rand_location(boundary) obj.rotation_euler = rand_rotation() -def series(length, function = math.cos): - return list(map(lambda x: (0, x, function(x)), pitched_array(0.0, length, 0.1))) - -def randomize_reflectors_colors(): - for r in bpy.data.groups['Reflectors'].objects: - r.data.materials[-1].node_tree.nodes['Emission'].inputs[0].default_value = rand_color() - def add_object(obj, x, y, z, radius): - infer_primitive(obj, location=(x, y, z), radius=radius) - WIREFRAMES.append(last_added_object(obj)) - group_add(obj, last_added_object(obj)) - return last_added_object(obj) + new_obj = infer_primitive(obj, location=(x, y, z), radius=radius) + bpy.data.groups['neons'].objects.link(new_obj) + group_add(obj, new_obj) + return new_obj def infer_primitive(obj, **kwargs): - if obj == 'CUBE': + if obj == 'Cube': bpy.ops.mesh.primitive_cube_add(radius = kwargs['radius'], location = kwargs['location']) - elif obj == 'ICO': + elif obj == 'Ico': bpy.ops.mesh.primitive_ico_sphere_add(location = kwargs['location']) - elif obj == 'CONE': + elif obj == 'Cone': bpy.ops.mesh.primitive_cone_add(location = kwargs['location'], radius1 = kwargs['radius']) - elif obj == 'PYRAMID': - build_pyramid(location = kwargs['location']) - elif obj == 'PLANE': + elif obj == 'Pyramid': + return build_pyramid(location = kwargs['location']) + elif obj == 'Plane': bpy.ops.mesh.primitive_plane_add(location = kwargs['location'], radius = kwargs['radius']) + return bpy.context.object def group_add(group_name, obj): bpy.data.groups[group_name.lower().title()].objects.link(obj) -def last_added_object(object_name_start): - l = [] - for obj in bpy.data.objects: - if obj.name.startswith(object_name_start.lower().title()): - l.append(obj) - return l[-1] - def last_object_group(group_name): return bpy.data.groups[group_name.lower().title()].objects[-1] def build_composite_object(obj, size, radius): res = [] @@ -317,66 +235,44 @@ group_add(obj, new_obj) res.append(new_obj) new_obj.location = ((last_object_group(obj).location.x + 2 * radius), y_index, z_index) return res -# Displace vertex by random offset -def displace_vector(vector): - return mathutils.Vector((vector.x + random.uniform(-DISPLACEMENT_AMPLITUDE, DISPLACEMENT_AMPLITUDE), vector.y + random.uniform(-DISPLACEMENT_AMPLITUDE, DISPLACEMENT_AMPLITUDE), vector.z + random.uniform(-DISPLACEMENT_AMPLITUDE, DISPLACEMENT_AMPLITUDE))) - # Replace vertex coordinate everywhere def find_and_replace(vector, target, replacement): return mathutils.Vector((float(str(vector.x).replace(target, replacement)), float(str(vector.y).replace(target, replacement)), float(str(vector.z).replace(target, replacement)))) -def glitch(object): +def glitch(obj): bpy.ops.object.mode_set(mode='OBJECT') - assert object.type == 'MESH' - ints = list(range(10)) - target = str(ints.pop(int(random.uniform(0, len(ints) - 1)))) - replacement = str(ints.pop(int(random.uniform(0, len(ints))))) - for vertex in object.data.vertices: - vertex.co = find_and_replace(vertex.co, target, replacement) + if obj.type == 'MESH': + ints = list(range(10)) + target = str(ints.pop(int(random.uniform(0, len(ints) - 1)))) + replacement = str(ints.pop(int(random.uniform(0, len(ints))))) + for vertex in obj.data.vertices: + vertex.co = find_and_replace(vertex.co, target, replacement) + elif obj.type == 'CURVE': + for p in obj.data.splines.active.points: + max_amplitude = 0.5 + p.co.z += random.uniform(-max_amplitude, max_amplitude) + else: + raise TypeError("object cannot be glitched") -def displace(object): +def displace(obj, max_amplitude = 0.06): bpy.ops.object.mode_set(mode='OBJECT') - assert object.type == 'MESH' - for vertex in object.data.vertices: - vertex.co = displace_vector(vertex.co) + assert obj.type == 'MESH' + for vertex in obj.data.vertices: + vertex.co = mathutils.Vector((vertex.co.x + random.uniform(-max_amplitude, max_amplitude), vertex.co.y + random.uniform(-max_amplitude, max_amplitude), vertex.co.z + random.uniform(-max_amplitude, max_amplitude))) -def subdivide(object, cuts): - if SCENE.objects.active != object: - SCENE.objects.active = object - assert SCENE.objects.active == object +def subdivide(obj, cuts): + if bpy.context.scene.objects.active != obj: + bpy.context.scene.objects.active = obj + assert bpy.context.scene.objects.active == obj bpy.ops.object.mode_set(mode='EDIT') for index in range(0, cuts): bpy.ops.mesh.subdivide(cuts) bpy.ops.object.editmode_toggle() -def clone(obj): - new_obj = obj.copy() - new_obj.data = obj.data.copy() - new_obj.animation_data_clear() - SCENE.objects.link(new_obj) - return new_obj - -def add_ocean(spatial_size, resolution, depth = 100, scale=(4,4,4)): - bpy.ops.mesh.primitive_cube_add(location=(0, 0, -0.4),radius=1) - ocean = last_added_object('CUBE') - ocean.scale = scale - ocean.modifiers.new(name='Ocean', type='OCEAN') - ocean.modifiers["Ocean"].spatial_size = spatial_size - ocean.modifiers["Ocean"].resolution = resolution - ocean.modifiers["Ocean"].depth = depth - make_object_glossy(ocean, rand_color()) - make_object_gradient_fabulous(ocean, rand_color(), rand_color()) - shadow = clone(ocean) - shadow.location += mathutils.Vector((1,1,-0.4)) - wireframize(shadow) - shadow.name = 'shadow' - ocean.name = 'ocean' - return [ocean, shadow] - # Delete current objects def flush_objects(objs = bpy.data.objects): for obj in objs: bpy.data.objects.remove(obj, do_unlink=True) @@ -393,29 +289,43 @@ def delete_useless_materials(): for mat in bpy.data.materials: if mat.name.startswith('Material'): bpy.data.materials.remove(mat, do_unlink=True) -# Rotate hue to generate palette +# Rotate hue to generate a somewhat harmonious palette def adjacent_colors(r, g, b, number): - angle = (360 / 5) / 360 + print("Color scheme: adjacent colors") + angle = (360 / number) / 360 # angles are in ? h, l, s = colorsys.rgb_to_hls(r, g, b) hue_positions = [] for i in range(number): hue_positions.append(angle * i) h = [(h + offset) % 1 for offset in hue_positions] - adjacent = [colorsys.hls_to_rgb(hi, l, s) for hi in h] + return [colorsys.hls_to_rgb(hi, l, s) for hi in h] + +# Use saturation increments to generate a color ramp palette +def color_ramp(r, g, b, number): + print("Color scheme: color ramp") + h, l, s = colorsys.rgb_to_hls(r, g, b) + res = [] + for i in range(number): + saturation = ( s + i * random.uniform(-0.1, 0.1)) + lightness = (l + i * random.uniform(-0.1, 0.1) ) + hue = (h + i * random.uniform(-0.1, 0.1)) + res.append(colorsys.hls_to_rgb(h, lightness, saturation)) + return res + +def rand_color_palette(number): + function = random.choice([color_ramp, adjacent_colors]) + res = list(map(lambda x: list(x), function(rand_color_value(), rand_color_value(), rand_color_value(), number))) # add alpha component - res = list(map(lambda x: list(x), adjacent)) for i in res: i.append(1) + print("palette: " + str(res)) return res -def rand_color_palette(number): - return adjacent_colors(rand_color_value(), rand_color_value(), rand_color_value(), number) - -def build_pyramid(width=random.uniform(1,3), length=random.uniform(1,3), height=random.uniform(1,3), location=ORIGIN): +def build_pyramid(width=random.uniform(1,3), length=random.uniform(1,3), height=random.uniform(1,3), location=(0,0,0)): verts=[] faces=[] verts.append([-(width/2),(length/2),0.0]) verts.append([-(width/2),-(length/2),0.0]) verts.append([(width/2),-(length/2),0.0]) @@ -424,128 +334,190 @@ faces.append([0,1,2,3]) faces.append([0,1,4]) faces.append([1,2,4]) faces.append([2,3,4]) faces.append([3,0,4]) - return create_mesh('Pyramid ' + str(uuid.uuid1()), verts, faces, location) + return create_mesh('pyramid_' + str(uuid.uuid1()), verts, faces, location) -def build_segment(location, function = series, length = 2): - verts = function(length) - edges = [] - for v in range(0, (len(verts) - 1)): - edges.append([v, v+1]) - return create_mesh('Segment ' + str(uuid.uuid1()), verts, [], location, edges) +# Cuts a model horizontally into sub models like a scanner +def cut(obj, slices = 10): + thiccness = obj.dimensions.z / slices + gap = 0.01 * obj.dimensions.z + center(obj) + print("Slicing " + obj.name + " in " + str(slices) + " parts " + str(thiccness) + " thicc, gap: " + str(gap)) + base = obj.location.z - (obj.dimensions.z / 2) + for i in range(0,slices - 1): + dup = duplicate_object(obj) + dup.name = 'subcut_' + obj.name + '_' + str(i) + bpy.ops.object.select_all(action='DESELECT') + bpy.context.scene.objects.active = dup + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.bisect(plane_co=(0,0,base),plane_no=(0,0,1),clear_outer=False,clear_inner=True) + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.bisect(plane_co=(0,0,base + thiccness),plane_no=(0,0,1),clear_outer=True,clear_inner=False) + bpy.ops.object.mode_set(mode='OBJECT') + base += thiccness + dup.location.z += i * gap + dup.location.x += random.uniform(-0.2,0.2) + dup.location.y += random.uniform(-0.2,0.2) + obj.cycles_visibility.camera = False -def camera_path(pitch = NUMBER_OF_FRAMES): - res = [] - initial_z = INITIAL_CAMERA_LOCATION[2] - initial_x = INITIAL_CAMERA_LOCATION[0] - for y in pitched_array(initial_x, -initial_x, pitch): - res.append((initial_x, y, math.sin(0.5*y) + 0.5)) - for x in pitched_array(initial_x, -initial_x, pitch): - res.append((x,-initial_x, math.sin(0.5*x) + 0.5)) - for y in pitched_array(-initial_x, initial_x, pitch): - res.append((-initial_x, y, math.sin(0.5*y) + 0.5)) - for x in pitched_array(-initial_x, initial_x, pitch): - res.append((x, initial_x, math.sin(0.5*x) + 0.5)) - return res +def duplicate_object(obj): + print("Cloning -> " + obj.name) + new_object = obj.copy() + new_object.data = obj.data.copy() + new_object.animation_data_clear() + new_object.cycles_visibility.camera = True + # assign_material(new_object, obj.data.materials[-1]) + bpy.context.scene.objects.link(new_object) + return new_object -def pitched_array(minimum, maximum, pitch): - return list(map(lambda x: (minimum + pitch * x), range(int((maximum - minimum) / pitch)))) +def load_random_obj(path): + objs = [f for f in os.listdir(path) if f.endswith('.obj') and not f.endswith('_glitched.obj')] + bpy.ops.import_scene.obj(filepath = path + random.choice(objs), use_edges=True) + return bpy.context.selected_objects[0] -def still_routine(max_index, index = 1): - CAMERA.location = CAMERA_PATH[int((len(CAMERA_PATH) / max_index) * index)] - CAMERA.rotation_euler.y += math.radians(round(random.uniform(-25, +25))) - randomize_reflectors_colors() - if OCEAN: - make_object_glossy(OCEAN[0]) - assign_material(SUBJECT, random_material()) - rotate(SUBJECT, index) - for ocean in OCEAN: - ocean.modifiers['Ocean'].random_seed = round(random.uniform(0, 100)) - ocean.modifiers['Ocean'].choppiness += random.uniform(0, 0.3) - if bpy.data.groups['Lines'].objects: - for l in bpy.data.groups['Lines'].objects: - rotation = rand_rotation() - l.rotation_euler = rotation - if props: - for prop in props: - prop.location = rand_location() - prop.rotation_euler = rand_rotation() - if WIREFRAMES: - for obj in WIREFRAMES: - obj.location += mathutils.Vector((random.uniform(0,1),random.uniform(0,1),random.uniform(0,1))) - obj.rotation_euler = rand_rotation() - if bpy.data.groups['Displays'].objects: - for display in bpy.data.groups['Displays'].objects: - display.location = rand_location() - rotate(display, index) +def random_text(file_path): + lines = open(file_path).readlines() + return lines[random.randrange(len(lines))] -def animation_routine(frame): - CAMERA.location = CAMERA_PATH[frame] - look_at(SUBJECT) - assign_material(SUBJECT, random_material()) - randomize_reflectors_colors() - displace(SUBJECT) - for ocean in OCEAN: - ocean.modifiers['Ocean'].time += 0.5 - if OCEAN: - make_object_glossy(OCEAN[0]) - for particle_system in bpy.data.particles: - particle_system.phase_factor_random += 0.01 - SUBJECT.rotation_euler.z += math.radians(1) - for l in bpy.data.groups['Lines'].objects: - l.rotation_euler.x += math.radians(1) - l.rotation_euler.z += math.radians(1) - if props: - for prop in props: - prop.rotation_euler.x += math.radians(5) - if WIREFRAMES: - for obj in WIREFRAMES: - obj.location.z = math.sin(frame) - obj.rotation_euler.rotate(mathutils.Euler((math.radians(1), math.radians(1), math.radians(1)), 'XYZ')) - if bpy.data.groups['Displays'].objects: - for display in bpy.data.groups['Displays'].objects: - display.rotation_euler.x += math.radians(2) +def add_faces(obj): + vertices = [] + for v in obj.data.vertices: + vertices.append(v.co) + new_obj = create_mesh(obj.name, vertices, random_faces(vertices), obj.location) + bpy.data.objects.remove(obj, do_unlink=True) + return new_obj -def create_line(name, point_list, thickness = 0.002, location = (0, -10, 0)): +def random_faces(vertices): + faces = [] + for i in range(int(len(vertices)/100)): + target = vertices[random.choice((range(len(vertices))))] + if (random.randint(0, 1) == 1): + faces.append(((target + 2), int(target / 6), int(target - 1), target)) + else: + faces.append((int(target / 6), int(target - 1), target)) + return faces + +############ +# <geometry> +############ + +def center(obj): + bpy.context.scene.objects.active = obj + bpy.ops.object.transform_apply(location=False, rotation=True, scale=True) + bpy.ops.object.origin_set(type="ORIGIN_CENTER_OF_MASS") + local_bounding_box_center = 0.125 * sum((mathutils.Vector(b) for b in obj.bound_box), mathutils.Vector()) + obj.location -= local_bounding_box_center + return obj + +def resize(obj, pace = 0.05, minimum = 3.0, maximum = 8.0): + print("Resizing: " + obj.name) + assert minimum < maximum + obj.scale = (1,1,1) + scale_multiplier = max(obj.dimensions) / (maximum - minimum) + if max(obj.dimensions) > maximum: + init_scale = obj.scale + obj.scale = init_scale - init_scale * scale_multiplier # downscale + if obj.scale.x < 0: + obj.scale = init_scale * scale_multiplier + else: + obj.scale = obj.scale + obj.scale * scale_multiplier # upscale + +def extrude(obj, thickness=0.05): + bpy.context.scene.objects.active = obj + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.extrude_region_move(MESH_OT_extrude_region={"mirror":False}, TRANSFORM_OT_translate={"value":(thickness, 0, 0), "constraint_orientation":'GLOBAL', "mirror":True, "proportional":'DISABLED', "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "gpencil_strokes":False, "texture_space":False, "remove_on_cancel":False, "release_confirm":False, "use_accurate":False}) + bpy.ops.object.mode_set(mode='OBJECT') + +def create_line(name, point_list, color, thickness = 0.002, location = (0,0,0)): line_data = bpy.data.curves.new(name=name,type='CURVE') line_data.dimensions = '3D' line_data.fill_mode = 'FULL' + # line_data.resolution_u = 4 line_data.bevel_depth = thickness polyline = line_data.splines.new('POLY') - polyline.points.add(len(point_list)-1) - for idx in range(len(point_list)): - polyline.points[idx].co = (point_list[idx])+(1.0,) - line = bpy.data.objects.new('line' + str(uuid.uuid1()), line_data) - SCENE.objects.link(line) + # polyline = line_data.splines.new('BEZIER') + polyline.points.add(len(point_list)-1) # splines.new return already 1 point + # polyline.bezier_points.add(len(point_list)-1) # splines.new return already 1 point + for idx, coord in enumerate(point_list): + x,y,z = coord + polyline.points[idx].co = (x, y, z, 1) # add weight + # polyline.bezier_points[idx].co = (x, y, z) + polyline.order_u = len(polyline.points)-1 + # polyline.use_endpoint_u = True + line = bpy.data.objects.new(name, line_data) + bpy.context.scene.objects.link(line) line.location = location - make_object_emitter(line, 0.8) + make_object_emitter(line, color, 1.1) return line -def add_spotlight(location, intensity, radians): - bpy.ops.object.lamp_add(type='SPOT', radius=1.0, view_align=False, location=location) - spot = last_added_object('Spot') - spot.data.node_tree.nodes['Emission'].inputs[1].default_value = intensity - spot.data.spot_size = radians - return spot +def build_segment(location, function, length = 2, pitch = 0.5, name = None): + verts = series(length, function, pitch) + edges = [] + for v in range(0, (len(verts) - 1)): + edges.append([v, v+1]) + name = name if name else 'segment_' + str(uuid.uuid1()) + return create_mesh(name, verts, [], location, edges) -def make_world_volumetric(world, scatter_intensity = SCATTER_INTENSITY, absorption_intensity = ABSORPTION_INTENSITY): - assert world.use_nodes == True - output = world.node_tree.nodes['World Output'] - bg_node = world.node_tree.nodes.new('ShaderNodeBackground') - absorption_node = world.node_tree.nodes.new('ShaderNodeVolumeAbsorption') - scatter_node = world.node_tree.nodes.new('ShaderNodeVolumeScatter') - add_shader = world.node_tree.nodes.new('ShaderNodeAddShader') - world.node_tree.links.new(add_shader.outputs[0], output.inputs['Volume']) - world.node_tree.links.new(bg_node.outputs['Background'], output.inputs['Surface']) - world.node_tree.links.new(scatter_node.outputs[0], add_shader.inputs[0]) - world.node_tree.links.new(absorption_node.outputs[0], add_shader.inputs[1]) - scatter_node.inputs['Density'].default_value = SCATTER_INTENSITY - absorption_node.inputs['Density'].default_value = ABSORPTION_INTENSITY - bg_node.inputs[0].default_value = rand_color() +def series(length, function, pitch): + return list(map(lambda x: (0, x, function(x)), pitched_array(0.0, length, pitch))) -def add_frame(collection = bpy.data.objects, blacklist = set([])): - for obj in set(collection) - blacklist: - obj.keyframe_insert(data_path="rotation_euler", index=-1) - obj.keyframe_insert(data_path="location", index=-1) - obj.keyframe_insert(data_path="scale", index=-1) +def pitched_array(minimum, maximum, pitch): + return list(map(lambda x: (minimum + pitch * x), range(int((maximum - minimum) / pitch)))) + +def create_mesh(name, verts, faces, location, edges=[]): + mesh_data = bpy.data.meshes.new("mesh_data") + faces = faces if len(faces) == 0 else random_faces(verts) + mesh_data.from_pydata(verts, edges, faces) + mesh_data.update() + obj = bpy.data.objects.new(name, mesh_data) + obj.location = location + bpy.context.scene.objects.link(obj) + bpy.context.scene.objects.active = obj + center(obj) + return obj + +def camera_path(frame_number, radius = 5): + fx = lambda x: radius * math.cos(x) + fy = lambda y: radius * math.sin(y) + factor = (2 * math.pi / NUMBER_OF_FRAMES) + return list(map( lambda t: (fx(t * factor), fy(t * factor), INITIAL_CAMERA_LOCATION[2]), range(0, NUMBER_OF_FRAMES))) + +# Rotate vector +def rotate_vector(angle, axis, vin): + # Assume axis is a unit vector. + # Find squares of each axis component. + xsq = axis.x * axis.x + ysq = axis.y * axis.y + zsq = axis.z * axis.z + cosa = math.cos(angle) + sina = math.sin(angle) + complcos = 1.0 - cosa + complxy = complcos * axis.x * axis.y + complxz = complcos * axis.x * axis.z + complyz = complcos * axis.y * axis.z + sinx = sina * axis.x + siny = sina * axis.y + sinz = sina * axis.z + # Construct the x-axis (i). + ix = complcos * xsq + cosa + iy = complxy + sinz + iz = complxz - siny + # Construct the y-axis (j). + jx = complxy - sinz + jy = complcos * ysq + cosa + jz = complyz + sinx + # Construct the z-axis (k). + kx = complxz + siny + ky = complyz - sinx + kz = complcos * zsq + cosa + vout = mathutils.Vector((0.0, 0.0, 0.0)) + vout.x = ix * vin.x + jx * vin.y + kx * vin.z + vout.y = iy * vin.x + jy * vin.y + ky * vin.z + vout.z = iz * vin.x + jz * vin.y + kz * vin.z + return vout + +############# +# </geometry> +############# \ No newline at end of file