Spaces:
Build error
Build error
| import bpy | |
| import sys | |
| import os | |
| def create_tex_node(nodes, img_path, label, color_space, location): | |
| img = bpy.data.images.load(img_path) | |
| tex = nodes.new(type='ShaderNodeTexImage') | |
| tex.image = img | |
| tex.label = label | |
| tex.location = location | |
| tex.image.colorspace_settings.name = color_space | |
| return tex | |
| def setup_environment_lighting(hdri_path): | |
| if not bpy.data.worlds: | |
| bpy.data.worlds.new(name="World") | |
| if bpy.context.scene.world is None: | |
| bpy.context.scene.world = bpy.data.worlds[0] | |
| world = bpy.context.scene.world | |
| world.use_nodes = True | |
| nodes = world.node_tree.nodes | |
| links = world.node_tree.links | |
| nodes.clear() | |
| env_tex = nodes.new(type="ShaderNodeTexEnvironment") | |
| env_tex.image = bpy.data.images.load(hdri_path) | |
| env_tex.location = (-300, 0) | |
| bg = nodes.new(type="ShaderNodeBackground") | |
| bg.location = (0, 0) | |
| output = nodes.new(type="ShaderNodeOutputWorld") | |
| output.location = (300, 0) | |
| links.new(env_tex.outputs["Color"], bg.inputs["Color"]) | |
| links.new(bg.outputs["Background"], output.inputs["Surface"]) | |
| def setup_gpu_rendering(): | |
| bpy.context.scene.render.engine = 'CYCLES' | |
| prefs = bpy.context.preferences | |
| cprefs = prefs.addons['cycles'].preferences | |
| # Choose backend depending on GPU type: 'CUDA', 'OPTIX', 'HIP', 'METAL' | |
| cprefs.compute_device_type = 'CUDA' | |
| bpy.context.scene.cycles.device = 'GPU' | |
| def generate_blend(obj_path, base_color_path, normal_map_path, roughness_path, metallic_path, output_blend): | |
| # Reset scene | |
| bpy.ops.wm.read_factory_settings(use_empty=True) | |
| # Import OBJ | |
| bpy.ops.import_scene.obj(filepath=obj_path) | |
| obj = bpy.context.selected_objects[0] | |
| # Create material | |
| mat = bpy.data.materials.new(name="BRDF_Material") | |
| mat.use_nodes = True | |
| nodes = mat.node_tree.nodes | |
| links = mat.node_tree.links | |
| nodes.clear() | |
| output = nodes.new(type='ShaderNodeOutputMaterial') | |
| output.location = (400, 0) | |
| principled = nodes.new(type='ShaderNodeBsdfPrincipled') | |
| principled.location = (100, 0) | |
| links.new(principled.outputs['BSDF'], output.inputs['Surface']) | |
| # Base Color | |
| base_color = create_tex_node(nodes, base_color_path, "Base Color", 'sRGB', (-600, 200)) | |
| links.new(base_color.outputs['Color'], principled.inputs['Base Color']) | |
| # Roughness | |
| rough = create_tex_node(nodes, roughness_path, "Roughness", 'Non-Color', (-600, 0)) | |
| links.new(rough.outputs['Color'], principled.inputs['Roughness']) | |
| # Metallic | |
| metal = create_tex_node(nodes, metallic_path, "Metallic", 'Non-Color', (-600, -200)) | |
| links.new(metal.outputs['Color'], principled.inputs['Metallic']) | |
| # Normal Map | |
| normal_tex = create_tex_node(nodes, normal_map_path, "Normal Map", 'Non-Color', (-800, -400)) | |
| normal_map = nodes.new(type='ShaderNodeNormalMap') | |
| normal_map.location = (-400, -400) | |
| links.new(normal_tex.outputs['Color'], normal_map.inputs['Color']) | |
| links.new(normal_map.outputs['Normal'], principled.inputs['Normal']) | |
| # Assign material | |
| if obj.data.materials: | |
| obj.data.materials[0] = mat | |
| else: | |
| obj.data.materials.append(mat) | |
| # Global Illumination using Blender's default forest HDRI | |
| blender_data_path = bpy.utils.resource_path('LOCAL') | |
| forest_hdri_path = os.path.join(blender_data_path, "datafiles", "studiolights", "world", "forest.exr") | |
| print(f"Using HDRI: {forest_hdri_path}") | |
| setup_environment_lighting(forest_hdri_path) | |
| # GPU rendering setup | |
| setup_gpu_rendering() | |
| # Pack textures into .blend | |
| bpy.ops.file.pack_all() | |
| # Set the 3D View to Rendered mode and focus on object | |
| for area in bpy.context.screen.areas: | |
| if area.type == 'VIEW_3D': | |
| for space in area.spaces: | |
| if space.type == 'VIEW_3D': | |
| space.shading.type = 'RENDERED' # Set viewport shading to Rendered | |
| for region in area.regions: | |
| if region.type == 'WINDOW': | |
| override = {'area': area, 'region': region, 'scene': bpy.context.scene} | |
| bpy.ops.view3d.view_all(override, center=True) | |
| elif area.type == 'NODE_EDITOR': | |
| for space in area.spaces: | |
| if space.type == 'NODE_EDITOR': | |
| space.tree_type = 'ShaderNodeTree' # Switch to Shader Editor | |
| space.shader_type = 'OBJECT' | |
| # Optional: Switch active workspace to Shading (if it exists) | |
| for workspace in bpy.data.workspaces: | |
| if workspace.name == 'Shading': | |
| bpy.context.window.workspace = workspace | |
| break | |
| # Save the .blend file | |
| bpy.ops.wm.save_as_mainfile(filepath=output_blend) | |
| print(f"✅ Saved .blend file with BRDF, HDRI, GPU: {output_blend}") | |
| if __name__ == "__main__": | |
| argv = sys.argv | |
| argv = argv[argv.index("--") + 1:] # Only use args after "--" | |
| if len(argv) != 6: | |
| print("Usage:\n blender --background --python generate_blend.py -- obj base_color normal roughness metallic output.blend") | |
| sys.exit(1) | |
| generate_blend(*argv) | |