Source code for ddg.visualization.blender.render

import os
from datetime import datetime

import bpy


[docs]def set_world_background(color=(1, 1, 1, 1), strength=0.2, world=None): """Set the world background color and emission. Parameters ---------- color : Sequence of 4 floats between 0 and 1 (default=(1, 1, 1, 1)) Color the background will have. strength : float (default=0.2) Emission strength of the background. world : bpy.types.World (default=None) World to modify. If None, use world of the current scene. """ if world is None: world = bpy.context.scene.world world_background_shader_inputs = world.node_tree.nodes["Background"].inputs background_color = world_background_shader_inputs[0] background_strength = world_background_shader_inputs[1] background_color.default_value = color background_strength.default_value = strength
[docs]def set_film_transparency(scene=None, transparent=True): """Set the transparency of the render's film. Parameters ---------- scene : bpy.types.Scene (default=None) Scene to apply the render setup to. If None, use the current scene. transparent : bool (default=True) If True make the film transparent, else use opaque world background. """ if scene is None: scene = bpy.context.scene scene.render.film_transparent = transparent
[docs]def setup_eevee_renderer(scene=None, samples=64, shadows_px="128"): """Set render settings for the Eevee engine. Parameters ---------- scene : bpy.types.Scene (default=None) Scene to which to apply the render settings. If None use the current scene. samples : int (default=64) Number of samples. shadows_px : enum in ["64", "128", "256", "512", "1024", "2048", "4096"], (default="128") Number of pixels to use for rendering of shadows. """ if scene is None: scene = bpy.context.scene render = scene.render render.engine = "BLENDER_EEVEE" scene.eevee.taa_render_samples = samples scene.eevee.shadow_cube_size = shadows_px scene.eevee.shadow_cascade_size = shadows_px
[docs]def setup_cycles_renderer( scene=None, device="CPU", noise_threshold=0.01, min_samples=0, max_samples=512, time_limit=5, denoise=False, persistent_data=True, ): """Set render settings for the Cycles engine with adaptive sampling. Parameters ---------- scene : bpy.types.Scene (default=None) Scene to which to apply the render settings. If None, use the current scene. device : str (default="CPU") Cycles render device, either "CPU" or "GPU". noise_threshold : float (default=0.01) The error threshold used in adaptive sampling. min_samples : int (default=0) Minimum number of samples. max_samples : int (default=512) Minimum number of samples. time_limit : float (default=5) Maximum time of a render. Zero means no time limit. denoise : bool (default=False) Whether or not to denoise the output after render. persistent_data : bool (default=True) Whether or not to keep render data for faster re-renders and animation renders. """ if scene is None: scene = bpy.context.scene scene.render.engine = "CYCLES" scene.render.use_persistent_data = persistent_data cycles = scene.cycles cycles.device = device cycles.use_adaptive_sampling = True cycles.samples = max_samples cycles.time_limit = time_limit cycles.adaptive_min_samples = min_samples cycles.adaptive_threshold = noise_threshold cycles.use_denoising = denoise
def _timestamp_path(path): """Get path to a timestamp subdirectory under path. Parameters ---------- path : str Prefix path to which to append a timestamp subdir. Returns ------- str """ timestamp = format(datetime.now(), "%y%m%d-%H%M") return os.path.join(path, timestamp, "")
[docs]def set_render_output_images( output_path, time=True, scene=None, file_format="PNG", alpha=True, quality=100, ): """Set the rendering output for an image sequence. Unless time=False, each time this function is called a new timestamp is set, and the output images will be saved under {output_path}/{timestamp}/ in order to isolate renders between sessions. Parameters ---------- output_path : str The directory path to which to save to ouput. time : bool (default=True) Whether or not to create a timestamp subdirectory and save the rendered images \ under it. scene : bpy.types.Scenes (default=None) The scene to which to apply the settings. If None use the current scene. file_format : str (default="PNG") The file format of the images. In upper letters. For example 'PNG' or 'JPEG2000' alpha : bool (default=True) Whether to use alpha in the output image. quality : int (default=100) Quality of the output image in percent. See Also -------- render_animation """ if scene is None: scene = bpy.context.scene render = scene.render render.image_settings.file_format = file_format if alpha: render.image_settings.color_mode = "RGBA" else: render.image_settings.color_mode = "RGB" render.image_settings.quality = quality render.filepath = ( _timestamp_path(output_path) if time else os.path.join(output_path, "") )
def _zfill(frame, end_frame): """Format frame with enough prefix zeros to match end_frame. Parameters ---------- frame : int Frame number to format. end_frame : int Reference frame. """ return str(frame).zfill(len(str(end_frame)))
[docs]def render_frame(frame, full_path, camera=None): """Render a frame to full_path. Parameters ---------- frame : int Frame to use for the render. full_path : str Output path with file name and extension. camera : bpy.types.Camera (default=None) Camera to use for the render. If None use the current scene camera. """ if camera: bpy.context.scene.camera = camera print(f"Rendering frame {frame}") bpy.context.scene.frame_current = frame bpy.ops.render.render() image = bpy.data.images["Render Result"] print(f"Saving {full_path}") image.save_render(full_path)
[docs]def render_animation(path, start=None, end=None, camera=None): """Render all frames between start and end to path. Parameters ---------- path : str Path of the output. start : int (default=None) Start frame. If None use current scene start frame. end : int (default=None) End frame. If None use current scene end frame. camera : bpy.types.Camera (default=None) Camera to use for the render. If None, use the current scene camera. See Also -------- set_render_output_images """ if start is None: start = bpy.context.scene.frame_start if end is None: end = bpy.context.scene.frame_end if camera: bpy.context.scene.camera = camera print(f"Rendering frames {start} to {end}...") for frame in range(start, end + 1): name = os.path.join(_timestamp_path(path), _zfill(frame, end)) render_frame(frame, name) print("Rendering done.")