1
This commit is contained in:
@ -74,7 +74,7 @@ export class GameManager extends Monobehiver {
|
||||
for (const mat of scene.materials) {
|
||||
if (!this.materialDic.Has(mat.name)) {
|
||||
// 初始化材质属性
|
||||
mat.transparencyMode = PBRMaterial.PBRMATERIAL_ALPHABLEND;
|
||||
// mat.transparencyMode = PBRMaterial.PBRMATERIAL_ALPHABLEND;
|
||||
this.materialDic.Set(mat.name, mat as PBRMaterial);
|
||||
}
|
||||
}
|
||||
@ -390,9 +390,28 @@ export class GameManager extends Monobehiver {
|
||||
|
||||
const targets = this.rollerDoorMeshes.map(mesh => {
|
||||
const baseY = this.rollerDoorInitialY.get(mesh.name) ?? mesh.position.y;
|
||||
const targetY = open ? (options?.upY ?? baseY + 3) : (options?.downY ?? baseY);
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
// 下降时:回到各自的初始位置
|
||||
targetY = options?.downY ?? baseY;
|
||||
}
|
||||
|
||||
const direction = targetY >= mesh.position.y ? 1 : -1;
|
||||
return { mesh, targetY, direction };
|
||||
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);
|
||||
@ -401,17 +420,23 @@ export class GameManager extends Monobehiver {
|
||||
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;
|
||||
const step = speed * dt;
|
||||
let finished = true;
|
||||
|
||||
for (const item of targets) {
|
||||
const current = item.mesh.position.y;
|
||||
const dir = item.direction;
|
||||
|
||||
// 根据每个门的移动距离占比调整速度,确保同时到达
|
||||
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)) {
|
||||
@ -437,7 +462,7 @@ export class GameManager extends Monobehiver {
|
||||
|
||||
/**
|
||||
* 设置基于 Y 轴的剖切平面,keepAbove=true 时保留平面以上部分
|
||||
* 使用场景级别的 clipPlane,作用于所有网格
|
||||
* onlyMeshNames 指定只作用于哪些网格,其他网格不受影响
|
||||
*/
|
||||
setYAxisClip(
|
||||
height: number,
|
||||
@ -453,13 +478,15 @@ export class GameManager extends Monobehiver {
|
||||
const normal = new Vector3(0, keepAbove ? 1 : -1, 0);
|
||||
this.yClipPlane = Plane.FromPositionAndNormal(new Vector3(0, height, 0), normal);
|
||||
|
||||
// 直接设置场景的剖切平面,作用于所有网格
|
||||
scene.clipPlane = this.yClipPlane;
|
||||
// 如果指定了特定网格,只对这些网格应用剖切
|
||||
if (onlyMeshNames?.length) {
|
||||
this.applyClipPlaneToMeshes(this.yClipPlane, onlyMeshNames);
|
||||
} else {
|
||||
// 否则使用场景级别的剖切,作用于所有网格
|
||||
scene.clipPlane = this.yClipPlane;
|
||||
}
|
||||
|
||||
// 创建可视化平面
|
||||
this.createClipPlaneVisualization(height, scene);
|
||||
|
||||
console.log('[clipping] Scene clipPlane set:', { height, keepAbove, normal: normal.asArray() });
|
||||
console.log('[clipping] Scene clipPlane set:', { height, keepAbove, normal: normal.asArray(), targets: onlyMeshNames || 'all' });
|
||||
}
|
||||
|
||||
/** 关闭 Y 轴剖切 */
|
||||
@ -471,11 +498,13 @@ export class GameManager extends Monobehiver {
|
||||
this.yClipPlane = null;
|
||||
this.yClipTargets = null;
|
||||
|
||||
// 移除可视化平面
|
||||
if (this.clipPlaneVisualization) {
|
||||
this.clipPlaneVisualization.dispose();
|
||||
this.clipPlaneVisualization = null;
|
||||
}
|
||||
// 清除所有网格材质上的 clipPlane
|
||||
this.meshDic.Values().forEach((mesh) => {
|
||||
const mat = mesh.material as any;
|
||||
if (mat && 'clipPlane' in mat) {
|
||||
mat.clipPlane = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private cacheRollerDoorMeshes(customNames?: string[]): void {
|
||||
@ -502,27 +531,34 @@ export class GameManager extends Monobehiver {
|
||||
this.rollerDoorObserver = null;
|
||||
}
|
||||
|
||||
/** 创建剖切平面的可视化 */
|
||||
private createClipPlaneVisualization(height: number, scene: Scene): void {
|
||||
// 移除旧的可视化平面
|
||||
if (this.clipPlaneVisualization) {
|
||||
this.clipPlaneVisualization.dispose();
|
||||
/** 将 clipPlane 只作用到指定网格的材质 */
|
||||
private applyClipPlaneToMeshes(plane: Plane, targetNames: string[]): void {
|
||||
const targetSet = new Set(targetNames);
|
||||
let appliedCount = 0;
|
||||
|
||||
this.meshDic.Values().forEach((mesh) => {
|
||||
const mat = mesh.material as any;
|
||||
if (!mat) {
|
||||
console.log('[clipping] Mesh has no material:', mesh.name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetSet.has(mesh.name)) {
|
||||
// 目标网格:应用剖切
|
||||
mat.clipPlane = plane;
|
||||
appliedCount++;
|
||||
console.log('[clipping] Applied to mesh:', mesh.name, 'material:', mat.name);
|
||||
} else {
|
||||
// 非目标网格:清除剖切
|
||||
mat.clipPlane = null;
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[clipping] Total meshes processed:', this.meshDic.Keys().length, 'Applied to:', appliedCount);
|
||||
if (appliedCount === 0) {
|
||||
console.warn('[clipping] No meshes found with names:', targetNames);
|
||||
console.log('[clipping] Available mesh names:', this.meshDic.Keys());
|
||||
}
|
||||
|
||||
// 创建一个半透明的平面网格
|
||||
const plane = Mesh.CreatePlane("clipPlaneVisualization", 20, scene);
|
||||
plane.position.y = height;
|
||||
plane.rotation.x = Math.PI / 2; // 旋转使其水平
|
||||
|
||||
// 创建半透明红色材质
|
||||
const mat = new PBRMaterial("clipPlaneMat", scene);
|
||||
mat.albedoColor = new Color3(1, 0, 0); // 红色
|
||||
mat.alpha = 0.3; // 半透明
|
||||
mat.backFaceCulling = false; // 双面显示
|
||||
plane.material = mat;
|
||||
|
||||
this.clipPlaneVisualization = plane;
|
||||
console.log('[clipping] Visualization plane created at height:', height);
|
||||
}
|
||||
|
||||
/** 获取公共URL */
|
||||
|
||||
Reference in New Issue
Block a user