This commit is contained in:
2026-05-13 10:43:06 +08:00
parent 6cefd063f2
commit 223fa5dd4e
19 changed files with 2282 additions and 104 deletions

View File

@ -0,0 +1,257 @@
import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
import { PointerDragBehavior } from '@babylonjs/core/Behaviors/Meshes/pointerDragBehavior';
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
import { Scene } from '@babylonjs/core/scene';
import { Monobehiver } from '../base/Monobehiver';
/**
* 拖拽配置接口
*/
export interface DragConfig {
enable: boolean;
axis?: 'x' | 'y' | 'z' | 'xy' | 'xz' | 'yz' | 'xyz';
step?: number;
}
/**
* 模型拖拽信息
*/
interface ModelDragInfo {
config: DragConfig;
behavior: PointerDragBehavior | null;
currentAxis: 'x' | 'y' | 'z' | null;
}
/**
* 模型拖拽管理器 - 负责处理模型的拖拽交互
*/
export class AppModelDrag extends Monobehiver {
private modelDragMap: Map<string, ModelDragInfo>;
private scene: Scene | null;
constructor(mainApp: any) {
super(mainApp);
this.modelDragMap = new Map();
this.scene = null;
}
/**
* 初始化拖拽管理器
*/
Awake(): void {
this.scene = this.mainApp.appScene.object;
if (!this.scene) {
console.warn('Scene not initialized');
return;
}
}
/**
* 为模型配置拖拽
* @param modelId 模型ID
* @param config 拖拽配置
*/
configureDrag(modelId: string, config: DragConfig): void {
// 获取模型的根网格
const meshes = this.mainApp.appModel?.modelDic?.Get(modelId);
if (!meshes || !meshes.length) {
console.warn(`Model not found: ${modelId}`);
return;
}
const rootMesh = meshes[0]; // 第一个是根节点
// 如果已存在,先移除旧的行为
const existingInfo = this.modelDragMap.get(modelId);
if (existingInfo?.behavior) {
rootMesh.removeBehavior(existingInfo.behavior);
}
// 创建拖拽信息
const dragInfo: ModelDragInfo = {
config: { ...config },
behavior: null,
currentAxis: this.getFirstAvailableAxis(config.axis || 'xyz')
};
if (config.enable) {
// 创建并配置拖拽行为
dragInfo.behavior = this.createDragBehavior(modelId, dragInfo);
rootMesh.addBehavior(dragInfo.behavior);
}
this.modelDragMap.set(modelId, dragInfo);
}
/**
* 创建拖拽行为
*/
private createDragBehavior(modelId: string, dragInfo: ModelDragInfo): PointerDragBehavior {
const axis = dragInfo.currentAxis;
let dragAxis: Vector3;
// 根据当前激活的轴创建拖拽向量
switch (axis) {
case 'x':
dragAxis = new Vector3(1, 0, 0);
break;
case 'y':
dragAxis = new Vector3(0, 1, 0);
break;
case 'z':
dragAxis = new Vector3(0, 0, 1);
break;
default:
dragAxis = new Vector3(1, 0, 0);
}
// 创建拖拽行为
const pointerDragBehavior = new PointerDragBehavior({ dragAxis: dragAxis });
// 使用世界坐标系而不是物体本地坐标系
pointerDragBehavior.useObjectOrientationForDragging = false;
// 监听拖拽开始事件
pointerDragBehavior.onDragStartObservable.add(() => {
// 禁用相机控制
this.disableCameraControl();
});
// 监听拖拽结束事件
pointerDragBehavior.onDragEndObservable.add(() => {
// 恢复相机控制
this.enableCameraControl();
});
return pointerDragBehavior;
}
/**
* 获取模型的拖拽配置
* @param modelId 模型ID
*/
getDragConfig(modelId: string): DragConfig | undefined {
return this.modelDragMap.get(modelId)?.config;
}
/**
* 启用/禁用模型拖拽
* @param modelId 模型ID
* @param enable 是否启用
*/
setDragEnabled(modelId: string, enable: boolean): void {
const dragInfo = this.modelDragMap.get(modelId);
if (!dragInfo) return;
dragInfo.config.enable = enable;
const meshes = this.mainApp.appModel?.modelDic?.Get(modelId);
if (!meshes || !meshes.length) return;
const rootMesh = meshes[0];
if (enable) {
// 启用:创建并添加行为
if (!dragInfo.behavior) {
dragInfo.behavior = this.createDragBehavior(modelId, dragInfo);
rootMesh.addBehavior(dragInfo.behavior);
}
} else {
// 禁用:移除行为
if (dragInfo.behavior) {
rootMesh.removeBehavior(dragInfo.behavior);
dragInfo.behavior = null;
}
}
}
/**
* 切换激活的轴向
* @param modelId 模型ID
* @param axis 要激活的轴向
*/
switchAxis(modelId: string, axis: 'x' | 'y' | 'z'): void {
const dragInfo = this.modelDragMap.get(modelId);
if (!dragInfo) return;
// 检查该轴是否在允许的轴向中
if (!this.isAxisAllowed(axis, dragInfo.config.axis || 'xyz')) {
console.warn(`Axis ${axis} is not allowed for model ${modelId}`);
return;
}
// 更新当前轴
dragInfo.currentAxis = axis;
// 重新创建拖拽行为
const meshes = this.mainApp.appModel?.modelDic?.Get(modelId);
if (!meshes || !meshes.length) return;
const rootMesh = meshes[0];
// 移除旧行为
if (dragInfo.behavior) {
rootMesh.removeBehavior(dragInfo.behavior);
}
// 创建新行为
if (dragInfo.config.enable) {
dragInfo.behavior = this.createDragBehavior(modelId, dragInfo);
rootMesh.addBehavior(dragInfo.behavior);
}
}
/**
* 获取配置中的第一个可用轴
*/
private getFirstAvailableAxis(axisConfig: string): 'x' | 'y' | 'z' | null {
if (axisConfig.includes('x')) return 'x';
if (axisConfig.includes('y')) return 'y';
if (axisConfig.includes('z')) return 'z';
return null;
}
/**
* 检查轴是否在允许的配置中
*/
private isAxisAllowed(axis: 'x' | 'y' | 'z', axisConfig: string): boolean {
return axisConfig.includes(axis);
}
/**
* 禁用相机控制
*/
private disableCameraControl(): void {
const camera = this.mainApp.appCamera?.object;
if (camera) {
camera.detachControl();
}
}
/**
* 启用相机控制
*/
private enableCameraControl(): void {
const camera = this.mainApp.appCamera?.object;
const canvas = this.mainApp.appEngin?.object?.getRenderingCanvas();
if (camera && canvas) {
camera.attachControl(canvas, true);
}
}
/**
* 清理资源
*/
dispose(): void {
// 移除所有拖拽行为
this.modelDragMap.forEach((dragInfo, modelId) => {
if (dragInfo.behavior) {
const meshes = this.mainApp.appModel?.modelDic?.Get(modelId);
if (meshes && meshes.length) {
meshes[0].removeBehavior(dragInfo.behavior);
}
}
});
this.modelDragMap.clear();
}
}