Spaces:
Paused
Paused
File size: 5,473 Bytes
7e51d94 cad0c51 7e51d94 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
import argparse
import math
import os
import sys
from contextlib import contextmanager
from pathlib import Path
import bpy
# Add path to ImportLDraw module
root_dir = Path(__file__).resolve().parents[2]
sys.path.append(str(root_dir))
import ImportLDraw
from ImportLDraw.loadldraw.loadldraw import Options, Configure, loadFromFile, FileSystem
def render_bricks(
in_file: str,
out_file: str,
reposition_camera: bool = True,
square_image: bool = True,
instructions_look: bool = False,
fov: float = 45,
img_resolution: int = 512,
) -> None:
in_file = os.path.abspath(in_file)
out_file = os.path.abspath(out_file)
# Set the path to the ImportLDraw and LDraw libraries
plugin_path = Path(ImportLDraw.__file__).parent
ldraw_lib_path = os.environ.get('LDRAW_LIBRARY_PATH')
if not ldraw_lib_path or not os.path.exists(ldraw_lib_path):
# Default path to LDraw library is home directory
ldraw_lib_path = Path.home() / 'ldraw'
ldraw_lib_path = os.path.abspath(ldraw_lib_path)
# Initialize bpy
with stdout_redirected(os.devnull):
bpy.data.scenes[0].render.engine = 'CYCLES'
# Set the device_type
if sys.platform == 'darwin': # macOS
bpy.context.preferences.addons['cycles'].preferences.compute_device_type = 'METAL'
else:
bpy.context.preferences.addons['cycles'].preferences.compute_device_type = 'CUDA'
# Set the device and feature set
bpy.context.scene.cycles.device = 'GPU'
bpy.context.scene.cycles.samples = 512
# get_devices() to let Blender detects GPU device
bpy.context.preferences.addons['cycles'].preferences.get_devices()
print(bpy.context.preferences.addons['cycles'].preferences.compute_device_type)
for d in bpy.context.preferences.addons['cycles'].preferences.devices:
d['use'] = 0
if d['name'].startswith('NVIDIA') or d['name'].startswith('Apple'):
d['use'] = 1
print(d['name'], d['use'])
# Remove all objects but keep the camera
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_by_type(type='MESH')
bpy.ops.object.delete()
Options.ldrawDirectory = ldraw_lib_path
Options.instructionsLook = instructions_look
Options.useLogoStuds = True
Options.useUnofficialParts = True
Options.gaps = True
Options.studLogoDirectory = os.path.join(plugin_path, 'studs')
Options.LSynthDirectory = os.path.join(plugin_path, 'lsynth')
Options.verbose = 0
Options.overwriteExistingMaterials = True
Options.overwriteExistingMeshes = True
Options.scale = 0.01
Options.createInstances = True # Multiple bricks share geometry (recommended)
Options.removeDoubles = True # Remove duplicate vertices (recommended)
Options.positionObjectOnGroundAtOrigin = True # Centre the object at the origin, sitting on the z=0 plane
Options.flattenHierarchy = False # All parts are under the root object - no sub-models
Options.edgeSplit = True # Add the edge split modifier
Options.addBevelModifier = True # Adds a bevel modifier to each part (for rounded edges)
Options.bevelWidth = 0.5 # Bevel width
Options.addEnvironmentTexture = True
Options.scriptDirectory = os.path.join(plugin_path, 'loadldraw')
Options.addWorldEnvironmentTexture = True # Add an environment texture
Options.addGroundPlane = True # Add a ground plane
Options.setRenderSettings = True # Set render percentage, denoising
Options.removeDefaultObjects = True # Remove cube and lamp
Options.positionCamera = reposition_camera # Reposition the camera to a good place to see the scene
Options.cameraBorderPercent = 0.05 # Add a percentage border around the repositioned camera
Configure()
loadFromFile(None, FileSystem.locate(in_file))
if square_image:
bpy.context.scene.render.resolution_x = img_resolution
bpy.context.scene.render.resolution_y = img_resolution
bpy.context.scene.camera.data.angle = math.radians(fov)
bpy.context.scene.render.image_settings.file_format = 'PNG'
bpy.context.scene.render.filepath = out_file
# Redirect stdout to suppress the verbose render output
with stdout_redirected(os.devnull):
bpy.ops.render.render(write_still=True)
@contextmanager
def stdout_redirected(to: str):
"""
Redirects stdout to a file.
"""
fd = sys.stdout.fileno()
def _redirect_stdout(to_file):
sys.stdout.close() # + implicit flush()
os.dup2(to_file.fileno(), fd) # fd writes to 'to' file
sys.stdout = os.fdopen(fd, 'w') # Python writes to fd
with os.fdopen(os.dup(fd), 'w') as old_stdout:
with open(to, 'w') as file:
_redirect_stdout(file)
try:
yield # allow code to be run with the redirected stdout
finally:
_redirect_stdout(old_stdout) # restore stdout.
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--in_file', type=str, help='Path to LDR file')
parser.add_argument('--out_file', type=str, help='Path to output image file')
args = parser.parse_args()
# Get the absolute path of the input file
render_bricks(args.in_file, args.out_file, square_image=True, instructions_look=False)
print(f'Rendered image to {args.out_file}')
if __name__ == '__main__':
main()
|