邵佳豪 3 years ago
parent
commit
b9346b2ef4
  1. 24
      README.md
  2. 27
      src/app/babylon/controller/scene-manager.ts
  3. 28
      src/app/babylon/model/info/model/model-info-building.ts
  4. 65
      src/app/babylon/tool/babylon-tool.ts
  5. 2
      src/app/babylon/tool/mesh-pool.ts
  6. 111
      src/app/babylon/view/building-window/building-window.ts
  7. 4
      src/app/pages/left-domain/left-domain.component.ts
  8. 4
      src/app/pages/plan/plan.component.html
  9. 8
      src/app/pages/plan/plan.component.ts

24
README.md

@ -1,5 +1,29 @@
# 中国石化加油站项目
## 🌼v1.1.0
### 🌻 简介
> 时间:2022、1、22 周六
> 优化加载
> 增加镜头限制、增加吸附功能
### 🌻 详情
> 前端部分
- [🚩 重大变更]
- [🌱 新增]
- [🍀 完善]
> 三维部分
- [🚩 重大变更] 增加对关联复制模型的支持,可以大幅减少 bin 文件的大小,增加解析速度与渲染速度
- [🚩 重大变更] 暂时停止 1+n 的模型加载模式(indexDB 问题以在另外的地方进行解决),充分利用并发加载
- [🌱 新增] 摄像头旋转时设置限制,避免看到场景的底部
- [🌱 新增] 增加建筑吸附、对齐到场景中的功能,确定对齐规则,使用“WAI”节点作为插槽
- [🍀 完善]
## 🌼v1.0.9
### 🌻 简介

27
src/app/babylon/controller/scene-manager.ts

