[Blender] обертка аддона Bake Wrangler #73

Closed
opened 2023-05-27 20:50:28 +03:00 by brothermechanic · 10 comments
brothermechanic commented 2023-05-27 20:50:28 +03:00 (Migrated from gitlab.com)

Bake Wrangler имеет нодовый интерфейс. Идея исключить задание параметров для Bake Wrangler, исползуя наш Robossembler Naming Convention. Затем импортировать все обратно в сцену.

Пример структуры сцены блендера, готовой для запекания

Scene
├── коллекция Baking
│   ├── коллекция High-Poly
│   │    ├── коллекция <деталь_1_hp>
│   │    ├── коллекция <деталь_2_hp>
│   │    └── ...
│   ├── коллекция Low-Poly
│   │    ├── объект <деталь_1_lp>
│   │    ├── объект <деталь_2_lp>
│   │    └── ...
│   └── коллекция Export
│        ├── объект <деталь_1>
│        ├── объект <деталь_2>
│        └── ...
└── коллекция Остальное в сцене
  • Low-Poly объекты сравниваются с High-Poly коллекциями по маске имени
  • запекаются сырые PBR паки: деталь_1_pbr, деталь_2_pbr...
  • фильтр-композинг-сжатие текстур в технической (другой) blender сцене
  • создание коллекции Export и автоассоциация их с запеченными текстурами
Bake Wrangler имеет нодовый интерфейс. Идея исключить задание параметров для Bake Wrangler, исползуя наш Robossembler Naming Convention. Затем импортировать все обратно в сцену. Пример структуры сцены блендера, готовой для запекания ``` Scene ├── коллекция Baking │ ├── коллекция High-Poly │ │ ├── коллекция <деталь_1_hp> │ │ ├── коллекция <деталь_2_hp> │ │ └── ... │ ├── коллекция Low-Poly │ │ ├── объект <деталь_1_lp> │ │ ├── объект <деталь_2_lp> │ │ └── ... │ └── коллекция Export │ ├── объект <деталь_1> │ ├── объект <деталь_2> │ └── ... └── коллекция Остальное в сцене ``` - Low-Poly объекты сравниваются с High-Poly коллекциями по маске имени - запекаются сырые PBR паки: деталь_1_pbr, деталь_2_pbr... - фильтр-композинг-сжатие текстур в технической (другой) blender сцене - создание коллекции Export и автоассоциация их с запеченными текстурами
brothermechanic commented 2023-05-27 21:19:59 +03:00 (Migrated from gitlab.com)

changed title from [Blender] {-адаптирование Bake Wrangler аддона в качестве библиотеки-} to [Blender] {+обертка аддона Bake Wrangler+}

changed title from **[Blender] {-адаптирование Bake Wrangler аддона в качестве библиотеки-}** to **[Blender] {+обертка аддона Bake Wrangler+}**
brothermechanic commented 2023-05-27 21:19:59 +03:00 (Migrated from gitlab.com)

changed the description

changed the description
brothermechanic commented 2023-05-27 21:20:23 +03:00 (Migrated from gitlab.com)

changed the description

changed the description
brothermechanic commented 2023-05-27 21:21:17 +03:00 (Migrated from gitlab.com)

changed the description

changed the description
brothermechanic commented 2023-05-27 21:22:19 +03:00 (Migrated from gitlab.com)

assigned to @brothermechanic

assigned to @brothermechanic
brothermechanic commented 2023-06-04 17:46:06 +03:00 (Migrated from gitlab.com)
import bpy
import os
from BakeWrangler.nodes.node_tree import BW_TREE_VERSION

asm_name = os.path.basename(bpy.context.blend_data.filepath).split('.')[0]
asm_path = os.path.dirname(bpy.context.blend_data.filepath)
textures_path = os.path.join(asm_path,"textures").replace('\\', '/')
bake_path = os.path.join(textures_path,"bake")
if not os.path.isdir(bake_path):
    os.makedirs(bake_path)
resolution = 4096
tree_name = 'robossembler'
lowpoly_col_name = 'Lowpoly Parts'

