plot.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. import pyvista as pv
  2. import numpy as np
  3. class AIDog:
  4. def __init__(self):
  5. """初始化渲染器,启用高质量渲染"""
  6. self.plotter = pv.Plotter()
  7. # 启用抗锯齿和高质量渲染
  8. self.plotter.enable_anti_aliasing()
  9. self.plotter.enable_depth_peeling(10)
  10. # 添加快捷键
  11. self.plotter.add_key_event('s', self.save_screenshot)
  12. self.plotter.add_key_event('q', self.plotter.close)
  13. # 添加快捷键提示
  14. self.plotter.add_text(
  15. "Keyboard shortcuts:\n"
  16. "S: Save screenshot\n"
  17. "Q: Quit",
  18. position='upper_left',
  19. font_size=12,
  20. color='black'
  21. )
  22. # 整体下移的偏移量
  23. self.z_offset = -0.1
  24. def create_head(self):
  25. """创建狗头"""
  26. parts = []
  27. # 主体 - 使用圆柱体和球体组合
  28. head_base = pv.Cylinder(
  29. center=(0.25, 0, 0.33),
  30. direction=(1, 0, 0),
  31. radius=0.06,
  32. height=0.1,
  33. resolution=32
  34. )
  35. parts.append(head_base)
  36. # 头部圆角
  37. head_front = pv.Sphere(
  38. center=(0.3, 0, 0.33),
  39. radius=0.06,
  40. phi_resolution=32,
  41. theta_resolution=32
  42. )
  43. head_back = pv.Sphere(
  44. center=(0.2, 0, 0.33),
  45. radius=0.06,
  46. phi_resolution=32,
  47. theta_resolution=32
  48. )
  49. parts.extend([head_front, head_back])
  50. # 眼睛外壳 - 凸起的圆柱体
  51. left_eye_shell = pv.Cylinder(
  52. center=(0.32, 0.04, 0.34),
  53. direction=(1, 0.1, 0),
  54. radius=0.015,
  55. height=0.01,
  56. resolution=32
  57. )
  58. right_eye_shell = pv.Cylinder(
  59. center=(0.32, -0.04, 0.34),
  60. direction=(1, -0.1, 0),
  61. radius=0.015,
  62. height=0.01,
  63. resolution=32
  64. )
  65. parts.extend([left_eye_shell, right_eye_shell])
  66. # 眼睛镜片 - 稍微凸出的深色圆柱体
  67. left_eye_lens = pv.Cylinder(
  68. center=(0.325, 0.04, 0.34),
  69. direction=(1, 0.1, 0),
  70. radius=0.01,
  71. height=0.005,
  72. resolution=32
  73. )
  74. right_eye_lens = pv.Cylinder(
  75. center=(0.325, -0.04, 0.34),
  76. direction=(1, -0.1, 0),
  77. radius=0.01,
  78. height=0.005,
  79. resolution=32
  80. )
  81. parts.extend([left_eye_lens, right_eye_lens])
  82. # 鼻子部分 - 传感器样式
  83. nose = pv.Cylinder(
  84. center=(0.35, 0, 0.32),
  85. direction=(1, 0, 0),
  86. radius=0.015,
  87. height=0.01,
  88. resolution=32
  89. )
  90. nose_sensor = pv.Cylinder(
  91. center=(0.355, 0, 0.32),
  92. direction=(1, 0, 0),
  93. radius=0.01,
  94. height=0.005,
  95. resolution=32
  96. )
  97. parts.extend([nose, nose_sensor])
  98. return parts, [left_eye_lens, right_eye_lens, nose_sensor] # 返回两组部件,第二组是深色部件
  99. def create_body(self):
  100. """创建机器狗躯干"""
  101. parts = []
  102. # 主体 - 使用圆柱体组合
  103. body_main = pv.Cylinder(
  104. center=(0, 0, 0.3),
  105. direction=(1, 0, 0),
  106. radius=0.08,
  107. height=0.3,
  108. resolution=32
  109. )
  110. parts.append(body_main)
  111. # 前后圆角
  112. front_cap = pv.Sphere(
  113. center=(0.15, 0, 0.3),
  114. radius=0.08,
  115. phi_resolution=32,
  116. theta_resolution=32
  117. )
  118. back_cap = pv.Sphere(
  119. center=(-0.15, 0, 0.3),
  120. radius=0.08,
  121. phi_resolution=32,
  122. theta_resolution=32
  123. )
  124. parts.extend([front_cap, back_cap])
  125. # 顶部装甲 - 更薄的圆柱体
  126. top_armor = pv.Cylinder(
  127. center=(0, 0, 0.36),
  128. direction=(1, 0, 0),
  129. radius=0.07,
  130. height=0.25,
  131. resolution=32
  132. )
  133. parts.append(top_armor)
  134. return parts
  135. def create_leg(self, position, side='right'):
  136. """创建单条腿"""
  137. # 髋关节
  138. hip = pv.Sphere(radius=0.03, center=position)
  139. # 大腿
  140. thigh_length = 0.12
  141. thigh_pos = (position[0],
  142. position[1],
  143. position[2] - thigh_length/2)
  144. thigh = pv.Cylinder(
  145. center=thigh_pos,
  146. direction=(0, 0, 1),
  147. radius=0.015,
  148. height=thigh_length,
  149. resolution=32
  150. )
  151. # 膝关节
  152. knee_pos = (position[0],
  153. position[1],
  154. position[2] - thigh_length)
  155. knee = pv.Sphere(radius=0.02, center=knee_pos)
  156. # 小腿
  157. shin_length = 0.15
  158. shin_pos = (knee_pos[0],
  159. knee_pos[1],
  160. knee_pos[2] - shin_length/2)
  161. shin = pv.Cylinder(
  162. center=shin_pos,
  163. direction=(0, 0, 1),
  164. radius=0.012,
  165. height=shin_length,
  166. resolution=32
  167. )
  168. # 脚部
  169. foot_pos = (knee_pos[0],
  170. knee_pos[1],
  171. knee_pos[2] - shin_length)
  172. foot = pv.Box(bounds=(
  173. foot_pos[0]-0.02, foot_pos[0]+0.02,
  174. foot_pos[1]-0.015, foot_pos[1]+0.015,
  175. foot_pos[2]-0.01, foot_pos[2]+0.01
  176. ))
  177. return [hip, thigh, knee, shin, foot]
  178. def create_model(self):
  179. """创建完整模型"""
  180. # 材质颜色定义 - 更亮的金属色
  181. colors = {
  182. 'head': '#BDC3C7', # 更亮的金属灰
  183. 'body': '#BDC3C7', # 更亮的金属灰
  184. 'limbs': '#95A5A6', # 金属灰
  185. 'sensors': '#34495E' # 深色传感器
  186. }
  187. # 统一的金属材质参数 - 增加光泽
  188. metal_props = {
  189. 'metallic': 0.9,
  190. 'roughness': 0.1, # 降低粗糙度
  191. 'specular': 1.0, # 增加反光
  192. 'specular_power': 20
  193. }
  194. # 传感器材质参数
  195. sensor_props = {
  196. 'metallic': 0.9,
  197. 'roughness': 0.1,
  198. 'specular': 1.0,
  199. 'specular_power': 20
  200. }
  201. # 添加头部
  202. head_parts, sensor_parts = self.create_head()
  203. for part in head_parts:
  204. self.plotter.add_mesh(part,
  205. color=colors['head'],
  206. **metal_props)
  207. # 添加深色传感器部件
  208. for part in sensor_parts:
  209. self.plotter.add_mesh(part,
  210. color=colors['sensors'],
  211. **sensor_props)
  212. # 添加躯干
  213. for part in self.create_body():
  214. self.plotter.add_mesh(part,
  215. color=colors['body'],
  216. **metal_props)
  217. # 添加四条腿
  218. leg_positions = [
  219. (0.12, 0.08, 0.3), # 右前
  220. (0.12, -0.08, 0.3), # 左前
  221. (-0.12, 0.08, 0.3), # 右后
  222. (-0.12, -0.08, 0.3) # 左后
  223. ]
  224. for pos in leg_positions:
  225. for part in self.create_leg(pos):
  226. self.plotter.add_mesh(part,
  227. color=colors['limbs'],
  228. **metal_props)
  229. # 渲染设置 - 使用更亮的背景
  230. self.plotter.set_background('#CCCCCC') # 更亮的灰色背景
  231. self.plotter.camera_position = 'iso'
  232. self.plotter.camera.zoom(1.5)
  233. def show(self):
  234. """显示模型"""
  235. self.plotter.show()
  236. def save_screenshot(self, filename=None):
  237. """保存截图并显示提示"""
  238. if filename is None:
  239. from datetime import datetime
  240. timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
  241. filename = f'aidog_{timestamp}.png'
  242. self.plotter.screenshot(filename)
  243. print(f"Screenshot saved as: {filename}")
  244. # 添加临时提示文字
  245. self.plotter.add_text(
  246. f"Saved: {filename}",
  247. position='upper_right',
  248. font_size=12,
  249. color='black'
  250. )
  251. if __name__ == '__main__':
  252. dog = AIDog()
  253. dog.create_model()
  254. dog.show()