@ -11,6 +11,7 @@ import {
EventState,
HemisphericLight,
HighlightLayer,
InstancedMesh,
IParticleSystem,
ISceneLoaderProgressEvent,
Mesh,
@ -57,10 +58,13 @@ import { ModelInfo_mark_multiArrow } from '../model/info/mark/other/mark-plan-mu
import { ModelInfo_mark_particle } from '../model/info/mark/other/mark-plan-particle-info';
import { FacilityPosType, ModelData_facility } from '../model/data/model-data/model-data-facility';
import { LoadTool } from '../tool/load-tool';
import { flatten } from 'earcut';
//场景管理器
export class SceneManager {
//----------------Camera-----------------\\
public engine: Engine;
@ -75,7 +79,7 @@ export class SceneManager {
static s_openLight: boolean = true;//开启光照效果(关闭是要同时关闭阴影)
static s_openShadow: boolean = true;//开启阴影(必须开启阴影
static s_openShadow: boolean = true;//开启阴影(必须开启光照
static s_openSkyBox: boolean = true;//使用天空盒
static s_environmentCubeTexture: CubeTexture;//环境所用的cubeTexture
static s_openEnvironmentReflection: boolean = true;//使用环境反射
@ -161,7 +165,7 @@ export class SceneManager {
);
camera.minZ = 0;//最近拍摄距离
camera.maxZ = 6000; //摄像机拍摄的最远距离
// camera.upperBetaLimit = 1.5; //beta方向上的旋转限制(防止看到模型底面)
camera.upperBetaLimit = 1.5; //beta方向上的旋转限制(防止看到模型底面)
camera.lowerRadiusLimit = 1; //相机距离拍摄目标的最小距离(防止穿插)
camera.setTarget(Vector3.Zero()); //设置拍摄目标
camera.radius = 100;
@ -229,7 +233,7 @@ export class SceneManager {
}
else {
if (this.sunLight == null) {
if (this.sunLight != null) {
this.sunLight.setEnabled(false);
}
@ -241,7 +245,7 @@ export class SceneManager {
*
*/
public updateShadow() {
if (SceneManager.s_openShadow) {
if (SceneManager.s_openLight && SceneManager.s_openShadow) {
if (this.shadowGenerator == null) {
this.shadowGenerator = new ShadowGenerator(2048, this.sunLight);
}
@ -663,7 +667,7 @@ export class SceneManager {
canPick = true;
//}
if (SceneManager.s_openShadow) {
if (SceneManager.s_openShadow && !(newMeshes[i] instanceof InstancedMesh)) {
newMeshes[i].receiveShadows = true;
// let mat = newMeshes[i].material;
@ -873,13 +877,22 @@ export class SceneManager {
*/
public static meshAdsorbY(mover: AbstractMesh, target: AbstractMesh, pickPos: Vector3) {
ModeManager.log("吸附模型" + target);
// console.log("吸附模型" + target);
let targetRoot = SceneManager.getRootTransformNode(target);
let targetRoot = SceneManager.getRootTransformNode(target) as AbstractMesh;
if (mover == targetRoot) {
return;
}
//先通过吸附点吸附
let byAdsorbPoint = BabylonTool.adsorb2MeshByPoint(mover, targetRoot, "WAI")
//完成吸附了
if (byAdsorbPoint) {
return;
}
let aimPos_y: number = 0;
let direction = 0.5;

28
src/app/babylon/model/info/model/model-info-building.ts

@ -12,6 +12,7 @@ import { StatusManager } from "src/app/babylon/controller/status/status-manager"
import { BabylonUIStyleTool } from "src/app/babylon/tool/babylon-ui-style-tool";
import { GizmoTool } from "src/app/babylon/tool/gizmo-tool";
import { TsTool } from "src/app/babylon/tool/ts-tool";
import { BuildingWindow } from "src/app/babylon/view/building-window/building-window";
import { FacilityWindow } from "src/app/babylon/view/facility-window/facility-window";
@ -27,7 +28,7 @@ export class ModelInfo_building extends ModelInfo {
facilityInfos: FacilityInfoByType[] = [];
buildingType: BuildingType = BuildingType.Normal;
neiRoot: TransformNode; //facilityRoot参照的节点
anchorRoot: TransformNode; //facilityRoot参照的节点
updateObserver: Observer<Scene>;
onSetModelBox() {
@ -38,30 +39,29 @@ export class ModelInfo_building extends ModelInfo {
initFacilityRoot() {
let allTransformNode = this.modelBox.getChildTransformNodes();
this.neiRoot = null;
this.anchorRoot = null;
for (let i = 0; i < allTransformNode.length; i++) {
if (TsTool.stringContain(allTransformNode[i].name, "nei")) {
this.neiRoot = allTransformNode[i];
this.anchorRoot = allTransformNode[i];
break;
}
}
if (this.neiRoot == null) {
if (this.anchorRoot == null) {
for (let i = 0; i < allTransformNode.length; i++) {
if (TsTool.stringContain(allTransformNode[i].name, "WAI")) {
this.neiRoot = allTransformNode[i];
this.anchorRoot = allTransformNode[i];
break;
}
}
}
if (this.neiRoot == null) {
if (this.anchorRoot == null) {
if (!TsTool.stringContain(this.modelBox.name, "Box")) {
console.error("没有关键节点", this.modelBox.name);
}
this.neiRoot = this.modelBox;
this.anchorRoot = this.modelBox;
}
if (this.facilityRoot != null) {
@ -207,13 +207,17 @@ export class ModelInfo_building extends ModelInfo {
onBeforeRender() {
// console.log(this.modelBox.absolutePosition);
this.facilityRoot.position = this.neiRoot.absolutePosition.clone();
this.facilityRoot.rotation = this.neiRoot.rotation.clone();
this.facilityRoot.position = this.anchorRoot.absolutePosition.clone();
this.facilityRoot.rotation = this.anchorRoot.rotation.clone();
//if (this.modelBox.rotationQuaternion != null) {
this.facilityRoot.rotationQuaternion = this.neiRoot.absoluteRotationQuaternion.clone();
if (this.neiRoot.parent != null && (this.neiRoot.parent as TransformNode).scaling.y < 0) {
this.facilityRoot.rotationQuaternion = this.anchorRoot.absoluteRotationQuaternion.clone();
if (this.anchorRoot.parent != null && (this.anchorRoot.parent as TransformNode).scaling.y < 0) {
this.facilityRoot.scaling.y = -1;
}
if (TsTool.stringContain(this.anchorRoot.name, "WAI") && BuildingWindow.instance != null) {
BuildingWindow.instance.setLimitCameraY_min(this.anchorRoot.absolutePosition.y);
}
//}
}

65
src/app/babylon/tool/babylon-tool.ts

@ -10,6 +10,7 @@ import {
ISceneLoaderPluginAsync,
ISceneLoaderProgressEvent,
Mesh,
Node,
NodeMaterial,
PBRMaterial,
QuadraticEase,
@ -146,10 +147,14 @@ export class BabylonTool {
).then(function (result) {
LoadTool.remove(modelPath);
isSuccess = true;
onSuccess(result.meshes, result.particleSystems, result.skeletons, result.animationGroups);
}).catch(function (result) {
onError(scene, "load error", result);
if (onSuccess) {
onSuccess(result.meshes, result.particleSystems, result.skeletons, result.animationGroups);
}
}).catch(function (result) {
if (onError) {
onError(scene, "load error", result);
}
});
// setTimeout(() => {
@ -274,14 +279,14 @@ export class BabylonTool {
}
else {
let alpha = BabylonTool.alpha_N;
camera.target = BabylonTool.getWorldPosition(mesh).clone();
camera.target = BabylonTool.getWorldPosition(mesh);
camera.radius = maxScaleAxis + 50;
camera.alpha = alpha;
camera.beta = 1;
BabylonTool.AnimMoveCameraTarget(
camera,
60,
BabylonTool.getWorldPosition(mesh).clone(),
BabylonTool.getWorldPosition(mesh),
maxScaleAxis + 5
);
}
@ -537,6 +542,56 @@ export class BabylonTool {
}
/**
* mesh
* key的节点
* @param mover
* @param targetRoot
* @param key
*/
public static adsorb2MeshByPoint(mover: AbstractMesh, targetRoot: AbstractMesh, key: string) {
//吸附成功
let isSuccess = false;
//找到移动者的对齐点
let moverAdsorbNode = BabylonTool.getNodeContainKey(mover, key);
if (moverAdsorbNode != null && moverAdsorbNode.length > 0 && targetRoot instanceof Mesh) {
let moverAdsorbPoint = moverAdsorbNode[0] as AbstractMesh;
let aimNode = BabylonTool.getNodeContainKey(targetRoot, moverAdsorbPoint.name);
if (aimNode != null && aimNode.length > 0) {
let aimAdsorbPoint = aimNode[0] as AbstractMesh;
let aimPos = aimAdsorbPoint.getAbsolutePosition();
//世界坐标下,移动者的吸附点相对于根节点的偏移
let moverLocalPos = moverAdsorbPoint.getAbsolutePosition().subtract(mover.getAbsolutePosition());
let moverNewPos = aimPos.subtract(moverLocalPos);
mover.setAbsolutePosition(moverNewPos);
isSuccess = true;
}
}
return isSuccess;
}
/**
*
* Adsorb_
* @param mesh
*/
public static getNodeContainKey(mesh: AbstractMesh, key: string) {
let moverAdsorbNode = mesh.getChildren((node: Node) => {
if (TsTool.stringContain(node.name, key)) {
return true;
}
else {
return false;
}
}, false)
return moverAdsorbNode;
}
}
//输入提示界面

2
src/app/babylon/tool/mesh-pool.ts

@ -307,7 +307,7 @@ export class MeshPoolInfo {
// let box = MeshBuilder.CreateBox("box", { size: 1 }); //用于测试阴影
// box.setParent(modelInfo.modelBox);
// box.position = new Vector3(0, 2, 0);
if (SceneManager.s_openShadow) {
if (SceneManager.s_openLight && SceneManager.s_openShadow) {
SceneManager.Instance.shadowGenerator.addShadowCaster(modelInfo.modelBox, true);
// console.log("添加到阴影", modelInfo.modelBox.name);
}

111
src/app/babylon/view/building-window/building-window.ts

@ -342,6 +342,7 @@ export class BuildingWindow extends UIBase {
onUpdate() {
this.updateUVAnim();
this.updateLimitCameraY();
}
@ -553,47 +554,58 @@ export class BuildingWindow extends UIBase {
}
}
if (allModelNumber > 1) {
//暂时关闭 1+ n的加载模式
// if (allModelNumber > 1) {
if (firstType == BuildingType.Environment) {
instance.createOneBuildingItem(firstItem, 0, (uiItem, index) => {
instance.onChangeCurrentBuildingItem(uiItem, false);
// uiItem.lookAt(false);
if (buildingDatas_Environment.length > 1) {
instance.addBuildings(BuildingType.Environment, 1);
}
// if (firstType == BuildingType.Environment) {
// instance.createOneBuildingItem(firstItem, 0, (uiItem, index) => {
// instance.onChangeCurrentBuildingItem(uiItem, false);
// // uiItem.lookAt(false);
// if (buildingDatas_Environment.length > 1) {
// instance.addBuildings(BuildingType.Environment, 1);
// }
instance.addBuildings(BuildingType.Normal, 0);
// instance.addBuildings(BuildingType.Normal, 0);
});
// });
}
else {
instance.createOneBuildingItem(firstItem, 0, (uiItem, index) => {
instance.onChangeCurrentBuildingItem(uiItem, false);
// uiItem.lookAt(false);
if (buildingDatas_mormal.length > 1) {
instance.addBuildings(BuildingType.Normal, 1);
}
instance.addBuildings(BuildingType.Environment, 0);
// }
// else {
// instance.createOneBuildingItem(firstItem, 0, (uiItem, index) => {
// instance.onChangeCurrentBuildingItem(uiItem, false);
// // uiItem.lookAt(false);
// if (buildingDatas_mormal.length > 1) {
// instance.addBuildings(BuildingType.Normal, 1);
// }
// instance.addBuildings(BuildingType.Environment, 0);
});
}
// });
// }
}
else {
// }
// else {
instance.addBuildings(BuildingType.Normal, 0, (uiItem, index) => {
if (index == 0 && uiItem.buildingInfo.isEnable) {
instance.onChangeCurrentBuildingItem(uiItem, false);
//uiItem.lookAt(false);
// console.log("默认选中" + uiItem.buildingInfo.buildingData.normalData.key);
}
});
// instance.addBuildings(BuildingType.Normal, 0, (uiItem, index) => {
// if (index == 0 && uiItem.buildingInfo.isEnable) {
// instance.onChangeCurrentBuildingItem(uiItem, false);
// //uiItem.lookAt(false);
// // console.log("默认选中" + uiItem.buildingInfo.buildingData.normalData.key);
// }
// });
instance.addBuildings(BuildingType.Environment, 0);
}
// instance.addBuildings(BuildingType.Environment, 0);
// }
instance.addBuildings(BuildingType.Normal, 0, (uiItem, index) => {
if (index == 0 && uiItem.buildingInfo.isEnable) {
instance.onChangeCurrentBuildingItem(uiItem, false);
//uiItem.lookAt(false);
// console.log("默认选中" + uiItem.buildingInfo.buildingData.normalData.key);
}
});
instance.addBuildings(BuildingType.Environment, 0);
}
@ -1091,8 +1103,6 @@ export class BuildingWindow extends UIBase {
}
/**
*
*/
@ -1128,6 +1138,39 @@ export class BuildingWindow extends UIBase {
//#endregion
//#region 限制摄像机Y
/**
* Y高度的限制
*/
limitCameraY_min: number = null;
/**
* target最小Y
* @param value
*/
setLimitCameraY_min(value: number) {
this.limitCameraY_min = value;
}
/**
* Y
*/
updateLimitCameraY() {
if (SceneManager.Instance.defaultCamera != null) {
if (this.limitCameraY_min != null) {
if (SceneManager.Instance.defaultCamera.target.y < this.limitCameraY_min) {
SceneManager.Instance.defaultCamera.target.y = this.limitCameraY_min;
}
}
}
}
//#endregion
}

4
src/app/pages/left-domain/left-domain.component.ts

@ -371,8 +371,8 @@ export class LeftDomainComponent implements OnInit {
} else if (this.selectPlanId === item.id && this.selectNodeId === e.id) { //取消选中
this.selectPlanId = null
this.selectNodeId = null
PlanComponent.instance.beforeEmergencyPlan = new MarkPlanData(-99, "请选择节点")
PlanComponent.instance.beforePlanNode = new MarkNodeData(-99, "请选择节点")
PlanComponent.instance.beforeEmergencyPlan = new MarkPlanData(-99, "请选择应急预案")
PlanComponent.instance.beforePlanNode = new MarkNodeData(-99, "请选择应急预案")
this.updateFatherData(index) //更新/初始化父组件 数据
MarkWindow.instance.selectMarkNode(null, null)
}

4
src/app/pages/plan/plan.component.html

@ -143,8 +143,8 @@
<button title="平移" (click)="translation()" [ngClass]="{'selectRightTopFast': selectRightTopFast == 0}"></button>
<button title="旋转" (click)="revolve()" [ngClass]="{'selectRightTopFast': selectRightTopFast == 1}"></button>
<button title="缩放" (click)="scale()" [ngClass]="{'selectRightTopFast': selectRightTopFast == 2}"></button>
<!-- <button title="吸附" (click)="adsorb()" [ngClass]="{'leftFastIsTure': selectAdsorb }"></button>
<button title="切换至顶视图" (click)="toggleTopLevelView()" [ngClass]="{'leftFastIsTure': topLevelView }"></button> -->
<button title="吸附" (click)="adsorb()" [ngClass]="{'leftFastIsTure': selectAdsorb }"></button>
<!-- <button title="切换至顶视图" (click)="toggleTopLevelView()" [ngClass]="{'leftFastIsTure': topLevelView }"></button> -->
</div>
<div class="save">
<button (click)="preserve(false)" title="保存模块"><i nz-icon nzType="file-done" nzTheme="outline"></i></button>

8
src/app/pages/plan/plan.component.ts

@ -497,8 +497,8 @@ export class PlanComponent implements OnInit {
}
allMarkPlanData: AllMarkPlanData; //处置预案节点 数据
beforeEmergencyPlan: MarkPlanData = new MarkPlanData(-99, "请选择节点"); //当前选择 应急预案
beforePlanNode: MarkNodeData = new MarkNodeData(-99, "请选择节点"); //当前选择 预案节点
beforeEmergencyPlan: MarkPlanData = new MarkPlanData(-99, "请选择应急预案"); //当前选择 应急预案
beforePlanNode: MarkNodeData = new MarkNodeData(-99, "请选择应急预案"); //当前选择 预案节点
nzCurrent: number = -1; //当前选择 预案节点Index
isSuspend: boolean = false; //是否暂停 自动切换节点
progressList: number[] = []; //进度条 条/值
@ -506,8 +506,8 @@ export class PlanComponent implements OnInit {
//初始化 应急预案模块
initializePlan() {
this.beforeEmergencyPlan = new MarkPlanData(-99, "请选择节点")
this.beforePlanNode = new MarkNodeData(-99, "请选择节点")
this.beforeEmergencyPlan = new MarkPlanData(-99, "请选择应急预案")
this.beforePlanNode = new MarkNodeData(-99, "请选择应急预案")
this.isSuspend = false //初始化暂停状态
this.progressList = []
window.clearTimeout(this.updateTimer) //清除定时器

Loading…
Cancel
Save