# create node tree
##bpy.ops.node.new_node_tree(type='BakeWrangler_Tree', name=tree_name)
##tree = bpy.data.node_groups[tree_name]
tree = bpy.data.node_groups.new(name=tree_name, type='BakeWrangler_Tree')

# TODO
#bpy.context.area.type = "NODE_EDITOR"
bpy.data.workspaces['Shading'].screens['Shading'].areas[0].type = 'NODE_EDITOR'
#bpy.context.space_data.tree_type = "BakeWrangler_Tree"
bpy.data.workspaces['Shading'].screens['Shading'].areas[0].spaces[0].tree_type = 'BakeWrangler_Tree'
#bpy.context.space_data.path.start(tree)
bpy.data.workspaces['Shading'].screens['Shading'].areas[0].spaces[0].path.start(tree)


tree.tree_version = BW_TREE_VERSION
tree.initialised = True

# clear default nodes
for node in tree.nodes:
    tree.nodes.remove(node)

# bw settings
tree.nodes.new('BakeWrangler_MeshSettings').location = (0, 0)
tree.nodes.new('BakeWrangler_SampleSettings').location = (200, 0)
tree.nodes.new('BakeWrangler_PassSettings').location = (400, 0)
tree.nodes.new('BakeWrangler_OutputSettings').location = (600, 0)

tree.nodes['Mesh Settings'].pinned = True
tree.nodes['Mesh Settings']['margin'] = 8
tree.nodes['Mesh Settings']['ray_dist'] = 0.002
tree.nodes['Sample Settings'].pinned = True
tree.nodes['Sample Settings']['bake_samples'] = 4
tree.nodes['Pass Settings'].pinned = True
tree.nodes['Pass Settings']['res_bake_x'] = resolution
tree.nodes['Pass Settings']['res_bake_y'] = resolution
tree.nodes['Output Settings'].pinned = True
tree.nodes['Output Settings']['img_xres'] = resolution
tree.nodes['Output Settings']['img_yres'] = resolution
tree.nodes['Output Settings']['img_type'] = 2  # PNG
tree.nodes['Output Settings']['img_compression'] = 50
tree.nodes['Output Settings']['img_color_mode'] = 1  # RGB

## batch bake node
node_batch = tree.nodes.new('BakeWrangler_Output_Batch_Bake')
node_batch.location = (1000, -500)

