This commit is contained in:
2026-05-20 11:26:47 +08:00
parent 127100d27b
commit 8dc9371cc5
7 changed files with 192 additions and 358647 deletions

View File

@ -135,27 +135,25 @@ const getEvent = async (dropzone_data, sku) => {
//点击放置区域执行事件
const executeEvent = async (dropzone_data, result) => {
const kernel = getKernel();
const kernel = getKernel();
const { wallName, index, transform } = dropzone_data;
const { position, rotation } = transform;
let modelId = null; // 在外部声明,用于在两个循环之间传递
let modelName = null;
// 第一次循环:处理 change_model
for (const event of result.data.events) {
if (event.event_type === 'change_model') {
console.log(event.target_data);
const { id, name, file_url, model_control_type, category } = event.target_data;
console.log('替换百叶模型:', event);
console.log('替换百叶模型类型:', category);
const { name, file_url, model_control_type, category } = event.target_data;
// 生成唯一的模型ID
const modelId = id + '_' + Date.now();
modelId = Date.now();
modelName = name;
kernel.dropZone.recordModelPlacement(wallName, index, name + '_' + 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({
modelName: name,
modelId: modelId,
modelUrl: file_url,
modelControlType: model_control_type,
@ -170,21 +168,24 @@ const executeEvent = async (dropzone_data, result) => {
}
});
console.log(`百叶模型已放置为 ${name}`);
console.log(`百叶模型已放置为 ${name + '_' + modelId}`);
}
}
// 第二次循环:处理 change_color此时模型已加载完成
for (const event of result.data.events) {
if (event.event_type === 'change_color') {
const materialName = event.material_name;
const { color, color_map_url, normal_map_url, metallic, roughness } = event.target_data;
console.log('替换百叶模型颜色:', event.target_data);
kernel.material.apply({
target: materialName,
modelId: modelName + '_' + modelId, // 传入 modelId只替换该模型的材质
albedoColor: color,
albedoTexture: color_map_url,
normalMap: normal_map_url,
metallic: metallic,
roughness: roughness
metallic: +metallic,
roughness: +roughness
});
console.log(`百叶模型颜色已替换为 ${color}`);
@ -277,15 +278,13 @@ const isModelExists = (modelId) => {
if (event.event_type === 'change_color') {
const materialName = event.material_name;
const { color, color_map_url, normal_map_url, metallic, roughness } = event.target_data;
console.log('替换百叶模型颜色:', event.target_data);
console.log('替换模型颜色:', event.target_data);
kernel.material.apply({
target: materialName,
albedoColor: color,
albedoTexture: color_map_url,
normalMap: normal_map_url,
metallic: metallic,
roughness: roughness
});
console.log(`百叶模型颜色已替换为 ${color}`);

View File

@ -333,11 +333,14 @@
</div>
<div class="category-content">
<div class="option-group">
<button class="option-btn" data-option="louver-1">整体</button>
<button class="option-btn" data-option="louver-2">3m百叶</button>
<button class="option-btn" data-option="louver-1">SPFPDS13FTW</button>
<button class="option-btn" data-option="louver-2">SPFPDS13FTC</button>
<button class="option-btn" data-option="louver-3">3m下拉帘</button>
<button class="option-btn" data-option="louver-4">百叶4</button>
<button class="option-btn" data-option="louver-4">卷帘小</button>
<button class="option-btn" data-option="louver-4">SPFSW13FTW</button>
<button class="option-btn" data-option="louver-4">SPFSW10FTW</button>
<button class="option-btn" data-option="louver-4">SPFPDS10FTC</button>
<button class="option-btn" data-option="louver-4">SPFPDS10FTW</button>
</div>
</div>
</div>
@ -350,10 +353,14 @@
</div>
<div class="category-content">
<div class="option-group">
<button class="option-btn" data-option="color-1">SPF111S1010C</button>
<button class="option-btn" data-option="color-2">SPF111S1010W</button>
13
<button class="option-btn" data-option="color-1">SPF111S1013W</button>
<button class="option-btn" data-option="color-2">SPF111S1013C</button>
<button class="option-btn" data-option="color-3">SPF111S1013TA</button>
10
<button class="option-btn" data-option="color-1">SPF111S1010W</button>
<button class="option-btn" data-option="color-2">SPF111S1010C</button>
<button class="option-btn" data-option="color-3">SPF111S1010TA</button>
<button class="option-btn" data-option="color-4">木色</button>
</div>
</div>
</div>
@ -761,23 +768,24 @@
}
});
// 移除按钮事件
document.getElementById('remove-model-btn').addEventListener('click', function () {
var pickedMesh = window.getCurrentPickedMesh();
if (pickedMesh) {
var meshName = pickedMesh.name;
var success = kernel.model.remove(meshName);
if (success) {
console.log('模型已移除');
// 关闭信息框
kernel.domTo3D.detach('model-info');
} else {
console.log('移除失败:未找到该网格所属的模型');
}
} else {
console.log('没有选中的网格');
}
});
// 移除按钮事件
document.getElementById('remove-model-btn').addEventListener('click', () => {
const pickedMesh = window.getCurrentPickedMesh();
if (pickedMesh) {
const meshName = pickedMesh.name;
const modelName = kernel.model.findModelNameByMesh(pickedMesh);
const success = kernel.model.removeByName(modelName);
if (success) {
console.log('模型已移除');
// 关闭信息框
kernel.domTo3D.detach('model-info');
} else {
console.log('移除失败:未找到该网格所属的模型');
}
} else {
console.log('没有选中的网格');
}
});
// 生成放置区域按钮事件
var dropZoneVisible = false;

File diff suppressed because one or more lines are too long

View File

@ -341,6 +341,15 @@
<button class="option-btn" data-option="louver-4">SPFPDS10FTC</button>
<button class="option-btn" data-option="louver-4">SPFPDS10FTW</button>
<div>13</div>
<button class="option-btn" data-option="color-1">SPFPDS13FTW</button>
<button class="option-btn" data-option="color-2">SPFPDS13FTC</button>
<div>10</div>
<button class="option-btn" data-option="color-1">SPFPDS10FTW</button>
<button class="option-btn" data-option="color-2">SPFPDS10FTC</button>
</div>
</div>
</div>
@ -352,13 +361,9 @@
</div>
<div class="category-content">
<div class="option-group">
13
<div>13</div>
<button class="option-btn" data-option="color-1">SPF111S1013W</button>
<button class="option-btn" data-option="color-2">SPF111S1013C</button>
<button class="option-btn" data-option="color-3">SPF111S1013TA</button>
10
<button class="option-btn" data-option="color-1">SPF111S1010W</button>
<button class="option-btn" data-option="color-2">SPF111S1010C</button>
<div>10</div>
<button class="option-btn" data-option="color-3">SPF111S1010TA</button>
</div>
@ -461,7 +466,10 @@
<script type="module" src="./index.js"></script>
<script type="module">
import { kernel } from './src/main.ts';
import { initApp, init, getAutoLoadModelList, getPlacementZone, getEvent, getHotspot, executeEvent2, getProductConfig } from './index.js';
import { initApp, init, getAutoLoadModelList, getPlacementZone, getEvent, getHotspot, executeEvent2, getProductConfig, getSkuByModelId } from './index.js';
// 将 getSkuByModelId 挂载到 window 对象,供事件处理器使用
window.getSkuByModelId = getSkuByModelId;
// 注入 kernel 实例到业务逻辑
initApp(kernel);
@ -754,13 +762,9 @@
// 移除按钮事件
document.getElementById('remove-model-btn').addEventListener('click', () => {
const pickedMesh = window.getCurrentPickedMesh();
console.log(pickedMesh);
if (pickedMesh) {
const meshName = pickedMesh.name;
const modelName = kernel.model.findModelNameByMesh(pickedMesh);
console.log(modelName);
const success = kernel.model.removeByName(modelName);
if (success) {
console.log('模型已移除');
@ -873,6 +877,13 @@
kernel.on('model:click', (data) => {
console.log('模型点击事件', data);
console.log('模型控制类型:', data.modelControlType);
// 获取模型关联的 SKU
const modelName = data.modelName;
const sku = window.getSkuByModelId(modelName);
console.log('点击的模型ID:', modelName);
console.log('关联的SKU:', sku || '未找到关联的SKU');
switch (data.modelControlType) {
case "color":
// DOM 2D转3D 示例:点击模型时显示信息框

View File

@ -1,9 +1,13 @@
import { EXRCubeTexture } from '@babylonjs/core';
import apiConfig from './src/config.js';
import { setSkuMapping, getSkuByModelId, clearSkuMapping, clearAllSkuMappings } from './src/skuMapping.js';
// 存储 kernel 实例
let kernelInstance = null;
// 导出 SKU 映射相关函数,方便外部使用
export { getSkuByModelId, clearSkuMapping, clearAllSkuMappings };
/**
* 初始化应用逻辑 - 注入 kernel 实例
* @param {Object} kernel - SDK kernel 实例
@ -131,7 +135,7 @@ export const getEvent = async (dropzone_data, sku) => {
console.log('关联事件:', result.data.events);
// 使用 for...of 循环以支持 await
await executeEvent(dropzone_data, result)
await executeEvent(dropzone_data, result, sku)
} else {
console.log(`未查询到数据`);
}
@ -141,8 +145,7 @@ export const getEvent = async (dropzone_data, sku) => {
}
//点击放置区域执行事件 一般是换配件
//点击放置区域执行事件 一般是换配件
export const executeEvent = async (dropzone_data, result) => {
export const executeEvent = async (dropzone_data, result, sku) => {
const kernel = getKernel();
const { wallName, index, transform } = dropzone_data;
@ -160,6 +163,9 @@ export const executeEvent = async (dropzone_data, result) => {
modelName = name;
kernel.dropZone.recordModelPlacement(wallName, index, name + '_' + modelId);
// 记录模型ID到SKU的映射
setSkuMapping(modelId, sku);
await kernel.model.add({
modelName: name,
modelId: modelId,
@ -192,8 +198,8 @@ export const executeEvent = async (dropzone_data, result) => {
albedoColor: color,
albedoTexture: color_map_url,
normalMap: normal_map_url,
metallic: metallic,
roughness: roughness
metallic: +metallic,
roughness: +roughness
});
console.log(`百叶模型颜色已替换为 ${color}`);
@ -203,7 +209,7 @@ export const executeEvent = async (dropzone_data, result) => {
//一般是换棚子/换颜色/设置放置区域
export const executeEvent2 = async (result) => {
export const executeEvent2 = async (result, sku) => {
const kernel = getKernel();
// 检查是否有模型更换事件
@ -219,15 +225,15 @@ export const executeEvent2 = async (result) => {
console.log(`检查模型 ${name + '_' + category} 是否存在:`, modelAlreadyExists);
}
}
console.log(hasModelChange && !modelAlreadyExists);
kernel.dropZone.hide();
// 只有在需要更换模型且模型不存在时才清除
if (hasModelChange && !modelAlreadyExists) {
console.log('模型不存在,执行清除操作');
kernel.model.removeAll();
} else if (modelAlreadyExists) {
kernel.dropZone.hide();
console.log('模型已存在,跳过清除操作,仅更新材质');
// 清除所有 SKU 映射
clearAllSkuMappings();
}
// 先处理所有 change_model 事件
@ -259,6 +265,9 @@ export const executeEvent2 = async (result) => {
});
}
// 记录模型ID到SKU的映射
setSkuMapping(category, sku);
// 加载并放置模型(使用 category 作为 modelId
await kernel.model.add({
modelName: name,
@ -276,15 +285,13 @@ export const executeEvent2 = async (result) => {
if (event.event_type === 'change_color') {
const materialName = event.material_name;
const { color, color_map_url, normal_map_url, metallic, roughness } = event.target_data;
console.log('替换百叶模型颜色:', event.target_data);
console.log('替换模型颜色:', event.target_data);
kernel.material.apply({
target: materialName,
albedoColor: color,
albedoTexture: color_map_url,
normalMap: normal_map_url,
metallic: metallic,
roughness: roughness
});
console.log(`百叶模型颜色已替换为 ${color}`);
@ -341,7 +348,7 @@ export const getProductConfig = async (sku) => {
getPlacementZone(sku)
}
else {
executeEvent2(result)
executeEvent2(result, sku)
}
}
} catch (error) {

View File

@ -787,9 +787,11 @@ export class GameManager extends Monobehiver {
}
});
} else {
// 没有提供 modelId全局查找保持向后兼容
this.materialDic.Values().forEach(material => {
if (material.name === options.target || material.name.startsWith(`${options.target}_`)) {
console.log(material.name);
targetMaterials.push(material);
}
});
@ -799,7 +801,7 @@ export class GameManager extends Monobehiver {
console.warn(`Material not found: ${options.target}${options.modelId ? ` in model ${options.modelId}` : ''}`);
return;
}
console.log(options);
// 应用材质属性到目标材质
targetMaterials.forEach(material => {
// 应用颜色
@ -818,35 +820,36 @@ export class GameManager extends Monobehiver {
}
}
// 应用法线贴图
if (options.normalMap !== undefined) {
if (options.normalMap) {
material.bumpTexture = new Texture(options.normalMap);
} else {
// 传入空字符串或 null 时清空贴图
material.bumpTexture = null;
}
}
// // 应用法线贴图
// if (options.normalMap !== undefined) {
// if (options.normalMap) {
// material.bumpTexture = new Texture(options.normalMap);
// } else {
// // 传入空字符串或 null 时清空贴图
// material.bumpTexture = null;
// }
// }
// 应用金属度贴图
if (options.metallicTexture !== undefined) {
if (options.metallicTexture) {
material.metallicTexture = new Texture(options.metallicTexture);
} else {
// 传入空字符串或 null 时清空贴图
material.metallicTexture = null;
}
}
// // 应用金属度贴图
// if (options.metallicTexture !== undefined) {
// if (options.metallicTexture) {
// material.metallicTexture = new Texture(options.metallicTexture);
// } else {
// // 传入空字符串或 null 时清空贴图
// material.metallicTexture = null;
// }
// }
// 应用粗糙度值
if (options.roughness !== undefined) {
material.roughness = options.roughness;
}
// if (options.roughness !== undefined) {
// material.roughness = options.roughness;
// }
// 应用金属度值
if (options.metallic !== undefined) {
material.metallic = options.metallic;
}
// // 应用金属度值
// if (options.metallic !== undefined) {
// material.metallic = options.metallic;
// }
// alert(typeof options.metallic + ' ' + typeof options.roughness);
// 强制刷新材质
material.markDirty();

69
src/skuMapping.js Normal file
View File

@ -0,0 +1,69 @@
/**
* SKU 映射管理模块
* 用于维护模型ID与SKU之间的映射关系
*/
// 存储模型ID到SKU的映射
const modelIdToSkuMap = new Map();
/**
* 记录模型ID与SKU的映射关系
* @param {string} modelId - 模型ID
* @param {string} sku - SKU编码
*/
export const setSkuMapping = (modelId, sku) => {
if (!modelId || !sku) {
console.warn('modelId 和 sku 不能为空');
return;
}
modelIdToSkuMap.set(modelId, sku);
console.log(`已记录映射: ${modelId} -> ${sku}`);
};
/**
* 根据模型ID获取关联的SKU
* @param {string} modelId - 模型ID
* @returns {string|undefined} SKU编码未找到返回 undefined
*/
export const getSkuByModelId = (modelId) => {
return modelIdToSkuMap.get(modelId);
};
/**
* 清除指定模型ID的SKU映射
* @param {string} modelId - 模型ID
* @returns {boolean} 是否成功删除
*/
export const clearSkuMapping = (modelId) => {
const deleted = modelIdToSkuMap.delete(modelId);
if (deleted) {
console.log(`已清除映射: ${modelId}`);
}
return deleted;
};
/**
* 清除所有SKU映射
*/
export const clearAllSkuMappings = () => {
const count = modelIdToSkuMap.size;
modelIdToSkuMap.clear();
console.log(`已清除所有映射,共 ${count}`);
};
/**
* 获取所有映射关系(用于调试)
* @returns {Object} 映射关系对象
*/
export const getAllMappings = () => {
return Object.fromEntries(modelIdToSkuMap);
};
/**
* 检查模型ID是否有映射
* @param {string} modelId - 模型ID
* @returns {boolean} 是否存在映射
*/
export const hasSkuMapping = (modelId) => {
return modelIdToSkuMap.has(modelId);
};