|
@@ -0,0 +1,288 @@
|
|
|
|
+import pyvista as pv
|
|
|
|
+import numpy as np
|
|
|
|
+
|
|
|
|
+class AIDog:
|
|
|
|
+ def __init__(self):
|
|
|
|
+ """初始化渲染器,启用高质量渲染"""
|
|
|
|
+ self.plotter = pv.Plotter()
|
|
|
|
+ # 启用抗锯齿和高质量渲染
|
|
|
|
+ self.plotter.enable_anti_aliasing()
|
|
|
|
+ self.plotter.enable_depth_peeling(10)
|
|
|
|
+
|
|
|
|
+ # 添加快捷键
|
|
|
|
+ self.plotter.add_key_event('s', self.save_screenshot)
|
|
|
|
+ self.plotter.add_key_event('q', self.plotter.close)
|
|
|
|
+
|
|
|
|
+ # 添加快捷键提示
|
|
|
|
+ self.plotter.add_text(
|
|
|
|
+ "Keyboard shortcuts:\n"
|
|
|
|
+ "S: Save screenshot\n"
|
|
|
|
+ "Q: Quit",
|
|
|
|
+ position='upper_left',
|
|
|
|
+ font_size=12,
|
|
|
|
+ color='black'
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 整体下移的偏移量
|
|
|
|
+ self.z_offset = -0.1
|
|
|
|
+
|
|
|
|
+ def create_head(self):
|
|
|
|
+ """创建狗头"""
|
|
|
|
+ parts = []
|
|
|
|
+
|
|
|
|
+ # 主体 - 使用圆柱体和球体组合
|
|
|
|
+ head_base = pv.Cylinder(
|
|
|
|
+ center=(0.25, 0, 0.33),
|
|
|
|
+ direction=(1, 0, 0),
|
|
|
|
+ radius=0.06,
|
|
|
|
+ height=0.1,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+ parts.append(head_base)
|
|
|
|
+
|
|
|
|
+ # 头部圆角
|
|
|
|
+ head_front = pv.Sphere(
|
|
|
|
+ center=(0.3, 0, 0.33),
|
|
|
|
+ radius=0.06,
|
|
|
|
+ phi_resolution=32,
|
|
|
|
+ theta_resolution=32
|
|
|
|
+ )
|
|
|
|
+ head_back = pv.Sphere(
|
|
|
|
+ center=(0.2, 0, 0.33),
|
|
|
|
+ radius=0.06,
|
|
|
|
+ phi_resolution=32,
|
|
|
|
+ theta_resolution=32
|
|
|
|
+ )
|
|
|
|
+ parts.extend([head_front, head_back])
|
|
|
|
+
|
|
|
|
+ # 眼睛外壳 - 凸起的圆柱体
|
|
|
|
+ left_eye_shell = pv.Cylinder(
|
|
|
|
+ center=(0.32, 0.04, 0.34),
|
|
|
|
+ direction=(1, 0.1, 0),
|
|
|
|
+ radius=0.015,
|
|
|
|
+ height=0.01,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+ right_eye_shell = pv.Cylinder(
|
|
|
|
+ center=(0.32, -0.04, 0.34),
|
|
|
|
+ direction=(1, -0.1, 0),
|
|
|
|
+ radius=0.015,
|
|
|
|
+ height=0.01,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+ parts.extend([left_eye_shell, right_eye_shell])
|
|
|
|
+
|
|
|
|
+ # 眼睛镜片 - 稍微凸出的深色圆柱体
|
|
|
|
+ left_eye_lens = pv.Cylinder(
|
|
|
|
+ center=(0.325, 0.04, 0.34),
|
|
|
|
+ direction=(1, 0.1, 0),
|
|
|
|
+ radius=0.01,
|
|
|
|
+ height=0.005,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+ right_eye_lens = pv.Cylinder(
|
|
|
|
+ center=(0.325, -0.04, 0.34),
|
|
|
|
+ direction=(1, -0.1, 0),
|
|
|
|
+ radius=0.01,
|
|
|
|
+ height=0.005,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+ parts.extend([left_eye_lens, right_eye_lens])
|
|
|
|
+
|
|
|
|
+ # 鼻子部分 - 传感器样式
|
|
|
|
+ nose = pv.Cylinder(
|
|
|
|
+ center=(0.35, 0, 0.32),
|
|
|
|
+ direction=(1, 0, 0),
|
|
|
|
+ radius=0.015,
|
|
|
|
+ height=0.01,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+ nose_sensor = pv.Cylinder(
|
|
|
|
+ center=(0.355, 0, 0.32),
|
|
|
|
+ direction=(1, 0, 0),
|
|
|
|
+ radius=0.01,
|
|
|
|
+ height=0.005,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+ parts.extend([nose, nose_sensor])
|
|
|
|
+
|
|
|
|
+ return parts, [left_eye_lens, right_eye_lens, nose_sensor] # 返回两组部件,第二组是深色部件
|
|
|
|
+
|
|
|
|
+ def create_body(self):
|
|
|
|
+ """创建机器狗躯干"""
|
|
|
|
+ parts = []
|
|
|
|
+
|
|
|
|
+ # 主体 - 使用圆柱体组合
|
|
|
|
+ body_main = pv.Cylinder(
|
|
|
|
+ center=(0, 0, 0.3),
|
|
|
|
+ direction=(1, 0, 0),
|
|
|
|
+ radius=0.08,
|
|
|
|
+ height=0.3,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+ parts.append(body_main)
|
|
|
|
+
|
|
|
|
+ # 前后圆角
|
|
|
|
+ front_cap = pv.Sphere(
|
|
|
|
+ center=(0.15, 0, 0.3),
|
|
|
|
+ radius=0.08,
|
|
|
|
+ phi_resolution=32,
|
|
|
|
+ theta_resolution=32
|
|
|
|
+ )
|
|
|
|
+ back_cap = pv.Sphere(
|
|
|
|
+ center=(-0.15, 0, 0.3),
|
|
|
|
+ radius=0.08,
|
|
|
|
+ phi_resolution=32,
|
|
|
|
+ theta_resolution=32
|
|
|
|
+ )
|
|
|
|
+ parts.extend([front_cap, back_cap])
|
|
|
|
+
|
|
|
|
+ # 顶部装甲 - 更薄的圆柱体
|
|
|
|
+ top_armor = pv.Cylinder(
|
|
|
|
+ center=(0, 0, 0.36),
|
|
|
|
+ direction=(1, 0, 0),
|
|
|
|
+ radius=0.07,
|
|
|
|
+ height=0.25,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+ parts.append(top_armor)
|
|
|
|
+
|
|
|
|
+ return parts
|
|
|
|
+
|
|
|
|
+ def create_leg(self, position, side='right'):
|
|
|
|
+ """创建单条腿"""
|
|
|
|
+ # 髋关节
|
|
|
|
+ hip = pv.Sphere(radius=0.03, center=position)
|
|
|
|
+
|
|
|
|
+ # 大腿
|
|
|
|
+ thigh_length = 0.12
|
|
|
|
+ thigh_pos = (position[0],
|
|
|
|
+ position[1],
|
|
|
|
+ position[2] - thigh_length/2)
|
|
|
|
+ thigh = pv.Cylinder(
|
|
|
|
+ center=thigh_pos,
|
|
|
|
+ direction=(0, 0, 1),
|
|
|
|
+ radius=0.015,
|
|
|
|
+ height=thigh_length,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 膝关节
|
|
|
|
+ knee_pos = (position[0],
|
|
|
|
+ position[1],
|
|
|
|
+ position[2] - thigh_length)
|
|
|
|
+ knee = pv.Sphere(radius=0.02, center=knee_pos)
|
|
|
|
+
|
|
|
|
+ # 小腿
|
|
|
|
+ shin_length = 0.15
|
|
|
|
+ shin_pos = (knee_pos[0],
|
|
|
|
+ knee_pos[1],
|
|
|
|
+ knee_pos[2] - shin_length/2)
|
|
|
|
+ shin = pv.Cylinder(
|
|
|
|
+ center=shin_pos,
|
|
|
|
+ direction=(0, 0, 1),
|
|
|
|
+ radius=0.012,
|
|
|
|
+ height=shin_length,
|
|
|
|
+ resolution=32
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ # 脚部
|
|
|
|
+ foot_pos = (knee_pos[0],
|
|
|
|
+ knee_pos[1],
|
|
|
|
+ knee_pos[2] - shin_length)
|
|
|
|
+ foot = pv.Box(bounds=(
|
|
|
|
+ foot_pos[0]-0.02, foot_pos[0]+0.02,
|
|
|
|
+ foot_pos[1]-0.015, foot_pos[1]+0.015,
|
|
|
|
+ foot_pos[2]-0.01, foot_pos[2]+0.01
|
|
|
|
+ ))
|
|
|
|
+
|
|
|
|
+ return [hip, thigh, knee, shin, foot]
|
|
|
|
+
|
|
|
|
+ def create_model(self):
|
|
|
|
+ """创建完整模型"""
|
|
|
|
+ # 材质颜色定义 - 更亮的金属色
|
|
|
|
+ colors = {
|
|
|
|
+ 'head': '#BDC3C7', # 更亮的金属灰
|
|
|
|
+ 'body': '#BDC3C7', # 更亮的金属灰
|
|
|
|
+ 'limbs': '#95A5A6', # 金属灰
|
|
|
|
+ 'sensors': '#34495E' # 深色传感器
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ # 统一的金属材质参数 - 增加光泽
|
|
|
|
+ metal_props = {
|
|
|
|
+ 'metallic': 0.9,
|
|
|
|
+ 'roughness': 0.1, # 降低粗糙度
|
|
|
|
+ 'specular': 1.0, # 增加反光
|
|
|
|
+ 'specular_power': 20
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ # 传感器材质参数
|
|
|
|
+ sensor_props = {
|
|
|
|
+ 'metallic': 0.9,
|
|
|
|
+ 'roughness': 0.1,
|
|
|
|
+ 'specular': 1.0,
|
|
|
|
+ 'specular_power': 20
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ # 添加头部
|
|
|
|
+ head_parts, sensor_parts = self.create_head()
|
|
|
|
+ for part in head_parts:
|
|
|
|
+ self.plotter.add_mesh(part,
|
|
|
|
+ color=colors['head'],
|
|
|
|
+ **metal_props)
|
|
|
|
+ # 添加深色传感器部件
|
|
|
|
+ for part in sensor_parts:
|
|
|
|
+ self.plotter.add_mesh(part,
|
|
|
|
+ color=colors['sensors'],
|
|
|
|
+ **sensor_props)
|
|
|
|
+
|
|
|
|
+ # 添加躯干
|
|
|
|
+ for part in self.create_body():
|
|
|
|
+ self.plotter.add_mesh(part,
|
|
|
|
+ color=colors['body'],
|
|
|
|
+ **metal_props)
|
|
|
|
+
|
|
|
|
+ # 添加四条腿
|
|
|
|
+ leg_positions = [
|
|
|
|
+ (0.12, 0.08, 0.3), # 右前
|
|
|
|
+ (0.12, -0.08, 0.3), # 左前
|
|
|
|
+ (-0.12, 0.08, 0.3), # 右后
|
|
|
|
+ (-0.12, -0.08, 0.3) # 左后
|
|
|
|
+ ]
|
|
|
|
+
|
|
|
|
+ for pos in leg_positions:
|
|
|
|
+ for part in self.create_leg(pos):
|
|
|
|
+ self.plotter.add_mesh(part,
|
|
|
|
+ color=colors['limbs'],
|
|
|
|
+ **metal_props)
|
|
|
|
+
|
|
|
|
+ # 渲染设置 - 使用更亮的背景
|
|
|
|
+ self.plotter.set_background('#CCCCCC') # 更亮的灰色背景
|
|
|
|
+ self.plotter.camera_position = 'iso'
|
|
|
|
+ self.plotter.camera.zoom(1.5)
|
|
|
|
+
|
|
|
|
+ def show(self):
|
|
|
|
+ """显示模型"""
|
|
|
|
+ self.plotter.show()
|
|
|
|
+
|
|
|
|
+ def save_screenshot(self, filename=None):
|
|
|
|
+ """保存截图并显示提示"""
|
|
|
|
+ if filename is None:
|
|
|
|
+ from datetime import datetime
|
|
|
|
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
|
+ filename = f'aidog_{timestamp}.png'
|
|
|
|
+
|
|
|
|
+ self.plotter.screenshot(filename)
|
|
|
|
+ print(f"Screenshot saved as: {filename}")
|
|
|
|
+ # 添加临时提示文字
|
|
|
|
+ self.plotter.add_text(
|
|
|
|
+ f"Saved: {filename}",
|
|
|
|
+ position='upper_right',
|
|
|
|
+ font_size=12,
|
|
|
|
+ color='black'
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+if __name__ == '__main__':
|
|
|
|
+ dog = AIDog()
|
|
|
|
+ dog.create_model()
|
|
|
|
+ dog.show()
|