模块7: 相机与变换系统
2D/3D 变换矩阵、坐标系与相机控制
1. 变换系统概述
每个 DisplayObject 都有一个 Transform 组件,管理本地坐标和世界坐标之间的矩阵变换。
底层使用 gl-matrix 库进行矩阵运算,支持 2D (3x3) 和 3D (4x4) 变换。
2. Transform 组件
// 位移 circle.setPosition(100, 200); // 设置绝对位置 circle.setPosition(100, 200, 50); // 3D 位置 circle.translate(10, 20); // 相对移动 circle.translateLocal(10, 0); // 本地坐标系移动 // 旋转 circle.setEulerAngles(0, 0, 45); // 欧拉角 (度) circle.rotate(0, 0, 30); // 相对旋转 circle.rotateLocal(0, 0, 15); // 本地旋转 // 缩放 circle.setLocalScale(2); // 等比缩放 circle.setLocalScale(2, 1.5); // 非等比 circle.scaleLocal(1.1, 1.1); // 相对缩放 // CSS transform 语法也支持 circle.style.transform = 'translate(100px, 50px) rotate(45deg) scale(1.5)';
3. 本地坐标 vs 世界坐标
世界坐标 (World) 本地坐标 (Local) ┌─────────────────┐ ┌─────────────────┐ │ Canvas (0,0) │ │ Group 坐标原点 │ │ ┌─── Group ────│──┐ │ ┌── Circle ──┐ │ │ │ pos(200,100) │ │ │ │ pos(50,30) │ │ │ │ ┌─ Circle │ │ │ │ 相对于 Group │ │ │ │ │ 世界(250,130) │ │ └────────────┘ │ │ └──────────────┘ │ └─────────────────┘ └────────────────────┘ 世界坐标 = 父世界矩阵 × 本地矩阵
// 获取坐标 circle.getPosition(); // 世界坐标 [x, y, z] circle.getLocalPosition(); // 本地坐标 [x, y, z] // 获取变换矩阵 circle.getWorldTransform(); // 4x4 世界矩阵 circle.getLocalTransform(); // 4x4 本地矩阵 // 坐标转换 circle.setPosition(worldX, worldY); const local = circle.getLocalPosition();
4. 相机系统
@antv/g 提供统一的 Camera 类,支持 2D 和 3D 场景:
const camera = canvas.getCamera(); // 2D 场景 - 平移和缩放 camera.pan(100, 50); // 平移视图 camera.setZoom(1.5); // 缩放 camera.setZoomByViewportPoint(2, [400, 300]); // 以某点为中心缩放
5. 投影方式
| 投影 | 适用 | 特点 |
|---|---|---|
正交投影 (Orthographic) | 2D 场景 | 远近物体大小相同 |
透视投影 (Perspective) | 3D 场景 | 近大远小,有深度感 |
// 切换到透视投影(3D 场景) camera .setPosition(300, 200, 500) .setFocalPoint(300, 200, 0) .setPerspective(0.1, 1000, 50, 1); // 参数: near, far, fov(度), aspect // 正交投影(默认) camera.setOrthographic(width / -2, width / 2, height / 2, height / -2, 0.1, 1000);
6. 相机跟踪模式
| 模式 | 说明 |
|---|---|
CameraTrackingMode.DEFAULT | 固定不动 |
CameraTrackingMode.ROTATIONAL | 跟随目标旋转 |
CameraTrackingMode.TRANSLATIONAL | 跟随目标平移 |
CameraTrackingMode.CINEMATIC | 电影式跟随(有延迟) |
7. Landmark 相机书签
// 保存当前相机状态 camera.createLandmark('overview', { position: [300, 200, 500], focalPoint: [300, 200, 0], zoom: 1, }); camera.createLandmark('detail', { position: [100, 100, 200], focalPoint: [100, 100, 0], zoom: 3, }); // 平滑过渡到书签位置 camera.gotoLandmark('detail', { duration: 1000, easing: 'ease-in-out', });
8. AABB 包围盒
// 每个图形都有轴对齐包围盒 const bounds = circle.getBounds(); bounds.min // [minX, minY, minZ] bounds.max // [maxX, maxY, maxZ] bounds.getCenter() // 中心点 bounds.getSize() // 尺寸 // 本地包围盒(不含父变换) circle.getLocalBounds(); // 几何包围盒(不含描边/阴影) circle.getBBox();