Files
zhengte.babylonjs-sdk/examples/index.js
2026-05-18 12:13:34 +08:00

338 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { EXRCubeTexture } from '@babylonjs/core';
// SDK 配置
const config = {
// API 基础地址
apiBaseUrl: import.meta.env.VITE_API_BASE_URL || 'http://localhost:26517',
// 获取完整的 API 地址
getApiUrl(path) {
return `${this.apiBaseUrl}${path}`
}
}
export default config
// 存储 kernel 实例
let kernelInstance = null;
/**
* 初始化应用逻辑 - 注入 kernel 实例
* @param {Object} kernel - SDK kernel 实例
* @returns {Object} kernel 实例
*/
export const initApp = (kernel) => {
if (!kernel) {
throw new Error('kernel 实例是必需的');
}
kernelInstance = kernel;
console.log('应用逻辑已初始化kernel 实例已注入');
return kernelInstance;
};
/**
* 获取当前 kernel 实例
*/
const getKernel = () => {
if (!kernelInstance) {
throw new Error('请先调用 initApp(kernel) 初始化 kernel 实例');
}
return kernelInstance;
};
//初始化
export const init = async (customConfig = {}) => {
const kernel = getKernel();
const defaultConfig = {
container: document.querySelector('#renderDom'),
modelUrlList: [],
env: { envPath: 'https://sdk.zguiy.com/resurces/hdr/hdr.env', intensity: 1.2, rotationY: 0.3, background: true },
gizmo: {
position: true,
rotation: true,
scale: true
},
outline: {
enable: true,
color: "#2196F3",
thickness: 1,
occlusionStrength: 0.1,
occlusionThreshold: 0.0002
}
};
// 合并用户自定义配置
const config = { ...defaultConfig, ...customConfig };
kernel.init(config);
}
//初始化加载模型
export const getAutoLoadModelList = async () => {
const kernel = getKernel();
const url = apiConfig.getApiUrl('/api/models/auto-load/list')
console.log('API URL:', url)
console.log('apiConfig:', apiConfig)
const response = await fetch(url)
const data = await response.json()
const models = data.data // 这就是模型列表
models.forEach(model => {
console.log(model.placement_zone);
if (model.placement_zone) {
const { alpha, border_color, color, show_border, thickness, walls } = model.placement_zone
kernel.dropZone.setData({
color: color,
alpha: +alpha,
thickness: thickness,
showBorder: !show_border,
borderColor: border_color,
walls: walls
});
}
kernel.model.add({
modelId: model.category,
modelUrl: model.file_url,
modelControlType: model.model_control_type,
});
})
}
//获取放置区域
export const getPlacementZone = async (sku) => {
const kernel = getKernel();
const response = await fetch(apiConfig.getApiUrl(`/api/product-configs/by-sku/${sku}`));
const result = await response.json();
if (result.code === 200) {
// await initPlacementZoneConfig();
const { enable_placement_zone, wall_divisions } = result.data;
// const {position_x, position_y, position_z} = data;
if (enable_placement_zone && wall_divisions != undefined) {
// 只清除旧的放置区域网格,不清除模型
kernel.dropZone.clearZones();
const divisions = wall_divisions.map(wall => ({
name: wall.name, // 获取最后一个下划线后的部分
divisions: wall.divisions
}))
kernel.dropZone.updateDivisions(divisions);
// 显示放置区域
kernel.dropZone.show();
}
}
}
//执行事件
export const getEvent = async (dropzone_data, sku) => {
// 将模型放置到该区域
try {
const response = await fetch(apiConfig.getApiUrl(`/api/product-configs/by-sku/${sku}`));
const result = await response.json();
if (result.code === 200 && result.data) {
console.log('SKU配置数据:', result.data);
console.log('关联事件:', result.data.events);
// 使用 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 kernel = getKernel();
const { wallName, index, transform } = dropzone_data;
const { position, rotation } = transform;
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);
// 生成唯一的模型ID
const modelId = id + '_' + Date.now();
// 先记录模型放置(会自动处理替换逻辑)
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({
modelId: modelId,
modelUrl: file_url,
modelControlType: model_control_type,
drag: {
enable: true,
axis: rotation.y === 0 || rotation.y === 180 ? 'x' : 'z',
step: 0.1,
},
transform: {
position: position,
rotation: rotation,
}
});
console.log(`百叶模型已放置为 ${name}`);
}
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,
albedoColor: color,
albedoTexture: color_map_url,
normalMap: normal_map_url,
metallic: metallic,
roughness: roughness
});
console.log(`百叶模型颜色已替换为 ${color}`);
}
}
}
//换棚子
export const executeEvent2 = async (result) => {
const kernel = getKernel();
// 检查是否有模型更换事件
const hasModelChange = result.data.events.some(e => e.event_type === 'change_model');
// 只有在需要更换模型时才清除
if (hasModelChange) {
kernel.dropZone.clearZones();
kernel.model.removeAll();
}
// 先处理所有 change_model 事件
for (const event of result.data.events) {
if (event.event_type === 'change_model') {
const { target_data } = event;
console.log(event.target_data);
if (!target_data) {
console.error('change_model事件缺少target_data')
return;
};
const { id, name, file_url, model_control_type, category, placement_zone } = 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
});
}
// 加载并放置模型(使用 category 作为 modelId
await kernel.model.add({
modelId: category,
modelUrl: file_url,
modelControlType: model_control_type,
})
console.log(`百叶模型已放置为 ${name}`);
}
}
// 等待模型加载完成后,再处理 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,
albedoColor: color,
albedoTexture: color_map_url,
normalMap: normal_map_url,
metallic: metallic,
roughness: roughness
});
console.log(`百叶模型颜色已替换为 ${color}`);
}
}
}
//加载热点
export const getHotspot = async () => {
const kernel = getKernel();
try {
// 从后端获取激活状态的热点列表
const response = await fetch(apiConfig.getApiUrl('/api/hotspots?status=active&page=1&pageSize=100'));
const result = await response.json();
if (result.code === 200 && result.data.list.length > 0) {
// 将后端数据转换为 SDK 需要的格式
const hotspots = result.data.list.map(item => ({
id: item.id,
type: 'hotspot',
name: item.name,
meshName: item.name, // 可以根据实际情况调整
icon: item.image_url,
position: [item.position_x, item.position_y, item.position_z],
radius: item.radius,
color: "#000000",
payload: {
skus: item.skus || [],
},
}));
// 渲染热点
kernel.hotspot.render(hotspots);
console.log('热点渲染成功:', hotspots);
} else {
console.log('没有可用的热点数据');
}
} catch (error) {
console.error('获取热点数据失败:', error);
}
}
export const getProductConfig = async (sku) => {
try {
const response = await fetch(`${apiConfig.getApiUrl(`/api/product-configs/by-sku/${sku}`)}`);
const result = await response.json();
if (result.code === 200) {
console.log(result.data);
const { enable_placement_zone } = result.data;
// await initPlacementZoneConfig();
if (enable_placement_zone) {
getPlacementZone(sku)
}
else {
executeEvent2(result)
}
}
} catch (error) {
console.error('获取产品配置失败:', error);
}
}