From 2f48948e43def5bfab5790e7bf8a69db2593da02 Mon Sep 17 00:00:00 2001 From: zguiy <1415466602@qq.com> Date: Mon, 16 Mar 2026 11:15:06 +0800 Subject: [PATCH] 1 --- index.html | 4 +- src/babylonjs/GameManager.ts | 177 +++++++++++++++++++++++------------ 2 files changed, 120 insertions(+), 61 deletions(-) diff --git a/index.html b/index.html index 04df6c1..69e033e 100644 --- a/index.html +++ b/index.html @@ -43,7 +43,7 @@ const config = { container: document.querySelector('#renderDom'), - modelUrlList: ['https://sdk.zguiy.com/resurces/model/model_new.glb'], + modelUrlList: ['https://sdk.zguiy.com/resurces/model/model.glb'], env: { envPath: 'https://sdk.zguiy.com/resurces/hdr/hdr.env', intensity: 1.2, rotationY: 0.3, background: false }, }; @@ -81,7 +81,7 @@ console.log('模型点击事件', data); // 切换卷帘门开关 - kernel.door.toggle({ speed: 1.2 }); + kernel.door.toggle({ upY: 28, downY: 0, speed: 12 }); // Y轴剖切,只作用于卷帘门网格,保留下方,剖掉上方 const clipHeight = 28; // 调整这个值找到合适的剖切高度 diff --git a/src/babylonjs/GameManager.ts b/src/babylonjs/GameManager.ts index 3ba3e28..833dfc9 100644 --- a/src/babylonjs/GameManager.ts +++ b/src/babylonjs/GameManager.ts @@ -24,6 +24,7 @@ export class GameManager extends Monobehiver { private meshDic: Dictionary; private oldTextureDic: Dictionary; private rollerDoorMeshes: AbstractMesh[]; + private rollerDoorGroup: AbstractMesh | null; private rollerDoorInitialY: Map; private rollerDoorObserver: Nullable>; private rollerDoorIsOpen: boolean; @@ -32,7 +33,7 @@ export class GameManager extends Monobehiver { private yClipTargets: string[] | null; private clipPlaneVisualization: Mesh | null; - // 记录加载失败的贴图 + // 记录加载失败的贴图 private failedTextures: Array<{ path: string; materialName?: string; @@ -47,6 +48,7 @@ export class GameManager extends Monobehiver { this.meshDic = new Dictionary(); this.oldTextureDic = new Dictionary(); this.rollerDoorMeshes = []; + this.rollerDoorGroup = null; this.rollerDoorInitialY = new Map(); this.rollerDoorObserver = null; this.rollerDoorIsOpen = false; @@ -82,12 +84,16 @@ export class GameManager extends Monobehiver { // 初始化网格字典 for (const mesh of scene.meshes) { if (mesh instanceof Mesh) { - + this.meshDic.Set(mesh.name, mesh); } } this.cacheRollerDoorMeshes(); - console.log('材质字典:', this.materialDic); + console.log('材质字典:', this.materialDic); + this.setRollerDoorScale("Box006.001", new Vector3(0.12,0.02,0.118)); + + // 单独设置 Box005.001 的缩放为 (1, 2, 1) + this.setRollerDoorScale("Box005.001", new Vector3(0.13,0.02,0.12)); } /** 初始化设置材质 */ @@ -278,14 +284,14 @@ export class GameManager extends Monobehiver { apply: (value: number) => { mat.metallic = value; } - }, + }, { key: "alpha", value: component.alpha, apply: (value: number) => { mat.alpha = value; } - }, + }, { key: "environmentIntensity", value: component.environmentIntensity, @@ -381,76 +387,63 @@ export class GameManager extends Monobehiver { this.cacheRollerDoorMeshes(options?.meshNames); - if (!this.rollerDoorMeshes.length) { - console.warn('Roller door meshes not found'); + if (!this.rollerDoorGroup || !this.rollerDoorMeshes.length) { + console.warn('Roller door group or meshes not found'); return; } const speed = Math.max(options?.speed ?? 1, 0.01); - const targets = this.rollerDoorMeshes.map(mesh => { - const baseY = this.rollerDoorInitialY.get(mesh.name) ?? mesh.position.y; - let targetY: number; - - if (open) { - // 上升时:如果指定了绝对高度就用绝对高度,否则用相对高度 - if (options?.upY !== undefined) { - targetY = options.upY; - } else { - // 找到所有门中最高的初始位置,让所有门都升到这个高度+3 - const maxBaseY = Math.max(...this.rollerDoorMeshes.map(m => - this.rollerDoorInitialY.get(m.name) ?? m.position.y - )); - targetY = maxBaseY + 3; - } + // 计算目标高度 + let targetY: number; + if (open) { + // 上升时:如果指定了绝对高度就用绝对高度,否则用相对高度 + if (options?.upY !== undefined) { + targetY = options.upY; } else { - // 下降时:回到各自的初始位置 - targetY = options?.downY ?? baseY; + // 找到所有门中最高的初始位置,让所有门都升到这个高度+3 + const maxBaseY = Math.max(...this.rollerDoorMeshes.map(m => + this.rollerDoorInitialY.get(m.name) ?? m.position.y + )); + targetY = maxBaseY + 3; } + } else { + // 下降时:回到初始位置 + targetY = 0; + } - const direction = targetY >= mesh.position.y ? 1 : -1; - const distance = Math.abs(targetY - mesh.position.y); - console.log(`[door] ${mesh.name}: current=${mesh.position.y.toFixed(2)}, target=${targetY.toFixed(2)}, distance=${distance.toFixed(2)}`); - return { mesh, targetY, direction, distance }; - }); - - const alreadyAtTarget = targets.every(({ mesh, targetY }) => Math.abs(mesh.position.y - targetY) < 0.001); - if (alreadyAtTarget) { + // 检查是否已经在目标位置 + if (Math.abs(this.rollerDoorGroup.position.y - targetY) < 0.001) { this.rollerDoorIsOpen = open; return; } - // 找到最大移动距离,用于计算统一的移动时间 - const maxDistance = Math.max(...targets.map(t => t.distance), 0.001); - this.rollerDoorIsOpen = open; this.stopRollerDoorAnimation(); this.rollerDoorObserver = scene.onBeforeRenderObservable.add(() => { const dt = scene.getEngine().getDeltaTime() / 1000; - let finished = true; + const current = this.rollerDoorGroup!.position.y; + const direction = targetY >= current ? 1 : -1; - for (const item of targets) { - const current = item.mesh.position.y; - const dir = item.direction; + // 使用固定速度变量 + const step = speed * dt; + let next = current + direction * step; - // 根据每个门的移动距离占比调整速度,确保同时到达 - const speedMultiplier = item.distance / maxDistance; - const step = speed * dt * speedMultiplier; - let next = current + dir * step; - - if ((dir > 0 && next >= item.targetY) || (dir < 0 && next <= item.targetY)) { - next = item.targetY; - } else { - finished = false; - } - - item.mesh.position.y = next; - } - - if (finished) { + if ((direction > 0 && next >= targetY) || (direction < 0 && next <= targetY)) { + next = targetY; this.stopRollerDoorAnimation(); this.rollerDoorIsOpen = open; + console.log('Roller door animation finished'); + } + + // 移动透明盒子 + this.rollerDoorGroup!.position.y = next; + + // 打印每个卷帘门的当前位置 + console.log('Roller door positions:'); + for (const mesh of this.rollerDoorMeshes) { + console.log(`${mesh.name}: ${mesh.position.y.toFixed(2)}`); } }); } @@ -460,6 +453,40 @@ export class GameManager extends Monobehiver { return this.rollerDoorIsOpen; } + /** + * 设置卷帘门的缩放 + * @param meshName - 卷帘门网格名称 + * @param scale - 缩放值(可以是单个数字或 Vector3) + */ + setRollerDoorScale(meshName: string, scale: number | Vector3): void { + const mesh = this.meshDic.Get(meshName); + if (mesh) { + if (typeof scale === 'number') { + mesh.scaling.set(scale, scale, scale); + } else { + mesh.scaling.copyFrom(scale); + } + console.log(`Set scale for ${meshName}:`, mesh.scaling.asArray()); + } else { + console.warn(`Roller door mesh not found: ${meshName}`); + } + } + + /** + * 设置所有卷帘门的缩放 + * @param scale - 缩放值(可以是单个数字或 Vector3) + */ + setAllRollerDoorsScale(scale: number | Vector3): void { + this.rollerDoorMeshes.forEach(mesh => { + if (typeof scale === 'number') { + mesh.scaling.set(scale, scale, scale); + } else { + mesh.scaling.copyFrom(scale); + } + console.log(`Set scale for ${mesh.name}:`, mesh.scaling.asArray()); + }); + } + /** * 设置基于 Y 轴的剖切平面,keepAbove=true 时保留平面以上部分 * onlyMeshNames 指定只作用于哪些网格,其他网格不受影响 @@ -508,15 +535,41 @@ export class GameManager extends Monobehiver { } private cacheRollerDoorMeshes(customNames?: string[]): void { + const scene = this.mainApp.appScene?.object; + if (!scene) return; + const names = customNames?.length ? customNames : this.rollerDoorNames; this.rollerDoorMeshes = []; + + // 创建或获取 group 作为父级 + if (!this.rollerDoorGroup) { + // 创建一个 AbstractMesh 作为组 + this.rollerDoorGroup = new AbstractMesh('rollerDoorGroup', scene); + // 确保 group 的缩放为 1 + // 确保 group 的初始位置为 (0, 0, 0) + this.rollerDoorGroup.position.set(0, 0, 0); + } + for (const name of names) { const mesh = this.meshDic.Get(name); if (mesh) { this.rollerDoorMeshes.push(mesh); + + // 保存网格的当前位置作为初始位置 if (!this.rollerDoorInitialY.has(name)) { this.rollerDoorInitialY.set(name, mesh.position.y); } + + // 保存网格的世界位置和缩放 + const worldPosition = mesh.getAbsolutePosition(); + const worldScaling = new Vector3(mesh.scaling.x, mesh.scaling.y, mesh.scaling.z); + + // 将网格添加到 group 中 + mesh.parent = this.rollerDoorGroup; + + // 调整网格的局部位置和缩放,保持世界位置和大小不变 + mesh.setAbsolutePosition(worldPosition); + mesh.scaling.copyFrom(worldScaling); } else { console.warn(`Roller door mesh not found: ${name}`); } @@ -579,6 +632,12 @@ export class GameManager extends Monobehiver { this.rollerDoorInitialY.clear(); this.rollerDoorIsOpen = false; + // 清理 rollerDoorGroup + if (this.rollerDoorGroup && this.rollerDoorGroup.dispose) { + this.rollerDoorGroup.dispose(); + this.rollerDoorGroup = null; + } + // 清理所有材质资源 this.materialDic.Values().forEach((material) => { if (material && material.dispose) { @@ -679,26 +738,26 @@ export class GameManager extends Monobehiver { applyMaterial(target: string, attribute: string, value: number | string): void { // 这里需要根据实际的材质管理逻辑实现 console.log(`Applying attribute ${attribute} to ${value}`); - + // 示例实现:根据目标和材质路径应用材质 // 1. 查找目标网格 const targetMaterials: PBRMaterial[] = []; this.materialDic.Values().forEach(material => { if (material.name.includes(target)) { - console.log(`${this.materialDic.Get(material.name)}`,material); + console.log(`${this.materialDic.Get(material.name)}`, material); targetMaterials.push(material); } }); - + if (targetMaterials.length === 0) { console.warn(`Target not found: ${target}`); return; } - + // 2. 处理材质路径 // 这里可以根据材质路径加载对应的材质配置 // 例如:paint/blue 可以映射到特定的材质配置 - + // 3. 应用材质到目标网格 targetMaterials.forEach(material => { if (material[attribute]) {