feat: 添加深度图和法线图渲染功能

- 新增场景属性 `sna_render_resolution` 用于选择渲染分辨率(1024x1024 或 2048x2048)
- 修改 `Comfy_OT_Mvgen_B6229` 操作符,在执行后自动渲染深度图和法线图
- 新增 `_render_depth` 和 `_render_normal` 函数,从 `Materials.blend` 资产文件加载专用材质和节点组进行渲染
- 在 UI 面板中添加分辨率选择下拉菜单并更新按钮文本
- 在 `unregister` 函数中安全清理新增的场景属性
This commit is contained in:
2026-02-13 11:11:22 +08:00
parent 52166873a0
commit 3f0baae7d3
2 changed files with 135 additions and 7 deletions

View File

@@ -21,9 +21,20 @@ def register():
bpy.types.Scene.sna_activeobject = bpy.props.PointerProperty(type=bpy.types.Object)
bpy.types.Scene.sna_bakecam = bpy.props.PointerProperty(type=bpy.types.Object)
bpy.types.Scene.sna_activeobject_name = bpy.props.StringProperty()
bpy.types.Scene.sna_render_resolution = bpy.props.EnumProperty(
name="Render Resolution",
description="Resolution for depth and normal map renders",
items=[
('1024', '1024 x 1024', ''),
('2048', '2048 x 2048', ''),
],
default='1024',
)
def unregister():
if hasattr(bpy.types.Scene, "sna_render_resolution"):
del bpy.types.Scene.sna_render_resolution
if hasattr(bpy.types.Scene, "sna_activeobject_name"):
del bpy.types.Scene.sna_activeobject_name
if hasattr(bpy.types.Scene, "sna_bakecam"):

131
utils.py
View File

@@ -35,8 +35,9 @@ class Comfy_OT_Aovbake_Ad980(bpy.types.Operator):
bpy.data.scenes["Scene"].render.engine = "CYCLES"
bpy.data.scenes["Scene"].view_layers["ViewLayer"].use_pass_z = True
bpy.data.scenes["Scene"].cycles.samples = 16
bpy.data.scenes["Scene"].render.resolution_x = 1024
bpy.data.scenes["Scene"].render.resolution_y = 1024
res = int(bpy.context.scene.sna_render_resolution)
bpy.data.scenes["Scene"].render.resolution_x = res
bpy.data.scenes["Scene"].render.resolution_y = res
bpy.data.scenes["Scene"].view_layers["ViewLayer"].use_pass_normal = True
bpy.context.scene.sna_activeobject = (
bpy.context.view_layer.objects.active
@@ -103,10 +104,119 @@ class Comfy_OT_Aovbake_Ad980(bpy.types.Operator):
return self.execute(context)
def _ensure_output_dir():
"""Ensure output directory exists next to the blend file and return its path."""
blend_dir = os.path.dirname(bpy.data.filepath)
output_dir = os.path.join(blend_dir, 'output')
os.makedirs(output_dir, exist_ok=True)
return output_dir
def _append_from_materials_blend(data_type, name):
"""Append a data-block from Materials.blend if it doesn't already exist.
data_type: 'NodeTree' or 'Material'
"""
collection_map = {
'NodeTree': bpy.data.node_groups,
'Material': bpy.data.materials,
}
collection = collection_map[data_type]
if name in collection:
return collection[name]
blend_path = os.path.join(os.path.dirname(__file__), 'assets', 'Materials.blend')
bpy.ops.wm.append(
directory=blend_path + '\\' + data_type + '\\',
filename=name,
link=False,
)
return collection.get(name)
def _render_depth(operator):
"""Render depth map using Depth_Mat compositor NodeTree."""
scene = bpy.context.scene
output_dir = _ensure_output_dir()
# Append the Depth_Mat compositor node tree
depth_tree = _append_from_materials_blend('NodeTree', 'Depth_Mat')
if depth_tree is None:
operator.report({'ERROR'}, message='Failed to load Depth_Mat from Materials.blend')
return False
# Save original compositor state
orig_use_nodes = scene.use_nodes
orig_comp_group = scene.compositing_node_group
# Enable compositor and assign Depth_Mat as the compositing node group
scene.use_nodes = True
scene.compositing_node_group = depth_tree
# Setup output
scene.render.filepath = os.path.join(output_dir, 'depth.png')
scene.render.image_settings.file_format = 'PNG'
scene.render.image_settings.color_mode = 'RGB'
scene.view_layers["ViewLayer"].use_pass_z = True
# Render
bpy.ops.render.render(write_still=True)
# Restore original compositor state
scene.compositing_node_group = orig_comp_group
scene.use_nodes = orig_use_nodes
return True
def _render_normal(operator):
"""Render normal map by applying Normal_Mat material to active object."""
scene = bpy.context.scene
obj = scene.sna_activeobject
output_dir = _ensure_output_dir()
# Append the Normal_Mat material
normal_mat = _append_from_materials_blend('Material', 'Normal_Mat')
if normal_mat is None:
operator.report({'ERROR'}, message='Failed to load Normal_Mat from Materials.blend')
return False
# Find the converted object (the active object after convert)
converted_obj = bpy.context.view_layer.objects.active
if converted_obj is None or converted_obj.type != 'MESH':
converted_obj = obj
# Save original materials
orig_materials = [slot.material for slot in converted_obj.material_slots]
# Clear and assign Normal_Mat
converted_obj.data.materials.clear()
converted_obj.data.materials.append(normal_mat)
# Disable compositor for normal pass (direct render)
orig_use_nodes = scene.use_nodes
scene.use_nodes = False
# Setup output
scene.render.filepath = os.path.join(output_dir, 'normal.png')
scene.render.image_settings.file_format = 'PNG'
scene.render.image_settings.color_mode = 'RGB'
# Render
bpy.ops.render.render(write_still=True)
# Restore original materials
converted_obj.data.materials.clear()
for mat in orig_materials:
converted_obj.data.materials.append(mat)
scene.use_nodes = orig_use_nodes
return True
class Comfy_OT_Mvgen_B6229(bpy.types.Operator):
bl_idname = "comfyui.mvgen_b6229"
bl_label = "mvgen"
bl_description = ""
bl_label = "生成多视角视图"
bl_description = "Generate multi-view maps including depth and normal"
bl_options = {"REGISTER", "UNDO"}
@classmethod
@@ -149,6 +259,13 @@ class Comfy_OT_Mvgen_B6229(bpy.types.Operator):
bpy.ops.comfyui.aovbake_ad980('INVOKE_DEFAULT', )
bpy.data.objects[bpy.context.scene.sna_activeobject_name].modifiers.clear()
bpy.context.view_layer.objects[bpy.context.scene.sna_activeobject_name].hide_set(state=True, )
# --- Render Depth Map ---
_render_depth(self)
# --- Render Normal Map ---
_render_normal(self)
return {"FINISHED"}
def invoke(self, context, _event):
@@ -162,10 +279,10 @@ class Comfy_PT_ComfyProjectorPanel(bpy.types.Panel):
bl_region_type = "UI"
bl_category = "ComfyProjector"
def draw(self, _context):
def draw(self, context):
layout = self.layout
layout.operator("comfyui.aovbake_ad980", text="AOV Bake")
layout.operator("comfyui.mvgen_b6229", text="mvgen")
layout.prop(context.scene, "sna_render_resolution", text="Resolution")
layout.operator("comfyui.mvgen_b6229", text="生成多视角视图")
classes = (