# Rendering script # Run by calling the blender executable with -b -P <script_name> # Use `pry()` to pry into the script import sys, argparse, random, math, os, code, requests
def get_args():
parser = argparse.ArgumentParser() _, all_arguments = parser.parse_known_args() double_dash_index = all_arguments.index('--') script_args = all_arguments[double_dash_index + 1: ] parser.add_argument('-f', '--file', help="obj file to render") parser.add_argument('-n', '--shots-number', help="number of shots desired") parser.add_argument('-m', '--mode', help="quality mode: low | high") parser.add_argument('-p', '--path', help="root path of gem assets") parser.add_argument('-a', '--animate', help="render animation") # bool parser.add_argument('-frames', '--frames', help="number of frames") # int parser.add_argument('-normals', '--normals', help="normal render") # bool parser.add_argument('-d', '--debug', help="render blank scene with subject for testing purposes") # bool parser.add_argument('-width', '--width', help="width of render") # int parser.add_argument('-eight', '--eight', help="height of render") # int parser.add_argument('-assets', '--assets', help="user assets path") # string parser.add_argument('-canvas', '--canvas', help="selection of canvas modules by name") # string parser.add_argument('-post', '--post-process', help="post-processing") # bool parser.add_argument('-webhook', '--webhook', help="webhook url") # string parser.add_argument('-seed', '--seed', help="random seed") # int parsed_script_args, _ = parser.parse_known_args(script_args) return parsed_script_args
args = get_args() file = args.file mode = args.mode debug = (args.debug == 'True') path = str(args.path) animate = (args.animate == 'True') shots_number = int(args.shots_number) width = int(args.width) height = int(args.eight) post_process = (args.post_process == 'True') assets = args.assets webhook = args.webhook
# TODO: add proper args validation cycle ##################################### ##################################### #####################################
try:
NUMBER_OF_FRAMES = int(args.frames) NORMALS_RENDERING = (args.normals == 'True') random.seed = args.seed # Randomize module usage at runtime or pick selection from arguments canvas_path = os.path.dirname(__file__) + '/canvas' MODULES_AVAILABLE = args.canvas.split(",") if args.canvas else [ f[0:-3] for f in os.listdir(canvas_path) if os.path.isfile(os.path.join(canvas_path, f)) and f != 'canvas.py' and f != 'empty.py'] MODULES_ENABLED = MODULES_AVAILABLE if debug or args.canvas else random.sample(MODULES_AVAILABLE, int(random.uniform(0, len(MODULES_AVAILABLE)) + 1)) print("modules enabled: " + str(list(MODULES_ENABLED))) FIXTURES_FOLDER_PATH = assets if assets else path + '/../fixtures/' TEXTURE_FOLDER_PATH = FIXTURES_FOLDER_PATH + 'textures/' MODELS_FOLDER_PATH = FIXTURES_FOLDER_PATH + 'models/' HEIGHT_MAP_FOLDER_PATH = FIXTURES_FOLDER_PATH + 'height_maps/' FONT_FOLDER_PATH = FIXTURES_FOLDER_PATH + 'fonts/' SCENE_NAME = "glitch3d" REFLECTOR_SCALE = random.uniform(9, 10) REFLECTOR_STRENGTH = random.uniform(12, 15) REFLECTOR_LOCATION_PADDING = random.uniform(10, 12) REPLACE_TARGET = str(random.uniform(0, 9)) REPLACEMENT = str(random.uniform(0, 9)) OSL_ENABLED = True ORIGIN = (0,0,2) CANVAS_BOUNDARY = 6 SCATTER_INTENSITY = 0.015 ABSORPTION_INTENSITY = 0.25 DISPLAY_SCALE = (2, 2, 2) PRIMITIVES = ['Pyramid', 'Cube'] 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) RENDER_OUTPUT_PATHS = [] FIXED_CAMERA = False FUNCTIONS = { (lambda x: math.sin(x) * math.cos(20*x)): 4, (lambda x: math.sin(x) * math.sin(20*x)): 3, (lambda x: INITIAL_CAMERA_LOCATION[2]): 2, (lambda x: x) : 2, math.sin : 1, math.cos : 1, (lambda x: 0.5 * math.sin(0.5*x) * math.cos(x)) : 1, (lambda x: random.uniform(1, 10) * math.cos(x) ** 3) : 1, (lambda x: random.uniform(1, 10)) : 1, (lambda x: random.uniform(1, 2) + random.uniform(0.75, 3) * math.sin(random.uniform(0.1, 1)*x) + math.cos(random.uniform(0.75, 5)*x)) : 1, (lambda x: math.sin(math.pi*x) + x + 3 * math.pi) : 1, (lambda x: x**3 + math.cos(x/2)) : 2, (lambda x: random.uniform(1, 10) * math.sin(x)): 3 } import importlib.util, os, ntpath, bpy, datetime, math, random, mathutils, random, sys, logging, string, colorsys, code, numpy from subprocess import call def load_file(file_path): # load and define function and vars in global namespace, yolo exec(open(file_path).read(), globals()) def load_module_path(file_path): print("loading module " + file_path) sys.path.append(os.path.dirname(os.path.expanduser(file_path))) sys.path.append(os.environ['PYTHON_MODULES_PATH']) # Create directory for renders directory = os.path.dirname('./renders') if not os.path.exists(directory): os.makedirs(directory) load_file(os.path.join(path + '/glitch3d/bpy/helpers.py')) load_file(os.path.join(path + '/glitch3d/bpy/render_settings.py')) load_file(os.path.join(path + '/glitch3d/bpy/lighting.py')) # Create groups for s in ['texts', 'lines', 'displays', 'reflectors', 'neons']: bpy.data.groups.new(s) for primitive in PRIMITIVES: bpy.data.groups.new(primitive.lower().title()) FISHEYE = random.sample([True, False], 1) COLORS = rand_color_palette(5) CAMERA_OFFSET = 5 INITIAL_CAMERA_LOCATION = (CAMERA_OFFSET, CAMERA_OFFSET, random.uniform(0, 8)) TEXT_FILE_PATH = FIXTURES_FOLDER_PATH + 'texts/strings.txt' print("Loading materials...") MATERIALS_NAMES = [] load_osl_materials(FIXTURES_FOLDER_PATH + 'osl_shaders/') for mat in bpy.data.materials: # merge base scene materials + osl shaders if mat.name != 'emission': MATERIALS_NAMES.append(mat.name) print("Detected " + str(len(MATERIALS_NAMES)) + " materials in base scene: " + str(MATERIALS_NAMES)) # Scene new_scene = bpy.data.scenes[SCENE_NAME] bpy.context.screen.scene = new_scene SCENE = new_scene SCENE.render.engine = 'CYCLES' flush_objects() camera_data = bpy.data.cameras.new(name = 'CAMERA') bpy.data.objects.new('CAMERA', object_data=camera_data) CAMERA = bpy.data.objects['CAMERA'] new_scene.objects.link(CAMERA) SCENE.camera = CAMERA CAMERA.location = INITIAL_CAMERA_LOCATION SCENE.frame_start = 0 SCENE.frame_end = NUMBER_OF_FRAMES if FISHEYE: CAMERA.data.type = 'PANO' CAMERA.data.cycles.panorama_type = 'FISHEYE_EQUISOLID' CAMERA.data.cycles.fisheye_lens = 12 CAMERA.data.cycles.fisheye_fov = 2.5 CAMERA.data.sensor_width = 20 CAMERA.data.sensor_height = 20 ##################################### ##################################### ##################################### # Load model model_path = os.path.join(file) bpy.ops.import_scene.obj(filepath = model_path, use_edges=True) SUBJECT_NAME = '0_glitch3d_' + ntpath.basename(file).replace("_glitched.obj", '') SUBJECT = bpy.data.objects[SUBJECT_NAME] SUBJECT.select = True center(SUBJECT) SUBJECT.location = ORIGIN let_there_be_light(SCENE) random.shuffle(list(MODULES_ENABLED)) for module in MODULES_ENABLED: load_module_path(os.path.join(path + '/glitch3d/bpy/canvas', module + '.py')) mod = __import__(module) new_canvas = eval("mod." + module[:1].upper() + module[1:] + "(locals())") new_canvas.render() render_settings(animate, mode, NORMALS_RENDERING, width, height, debug) print('Rendering images with resolution: ' + str(SCENE.render.resolution_x) + ' x ' + str(SCENE.render.resolution_y)) if bpy.context.scene.rigidbody_world: bpy.ops.rigidbody.bake_to_keyframes(frame_start=0, frame_end=NUMBER_OF_FRAMES) CAMERA_PATH = camera_path(NUMBER_OF_FRAMES) for frame in range(0, NUMBER_OF_FRAMES): bpy.context.scene.frame_set(frame) bpy.context.scene.camera.location = CAMERA_PATH[frame] SUBJECT.rotation_euler.z += math.radians(1) look_at(SUBJECT) add_frame([bpy.context.scene.camera], ["location", "rotation_euler"]) if animate: print('ANIMATION RENDERING BEGIN') output_path = output_name(model_path) print('AVI file -> ' + output_path) shoot(output_path) else: print('STILL RENDERING BEGIN') for index in range(0, shots_number): frame_cursor = int(index * (bpy.context.scene.frame_end / shots_number)) print('>> FRAME #' + str(frame_cursor)) bpy.context.scene.frame_set(int(bpy.context.scene.frame_end/(index+1))) SUBJECT.rotation_euler.z = math.radians(index * (360.0 / shots_number)) output_path = output_name(model_path, index) print("-------------------------- " + str(index) + " --------------------------") print("PNG file -> " + output_path) shoot(output_path) # Save scene as .blend file bpy.ops.wm.save_as_mainfile(filepath=output_name(model_path) + '.blend') print("Files rendered with " + str(NUMBER_OF_FRAMES) + " frames in simulation:") for p in RENDER_OUTPUT_PATHS: print(p) if post_process: load_file(os.path.join(path + '/glitch3d/bpy/post-processing/optimize.py')) if shots_number > 1: load_file(os.path.join(path + '/glitch3d/bpy/post-processing/average.py')) if shots_number > 10: load_file(os.path.join(path + '/glitch3d/bpy/post-processing/mosaic.py')) load_file(os.path.join(path + '/glitch3d/bpy/post-processing/palette.py')) print('FINISHED ¯\_(ツ)_/¯ with seed: ' + random.seed) sys.exit(0)
except Exception as e:
if webhook: requests.post(webhook, data={'error': str(e)}) if debug: raise e # See error sys.exit(1) # Just return 1 error code in production