feat: move_camera.txt 改为速度段格式驱动相机运动

格式:
  1-60   vx=1.0  rx=10         # 1-60帧:x平移1/帧 + 绕x转10°/帧
  30-90  vy=2.0  ry=20  rz=10  # 30-90帧:y平移2/帧 + 绕y转20°/帧 + 绕z转10°/帧

draw.py 每帧累加平移速度修改center,累加旋转速度修改
elevation/azimuth,实现连续平滑的相机运动。
This commit is contained in:
2026-06-12 07:58:08 +08:00
parent 22b94011ee
commit e40f7a49e4
4 changed files with 89 additions and 63 deletions
+30 -35
View File
@@ -555,43 +555,38 @@ print(f"[draw] 渲染方式: {mode_str}")
print(f"[draw] 绘图参数: ball_radius={ball_radius}, box_color=({box_color_r:.2f},{box_color_g:.2f},{box_color_b:.2f}), alpha={alpha_list}")
# 运动相机关键帧(可选
_CAM_KF = json.loads(h.get("camera_keyframes", "null")) if h.get("camera_keyframes") else None
# 运动相机(速度段驱动
_CAM_MOTION = json.loads(h.get("camera_keyframes", "null")) if h.get("camera_keyframes") else None
if _CAM_MOTION:
_cam_center = [0.0, 0.0, 0.0]
_cam_elev = initial_camera["elevation"]
_cam_azim = initial_camera["azimuth"]
_cam_dist = initial_camera["distance"]
# ===========================================================================
# 每帧回调:仅推进帧索引,从预存数组读取位置,零物理计算
# ===========================================================================
def _interp_camera(f_idx):
"""根据关键帧插值相机位置。"""
if not _CAM_KF or len(_CAM_KF) < 2:
def _update_motion_camera(f_idx):
"""速度段驱动:每帧累加平移/旋转。"""
if not _CAM_MOTION:
return
# 找到当前帧对应的关键帧区间
n_kf = len(_CAM_KF)
# 映射到关键帧时间线
total_kf_frames = _CAM_KF[-1][0]
if total_kf_frames <= 0:
global _cam_center, _cam_elev, _cam_azim, _cam_dist
# 找当前帧属于哪个段
active = [seg for seg in _CAM_MOTION
if seg["start"] <= f_idx < seg["end"]]
if not active:
return
# 循环播放关键帧
t = (f_idx / N_FRAMES) * total_kf_frames
# 二分查找区间
lo, hi = 0, n_kf - 1
while hi - lo > 1:
mid = (lo + hi) // 2
if _CAM_KF[mid][0] <= t:
lo = mid
else:
hi = mid
f0, f1 = _CAM_KF[lo], _CAM_KF[hi]
if f1[0] - f0[0] == 0:
return
frac = (t - f0[0]) / (f1[0] - f0[0])
dist = f0[1] + (f1[1] - f0[1]) * frac
elev = f0[2] + (f1[2] - f0[2]) * frac
azim = f0[3] + (f1[3] - f0[3]) * frac
view.camera.distance = dist
view.camera.elevation = elev
view.camera.azimuth = azim
seg = active[0]
_cam_center[0] += seg["v"][0]
_cam_center[1] += seg["v"][1]
_cam_center[2] += seg["v"][2]
# rx → elevation, ry → azimuth, rz → 距离变化(绕z=roll/螺旋)
_cam_elev += seg["r"][0]
_cam_azim += seg["r"][1]
_cam_dist += seg["r"][2] * 0 # rz 可以忽略或做其他用途
view.camera.center = tuple(_cam_center)
view.camera.distance = _cam_dist
view.camera.elevation = _cam_elev
view.camera.azimuth = _cam_azim
def update(event):
@@ -605,8 +600,8 @@ def update(event):
if bond_lines is not None and len(BOND_PAIRS) > 0:
_update_bond_positions(frame_idx)
# 运动相机:按关键帧插值
_interp_camera(frame_idx)
# 运动相机:速度段驱动
_update_motion_camera(frame_idx)
# 信息面板显示 plot_atom 的数据
x = float(DISP_X[frame_idx])