File size: 5,125 Bytes
2eba94f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 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)