Composer 不支持直接创建带角度的剖切动画,所有效果均通过动态修改 sectionPlane 的法向量(需为单位向量)和原点实现;法向量必须归一化,origin 使用模型坐标并经坐标转换获取,推荐用 THREE.AnimationMixer 驱动关键帧动画。

Composer 本身不支持直接创建带角度的剖切动画,也没有内置的“自定义剖面平面坐标”配置项——所有看似“剖切动画”的效果,都是通过动态修改 sectionPlane 的法向量(normal)和原点(origin)实现的,本质是 JavaScript 控制器驱动的实时更新。
为什么 sectionPlane 的 normal 必须是单位向量
Revit API 和 Forge Viewer 的剖面平面定义严格遵循数学规范:法向量长度必须为 1。若传入 {x: 2, y: 1, z: 0} 这类非单位向量,Viewer 会静默归一化,但你后续计算旋转角度、插值路径时极易出错——比如用线性插值(lerp)混合两个未归一化的法向量,结果方向完全失真。
实操建议:
- 始终用
THREE.Vector3.normalize()处理法向量,或手算:const n = new THREE.Vector3(x, y, z).normalize(); - 调试时打印
n.length(),确认恒等于1;否则剖切位置会随视角缩放漂移 - 绕某轴旋转生成斜剖面?用
new THREE.Vector3(0, 0, 1).applyAxisAngle(new THREE.Vector3(1, 0, 0), angle)更可靠,避免手动写 sin/cos
sectionPlane.origin 坐标系陷阱:模型单位 vs 屏幕像素
origin 的单位是模型内部坐标(如 Revit 中的英尺或毫米),不是屏幕像素,也不是视图中心。常见错误是把鼠标点击位置直接当 origin,结果剖切面总在模型外“飞走”。
实操建议:
- 用
viewer.worldToClient()+viewer.clientToWorld()做坐标转换,而非viewer.getHitPoint()(它只对网格有效,对族实例常返回null) - 想让剖面过某个构件中心?先
viewer.model.getBBox()获取包围盒,再取bbox.center作为origin - 动画中平移剖面时,
origin每帧增量建议控制在模型尺寸的0.1%内,否则快速移动时会出现“跳跃感”
用 THREE.AnimationMixer 驱动剖切动画比 setTimeout 更稳
手动用 setTimeout 改 sectionPlane 会导致帧率抖动、暂停/恢复困难,且无法与 Viewer 自身渲染循环对齐。
实操建议:
- 创建独立的
THREE.AnimationMixer,绑定一个空的THREE.Object3D,将normal和origin映射为对象属性进行关键帧动画 - 关键帧数据必须用
FloatKeyframeTrack,每个分量(x,y,z)单独 track,例如:new THREE.VectorKeyframeTrack('.position', [0, 1], [ox,oy,oz, nx,ny,nz])不合法,要拆成三个FloatKeyframeTrack - 播放前调用
mixer.update(0)强制初始化,否则首帧可能跳变
真正难的不是算角度,而是确保 normal 和 origin 在整个动画生命周期里始终满足平面几何约束——稍有偏差,Viewer 就会丢弃该剖面,界面毫无提示。多打日志,少猜行为。