node_y_pos = 0
pass_socket = 0
for lp in bpy.data.collections[lowpoly_col_name].objects:
    """ run for eatch low poly object """
    hp = bpy.data.collections[(lp.name[:-2] + 'hp')]
    img_name = '{}_{}'.format(asm_name, lp.name[:-2])

    node_hp = tree.nodes.new('BakeWrangler_Input_ObjectList')

    node_hp.location = (-1000, node_y_pos -500)
    node_lp = tree.nodes.new('BakeWrangler_Bake_Mesh')
    node_lp.location = (-700, node_y_pos -500)

    node_hp.filter_collection = True
    node_hp.inputs['Object'].value = hp
    node_hp.inputs['Object'].recursive = True
    node_lp.inputs['Target'].value = lp

    tree.links.new(node_hp.outputs['Objects'], node_lp.inputs['Source'])

    # bake passes
    ## Diffuse
    node_d_pass = tree.nodes.new('BakeWrangler_Bake_Pass')
    node_d_pass.location = (-200, node_y_pos -500)
    node_d_img = tree.nodes.new('BakeWrangler_Output_Image_Path')
    node_d_img.location = (200, node_y_pos -500)

    tree.links.new(node_d_pass.outputs['Color'], node_d_img.inputs['Color'])

    node_d_pass.bake_cat = 'PBR'
    node_d_pass.bake_pbr = 'ALBEDO'
    node_d_img.inputs['Color'].suffix = 'D'
    node_d_img.inputs['Split Output'].disp_path = bake_path
    node_d_img.inputs['Split Output'].img_name = img_name

    ## Curvature
    node_c_pass = tree.nodes.new('BakeWrangler_Bake_Pass')
    node_c_pass.location = (-200, node_y_pos -1000)
    node_c_img = tree.nodes.new('BakeWrangler_Output_Image_Path')
    node_c_img.location = (200, node_y_pos -1000)

    tree.links.new(node_c_pass.outputs['Color'], node_c_img.inputs['Color'])

    node_c_pass.bake_cat = 'WRANG'
    node_c_pass.bake_wrang = 'CURVATURE'
    node_c_img.inputs['Color'].suffix = 'C'
    node_c_img.inputs['Split Output'].disp_path = bake_path
    node_c_img.inputs['Split Output'].img_name = img_name

    ## Normal
    node_n_pass = tree.nodes.new('BakeWrangler_Bake_Pass')
    #tree.nodes['Bake Pass.001'].name = 'normal_pass'
    node_n_pass.location = (-200, node_y_pos -1500)
    node_n_img = tree.nodes.new('BakeWrangler_Output_Image_Path')
    node_n_img.location = (200, node_y_pos -1500)

    tree.links.new(node_n_pass.outputs['Color'], node_n_img.inputs['Color'])

    node_n_pass.bake_cat = 'CORE'
    node_n_pass.bake_core = 'NORMAL'
    node_n_img.inputs['Color'].suffix = 'N'
    node_n_img.inputs['Split Output'].disp_path = bake_path
    node_n_img.inputs['Split Output'].img_name = img_name

    ## AO
    node_ao_pass = tree.nodes.new('BakeWrangler_Bake_Pass')
    node_ao_pass.location = (-200, node_y_pos -2000)
    node_ao_img = tree.nodes.new('BakeWrangler_Output_Image_Path')
    node_ao_img.location = (200, node_y_pos -2000)

    tree.links.new(node_ao_pass.outputs['Color'], node_ao_img.inputs['Color'])

    node_ao_pass.bake_cat = 'CORE'
    node_ao_pass.bake_core = 'AO'
    node_ao_pass.bake_samples = 32
    node_ao_img.inputs['Color'].suffix = 'AO'
    node_ao_img.inputs['Split Output'].disp_path = bake_path
    node_ao_img.inputs['Split Output'].img_name = img_name

    ## Roughness
    node_r_pass = tree.nodes.new('BakeWrangler_Bake_Pass')
    node_r_pass.location = (-200, node_y_pos -2500)
    node_r_img = tree.nodes.new('BakeWrangler_Output_Image_Path')
    node_r_img.location = (200, node_y_pos -2500)

    tree.links.new(node_r_pass.outputs['Color'], node_r_img.inputs['Color'])

    node_r_pass.bake_cat = 'CORE'
    node_r_pass.bake_core = 'ROUGHNESS'
    node_r_img.inputs['Color'].suffix = 'R'
    node_r_img.inputs['Split Output'].disp_path = bake_path
    node_r_img.inputs['Split Output'].img_name = img_name

    ## Metallic
    node_m_pass = tree.nodes.new('BakeWrangler_Bake_Pass')
    node_m_pass.location = (-200, node_y_pos -3000)
    node_m_img = tree.nodes.new('BakeWrangler_Output_Image_Path')
    node_m_img.location = (200, node_y_pos -3000)

    tree.links.new(node_m_pass.outputs['Color'], node_m_img.inputs['Color'])

    node_m_pass.bake_cat = 'PBR'
    node_m_pass.bake_pbr = 'METALLIC'
    node_m_img.inputs['Color'].suffix = 'M'
    node_m_img.inputs['Split Output'].disp_path = bake_path
    node_m_img.inputs['Split Output'].img_name = img_name

    ## UV
    node_uv_pass = tree.nodes.new('BakeWrangler_Bake_Pass')
    node_uv_pass.location = (-200, node_y_pos -3500)
    node_uv_img = tree.nodes.new('BakeWrangler_Output_Image_Path')
    node_uv_img.location = (200, node_y_pos -3500)

    tree.links.new(node_uv_pass.outputs['Color'], node_uv_img.inputs['Color'])

    node_uv_pass.bake_cat = 'WRANG'
    node_uv_pass.bake_wrang = 'ISLANDID'
    node_uv_img.inputs['Color'].suffix = 'UV'
    node_uv_img.inputs['Split Output'].disp_path = bake_path
    node_uv_img.inputs['Split Output'].img_name = img_name

    # connect meshes to passes
    tree.links.new(node_lp.outputs['Mesh'], node_d_pass.inputs[1])
    tree.links.new(node_lp.outputs['Mesh'], node_c_pass.inputs[1])
    tree.links.new(node_lp.outputs['Mesh'], node_n_pass.inputs[1])
    tree.links.new(node_lp.outputs['Mesh'], node_ao_pass.inputs[1])
    tree.links.new(node_lp.outputs['Mesh'], node_r_pass.inputs[1])
    tree.links.new(node_lp.outputs['Mesh'], node_m_pass.inputs[1])
    tree.links.new(node_lp.outputs['Mesh'], node_uv_pass.inputs[1])

    ## batch bake node
    tree.links.new(node_d_img.outputs['Bake'], node_batch.inputs[pass_socket])
    pass_socket += 1
    tree.links.new(node_c_img.outputs['Bake'], node_batch.inputs[pass_socket])
    pass_socket += 1
    tree.links.new(node_n_img.outputs['Bake'], node_batch.inputs[pass_socket])
    pass_socket += 1
    tree.links.new(node_ao_img.outputs['Bake'], node_batch.inputs[pass_socket])
    pass_socket += 1
    tree.links.new(node_r_img.outputs['Bake'], node_batch.inputs[pass_socket])
    pass_socket += 1
    tree.links.new(node_m_img.outputs['Bake'], node_batch.inputs[pass_socket])
    pass_socket += 1
    tree.links.new(node_uv_img.outputs['Bake'], node_batch.inputs[pass_socket])
    pass_socket += 1

    node_y_pos -= 4000

