This commit is contained in:
2026-03-16 11:15:06 +08:00
parent 12ae95340f
commit 2f48948e43
2 changed files with 120 additions and 61 deletions

View File

@ -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; // 调整这个值找到合适的剖切高度

View File

@ -24,6 +24,7 @@ export class GameManager extends Monobehiver {
private meshDic: Dictionary<any>;
private oldTextureDic: Dictionary<any>;
private rollerDoorMeshes: AbstractMesh[];
private rollerDoorGroup: AbstractMesh | null;
private rollerDoorInitialY: Map<string, number>;
private rollerDoorObserver: Nullable<Observer<Scene>>;
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<any>();
this.oldTextureDic = new Dictionary<any>();
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]) {