This commit is contained in:
2026-05-17 13:59:16 +08:00
parent f76b19697c
commit 870477f864
7 changed files with 176 additions and 93 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 818 KiB

View File

@ -297,10 +297,14 @@
</div> </div>
<div class="category-content"> <div class="category-content">
<div class="option-group"> <div class="option-group">
<button class="option-btn" data-option="size-1">3x3米</button> <button class="option-btn" data-option="size-1">3*3</button>
<button class="option-btn" data-option="size-2">4x4米</button> <button class="option-btn" data-option="size-2">3x6</button>
<button class="option-btn" data-option="size-3">5x5米</button> <button class="option-btn" data-option="size-3">10x13EM星空篷</button>
<button class="option-btn" data-option="size-4">6x6</button> <button class="option-btn" data-option="size-4">全铁3x6</button>
<button class="option-btn" data-option="size-1">10x12</button>
<button class="option-btn" data-option="size-2">10x10星空篷</button>
<button class="option-btn" data-option="size-3">10x13星空篷</button>
<button class="option-btn" data-option="size-4">10x20星空篷</button>
</div> </div>
</div> </div>
</div> </div>
@ -346,8 +350,8 @@
</div> </div>
<div class="category-content"> <div class="category-content">
<div class="option-group"> <div class="option-group">
<button class="option-btn" data-option="color-1">222222</button> <button class="option-btn" data-option="color-1">Charcoal</button>
<button class="option-btn" data-option="color-2">灰色</button> <button class="option-btn" data-option="color-2">Cherry</button>
<button class="option-btn" data-option="color-3">黑色</button> <button class="option-btn" data-option="color-3">黑色</button>
<button class="option-btn" data-option="color-4">木色</button> <button class="option-btn" data-option="color-4">木色</button>
</div> </div>
@ -450,7 +454,7 @@
<script type="module" src="./index.js"></script> <script type="module" src="./index.js"></script>
<script type="module"> <script type="module">
import { kernel } from './src/main.ts'; import { kernel } from './src/main.ts';
import { init, getAutoLoadModelList,getPlacementZone,executeEvent ,getHotspot} from './index.js'; import { init, getAutoLoadModelList, getPlacementZone, getEvent, getHotspot,executeEvent2 } from './index.js';
await init() await init()
await getAutoLoadModelList() await getAutoLoadModelList()
@ -531,11 +535,19 @@
const result = await response.json(); const result = await response.json();
if (result.code === 200) { if (result.code === 200) {
console.log(result.data); console.log(result.data);
const { enable_placement_zone } = result.data;
sku = currentText; sku = currentText;
// await initPlacementZoneConfig(); // await initPlacementZoneConfig();
if (enable_placement_zone) {
getPlacementZone(currentText)
}
else {
executeEvent2(result)
} }
getPlacementZone(currentText) }
}); });
}); });
@ -846,7 +858,7 @@
// 监听放置区域点击事件 // 监听放置区域点击事件
kernel.on('dropzone:click', async (dropzone_data) => { kernel.on('dropzone:click', async (dropzone_data) => {
executeEvent(dropzone_data,sku) getEvent(dropzone_data, sku)
}); });

View File