bpy.ops.bake_wrangler.bake_pass(tree=tree_name, node="Batch Bake", sock=-1)

```python import bpy import os from BakeWrangler.nodes.node_tree import BW_TREE_VERSION asm_name = os.path.basename(bpy.context.blend_data.filepath).split('.')[0] asm_path = os.path.dirname(bpy.context.blend_data.filepath) textures_path = os.path.join(asm_path,"textures").replace('\\', '/') bake_path = os.path.join(textures_path,"bake") if not os.path.isdir(bake_path): os.makedirs(bake_path) resolution = 4096 tree_name = 'robossembler' lowpoly_col_name = 'Lowpoly Parts' # create node tree ##bpy.ops.node.new_node_tree(type='BakeWrangler_Tree', name=tree_name) ##tree = bpy.data.node_groups[tree_name] tree = bpy.data.node_groups.new(name=tree_name, type='BakeWrangler_Tree') # TODO #bpy.context.area.type = "NODE_EDITOR" bpy.data.workspaces['Shading'].screens['Shading'].areas[0].type = 'NODE_EDITOR' #bpy.context.space_data.tree_type = "BakeWrangler_Tree" bpy.data.workspaces['Shading'].screens['Shading'].areas[0].spaces[0].tree_type = 'BakeWrangler_Tree' #bpy.context.space_data.path.start(tree) bpy.data.workspaces['Shading'].screens['Shading'].areas[0].spaces[0].path.start(tree) tree.tree_version = BW_TREE_VERSION tree.initialised = True # clear default nodes for node in tree.nodes: tree.nodes.remove(node) # bw settings tree.nodes.new('BakeWrangler_MeshSettings').location = (0, 0) tree.nodes.new('BakeWrangler_SampleSettings').location = (200, 0) tree.nodes.new('BakeWrangler_PassSettings').location = (400, 0) tree.nodes.new('BakeWrangler_OutputSettings').location = (600, 0) tree.nodes['Mesh Settings'].pinned = True tree.nodes['Mesh Settings']['margin'] = 8 tree.nodes['Mesh Settings']['ray_dist'] = 0.002 tree.nodes['Sample Settings'].pinned = True tree.nodes['Sample Settings']['bake_samples'] = 4 tree.nodes['Pass Settings'].pinned = True tree.nodes['Pass Settings']['res_bake_x'] = resolution tree.nodes['Pass Settings']['res_bake_y'] = resolution tree.nodes['Output Settings'].pinned = True tree.nodes['Output Settings']['img_xres'] = resolution tree.nodes['Output Settings']['img_yres'] = resolution tree.nodes['Output Settings']['img_type'] = 2 # PNG tree.nodes['Output Settings']['img_compression'] = 50 tree.nodes['Output Settings']['img_color_mode'] = 1 # RGB ## batch bake node node_batch = tree.nodes.new('BakeWrangler_Output_Batch_Bake') node_batch.location = (1000, -500) node_y_pos = 0 pass_socket = 0 for lp in bpy.data.collections[lowpoly_col_name].objects: """ run for eatch low poly object """ hp = bpy.data.collections[(lp.name[:-2] + 'hp')] img_name = '{}_{}'.format(asm_name, lp.name[:-2]) node_hp = tree.nodes.new('BakeWrangler_Input_ObjectList') node_hp.location = (-1000, node_y_pos -500) node_lp = tree.nodes.new('BakeWrangler_Bake_Mesh') node_lp.location = (-700, node_y_pos -500) node_hp.filter_collection = True node_hp.inputs['Object'].value = hp node_hp.inputs['Object'].recursive = True node_lp.inputs['Target'].value = lp tree.links.new(node_hp.outputs['Objects'], node_lp.inputs['Source']) # bake passes ## Diffuse node_d_pass = tree.nodes.new('BakeWrangler_Bake_Pass') node_d_pass.location = (-200, node_y_pos -500) node_d_img = tree.nodes.new('BakeWrangler_Output_Image_Path') node_d_img.location = (200, node_y_pos -500) tree.links.new(node_d_pass.outputs['Color'], node_d_img.inputs['Color']) node_d_pass.bake_cat = 'PBR' node_d_pass.bake_pbr = 'ALBEDO' node_d_img.inputs['Color'].suffix = 'D' node_d_img.inputs['Split Output'].disp_path = bake_path node_d_img.inputs['Split Output'].img_name = img_name ## Curvature node_c_pass = tree.nodes.new('BakeWrangler_Bake_Pass') node_c_pass.location = (-200, node_y_pos -1000) node_c_img = tree.nodes.new('BakeWrangler_Output_Image_Path') node_c_img.location = (200, node_y_pos -1000) tree.links.new(node_c_pass.outputs['Color'], node_c_img.inputs['Color']) node_c_pass.bake_cat = 'WRANG' node_c_pass.bake_wrang = 'CURVATURE' node_c_img.inputs['Color'].suffix = 'C' node_c_img.inputs['Split Output'].disp_path = bake_path node_c_img.inputs['Split Output'].img_name = img_name ## Normal node_n_pass = tree.nodes.new('BakeWrangler_Bake_Pass') #tree.nodes['Bake Pass.001'].name = 'normal_pass' node_n_pass.location = (-200, node_y_pos -1500) node_n_img = tree.nodes.new('BakeWrangler_Output_Image_Path') node_n_img.location = (200, node_y_pos -1500) tree.links.new(node_n_pass.outputs['Color'], node_n_img.inputs['Color']) node_n_pass.bake_cat = 'CORE' node_n_pass.bake_core = 'NORMAL' node_n_img.inputs['Color'].suffix = 'N' node_n_img.inputs['Split Output'].disp_path = bake_path node_n_img.inputs['Split Output'].img_name = img_name ## AO node_ao_pass = tree.nodes.new('BakeWrangler_Bake_Pass') node_ao_pass.location = (-200, node_y_pos -2000) node_ao_img = tree.nodes.new('BakeWrangler_Output_Image_Path') node_ao_img.location = (200, node_y_pos -2000) tree.links.new(node_ao_pass.outputs['Color'], node_ao_img.inputs['Color']) node_ao_pass.bake_cat = 'CORE' node_ao_pass.bake_core = 'AO' node_ao_pass.bake_samples = 32 node_ao_img.inputs['Color'].suffix = 'AO' node_ao_img.inputs['Split Output'].disp_path = bake_path node_ao_img.inputs['Split Output'].img_name = img_name ## Roughness node_r_pass = tree.nodes.new('BakeWrangler_Bake_Pass') node_r_pass.location = (-200, node_y_pos -2500) node_r_img = tree.nodes.new('BakeWrangler_Output_Image_Path') node_r_img.location = (200, node_y_pos -2500) tree.links.new(node_r_pass.outputs['Color'], node_r_img.inputs['Color']) node_r_pass.bake_cat = 'CORE' node_r_pass.bake_core = 'ROUGHNESS' node_r_img.inputs['Color'].suffix = 'R' node_r_img.inputs['Split Output'].disp_path = bake_path node_r_img.inputs['Split Output'].img_name = img_name ## Metallic node_m_pass = tree.nodes.new('BakeWrangler_Bake_Pass') node_m_pass.location = (-200, node_y_pos -3000) node_m_img = tree.nodes.new('BakeWrangler_Output_Image_Path') node_m_img.location = (200, node_y_pos -3000) tree.links.new(node_m_pass.outputs['Color'], node_m_img.inputs['Color']) node_m_pass.bake_cat = 'PBR' node_m_pass.bake_pbr = 'METALLIC' node_m_img.inputs['Color'].suffix = 'M' node_m_img.inputs['Split Output'].disp_path = bake_path node_m_img.inputs['Split Output'].img_name = img_name ## UV node_uv_pass = tree.nodes.new('BakeWrangler_Bake_Pass') node_uv_pass.location = (-200, node_y_pos -3500) node_uv_img = tree.nodes.new('BakeWrangler_Output_Image_Path') node_uv_img.location = (200, node_y_pos -3500) tree.links.new(node_uv_pass.outputs['Color'], node_uv_img.inputs['Color']) node_uv_pass.bake_cat = 'WRANG' node_uv_pass.bake_wrang = 'ISLANDID' node_uv_img.inputs['Color'].suffix = 'UV' node_uv_img.inputs['Split Output'].disp_path = bake_path node_uv_img.inputs['Split Output'].img_name = img_name # connect meshes to passes tree.links.new(node_lp.outputs['Mesh'], node_d_pass.inputs[1]) tree.links.new(node_lp.outputs['Mesh'], node_c_pass.inputs[1]) tree.links.new(node_lp.outputs['Mesh'], node_n_pass.inputs[1]) tree.links.new(node_lp.outputs['Mesh'], node_ao_pass.inputs[1]) tree.links.new(node_lp.outputs['Mesh'], node_r_pass.inputs[1]) tree.links.new(node_lp.outputs['Mesh'], node_m_pass.inputs[1]) tree.links.new(node_lp.outputs['Mesh'], node_uv_pass.inputs[1]) ## batch bake node tree.links.new(node_d_img.outputs['Bake'], node_batch.inputs[pass_socket]) pass_socket += 1 tree.links.new(node_c_img.outputs['Bake'], node_batch.inputs[pass_socket]) pass_socket += 1 tree.links.new(node_n_img.outputs['Bake'], node_batch.inputs[pass_socket]) pass_socket += 1 tree.links.new(node_ao_img.outputs['Bake'], node_batch.inputs[pass_socket]) pass_socket += 1 tree.links.new(node_r_img.outputs['Bake'], node_batch.inputs[pass_socket]) pass_socket += 1 tree.links.new(node_m_img.outputs['Bake'], node_batch.inputs[pass_socket]) pass_socket += 1 tree.links.new(node_uv_img.outputs['Bake'], node_batch.inputs[pass_socket]) pass_socket += 1 node_y_pos -= 4000 bpy.ops.bake_wrangler.bake_pass(tree=tree_name, node="Batch Bake", sock=-1) ```
brothermechanic commented 2023-07-05 17:26:52 +03:00 (Migrated from gitlab.com)

обновил скрипт

обновил скрипт
brothermechanic commented 2023-10-18 09:20:20 +03:00 (Migrated from gitlab.com)

marked this issue as related to #90

marked this issue as related to #90
brothermechanic commented 2023-10-18 09:22:03 +03:00 (Migrated from gitlab.com)

created branch 73-blender_bake-wrangler to address this issue

created branch [`73-blender_bake-wrangler`](/robossembler/framework/-/compare/master...73-blender_bake-wrangler) to address this issue
brothermechanic commented 2023-10-18 09:22:20 +03:00 (Migrated from gitlab.com)

mentioned in merge request !61

mentioned in merge request !61
movefasta (Migrated from gitlab.com) closed this issue 2023-10-25 13:54:39 +03:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
robossembler/framework#73
No description provided.