irg/auto_room.py

1021 lines
42 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Blender 4.2兼容版自动化脚本(白模版本)
自动创建等轴测房间并渲染白模
"""
import subprocess
import os
import sys
# Blender可执行文件路径
BLENDER_PATH = r"D:\Program Files\Blender Foundation\blender-4.2.11-windows-x64\blender.exe"
# 简化版Blender脚本只渲染白模
BLENDER_SIMPLE_SCRIPT = '''
import bpy
import bmesh
import os
import math
import time
def disable_problematic_addons():
"""禁用可能导致问题的插件"""
try:
# 禁用可能冲突的插件
problematic_addons = ['bl_tool']
for addon in problematic_addons:
if addon in bpy.context.preferences.addons:
bpy.ops.preferences.addon_disable(module=addon)
print(f"已禁用插件: {addon}")
except:
pass
def create_isometric_room():
"""创建等轴测房间使用isometric_room_gen插件"""
try:
# 禁用问题插件
#disable_problematic_addons()
# 清除默认立方体
if "Cube" in bpy.data.objects:
bpy.data.objects.remove(bpy.data.objects["Cube"], do_unlink=True)
# 设置3D游标位置到原点
bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
# 检查isometric_room_gen插件
if not hasattr(bpy.context.scene, 'sna_room_width'):
print("错误: isometric_room_gen插件未正确加载")
return False
# 设置isometric_room_gen插件参数
# 房间设置
bpy.context.scene.sna_wall_thickness = 0.10 # 墙体厚度10cm
bpy.context.scene.sna_room_width = 5.0 # 房间宽度8米
bpy.context.scene.sna_room_depth = 8.0 # 房间深度4米
bpy.context.scene.sna_room_height = 3.0 # 房间高度3米
# 窗户设置 - 不设置窗户
bpy.context.scene.sna_windows_enum = 'NONE' # 无窗户
# 设置房间类型为方形
bpy.context.scene.sna_style = 'Square'
# 设置拱门参数
bpy.context.scene.sna_arch_settings = True # 启用拱门设置
bpy.context.scene.sna_arch_placement = 'NONE' # 设置为后墙拱门BACK 不设置拱门NONE
bpy.context.scene.sna_arch_width = 1.2 # 拱门宽度1.2米
bpy.context.scene.sna_arch_height = 2.4 # 拱门高度2.4米
bpy.context.scene.sna_arch_thickness = 0.10 # 拱门厚度0.1米
# 找到3D视图区域
view3d_area = None
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
view3d_area = area
break
if view3d_area is None:
print("错误: 找不到3D视图区域")
return False
# 临时切换到3D视图上下文
with bpy.context.temp_override(area=view3d_area):
# 使用isometric_room_gen插件创建房间
result = bpy.ops.sna.gen_room_1803a()
if result == {'FINISHED'}:
print("等轴测房间创建完成!")
print(f"房间尺寸: {bpy.context.scene.sna_room_width}m x {bpy.context.scene.sna_room_depth}m x {bpy.context.scene.sna_room_height}m")
print(f"墙体厚度: {bpy.context.scene.sna_wall_thickness}m")
# 将生成的房间在Z轴上向下移动墙体厚度的距离
wall_thickness = bpy.context.scene.sna_wall_thickness
# 查找生成的房间对象
room_object = None
for obj in bpy.data.objects:
if obj.name == "IRG_IsoRoom_WithCeiling":
room_object = obj
break
return True
else:
print("房间创建失败")
return False
except Exception as e:
print(f"创建房间时出现错误: {str(e)}")
import traceback
traceback.print_exc()
return False
def create_door_with_archimesh():
"""使用archimesh插件创建门"""
try:
print("开始创建archimesh门...")
# 检查archimesh插件是否可用
if not hasattr(bpy.ops.mesh, 'archimesh_door'):
print("错误: archimesh插件未正确加载")
print("请确保archimesh插件已安装并启用")
return False
# 设置3D游标到原点
bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
# 找到3D视图区域
view3d_area = None
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
view3d_area = area
break
if view3d_area is None:
print("错误: 找不到3D视图区域")
return False
# 临时切换到3D视图上下文
with bpy.context.temp_override(area=view3d_area):
# 先创建门(使用默认参数)
result = bpy.ops.mesh.archimesh_door()
if result == {'FINISHED'}:
print("archimesh门创建完成!")
# 等待一帧以确保对象创建完成
bpy.context.view_layer.update()
# 找到刚创建的门组对象Door_Group
door_group = None
for obj in bpy.data.objects:
if obj.name == "Door_Group":
door_group = obj
break
if door_group:
print(f"找到门组: {door_group.name}")
# 查找主门对象DoorFrame
main_door_obj = None
for obj in bpy.data.objects:
if obj.name == "DoorFrame":
main_door_obj = obj
break
if main_door_obj and hasattr(main_door_obj, 'DoorObjectGenerator'):
# 获取门属性
door_props = main_door_obj.DoorObjectGenerator[0]
print("设置门属性...")
print(f"找到主门对象: {main_door_obj.name}")
# 先设置基本属性
door_props.frame_width = 1.0 # 门框宽度
door_props.frame_height = 2.1 # 门框高度
door_props.frame_thick = 0.08 # 门框厚度
door_props.openside = '1' # 右侧开门
# 设置门模型和把手这些会触发update_object回调
print("设置门模型为2...")
door_props.model = '2' # 门模型2
print("设置门把手为1...")
door_props.handle = '1' # 门把手1
print(f"门属性设置完成:")
print(f" - 门框宽度: {door_props.frame_width}")
print(f" - 门框高度: {door_props.frame_height}")
print(f" - 门框厚度: {door_props.frame_thick}")
print(f" - 开门方向: {door_props.openside}")
print(f" - 门模型: {door_props.model}")
print(f" - 门把手: {door_props.handle}")
# 等待更新完成
bpy.context.view_layer.update()
# 验证设置是否生效
print("验证门属性设置:")
print(f" - 当前门模型: {door_props.model}")
print(f" - 当前门把手: {door_props.handle}")
# 强制触发更新(如果需要)
try:
# 重新设置属性以触发更新
current_model = door_props.model
current_handle = door_props.handle
door_props.model = '1' # 临时设置为其他值
bpy.context.view_layer.update()
door_props.model = current_model # 设置回目标值
bpy.context.view_layer.update()
print("已强制触发门模型更新")
except Exception as update_error:
print(f"强制更新时出现错误: {update_error}")
# 在修改门全部属性后进行位移和旋转
print("开始移动和旋转门组...")
try:
door_group1 = None
for obj in bpy.data.objects:
if obj.name == "Door_Group":
door_group1 = obj
break
# 设置位置
door_group1.location = (0.0, 6.0, 0.0)
print(f"已将门组移动到位置: {door_group1.location}")
# 设置旋转
door_group1.rotation_euler = (math.radians(0), math.radians(0), math.radians(90)) # 旋转(0, 0, 90度)
print(f"已将门组旋转到: (0°, 0°, 90°)")
# 强制更新
bpy.context.view_layer.update()
print("门组位移和旋转完成")
except Exception as move_error:
print(f"移动和旋转门组时出现错误: {move_error}")
else:
print("警告: 未找到主门对象或DoorObjectGenerator属性")
# 尝试查找其他可能的门属性
for obj in bpy.data.objects:
if hasattr(obj, 'archimesh_door'):
print(f"找到archimesh_door属性在对象: {obj.name}")
# 打印门组的所有子对象信息
print("门组包含的对象:")
for obj in bpy.data.objects:
if obj.parent == door_group:
print(f" - {obj.name} (位置: {obj.location})")
return True
else:
print("警告: 未找到Door_Group对象")
# 尝试查找其他可能的门对象
door_objects = [obj for obj in bpy.data.objects if "Door" in obj.name]
if door_objects:
print("找到的门相关对象:")
for obj in door_objects:
print(f" - {obj.name} (类型: {obj.type})")
# 尝试移动第一个找到的门对象
first_door = door_objects[0]
first_door.location = (0.0, 2.0, 0.0)
print(f"已移动 {first_door.name} 到位置: {first_door.location}")
return True
else:
print("未找到任何门相关对象")
return False
else:
print("门创建失败")
return False
except Exception as e:
print(f"创建门时出现错误: {str(e)}")
import traceback
traceback.print_exc()
return False
def create_window_with_archimesh():
"""使用archimesh插件创建落地窗"""
try:
print("开始创建archimesh落地窗...")
# 检查archimesh插件是否可用
if not hasattr(bpy.ops.mesh, 'archimesh_winpanel'):
print("错误: archimesh插件未正确加载")
print("请确保archimesh插件已安装并启用")
return False
# 设置3D游标到原点
bpy.context.scene.cursor.location = (0.0, 0.0, 0.0)
# 找到3D视图区域
view3d_area = None
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
view3d_area = area
break
if view3d_area is None:
print("错误: 找不到3D视图区域")
return False
# 临时切换到3D视图上下文
with bpy.context.temp_override(area=view3d_area):
# 创建窗户
result = bpy.ops.mesh.archimesh_winpanel()
if result == {'FINISHED'}:
print("archimesh落地窗创建完成!")
# 等待一帧以确保对象创建完成
bpy.context.view_layer.update()
# 找到刚创建的窗户组对象Window_Group
window_group = None
for obj in bpy.data.objects:
if obj.name == "Window_Group":
window_group = obj
break
if window_group:
print(f"找到窗户组: {window_group.name}")
# 查找主窗户对象Window
main_window_obj = None
for obj in bpy.data.objects:
if obj.name == "Window":
main_window_obj = obj
break
if main_window_obj and hasattr(main_window_obj, 'WindowPanelGenerator'):
# 获取窗户属性
window_props = main_window_obj.WindowPanelGenerator[0]
print("设置窗户属性...")
print(f"找到主窗户对象: {main_window_obj.name}")
# 设置窗户的基本属性
window_props.gen = 4 # 4扇窗户水平
window_props.yuk = 1 # 1行垂直
window_props.kl1 = 5 # 外框厚度5cm
window_props.kl2 = 5 # 竖框厚度5cm
window_props.fk = 2 # 内框厚度2cm
# 设置窗户尺寸
window_props.gnx0 = 80 # 第1扇窗户宽度80cm
window_props.gnx1 = 80 # 第2扇窗户宽度80cm
window_props.gnx2 = 80 # 第3扇窗户宽度80cm
window_props.gnx3 = 80 # 第4扇窗户宽度80cm
window_props.gny0 = 250 # 窗户高度250cm落地窗
# 设置窗户类型为平窗
window_props.UST = '1' # 平窗
window_props.r = 0 # 旋转角度0度
# 设置窗台
window_props.mr = False # 启用窗台
#window_props.mr1 = 4 # 窗台高度4cm
#window_props.mr2 = 4 # 窗台深度4cm
#window_props.mr3 = 20 # 窗台宽度20cm
#window_props.mr4 = 0 # 窗台延伸0cm
# 设置材质
window_props.mt1 = '1' # 外框材质PVC
window_props.mt2 = '1' # 内框材质塑料
# 设置窗户开启状态
window_props.k00 = True # 第1扇窗户开启
window_props.k01 = True # 第2扇窗户开启
window_props.k02 = True # 第3扇窗户开启
window_props.k03 = True # 第4扇窗户开启如果有的话
print(f"窗户属性设置完成:")
print(f" - 水平扇数: {window_props.gen}")
print(f" - 垂直行数: {window_props.yuk}")
print(f" - 外框厚度: {window_props.kl1}cm")
print(f" - 竖框厚度: {window_props.kl2}cm")
print(f" - 内框厚度: {window_props.fk}cm")
print(f" - 窗户高度: {window_props.gny0}cm")
print(f" - 窗户类型: 平窗")
print(f" - 窗台: 启用")
print(f" - 窗户开启状态: k00={window_props.k00}, k01={window_props.k01}, k02={window_props.k02}, k03={window_props.k03}")
# 修复窗户玻璃材质
print("修复窗户玻璃材质...")
fix_window_glass_material()
# 等待更新完成
bpy.context.view_layer.update()
# 强制触发更新(如果需要)
try:
# 重新设置属性以触发更新
current_gen = window_props.gen
current_gny0 = window_props.gny0
window_props.gen = 2 # 临时设置为其他值
bpy.context.view_layer.update()
window_props.gen = current_gen # 设置回目标值
bpy.context.view_layer.update()
print("已强制触发窗户更新")
except Exception as update_error:
print(f"强制更新时出现错误: {update_error}")
# 在修改落地窗全部属性后进行位移和旋转
print("开始移动和旋转窗户组...")
try:
window_group1 = None
for obj in bpy.data.objects:
if obj.name == "Window_Group":
window_group1 = obj
break
# 设置位置
window_group1.location = (0, 4.0, 0.0)
print(f"已将窗户组移动到位置: {window_group1.location}")
# 设置旋转
window_group1.rotation_euler = (math.radians(0), math.radians(0), math.radians(90)) # 旋转(0, 0, 90度)
print(f"已将窗户组旋转到: (0°, 0°, 90°)")
# 强制更新
bpy.context.view_layer.update()
print("窗户组位移和旋转完成")
except Exception as move_error:
print(f"移动和旋转窗户组时出现错误: {move_error}")
else:
print("警告: 未找到主窗户对象或WindowPanelGenerator属性")
# 尝试查找其他可能的窗户属性
for obj in bpy.data.objects:
if hasattr(obj, 'archimesh_window'):
print(f"找到archimesh_window属性在对象: {obj.name}")
# 打印窗户组的所有子对象信息
print("窗户组包含的对象:")
for obj in bpy.data.objects:
if obj.parent == window_group:
print(f" - {obj.name} (位置: {obj.location})")
return True
else:
print("警告: 未找到Window_Group对象")
# 尝试查找其他可能的窗户对象
window_objects = [obj for obj in bpy.data.objects if "Window" in obj.name]
if window_objects:
print("找到的窗户相关对象:")
for obj in window_objects:
print(f" - {obj.name} (类型: {obj.type})")
# 尝试移动第一个找到的窗户对象
first_window = window_objects[0]
first_window.location = (0.0, 1.96, 0.0)
print(f"已移动 {first_window.name} 到位置: {first_window.location}")
return True
else:
print("未找到任何窗户相关对象")
return False
else:
print("窗户创建失败")
return False
except Exception as e:
print(f"创建窗户时出现错误: {str(e)}")
import traceback
traceback.print_exc()
return False
def fix_window_glass_material():
"""修复窗户玻璃材质将其改为高透BSDF"""
try:
print("开始修复窗户玻璃材质...")
# 查找Window_Group下的Window对象
window_group = None
for obj in bpy.data.objects:
if obj.name == "Window_Group":
window_group = obj
break
if not window_group:
print("未找到Window_Group对象")
return False
# 查找Window对象Window_Group的子对象
window_obj = None
for obj in bpy.data.objects:
if obj.name == "Window" and obj.parent == window_group:
window_obj = obj
break
if not window_obj:
print("未找到Window对象")
return False
print(f"找到Window对象: {window_obj.name}")
# 检查Window对象的材质
if not window_obj.material_slots:
print("Window对象没有材质槽")
return False
# 遍历所有材质槽
for slot in window_obj.material_slots:
if slot.material and "Glass" in slot.material.name:
print(f"找到Glass材质: {slot.material.name}")
# 启用节点编辑
slot.material.use_nodes = True
# 清除所有现有节点
slot.material.node_tree.nodes.clear()
# 创建半透BSDF节点
translucent_bsdf = slot.material.node_tree.nodes.new(type='ShaderNodeBsdfTranslucent')
translucent_bsdf.location = (0, 0)
# 设置半透BSDF参数
translucent_bsdf.inputs['Color'].default_value = (0.95, 0.98, 1.0, 1.0) # 几乎无色
# 半透BSDF节点没有Weight参数只有Color参数
# 创建材质输出节点
material_output = slot.material.node_tree.nodes.new(type='ShaderNodeOutputMaterial')
material_output.location = (300, 0)
# 连接节点
slot.material.node_tree.links.new(
translucent_bsdf.outputs['BSDF'],
material_output.inputs['Surface']
)
# 设置材质混合模式为Alpha Blend
slot.material.blend_method = 'BLEND'
print(f"已成功修改Glass材质为半透BSDF")
print(f" - 半透颜色: 几乎无色")
print(f" - 混合模式: Alpha Blend")
return True
print("未找到Glass材质")
return False
except Exception as e:
print(f"修复玻璃材质时出现错误: {str(e)}")
import traceback
traceback.print_exc()
return False
def setup_render_settings():
"""设置渲染参数EEVEE渲染优化速度"""
scene = bpy.context.scene
# 设置渲染引擎为EEVEE
scene.render.engine = 'BLENDER_EEVEE_NEXT'
print("已设置渲染引擎为EEVEE")
# 启用Freestyle线条渲染
# scene.render.use_freestyle = True
# print("已启用Freestyle线条渲染")
# # 配置Freestyle线条设置
# if hasattr(scene, 'view_layers'):
# view_layer = scene.view_layers[0] # 获取第一个视图层
# view_layer.use_freestyle = True
# # 获取Freestyle线条设置
# freestyle = view_layer.freestyle_settings
# # 启用线条渲染
# freestyle.use_smoothness = True
# freestyle.use_culling = True
# 设置线条宽度 - 使用正确的API 没有生效
# 设置世界环境
if hasattr(scene, 'world') and scene.world:
# 启用世界节点
scene.world.use_nodes = True
# 清除现有节点
scene.world.node_tree.nodes.clear()
# 创建自发光节点
emission_node = scene.world.node_tree.nodes.new(type='ShaderNodeEmission')
emission_node.location = (0, 0)
# 设置HSV颜色色相0饱和度0明度0.051Alpha 1
# 转换为RGBHSV(0, 0, 0.051) = RGB(0.051, 0.051, 0.051)
emission_node.inputs['Color'].default_value = (0.051, 0.051, 0.051, 1.0) # 深灰色
emission_node.inputs['Strength'].default_value = 8.0 # 强度8
# 创建世界输出节点
world_output = scene.world.node_tree.nodes.new(type='ShaderNodeOutputWorld')
world_output.location = (300, 0)
# 连接节点
scene.world.node_tree.links.new(
emission_node.outputs['Emission'],
world_output.inputs['Surface']
)
print("已设置世界环境为自发光")
print(f" - 颜色: HSV(0, 0, 0.051) = RGB(0.051, 0.051, 0.051)")
print(f" - 强度: 8.0")
# 设置EEVEE采样降低采样数提高速度
try:
if hasattr(scene.eevee, 'taa_render_samples'):
scene.eevee.taa_render_samples = 32 # 从64降低到32
print(f"已设置EEVEE渲染采样: {scene.eevee.taa_render_samples}")
elif hasattr(scene.eevee, 'taa_samples'):
scene.eevee.taa_samples = 32 # 从64降低到32
print(f"已设置EEVEE采样: {scene.eevee.taa_samples}")
else:
print("警告: 无法找到EEVEE采样设置使用默认值")
# 启用屏幕空间反射(简化设置)
if hasattr(scene.eevee, 'use_ssr'):
scene.eevee.use_ssr = True
print("已启用屏幕空间反射")
# 启用环境光遮蔽(简化设置)
if hasattr(scene.eevee, 'use_gtao'):
scene.eevee.use_gtao = True
print("已启用环境光遮蔽")
# 启用透明渲染(必要)
if hasattr(scene.eevee, 'use_transparent'):
scene.eevee.use_transparent = True
print("已启用透明渲染")
# 设置透明混合模式(必要)
if hasattr(scene.render, 'film_transparent'):
scene.render.film_transparent = True
print("已启用透明背景")
except AttributeError as e:
print(f"EEVEE设置警告: {e}")
print("使用默认EEVEE渲染设置")
# 设置分辨率
scene.render.resolution_x = 1080 # 宽度1080px
scene.render.resolution_y = 2400 # 高度2400px
scene.render.resolution_percentage = 100
# 设置输出格式
scene.render.image_settings.file_format = 'PNG'
scene.render.image_settings.color_mode = 'RGBA' # 支持透明
# 设置输出路径到桌面
desktop_path = os.path.join(os.path.expanduser("~"), "Desktop")
timestamp = time.strftime("%m%d_%H%M%S") # 日期_时分秒格式
filename = f"isometric_{timestamp}.png"
scene.render.filepath = os.path.join(desktop_path, filename)
print(f"EEVEE渲染设置完成输出路径: {scene.render.filepath}")
return scene.render.filepath
def setup_camera_and_lighting():
"""设置摄像机和照明160W点光源 + 150W日光"""
# 计算灯光高度(房间高度减一米)
room_height = 3.0
light_height = room_height - 1.0
# 设置摄像机
camera = None
if "Camera" in bpy.data.objects:
camera = bpy.data.objects["Camera"]
elif "Isometric Camera" in bpy.data.objects:
camera = bpy.data.objects["Isometric Camera"]
else:
# 创建新摄像机
bpy.ops.object.camera_add(location=(7, -7, 5))
camera = bpy.context.active_object
camera.name = "Isometric Camera"
# 设置摄像机位置和旋转
# 房间宽度5.0米,相机位置调整为(房间宽度-1, 1, 1.3)
room_width = 5.0
camera.location = (room_width - 1, 1, 1.3) # 相机位置:(4, 1, 1.3)
camera.rotation_euler = (math.radians(90), math.radians(0), math.radians(30)) # 相机旋转
# 设置为透视投影
camera.data.type = 'PERSP'
camera.data.lens = 35.0 # 35mm焦距
camera.data.sensor_width = 35.0 # 35mm传感器
camera.data.sensor_fit = 'AUTO' # 自动适配
# 设置为场景的活动摄像机
bpy.context.scene.camera = camera
print("摄像机设置完成")
print(f"相机位置: ({camera.location.x}, {camera.location.y}, {camera.location.z})")
# 设置蜡笔-场景线条画
print("设置蜡笔-场景线条画...")
try:
# 启用蜡笔渲染 - 在Blender 4.2中使用不同的属性
if hasattr(bpy.context.scene.render, 'use_grease_pencil'):
bpy.context.scene.render.use_grease_pencil = True
print("已启用蜡笔渲染")
else:
# 在Blender 4.2中,蜡笔渲染可能默认启用
print("蜡笔渲染已默认启用")
# 创建蜡笔对象(如果不存在)- 使用LINEART SCENE类型
grease_pencil_name = "Grease_pencil"
grease_pencil_obj = None
# 检查是否已存在蜡笔对象
for obj in bpy.data.objects:
if obj.name == grease_pencil_name and obj.type == 'GPENCIL':
grease_pencil_obj = obj
print(f"找到现有蜡笔对象: {grease_pencil_name}")
break
if grease_pencil_obj is None:
# 创建新的蜡笔对象
bpy.ops.object.gpencil_add(type='LINEART_SCENE')
grease_pencil_obj = bpy.context.active_object
grease_pencil_obj.name = grease_pencil_name
# 等待一帧以确保数据创建完成
bpy.context.view_layer.update()
print(f"已创建蜡笔场景线条画对象: {grease_pencil_name}")
# 设置笔画厚度缩放为0.38
if grease_pencil_obj and grease_pencil_obj.data:
grease_pencil_data = grease_pencil_obj.data
grease_pencil_data.pixel_factor = 0.38
print(f"已设置蜡笔笔画厚度缩放: {grease_pencil_data.pixel_factor}")
else:
print("警告: 未找到蜡笔数据")
# 确保蜡笔对象在渲染时可见
if grease_pencil_obj:
grease_pencil_obj.hide_render = False
grease_pencil_obj.hide_viewport = False
print("蜡笔对象已设置为可见")
print("蜡笔-场景线条画设置完成")
except Exception as e:
print(f"设置蜡笔时出现错误: {e}")
print("继续执行其他设置...")
# 创建第一个160W点光源房间中心
# try:
# # 计算点光源位置(房间中心上方)
# room_length = 4.0 # Y轴
# room_width = 8.0 # X轴4+4
# # 第一个点光源位置:房间中心上方
# light_x = 0 # X轴中心
# light_y = 0 # Y轴中心
# light_z = light_height
# # 创建第一个点光源
# bpy.ops.object.light_add(type='POINT', location=(light_x, light_y, light_z))
# point_light1 = bpy.context.active_object
# point_light1.name = "Main Point Light"
# point_light1.data.energy = 160 # 160W
# # 设置软衰减(简化设置)
# point_light1.data.shadow_soft_size = 0.5 # 0.5米半径,产生柔和阴影
# point_light1.data.use_shadow = True # 启用阴影
# print(f"已创建第一个点光源160W")
# print(f"点光源位置: x={light_x}, y={light_y}, z={light_z}")
# except Exception as e:
# print(f"创建第一个点光源时出错: {e}")
# 创建第二个150W日光位置12, 7, 6
# try:
# # 第二个光源位置 - 调整到窗户后方更远的位置
# light2_x = -6
# light2_y = 7 # 让日光更远
# light2_z = 6 # 提高高度
# # 创建日光
# bpy.ops.object.light_add(type='SUN', location=(light2_x, light2_y, light2_z))
# sun_light = bpy.context.active_object
# sun_light.name = "Sun Light"
# sun_light.data.energy = 20
# # 调整日光旋转角度,让光线更直接地照射窗户
# sun_light.rotation_euler = (math.radians(0), math.radians(-60), math.radians(0)) # 简化旋转角度
# # 设置日光属性(简化设置)
# sun_light.data.angle = 0.05 # 从0.1改为0.05,让阴影更锐利
# sun_light.data.use_shadow = True # 启用阴影
# print(f"已创建日光20W")
# print(f"日光位置: x={light2_x}, y={light2_y}, z={light2_z}")
# print(f"日光旋转: x={-70}°, y={0}°, z={0}°")
# except Exception as e:
# print(f"创建日光时出错: {e}")
print("照明设置完成")
print("灯光类型: 点光源 + 日光")
print(f"衰减类型: 点光源软衰减 + 日光平行光")
print(f"阴影设置: 启用,柔和阴影")
print(f"主灯光高度: {light_height}米 (房间高度减一米)")
print(f"日光位置: (0, 10, 6)米,旋转: (-70°, 0°, 0°)")
def render_scene():
"""渲染场景"""
print("开始EEVEE渲染...")
# 执行渲染
bpy.ops.render.render(write_still=True)
print(f"EEVEE渲染完成! 图片保存在: {bpy.context.scene.render.filepath}")
return bpy.context.scene.render.filepath
def main():
"""主函数"""
print("=" * 60)
print("开始自动创建等轴测房间并EEVEE渲染")
print("=" * 60)
try:
# 1. 创建房间
print("1. 创建等轴测房间...")
if not create_isometric_room():
print("房间创建失败,停止执行")
return False
# 2. 创建落地窗
print("2. 创建archimesh落地窗...")
if not create_window_with_archimesh():
print("落地窗创建失败,但继续执行")
# 不中断执行,窗户创建失败不影响渲染
# 2. 创建门
print("2. 创建archimesh门...")
if not create_door_with_archimesh():
print("落地窗创建失败,但继续执行")
# 不中断执行,窗户创建失败不影响渲染
# 3. 设置渲染参数EEVEE
print("3. 设置EEVEE渲染参数...")
output_path = setup_render_settings()
# 4. 设置摄像机和照明
print("4. 设置摄像机和照明...")
setup_camera_and_lighting()
# 5. 渲染场景
print("5. 开始EEVEE渲染...")
final_path = render_scene()
print("=" * 60)
print("EEVEE渲染完成!")
print(f"渲染图片已保存到桌面: {final_path}")
print("=" * 60)
return True
except Exception as e:
print(f"执行过程中出现错误: {str(e)}")
import traceback
traceback.print_exc()
return False
# 执行主函数
if __name__ == "__main__":
main()
'''
def check_blender_exists():
"""检查Blender是否存在于指定路径"""
if not os.path.exists(BLENDER_PATH):
print(f"错误: 在路径 '{BLENDER_PATH}' 找不到Blender")
print("请检查Blender安装路径是否正确")
return False
return True
def create_temp_script():
"""创建临时的Blender脚本文件"""
script_path = os.path.join(os.getcwd(), "temp_simple_blender_script.py")
with open(script_path, 'w', encoding='utf-8') as f:
f.write(BLENDER_SIMPLE_SCRIPT)
return script_path
def launch_blender_simple():
"""启动Blender并执行简化版自动化脚本"""
if not check_blender_exists():
return False
# 创建临时脚本文件
script_path = create_temp_script()
try:
print("正在启动Blender白模版本...")
print(f"Blender路径: {BLENDER_PATH}")
print("特点:")
print("- 不设置材质,使用默认白色材质")
print("- 快速渲染")
print("- 兼容Blender 4.2")
print("- 自动保存到桌面")
# 构建命令行参数
cmd = [
BLENDER_PATH,
"--background", # 后台运行模式
"--disable-crash-handler", # 禁用崩溃处理器
"--python", script_path # 执行Python脚本
]
print("\n开始执行白模渲染流程...")
# 启动Blender并等待完成
process = subprocess.run(
cmd,
capture_output=True,
text=True,
encoding='utf-8',
timeout=300 # 5分钟超时
)
# 输出结果
if process.stdout:
print("Blender输出:")
# 过滤掉重复的错误信息
lines = process.stdout.split('\n')
filtered_lines = []
for line in lines:
if not ("AttributeError: 'NoneType' object has no attribute 'idname'" in line or
"Error in bpy.app.handlers.depsgraph_update_post" in line):
filtered_lines.append(line)
print('\n'.join(filtered_lines))
if process.stderr and not "rotate_tool.py" in process.stderr:
print("重要错误信息:")
print(process.stderr)
if process.returncode == 0:
print("\n✅ 白模渲染执行成功!")
print("白模图片应该已经保存到桌面")
return True
else:
print(f"\n❌ 执行失败,返回码: {process.returncode}")
return False
except subprocess.TimeoutExpired:
print("\n⏰ 执行超时5分钟可能Blender仍在运行")
print("请检查桌面是否有生成的图片")
return False
except Exception as e:
print(f"启动Blender时出现错误: {str(e)}")
return False
finally:
# 清理临时文件
try:
if os.path.exists(script_path):
os.remove(script_path)
print(f"已清理临时文件: {script_path}")
except:
pass
def main():
"""主函数"""
print("=" * 70)
print("Blender 4.2兼容版自动化脚本 - 白模渲染")
print("=" * 70)
print("特点:")
print("✓ 移除所有材质设置")
print("✓ 使用默认白色材质")
print("✓ 快速渲染")
print("✓ 兼容Blender 4.2")
print("✓ 自动保存到桌面")
print("=" * 70)
success = launch_blender_simple()
if success:
print("\n🎉 白模渲染完成!")
print("请检查桌面上的渲染图片")
print("图片文件名格式: isometric_room_white_[时间戳].png")
else:
print("\n❌ 执行失败!")
print("可能的解决方案:")
print("1. 确保Isometquick插件已正确安装")
print("2. 禁用可能冲突的其他插件")
print("3. 检查磁盘空间是否足够")
if __name__ == "__main__":
main()