@ -1,3 +1,4 @@
import { EXRCubeTexture } from '@babylonjs/core';
import { kernel } from './src/main.ts'; import { kernel } from './src/main.ts';
//初始化 //初始化
@ -47,7 +48,7 @@ export const getAutoLoadModelList = async () => {
} }
kernel.model.add({ kernel.model.add({
modelId: model.id, modelId: model.category,
modelUrl: model.file_url, modelUrl: model.file_url,
modelControlType: model.model_control_type, modelControlType: model.model_control_type,
@ -80,10 +81,7 @@ export const getPlacementZone = async (sku) => {
} }
//执行事件 //执行事件
export const executeEvent = async (dropzone_data, sku) => { export const getEvent = async (dropzone_data, sku) => {
const { wallName, index, transform } = dropzone_data;
const { position, rotation } = transform;
// 将模型放置到该区域 // 将模型放置到该区域
try { try {
const response = await fetch(`http://localhost:3001/api/product-configs/by-sku/${sku}`); const response = await fetch(`http://localhost:3001/api/product-configs/by-sku/${sku}`);
@ -94,6 +92,19 @@ export const executeEvent = async (dropzone_data, sku) => {
console.log('关联事件:', result.data.events); console.log('关联事件:', result.data.events);
// 使用 for...of 循环以支持 await // 使用 for...of 循环以支持 await
await executeEvent(dropzone_data, result)
} else {
console.log(`未查询到数据`);
}
} catch (error) {
console.error(`查询SKU配置或替换模型失败:`, error);
}
}
export const executeEvent = async (dropzone_data, result) => {
const { wallName, index, transform } = dropzone_data;
const { position, rotation } = transform;
for (const event of result.data.events) { for (const event of result.data.events) {
if (event.event_type === 'change_model') { if (event.event_type === 'change_model') {
console.log(event.target_data); console.log(event.target_data);
@ -107,7 +118,7 @@ export const executeEvent = async (dropzone_data, sku) => {
// 先记录模型放置(会自动处理替换逻辑) // 先记录模型放置(会自动处理替换逻辑)
kernel.dropZone.recordModelPlacement(wallName, index, modelId); kernel.dropZone.recordModelPlacement(wallName, index, modelId);
console.log(Math.abs(rotation.y - 90) ,Math.abs(rotation.y - 90) > 5 ? 'x' : 'z' );
// 加载并放置模型 // 加载并放置模型
await kernel.model.add({ await kernel.model.add({
modelId: modelId, modelId: modelId,
@ -115,7 +126,7 @@ export const executeEvent = async (dropzone_data, sku) => {
modelControlType: model_control_type, modelControlType: model_control_type,
drag: { drag: {
enable: true, enable: true,
axis: Math.abs((rotation.y - 0)) < 90 ? 'x' : 'z', axis:rotation.y === 0 || rotation.y === 180 ? 'x' : 'z',
step: 0.1, step: 0.1,
}, },
transform: { transform: {
@ -134,7 +145,6 @@ export const executeEvent = async (dropzone_data, sku) => {
kernel.material.apply({ kernel.material.apply({
target: materialName, target: materialName,
modelId: modelId, // 指定模型ID只修改该模型的材质
albedoColor: color, albedoColor: color,
albedoTexture: color_map_url, albedoTexture: color_map_url,
normalMap: normal_map_url, normalMap: normal_map_url,
@ -143,12 +153,58 @@ export const executeEvent = async (dropzone_data, sku) => {
console.log(`百叶模型颜色已替换为 ${color}`); console.log(`百叶模型颜色已替换为 ${color}`);
} }
} }
} else { }
console.log(`未查询到数据`);
export const executeEvent2 = async (result) => {
kernel.dropZone.clearZones();
kernel.model.removeAll();
for (const event of result.data.events) {
const { target_data } = event;
if (event.event_type === 'change_model') {
console.log(event.target_data);
const { id, name, file_url, model_control_type, category, placement_zone } = event.target_data;
console.log('替换百叶模型:', event);
console.log('替换百叶模型类型:', category);
if (placement_zone) {
const { alpha, border_color, color, show_border, thickness, walls } = placement_zone
kernel.dropZone.setData({
color: color,
alpha: +alpha,
thickness: thickness,
showBorder: !show_border,
borderColor: border_color,
walls: walls
});
} }
} catch (error) { // 加载并放置模型
console.error(`查询SKU配置或替换模型失败:`, error); await kernel.model.replace({
modelId: target_data.category,
modelUrl: target_data.file_url,
modelControlType: target_data.model_control_type,
})
console.log(`百叶模型已放置为 ${name}`);
} }
if (event.event_type === 'change_color') {
const materialName = event.material_name;
const { color, color_map_url, normal_map_url } = event.target_data;
console.log('替换百叶模型颜色:', event.target_data);
kernel.material.apply({
target: materialName,
albedoColor: color,
albedoTexture: color_map_url,
normalMap: normal_map_url,
});
console.log(`百叶模型颜色已替换为 ${color}`);
}
}
} }

View File

@ -498,6 +498,28 @@ export class AppModel extends Monobehiver {
console.log(`Model removed: ${modelName}`); console.log(`Model removed: ${modelName}`);
} }
/**
* 清除所有已添加的模型并释放内存
* 主要用于切换尺寸后清除不适用的配件
*/
removeAll(): void {
const modelNames = this.modelDic.Keys();
console.log(`开始清除所有模型,共 ${modelNames.length} 个模型`);
modelNames.forEach(modelName => {
const meshes = this.modelDic.Get(modelName);
if (meshes?.length) {
this.getModelTransformTargets(meshes).forEach(mesh => mesh.dispose(false, true));
}
});
this.modelDic.Clear();
this.modelMetadataDic.Clear();
this.mainApp.gameManager?.updateDictionaries();
console.log('所有模型已清除,内存已释放');
}
/** /**
* 获取模型元数据 * 获取模型元数据
* @param modelName 模型名称 * @param modelName 模型名称

View File

@ -223,6 +223,7 @@ export class AppPlacementWall {
this.scene this.scene
); );
line.color = new Color3(1, 1, 1); // 白色 line.color = new Color3(1, 1, 1); // 白色
line.isPickable = false; // 禁用边框的点击
this.borderLines.push(line); this.borderLines.push(line);
}); });
} }
@ -265,6 +266,7 @@ export class AppPlacementWall {
this.scene this.scene
); );
line.color = lineColor; line.color = lineColor;
line.isPickable = false; // 禁用边框的点击
this.borderLines.push(line); this.borderLines.push(line);
}); });
} }

View File

@ -751,7 +751,6 @@ export class GameManager extends Monobehiver {
*/ */
applyMaterial(options: { applyMaterial(options: {
target: string; target: string;
modelId?: string; // 新增指定模型ID只修改该模型的材质
albedoColor?: string; albedoColor?: string;
albedoTexture?: string; albedoTexture?: string;
normalMap?: string; normalMap?: string;
@ -761,24 +760,8 @@ export class GameManager extends Monobehiver {
}): void { }): void {
this.updateDictionaries(); this.updateDictionaries();
// 1. 查找目标材质 // 查找目标材质(支持精确匹配和前缀匹配)
const targetMaterials: PBRMaterial[] = []; const targetMaterials: PBRMaterial[] = [];
if (options.modelId) {
// 如果指定了模型ID只查找该模型的材质
const materialName = `${options.target}_${options.modelId}`;
this.materialDic.Values().forEach(material => {
if (material.name === materialName) {
targetMaterials.push(material);
}
});
if (targetMaterials.length === 0) {
console.warn(`Material not found for model ${options.modelId}: ${materialName}`);
return;
}
} else {
// 没有指定模型ID查找所有匹配的材质旧逻辑
this.materialDic.Values().forEach(material => { this.materialDic.Values().forEach(material => {
if (material.name === options.target || material.name.startsWith(`${options.target}_`)) { if (material.name === options.target || material.name.startsWith(`${options.target}_`)) {
targetMaterials.push(material); targetMaterials.push(material);
@ -789,9 +772,8 @@ export class GameManager extends Monobehiver {
console.warn(`Material not found: ${options.target}`); console.warn(`Material not found: ${options.target}`);
return; return;
} }
}
// 2. 应用材质属性到目标材质 // 应用材质属性到目标材质
targetMaterials.forEach(material => { targetMaterials.forEach(material => {
// 应用颜色 // 应用颜色
if (options.albedoColor) { if (options.albedoColor) {
@ -828,6 +810,6 @@ export class GameManager extends Monobehiver {
material.markDirty(); material.markDirty();
}); });
console.log(`Material applied to: ${options.target}${options.modelId ? ` (model: ${options.modelId})` : ''}`, options); console.log(`Material applied to ${targetMaterials.length} material(s): ${options.target}`, options);
} }
} }

View File

@ -58,6 +58,16 @@ export class KernelAdapter {
*/ */
findModelNameByMesh: (mesh: any): string | undefined => { findModelNameByMesh: (mesh: any): string | undefined => {
return this.mainApp.appModel.findModelNameByMesh(mesh); return this.mainApp.appModel.findModelNameByMesh(mesh);
},
/**
* 清除所有已添加的模型并释放内存
* 主要用于切换尺寸后清除不适用的配件
* @example
* // 切换尺寸时清除所有配件
* kernel.model.removeAll();
*/
removeAll: (): void => {
this.mainApp.appModel.removeAll();
} }
}; };
@ -69,7 +79,6 @@ export class KernelAdapter {
*/ */
apply: (options: { apply: (options: {
target: string; target: string;
modelId?: string; // 可选指定模型ID只修改该模型的材质
albedoColor?: string; albedoColor?: string;
albedoTexture?: string; albedoTexture?: string;
normalMap?: string; normalMap?: string;