0xZohar's picture
Upload code/cube3d/render/render_bricks.py with huggingface_hub
cad0c51 verified
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()