File size: 4,948 Bytes
f783161
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import bpy
import math
import os
from paths import *

class BlendRenderer:
    def __init__(self, blend_file_path=RENDER_FILE):
        """
        初始化渲染器,加载指定的 .blend 文件并进行基础设置。
        
        :param blend_file_path: 要加载的 .blend 文件的完整路径
        """
        if not os.path.isfile(blend_file_path):
            raise FileNotFoundError(f"Blend file not found: {blend_file_path}")

        # 加载 blend 文件
        bpy.ops.wm.open_mainfile(filepath=blend_file_path)

        # 设置渲染引擎为 Cycles
        bpy.context.scene.render.engine = 'CYCLES'

        # 使用 CPU 渲染
        bpy.context.scene.cycles.device = 'CPU'

        # 设置采样数为 4
        bpy.context.scene.cycles.samples = 4

        # 设置所有反弹次数为 4(包括 diffuse, glossy, transmission, etc.)
        bpy.context.scene.cycles.max_bounces = 4

        # 设置渲染分辨率
        bpy.context.scene.render.resolution_x = 512
        bpy.context.scene.render.resolution_y = 512
        bpy.context.scene.render.resolution_percentage = 100

        # 启用透明背景(RGBA)
        bpy.context.scene.render.film_transparent = True

        # 遍历所有对象,初始化渲染可见性
        for obj in bpy.data.objects:
            if obj.type == 'LIGHT':
                obj.hide_render = False
            elif obj.type == 'CAMERA':
                obj.hide_render = False
            elif obj.type == 'MESH':
                obj.hide_render = True  # 默认所有网格不参与渲染

        # 设置活动摄像机(选第一个)
        cameras = [obj for obj in bpy.data.objects if obj.type == 'CAMERA']
        if cameras:
            bpy.context.scene.camera = cameras[0]

        print(f"Loaded blend file: {blend_file_path}")
        print("Render settings applied: 512x512, CPU, samples=4, bounces=4, transparent background.")
        
        self.alpha_axis_map = {
            0: "单轴平面",
            1: "三轴",
            2: "双向标注",
            4: "四向标注"
        }
        

    def _get_all_children(self, obj):
        """递归获取对象的所有子对象(包括嵌套子级)"""
        children = []
        for child in obj.children:
            children.append(child)
            children.extend(self._get_all_children(child))
        return children

    def render_axis(self, azi, ele, rot, alpha, save_path):
        """
        渲染特定方向的图像。
        
        :param azi: 方位角(绕 Z 轴旋转,弧度)
        :param ele: 仰角(绕 Y 轴旋转,弧度)
        :param rot: 自转(绕 X 轴旋转,弧度)
        :param save_path: 渲染结果保存路径(如 '/output/render.png')
        """
        # 遍历所有对象,初始化渲染可见性
        for obj in bpy.data.objects:
            if obj.type == 'LIGHT':
                obj.hide_render = False
            elif obj.type == 'CAMERA':
                obj.hide_render = False
            elif obj.type == 'MESH':
                obj.hide_render = True  # 默认所有网格不参与渲染
        # 根据 alpha 选择目标对象
        target_name = self.alpha_axis_map.get(alpha, "单轴平面")
        target_obj = None
        for obj in bpy.data.objects:
            # if obj.type == 'MESH' and obj.name == target_name:
            if obj.name == target_name:
                target_obj = obj
                break

        if target_obj is None:
            raise ValueError(f'Object named "{target_name}" not found in the scene.')

        # 获取该对象及其所有子对象
        all_objects_to_render = [target_obj] + self._get_all_children(target_obj)

        # 设置它们参与渲染
        for obj in all_objects_to_render:
            if obj.type == 'MESH':
                obj.hide_render = False

        # 设置旋转(ZYX 顺序:Z=azi, Y=ele, X=rot → Euler XYZ = (rot, ele, azi))
        # 注意:Blender 使用弧度
        target_obj.rotation_mode = 'ZYX'  # 确保使用欧拉角 ZYX 模式
        target_obj.rotation_euler = (rot*math.pi/180, ele*math.pi/180, -azi*math.pi/180)

        # 确保路径目录存在
        os.makedirs(os.path.dirname(save_path), exist_ok=True)

        # 设置输出路径
        bpy.context.scene.render.filepath = save_path

        # 执行渲染并保存
        bpy.ops.render.render(write_still=True)

        print(f"Rendered and saved to: {save_path}")
        
        
if __name__ == "__main__":
    renderer = BlendRenderer(RENDER_FILE)
    # Example usage:
    renderer.render_axis(45, 0, 0, 1, "./test_demo_output/render_1_dir_azi45.png")
    renderer.render_axis(0, 45, 0, 2, "./test_demo_output/render_2_dir_ele45.png")
    renderer.render_axis(0, 0, 45, 4, "./test_demo_output/render_4_dir_rot45.png")
    # renderer.render_1_dir()
    # renderer.render_2_dir()
    # renderer.render_4_dir()