1
This commit is contained in:
BIN
ScreenShot_2026-05-17_130307_268.png
Normal file
BIN
ScreenShot_2026-05-17_130307_268.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 818 KiB |
30
index.html
30
index.html
@ -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)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
80
index.js
80
index.js
@ -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}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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 模型名称
|
||||||
|
|||||||
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user