中化加油站项目
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

622 lines
19 KiB

import { AbstractMesh, ArcRotateCamera, BoundingBoxGizmo, Color3, EventState, GizmoManager, Mesh, Observable, PickingInfo, PointerEventTypes, PointerInfo, Quaternion, Scene, UtilityLayerRenderer, Vector3 } from "@babylonjs/core";
import { AdvancedDynamicTexture, Button, Container, InputText, Rectangle, StackPanel, TextBlock } from "@babylonjs/gui";
import { ModeManager, ModeType } from "../controller/mode-manager";
import { SceneManager } from "../controller/scene-manager";
import { Game } from "../game";
import { ModelInfo } from "../model/info/model/model-info";
import { UIBase } from "../view/window-base/ui-base";
import { BabylonTool } from "./babylon-tool";
import { BabylonUIStyleTool } from "./babylon-ui-style-tool";
//transform 信息的UI
export enum TransformUIType {
Hide,
Position,
Rotation,
Scale,
}
export class GizmoTool {
static s_gizmoManager: GizmoManager;
static s_boundingBoxGizmo: BoundingBoxGizmo;
static s_needUpdateGizmo: NeedUpdateGizmo; //需要更新的gizmo分量
static s_transformUIInfo: TransformUIInfo;
static s_camera: ArcRotateCamera;
static onPickMeshInfoObservable: Observable<ModelInfo>; //pick事件
static onGizmoAimMeshObservable: Observable<AbstractMesh>;
static s_nowPickAim: ModelInfo;//当前pick的目标
static s_nowPickAim_mesh: AbstractMesh;//当前pick的目标
static s_btn_poisition: Button;
static s_btn_rotation: Button;
static s_btn_scaling: Button;
static init(scene: Scene, uiRoot: AdvancedDynamicTexture, camera: ArcRotateCamera) {
GizmoTool.s_camera = camera;
GizmoTool.s_boundingBoxGizmo = new BoundingBoxGizmo();
GizmoTool.s_boundingBoxGizmo.setColor(new Color3(1, 0.52, 0.07));
GizmoTool.s_boundingBoxGizmo.setEnabledRotationAxis('');
GizmoTool.s_boundingBoxGizmo.setEnabledScaling(false);
GizmoTool.initTransformUI(uiRoot);
GizmoTool.s_needUpdateGizmo = new NeedUpdateGizmo();
GizmoTool.s_gizmoManager = new GizmoManager(scene, undefined);
GizmoTool.s_gizmoManager.positionGizmoEnabled = true;
GizmoTool.s_gizmoManager.rotationGizmoEnabled = true;
GizmoTool.s_gizmoManager.scaleGizmoEnabled = true;
GizmoTool.s_gizmoManager.gizmos.positionGizmo.planarGizmoEnabled = false;
GizmoTool.s_gizmoManager.gizmos.positionGizmo.yPlaneGizmo.isEnabled = true;
GizmoTool.s_gizmoManager.gizmos.positionGizmo.yPlaneGizmo.scaleRatio = 1;
GizmoTool.s_gizmoManager.gizmos.positionGizmo.updateGizmoRotationToMatchAttachedMesh = false;
GizmoTool.s_gizmoManager.usePointerToAttachGizmos = false;
GizmoTool.s_gizmoManager.gizmos.positionGizmo.onDragStartObservable.add(
GizmoTool.onPositionGizmoStart
);
GizmoTool.s_gizmoManager.gizmos.positionGizmo.onDragEndObservable.add(
GizmoTool.onPositionGizmoEnd
);
GizmoTool.s_gizmoManager.gizmos.rotationGizmo.onDragStartObservable.add(
GizmoTool.onRotationGizmoStart
);
GizmoTool.s_gizmoManager.gizmos.rotationGizmo.onDragEndObservable.add(
GizmoTool.onRotationGizmoEnd
);
GizmoTool.s_gizmoManager.gizmos.scaleGizmo.onDragStartObservable.add(
GizmoTool.onScaleGizmoStart
);
GizmoTool.s_gizmoManager.gizmos.scaleGizmo.onDragEndObservable.add(
GizmoTool.onScaleGizmoEnd
);
scene.onPointerObservable.add(GizmoTool.onPointerObservable);
GizmoTool.onGizmoAimMeshObservable = new Observable();
GizmoTool.onPickMeshInfoObservable = new Observable();
GizmoTool.onPickMeshInfoObservable.add(GizmoTool.onChangeGizmoAim);
scene.onBeforeRenderObservable.add(GizmoTool.onBeforeRender);
GizmoTool.onTransformUITypeChange(TransformUIType.Hide);
}
static dispose() {
}
static onBeforeRender(
eventData: Scene,
eventState: EventState
) {
GizmoTool.updateTransformUI();
let speed = 10 / GizmoTool.s_camera.radius;
speed *= 1000;
GizmoTool.s_camera.panningSensibility = speed;//动态修改平移灵敏度
GizmoTool.s_camera.wheelDeltaPercentage = 0.005;
if (SceneManager.Instance.cameraMode_Is2D) {
let camera = SceneManager.Instance.defaultCamera;
camera.beta = 0;
if (camera.beta > 0.2) {
SceneManager.Instance.changeCameraMode(false);
}
else {
//GizmoTool.s_camera.size = GizmoTool.s_camera.radius * 0.01;
//console.log(GizmoTool.s_camera.orthoTop);
let size_width = GizmoTool.s_camera.radius * Game.instance.canvas.width * 0.0008;
let size_height = GizmoTool.s_camera.radius * Game.instance.canvas.height * 0.0008;
camera.orthoTop = size_height;
camera.orthoBottom = - size_height;
camera.orthoLeft = - size_width;
camera.orthoRight = size_width;
}
}
}
//鼠标事件监听
static onPointerObservable(
eventData: PointerInfo,
eventState: EventState
) {
switch (eventData.type) {
case PointerEventTypes.POINTERDOWN:
//console.log("指针按下");
break;
case PointerEventTypes.POINTERUP:
//console.log("指针抬起");
GizmoTool.pickRayTest(eventData.pickInfo);
break;
case PointerEventTypes.POINTERMOVE:
//console.log("指针移动");
break;
}
}
/**
* 替换选中
* @param modelInfo 新的modelInfo
*/
static replacePick(modelInfo: ModelInfo) {
if (GizmoTool.s_nowPickAim != modelInfo) {
GizmoTool.onChangeGizmoAim(modelInfo);
}
}
//射线检测
static pickRayTest(pickResult: PickingInfo) {
if (!SceneManager.s_isPointerDrag) {
if (pickResult.hit) {
let meshName = pickResult.pickedMesh.name;
// GizmoTool.onPickMeshObservable.notifyObservers(pickResult.pickedMesh);
//GizmoTool.changeGizmoAim(pickResult.pickedMesh);
} else {
//GizmoTool.onPickMeshInfoObservable.notifyObservers(null);
}
}
// console.log("pickRayTest " + pickResult.hit);
}
//改变gizmo目标mesh
static onChangeGizmoAim(modelInfo: ModelInfo) {
// console.trace("改变目标", modelInfo);
let mesh = null;
GizmoTool.s_nowPickAim = modelInfo;
if (modelInfo != null) {
mesh = modelInfo.modelBox;
}
GizmoTool.changeGizmoAim(mesh);
if (ModeManager.currentMode == ModeType.Edit) {
GizmoTool.s_boundingBoxGizmo.attachedMesh = mesh;
}
GizmoTool.s_transformUIInfo.Mesh = mesh;
GizmoTool.s_transformUIInfo.modelInfo = modelInfo;
GizmoTool.updateTransformUI(mesh != null);
}
//改变Gizmo目标
static changeGizmoAim(mesh: AbstractMesh, x: boolean = true, y = true, z = true) {
//console.trace("目标", ModeManager.currentMode);
GizmoTool.s_nowPickAim_mesh = mesh;
GizmoTool.s_gizmoManager.attachToMesh(mesh);
GizmoTool.s_gizmoManager.gizmos.positionGizmo.xGizmo.isEnabled = x;
GizmoTool.s_gizmoManager.gizmos.positionGizmo.yGizmo.isEnabled = y;
GizmoTool.s_gizmoManager.gizmos.positionGizmo.yPlaneGizmo.isEnabled = x && z;
GizmoTool.s_gizmoManager.gizmos.positionGizmo.zGizmo.isEnabled = z;
GizmoTool.onGizmoAimMeshObservable.notifyObservers(mesh);
}
//离开当前目标(如果当前在这个)
static leaveTheGizmoAim(modelInfo: ModelInfo) {
if (GizmoTool.s_nowPickAim != null && GizmoTool.s_nowPickAim == modelInfo) {
GizmoTool.onChangeGizmoAim(null);
}
}
//离开当前目标(如果当前在这个)
static leaveTheGizmoAimMesh(mesh: AbstractMesh) {
if (GizmoTool.s_nowPickAim_mesh != null && GizmoTool.s_nowPickAim_mesh == mesh) {
GizmoTool.onChangeGizmoAim(null);
}
}
//初始化
static initTransformUI(advTexture: AdvancedDynamicTexture) {
let transformUIInfo = new TransformUIInfo();
GizmoTool.s_transformUIInfo = transformUIInfo;
let width = 200;
let height = 150;
let ui_transformUIRoot = new Rectangle('GizmoWindow');
ui_transformUIRoot.width = width + 'px';
ui_transformUIRoot.height = height + 'px';
ui_transformUIRoot.background = UIBase.color_gray;
ui_transformUIRoot.color = '#FFFFFF';
ui_transformUIRoot.alpha = 0.8;
ui_transformUIRoot.horizontalAlignment =
Container.HORIZONTAL_ALIGNMENT_LEFT;
ui_transformUIRoot.verticalAlignment =
Container.VERTICAL_ALIGNMENT_TOP;
ui_transformUIRoot.thickness = 0;
ui_transformUIRoot.cornerRadius = BabylonUIStyleTool.cornerRadius_window1;
ui_transformUIRoot.zIndex = BabylonUIStyleTool.c_zIndex_gizmo;
advTexture.addControl(ui_transformUIRoot);
transformUIInfo.root = ui_transformUIRoot;
let stackPanel = new StackPanel('verticalGroup');
stackPanel.isVertical = true;
stackPanel.width = width + 'px';
stackPanel.height = height + 'px';
ui_transformUIRoot.addControl(stackPanel);
let txt_title = new TextBlock('title', '信息:(x,y,z)');
transformUIInfo.titleText = txt_title;
txt_title.width = width + 'px';
txt_title.height = '45px';
stackPanel.addControl(txt_title);
for (let i = 0; i < 3; i++) {
let l_InputInfo: UIVector3InputInfo = new UIVector3InputInfo();
let postionRoot = new StackPanel('Group' + i);
stackPanel.addControl(postionRoot);
postionRoot.width = width + 'px';
postionRoot.height = height * 0.23 + 'px';
postionRoot.isVertical = false;
let groupName = Button.CreateSimpleButton(
'groupName',
'info:'
);
groupName.width = width * 0.22 + 'px';
groupName.height = height * 0.22 + 'px';
groupName.fontSize = 12;
groupName.background = '#FF8833';
groupName.color = 'white';
groupName.thickness = 0;
groupName.paddingBottom = '2px';
postionRoot.addControl(groupName);
groupName.onPointerClickObservable.add(() => {
switch (i) {
case 0:
transformUIInfo.OnTypeChangeObservable.notifyObservers(
TransformUIType.Position
);
break;
case 1:
transformUIInfo.OnTypeChangeObservable.notifyObservers(
TransformUIType.Rotation
);
break;
case 2:
transformUIInfo.OnTypeChangeObservable.notifyObservers(
TransformUIType.Scale
);
break;
}
});
switch (i) {
case 0:
transformUIInfo.position = l_InputInfo;
postionRoot.name = 'transform';
groupName.textBlock.text = '位置:';
GizmoTool.s_btn_poisition = groupName;
break;
case 1:
transformUIInfo.rotation = l_InputInfo;
postionRoot.name = 'rotation';
groupName.textBlock.text = '旋转:';
GizmoTool.s_btn_rotation = groupName;
break;
case 2:
transformUIInfo.scale = l_InputInfo;
postionRoot.name = 'scale';
groupName.textBlock.text = '缩放:';
GizmoTool.s_btn_scaling = groupName;
break;
}
for (let j = 0; j < 3; j++) {
let xyz = new InputText('xyz', '12');
xyz.width = width * 0.25 + 'px';
xyz.height = height * 0.22 + 'px';
xyz.color = 'white';
xyz.alpha = 0.8;
xyz.margin = '5px';
xyz.fontSize = 13;
xyz.thickness = 0.1;
xyz.paddingLeft = '0.1px';
xyz.paddingBottom = '2px';
switch (i) {
case 0:
xyz.onTextChangedObservable.add(GizmoTool.onGizmoUIInput_Position);
break;
case 1:
xyz.onTextChangedObservable.add(GizmoTool.onGizmoUIInput_Rotation);
break;
case 2:
xyz.onTextChangedObservable.add(GizmoTool.onGizmoUIInput_Scale);
break;
}
switch (j) {
case 0:
l_InputInfo.x = xyz;
xyz.name = 'x';
xyz.background = '#C20000';
break;
case 1:
l_InputInfo.y = xyz;
xyz.name = 'y';
xyz.background = '#00820F';
break;
case 2:
l_InputInfo.z = xyz;
xyz.name = 'z';
xyz.background = '#0047C2';
break;
}
postionRoot.addControl(xyz);
}
}
transformUIInfo.OnTypeChangeObservable.add(
GizmoTool.onTransformUITypeChange
);
}
static onPositionGizmoStart() {
GizmoTool.s_needUpdateGizmo.position = true;
}
static onPositionGizmoEnd() {
GizmoTool.s_needUpdateGizmo.position = false;
}
static onRotationGizmoStart() {
GizmoTool.s_needUpdateGizmo.rotation = true;
}
static onRotationGizmoEnd() {
GizmoTool.s_needUpdateGizmo.rotation = false;
}
static onScaleGizmoStart() {
GizmoTool.s_needUpdateGizmo.scale = true;
}
static onScaleGizmoEnd() {
GizmoTool.s_needUpdateGizmo.scale = false;
}
static currentGizmoType: TransformUIType = TransformUIType.Position;
//操作的类型发生变化: 隐藏、position、rotation、scale
static onTransformUITypeChange(uiType: TransformUIType) {
// console.log("改变type" + uiType);
let transformUIInfo = GizmoTool.s_transformUIInfo;
// if (uiType == TransformUIType.Hide) {
// transformUIInfo.root.isVisible = false;
// } else {
// transformUIInfo.root.isVisible = true;
// }
transformUIInfo.root.isVisible = ModeManager.isDebug;//先隐藏,因为效果图中没有
let isEditMode = ModeManager.currentMode == ModeType.Edit;
let isPosition = uiType == TransformUIType.Position && isEditMode;
GizmoTool.s_btn_poisition.background = isPosition
? UIBase.color_yellow
: UIBase.color_null;
GizmoTool.s_gizmoManager.positionGizmoEnabled = isPosition;
let isRotation = uiType == TransformUIType.Rotation && isEditMode;
GizmoTool.s_btn_rotation.background = isRotation
? UIBase.color_yellow
: UIBase.color_null;
GizmoTool.s_gizmoManager.rotationGizmoEnabled = isRotation;
let isScaling = uiType == TransformUIType.Scale && isEditMode;
GizmoTool.s_btn_scaling.background = isScaling
? UIBase.color_yellow
: UIBase.color_null;
GizmoTool.s_gizmoManager.scaleGizmoEnabled = isScaling;
if (uiType == TransformUIType.Hide || !ModeManager.s_isMakeMode) { //隐藏选中框
GizmoTool.s_boundingBoxGizmo.attachedMesh = null;
}
}
//更新显示
static updateTransformUI(updateAll = false) {
let transformUIInfo = GizmoTool.s_transformUIInfo;
let updateGizmoInfo = GizmoTool.s_needUpdateGizmo;
let mesh = transformUIInfo.mesh;
if (transformUIInfo == null || mesh == null) {
transformUIInfo.titleText.text = '';
return;
}
transformUIInfo.titleText.text = mesh.name;
if (updateGizmoInfo.position || updateAll) {
transformUIInfo.position.x.text = mesh.position.x.toPrecision(6);
transformUIInfo.position.y.text = mesh.position.y.toPrecision(6);
transformUIInfo.position.z.text = mesh.position.z.toPrecision(6);
}
if (updateGizmoInfo.rotation || updateAll) {
let augle = mesh.rotationQuaternion.toEulerAngles();
let radian1 = BabylonTool.c_radian1; //1弧度
augle = augle.multiplyByFloats(radian1, radian1, radian1);
transformUIInfo.rotation.x.text = augle.x.toPrecision(6);
transformUIInfo.rotation.y.text = augle.y.toPrecision(6);
transformUIInfo.rotation.z.text = augle.z.toPrecision(6);
}
if (updateGizmoInfo.scale || updateAll) {
let originalScaling =
GizmoTool.s_transformUIInfo.modelInfo.modelData.transformData
.originalScaling;
transformUIInfo.scale.x.text = (
mesh.absoluteScaling.x / originalScaling.x
).toPrecision(6);
transformUIInfo.scale.y.text = (
mesh.absoluteScaling.y / originalScaling.y
).toPrecision(6);
transformUIInfo.scale.z.text = (
mesh.absoluteScaling.z / originalScaling.z
).toPrecision(6);
}
}
//输入gizmo 数值 - position
static onGizmoUIInput_Position(
eventData: InputText,
eventState: EventState
) {
let transformUIInfo = GizmoTool.s_transformUIInfo;
switch (eventData.name) {
case 'x':
transformUIInfo.Mesh.position.x = Number.parseFloat(
transformUIInfo.position.x.text
);
break;
case 'y':
transformUIInfo.Mesh.position.y = Number.parseFloat(
transformUIInfo.position.y.text
);
break;
case 'z':
transformUIInfo.Mesh.position.z = Number.parseFloat(
transformUIInfo.position.z.text
);
break;
}
}
//输入gizmo 数值 - rotation
static onGizmoUIInput_Rotation(
eventData: InputText,
eventState: EventState
) {
let transformUIInfo = GizmoTool.s_transformUIInfo;
let eugle = new Vector3();
eugle.x =
Number.parseFloat(transformUIInfo.rotation.x.text) /
BabylonTool.c_radian1;
eugle.y =
Number.parseFloat(transformUIInfo.rotation.y.text) /
BabylonTool.c_radian1;
eugle.z =
Number.parseFloat(transformUIInfo.rotation.z.text) /
BabylonTool.c_radian1;
transformUIInfo.Mesh.rotationQuaternion = Quaternion.FromEulerAngles(
eugle.x,
eugle.y,
eugle.z
);
}
//输入gizmo 数值 - scale
static onGizmoUIInput_Scale(
eventData: InputText,
eventState: EventState
) {
let transformUIInfo = GizmoTool.s_transformUIInfo;
let originalScaling =
GizmoTool.s_transformUIInfo.modelInfo.modelData.transformData
.originalScaling;
switch (eventData.name) {
case 'x':
transformUIInfo.Mesh.scaling.x =
Number.parseFloat(transformUIInfo.scale.x.text) * originalScaling.x;
break;
case 'y':
transformUIInfo.Mesh.scaling.y =
Number.parseFloat(transformUIInfo.scale.y.text) * originalScaling.y;
break;
case 'z':
transformUIInfo.Mesh.scaling.z =
Number.parseFloat(transformUIInfo.scale.z.text) * originalScaling.z;
break;
}
}
}
//需要更新gizmo的类型
class NeedUpdateGizmo {
public position = true;
public rotation = false;
public scale = false;
}
//存储vector3 对应文本输入UI的映射
class UIVector3InputInfo {
public x: InputText;
public y: InputText;
public z: InputText;
}
//存储 transform 相关UI输入类的映射
class TransformUIInfo {
public root: Rectangle;
public position: UIVector3InputInfo;
public rotation: UIVector3InputInfo;
public scale: UIVector3InputInfo;
public titleText: TextBlock;
public nowType: TransformUIType = TransformUIType.Hide;
public mesh: AbstractMesh;
public modelInfo: ModelInfo;
public onTypeChangeObservable: Observable<TransformUIType>;
public onPositionChangeObservable: Observable<Vector3> = new Observable<Vector3>();
public onRotationChangeObservable: Observable<Vector3> = new Observable<Vector3>();
public onScaleChangeObservable: Observable<Vector3> = new Observable<Vector3>();
set Mesh(value: AbstractMesh) {
let lastMesh = this.mesh;
this.mesh = value;
if (value == null) {
this.NowType = TransformUIType.Hide;
} else {
//if (lastMesh == null) {
this.NowType = GizmoTool.currentGizmoType;// TransformUIType.Position;
//}
}
}
get Mesh() {
return this.mesh;
}
set NowType(value: TransformUIType) {
this.nowType = value;
// console.log("NowType====" + value);
this.OnTypeChangeObservable.notifyObservers(this.nowType);
}
get OnTypeChangeObservable(): Observable<TransformUIType> {
if (this.onTypeChangeObservable == null) {
this.onTypeChangeObservable = new Observable<TransformUIType>();
}
return this.onTypeChangeObservable;
}
}