MetaCoreEngineV2/samples/orbit_alt_drag.py
赵豪 0455dc6a8a ```
chore(git): 更新.gitignore文件以包含更多Python和项目特定文件

- 添加Python相关忽略规则(__pycache__、.pyc等)
- 添加虚拟环境相关忽略(venv、env等)
- 添加IDE相关忽略(.vscode、.idea等)
- 添加C++/CMake相关忽略(CMakeFiles、Makefile等)
- 添加Panda3D/RenderPipeline特定忽略(.bam、.egg等)
- 添加样本和测试模型相关忽略
- 添加操作系统特定文件忽略
- 移除旧的忽略规则并重新组织结构
```
2026-01-13 17:34:08 +08:00

159 lines
6.0 KiB
Python

import math
from direct.showbase.ShowBase import ShowBase
from panda3d.core import KeyboardButton, MouseButton, Point2, Vec3, loadPrcFileData
# Basic window settings for clarity.
loadPrcFileData("", "window-title Alt+LMB Orbit Demo")
loadPrcFileData("", "show-frame-rate-meter #t")
class OrbitDemo(ShowBase):
def __init__(self):
super().__init__()
self.disableMouse() # We manage the camera manually.
self.focus_distance = 8.0
self.orbit_active = False
self.pan_active = False
self.radius = self.focus_distance
self.azimuth = 0.0
self.elevation = 0.0
self.last_mouse = None
self.last_mouse_pan = None
self.pivot = Vec3(0, 0, 0)
self._setup_scene()
self._refresh_camera_from_angles()
self.accept("mouse1", self._on_mouse1_down)
self.accept("alt-mouse1", self._on_mouse1_down)
self.accept("mouse1-up", self._on_mouse1_up)
self.accept("mouse2", self._on_mouse2_down)
self.accept("mouse2-up", self._on_mouse2_up)
self.accept("wheel_up", lambda: self._on_wheel(1))
self.accept("wheel_down", lambda: self._on_wheel(-1))
bt = self.buttonThrowers[0].node()
bt.setButtonDownEvent("btn-down")
bt.setButtonUpEvent("btn-up")
bt.setKeystrokeEvent("keystroke")
self.accept("btn-down", lambda name: print("btn-down:", name))
self.accept("btn-up", lambda name: print("btn-up:", name))
self.accept("keystroke", lambda key: print("key:", key))
self.taskMgr.add(self._update_orbit, "update_orbit")
def _setup_scene(self):
env = self.loader.loadModel("models/environment")
env.reparentTo(self.render)
env.setScale(0.1)
env.setPos(-8, 42, 0)
# Small marker that shows the current orbit center.
self.focus_marker = self.loader.loadModel("models/smiley")
self.focus_marker.reparentTo(self.render)
self.focus_marker.setScale(0.15)
self.focus_marker.setColor(1, 0.9, 0.2, 1)
self.focus_marker.hide() # Shown only while orbiting.
def _point_in_front(self):
forward = self.camera.getQuat(self.render).getForward()
return self.camera.getPos(self.render) + forward.normalized() * self.focus_distance
def _sync_angles_from_camera(self):
offset = self.camera.getPos(self.render) - self.pivot
self.radius = offset.length()
if self.radius < 1e-5:
self.radius = self.focus_distance
offset = Vec3(0, -self.radius, 0)
self.azimuth = math.atan2(offset.x, offset.y)
self.elevation = math.asin(max(-1.0, min(1.0, offset.z / self.radius)))
def _refresh_camera_from_angles(self):
# print("Orbiting around:", self.pivot)
cos_el = math.cos(self.elevation)
x = math.sin(self.azimuth) * cos_el
y = math.cos(self.azimuth) * cos_el
z = math.sin(self.elevation)
self.camera.setPos(self.pivot + Vec3(x, y, z) * self.radius)
self.camera.lookAt(self.pivot)
def _on_mouse1_down(self):
self.orbit_active = True
print(self.orbit_active)
self.pivot = self._point_in_front()
self.focus_marker.setPos(self.pivot)
self.focus_marker.show()
self._sync_angles_from_camera()
self.last_mouse = Point2(self.mouseWatcherNode.getMouse())
def _on_mouse1_up(self):
self.orbit_active = False
self.last_mouse = None
self.focus_marker.hide()
print(self.orbit_active)
def _on_mouse2_down(self):
if not self.mouseWatcherNode.hasMouse():
return
self.pan_active = True
self.last_mouse_pan = Point2(self.mouseWatcherNode.getMouse())
def _on_mouse2_up(self):
self.pan_active = False
self.last_mouse_pan = None
def _on_wheel(self, direction):
# direction: +1 for wheel_up (zoom in), -1 for wheel_down (zoom out)
zoom_factor = 0.9 if direction > 0 else 1.1
self.radius = max(0.5, min(200.0, self.radius * zoom_factor))
self._refresh_camera_from_angles()
def _update_orbit(self, task):
# Middle mouse pan (translates camera and pivot together).
if self.pan_active and self.mouseWatcherNode.hasMouse():
current = Point2(self.mouseWatcherNode.getMouse())
if self.last_mouse_pan is not None:
delta = current - self.last_mouse_pan
right = self.camera.getQuat(self.render).getRight()
up = self.camera.getQuat(self.render).getUp()
pan_scale = self.radius * 0.8
offset = (right * delta.x + up * delta.y) * pan_scale
self.camera.setPos(self.camera.getPos(self.render) + offset)
self.pivot += offset
self._sync_angles_from_camera()
self.last_mouse_pan = current
elif self.pan_active and not self.mouseWatcherNode.isButtonDown(MouseButton.two()):
self._on_mouse2_up()
if not self.orbit_active:
return task.cont
if not self.mouseWatcherNode.isButtonDown(MouseButton.one()) or not self.mouseWatcherNode.isButtonDown(KeyboardButton.alt()):
# print("Press Alt+LMB to activate orbit mode.")
return task.cont
if not self.mouseWatcherNode.hasMouse() or self.last_mouse is None:
print("Mouse not available.")
return task.cont
current = Point2(self.mouseWatcherNode.getMouse())
delta = current - self.last_mouse
self.last_mouse = current
# Screen space is [-1, 1], so multiply by a comfortable radians-per-unit factor.
rot_speed = math.pi # 180° per full screen swipe.
self.azimuth += delta.x * rot_speed
self.elevation -= delta.y * rot_speed
self.elevation = max(math.radians(-85.0), min(math.radians(85.0), self.elevation))
self._refresh_camera_from_angles()
return task.cont
if __name__ == "__main__":
app = OrbitDemo()
app.run()