This commit is contained in:
2026-05-13 13:08:42 +08:00
parent 066294e74f
commit 52b369737a
6 changed files with 576 additions and 106 deletions

View File

@ -67,6 +67,40 @@
border-bottom: 2px solid rgba(255, 255, 255, 0.2); border-bottom: 2px solid rgba(255, 255, 255, 0.2);
} }
.click-info {
background: rgba(76, 175, 80, 0.2);
border: 1px solid rgba(76, 175, 80, 0.5);
border-radius: 8px;
padding: 12px;
margin-bottom: 15px;
color: #fff;
font-size: 13px;
line-height: 1.6;
}
.click-info-title {
font-weight: bold;
color: #4caf50;
margin-bottom: 8px;
font-size: 14px;
}
.click-info-item {
margin-bottom: 4px;
display: flex;
gap: 8px;
}
.click-info-label {
color: rgba(255, 255, 255, 0.7);
min-width: 70px;
}
.click-info-value {
color: #fff;
word-break: break-all;
}
.config-category { .config-category {
margin-bottom: 15px; margin-bottom: 15px;
border-radius: 8px; border-radius: 8px;
@ -227,12 +261,34 @@
<div id="progress-bar"></div> <div id="progress-bar"></div>
<div id="progress-text">0%</div> <div id="progress-text">0%</div>
</div> </div>
<!-- 生成放置区域按钮 -->
<button id="dropzone-btn" style="
position: absolute;
top: 20px;
left: 20px;
padding: 10px 20px;
background: #21c7ff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
z-index: 100;
">生成放置区域</button>
</div> </div>
<!-- 配置面板 --> <!-- 配置面板 -->
<div id="config-panel"> <div id="config-panel">
<div class="config-title">选装选配</div> <div class="config-title">选装选配</div>
<!-- 点击信息显示区域 -->
<div id="click-info" class="click-info" style="display: none;">
<div class="click-info-title">点击信息</div>
<div id="click-info-content"></div>
</div>
<!-- 棚子尺寸 --> <!-- 棚子尺寸 -->
<div class="config-category"> <div class="config-category">
<div class="category-header" data-category="size"> <div class="category-header" data-category="size">
@ -273,7 +329,7 @@
</div> </div>
<div class="category-content"> <div class="category-content">
<div class="option-group"> <div class="option-group">
<button class="option-btn" data-option="louver-1">百叶1</button> <button class="option-btn" data-option="louver-1">111</button>
<button class="option-btn" data-option="louver-2">百叶2</button> <button class="option-btn" data-option="louver-2">百叶2</button>
<button class="option-btn" data-option="louver-3">百叶3</button> <button class="option-btn" data-option="louver-3">百叶3</button>
<button class="option-btn" data-option="louver-4">百叶4</button> <button class="option-btn" data-option="louver-4">百叶4</button>
@ -290,13 +346,16 @@
</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">白色</button> <button class="option-btn" data-option="color-1">222222</button>
<button class="option-btn" data-option="color-2">灰色</button> <button class="option-btn" data-option="color-2">灰色</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>
</div> </div>
</div> </div>
<button id="hotspot-btn">生成热点</button>
<button id="prevent-btn">生成防止区域</button>
</div> </div>
</div> </div>
@ -390,6 +449,10 @@
<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';
// ========== UI 交互逻辑 ========== // ========== UI 交互逻辑 ==========
@ -439,48 +502,177 @@
}); });
// 百叶模型替换逻辑 // 百叶模型替换逻辑
if (categoryName === "louver") { // if (categoryName === "louver") {
const currentText = this.textContent; const currentText = this.textContent;
console.log(currentText);
// 根据 SKU 查询配置和事件 skuToFunc(currentText);
try { // }
const response = await fetch(`http://localhost:3000/api/product-configs/by-sku/${currentText}`);
const result = await response.json();
if (result.code === 200 && result.data) {
console.log('SKU配置数据:', result.data);
console.log('关联事件:', result.data.events);
// 使用配置数据中的模型路径(如果有)
const modelUrl = result.data.model_id
? `https://sdk.zguiy.com/resurces/model/${result.data.model_id}.glb`
: `https://sdk.zguiy.com/resurces/model/${currentText}.glb`;
console.log('替换百叶模型:', modelUrl);
await kernel.model.replace({
modelId: '卷帘小',
modelUrl: modelUrl,
modelControlType: 'color'
});
console.log(`百叶模型已替换为 ${currentText}`);
} else {
console.warn('未找到SKU配置使用默认模型路径');
const modelUrl = `https://sdk.zguiy.com/resurces/model/${currentText}.glb`;
console.log('替换百叶模型:', modelUrl);
await kernel.model.replace({
modelId: '卷帘小',
modelUrl: modelUrl,
modelControlType: 'color'
});
console.log(`百叶模型已替换为 ${currentText}`);
}
} catch (error) {
console.error(`查询SKU配置或替换模型失败:`, error);
}
}
}); });
}); });
document.querySelector('#hotspot-btn').addEventListener('click', async function () {
await hotspotRequest();
})
const skuToFunc = async (currentText) => {
// 根据 SKU 查询配置和事件
try {
const response = await fetch(`http://localhost:3000/api/product-configs/by-sku/${currentText}`);
const result = await response.json();
if (result.code === 200 && result.data) {
console.log('SKU配置数据:', result.data);
console.log('关联事件:', result.data.events);
placementWall(1);
// 使用 for...of 循环以支持 await
for (const event of result.data.events) {
if (event.event_type === 'change_model') {
const { file_url, model_control_type, category } = event.target_data;
console.log('替换百叶模型:', event);
await kernel.model.replace({
modelId: category,
modelUrl: file_url,
modelControlType: model_control_type,
drag: {
enable: true,
axis: 'x',
step: 0.1,
},
});
console.log(`百叶模型已替换为 ${currentText}`);
}
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}`);
}
}
} else {
console.log(`未查询到数据`);
}
} catch (error) {
console.error(`查询SKU配置或替换模型失败:`, error);
}
}
const hotspotRequest = async () => {
try {
// 从后端获取激活状态的热点列表
const response = await fetch('http://localhost:3001/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);
}
}
// 监听热点点击事件
window.addEventListener('hotspot:click', (event) => {
console.log('热点被点击:', event.detail);
const { id, name, payload } = event.detail;
const clickInfoDiv = document.getElementById('click-info');
const clickInfoContent = document.getElementById('click-info-content');
let html = `<div class="click-info-item">
<span class="click-info-label">类型:</span>
<span class="click-info-value">热点</span>
</div>
<div class="click-info-item">
<span class="click-info-label">名称:</span>
<span class="click-info-value">${name}</span>
</div>`;
if (payload && payload.skus && payload.skus.length > 0) {
html += `<div class="click-info-item">
<span class="click-info-label">关联SKU:</span>
<span class="click-info-value">${payload.skus.join(', ')}</span>
</div>`;
} else {
html += `<div class="click-info-item">
<span class="click-info-label">关联SKU:</span>
<span class="click-info-value">无</span>
</div>`;
}
clickInfoContent.innerHTML = html;
clickInfoDiv.style.display = 'block';
});
// 监听模型点击事件
window.addEventListener('model:click', (event) => {
console.log('模型被点击:', event.detail);
const { meshName, materialName, modelControlType } = event.detail;
const clickInfoDiv = document.getElementById('click-info');
const clickInfoContent = document.getElementById('click-info-content');
let html = `<div class="click-info-item">
<span class="click-info-label">类型:</span>
<span class="click-info-value">模型</span>
</div>
<div class="click-info-item">
<span class="click-info-label">网格名称:</span>
<span class="click-info-value">${meshName}</span>
</div>`;
if (materialName) {
html += `<div class="click-info-item">
<span class="click-info-label">材质名称:</span>
<span class="click-info-value">${materialName}</span>
</div>`;
}
if (modelControlType) {
html += `<div class="click-info-item">
<span class="click-info-label">控制类型:</span>
<span class="click-info-value">${modelControlType}</span>
</div>`;
}
clickInfoContent.innerHTML = html;
clickInfoDiv.style.display = 'block';
});
// 多选复选框逻辑 // 多选复选框逻辑
document.querySelectorAll('.option-checkbox input[type="checkbox"]').forEach(checkbox => { document.querySelectorAll('.option-checkbox input[type="checkbox"]').forEach(checkbox => {
checkbox.addEventListener('change', async function () { checkbox.addEventListener('change', async function () {
@ -545,7 +737,10 @@
const materialName = window.getCurrentMaterialName(); const materialName = window.getCurrentMaterialName();
if (materialName) { if (materialName) {
console.log('切换为白色,材质名:', materialName); console.log('切换为白色,材质名:', materialName);
kernel.material.color(materialName, '#FFFFFF'); kernel.material.apply({
target: materialName,
albedoColor: '#FFFFFF',
});
} else { } else {
console.log('没有选中材质'); console.log('没有选中材质');
} }
@ -556,7 +751,10 @@
const materialName = window.getCurrentMaterialName(); const materialName = window.getCurrentMaterialName();
if (materialName) { if (materialName) {
console.log('切换为黑色,材质名:', materialName); console.log('切换为黑色,材质名:', materialName);
kernel.material.color(materialName, '#000000'); kernel.material.apply({
target: materialName,
albedoColor: '#000000',
});
} else { } else {
console.log('没有选中材质'); console.log('没有选中材质');
} }
@ -617,6 +815,142 @@
console.log('没有选中的网格'); console.log('没有选中的网格');
} }
}); });
// 生成放置区域按钮事件
let dropZoneVisible = false;
document.getElementById('dropzone-btn').addEventListener('click', () => {
if (!dropZoneVisible) {
// 更新按钮文字
document.getElementById('dropzone-btn').textContent = '隐藏放置区域';
console.log('已生成并显示放置区域');
} else {
// 隐藏放置区域
kernel.dropZone.hideAll();
dropZoneVisible = false;
// 更新按钮文字
document.getElementById('dropzone-btn').textContent = '生成放置区域';
console.log('已隐藏放置区域');
}
});
const placementWall = (divisions) => {
// 先清除旧的放置区域
kernel.dropZone.clearAll();
// 生成新的放置区域使用新的墙面参数化API
// 调整 baseY 来控制整体高度(正数向上,负数向下)
const baseY = 0.08; // 修改这个值来调整整体高度
// 调整 offset 来控制每个面向外或向内的偏移
// 正数 = 向外移动,负数 = 向内移动
const wallOffset = -0.07; // 修改这个值来调整墙面偏移
kernel.dropZone.generate({
walls: [
{
name: 'front',
startPoint: [-1.43, baseY, -1.4],
endPoint: [1.37, baseY, -1.4],
height: 2.2,
divisions: divisions,
offset: wallOffset // 向外或向内偏移
},
{
name: 'back',
startPoint: [1.37, baseY, 1.4],
endPoint: [-1.43, baseY, 1.4],
height: 2.2,
divisions: divisions,
offset: wallOffset
},
{
name: 'left',
startPoint: [-1.43, baseY, 1.39],
endPoint: [-1.43, baseY, -1.43],
height: 2.2,
divisions: divisions,
offset: wallOffset
},
{
name: 'right',
startPoint: [1.37, baseY, -1.43],
endPoint: [1.37, baseY, 1.4],
height: 2.2,
divisions: divisions,
offset: wallOffset
}
],
color: "#21c7ff",
alpha: 0.3,
thickness: 2,
showBorder: true,
borderColor: "#ffffff"
});
// 显示放置区域
kernel.dropZone.showAll();
dropZoneVisible = true;
}
// 监听放置区域点击事件
kernel.on('dropzone:click', async (data) => {
// 将模型放置到该区域
try {
const response = await fetch(`http://localhost:3000/api/product-configs/by-sku/${currentText}`);
const result = await response.json();
if (result.code === 200 && result.data) {
console.log('SKU配置数据:', result.data);
console.log('关联事件:', result.data.events);
placementWall(1);
// 使用 for...of 循环以支持 await
for (const event of result.data.events) {
if (event.event_type === 'change_model') {
const { file_url, model_control_type, category } = event.target_data;
console.log('替换百叶模型:', event);
await kernel.model.replace({
modelId: category,
modelUrl: file_url,
modelControlType: model_control_type,
drag: {
enable: true,
axis: 'x',
step: 0.1,
},
});
console.log(`百叶模型已替换为 ${currentText}`);
}
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}`);
}
}
} else {
console.log(`未查询到数据`);
}
} catch (error) {
console.error(`查询SKU配置或替换模型失败:`, error);
}
});
</script> </script>
</body> </body>

View File

@ -516,58 +516,10 @@
await hotspotRequest(); await hotspotRequest();
}) })
let sku = ""
const skuToFunc = async (currentText) => { const skuToFunc = async (currentText) => {
// 根据 SKU 查询配置和事件 sku = currentText;
try { placementWall(1);
const response = await fetch(`http://localhost:3000/api/product-configs/by-sku/${currentText}`);
const result = await response.json();
if (result.code === 200 && result.data) {
console.log('SKU配置数据:', result.data);
console.log('关联事件:', result.data.events);
placementWall(1);
// 使用 for...of 循环以支持 await
for (const event of result.data.events) {
if (event.event_type === 'change_model') {
const { file_url, model_control_type, category } = event.target_data;
console.log('替换百叶模型:', event);
await kernel.model.replace({
modelId: category,
modelUrl: file_url,
modelControlType: model_control_type,
drag: {
enable: true,
axis: 'x',
step: 0.1,
},
});
console.log(`百叶模型已替换为 ${currentText}`);
}
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}`);
}
}
} else {
console.log(`未查询到数据`);
}
} catch (error) {
console.error(`查询SKU配置或替换模型失败:`, error);
}
} }
@ -899,12 +851,64 @@
// 监听放置区域点击事件 // 监听放置区域点击事件
kernel.on('dropzone:click', (data) => { kernel.on('dropzone:click', async (dropzone_data) => {
console.log('点击了放置区域:', data); const { position,rotation } = dropzone_data.transform;
console.log('中心点:', data.center);
console.log('宽度:', data.width); // 将模型放置到该区域
console.log('高度:', data.height); try {
console.log('法线:', data.normal); const response = await fetch(`http://localhost:3000/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
for (const event of result.data.events) {
if (event.event_type === 'change_model') {
const { file_url, model_control_type, category } = event.target_data;
console.log('替换百叶模型:', event);
await kernel.model.replace({
modelId: category,
modelUrl: file_url,
modelControlType: model_control_type,
drag: {
enable: true,
axis: 'x',
step: 0.1,
}
,
transform: {
position: position,
rotation: rotation,
}
});
console.log(`百叶模型已替换为 ${currentText}`);
}
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}`);
}
}
} else {
console.log(`未查询到数据`);
}
} catch (error) {
console.error(`查询SKU配置或替换模型失败:`, error);
}
}); });
</script> </script>
</body> </body>

View File

@ -24,11 +24,18 @@ type ModelConfig = {
type ModelControlType = 'rotation' | 'color'; type ModelControlType = 'rotation' | 'color';
type ModelTransform = {
position?: { x: number; y: number; z: number };
rotation?: { x: number; y: number; z: number };
scale?: { x: number; y: number; z: number };
};
type ModelMetadata = { type ModelMetadata = {
modelId: string; modelId: string;
modelUrl: string; modelUrl: string;
modelControlType?: ModelControlType; modelControlType?: ModelControlType;
drag?: DragConfig; drag?: DragConfig;
transform?: ModelTransform;
}; };
/** /**
@ -224,14 +231,15 @@ export class AppModel extends Monobehiver {
modelConfig.modelId, modelConfig.modelId,
modelConfig.modelUrl, modelConfig.modelUrl,
modelConfig.modelControlType, modelConfig.modelControlType,
modelConfig.drag modelConfig.drag,
modelConfig.transform
); );
} }
/** /**
* 添加单个模型 * 添加单个模型
*/ */
private async addSingle(modelName: string, modelUrl: string, modelControlType?: ModelControlType, drag?: DragConfig): Promise<LoadResult> { private async addSingle(modelName: string, modelUrl: string, modelControlType?: ModelControlType, drag?: DragConfig, transform?: ModelTransform): Promise<LoadResult> {
// 检查是否已存在 // 检查是否已存在
const existingMeshes = this.modelDic.Get(modelName); const existingMeshes = this.modelDic.Get(modelName);
if (existingMeshes?.length && !existingMeshes[0].isDisposed()) { if (existingMeshes?.length && !existingMeshes[0].isDisposed()) {
@ -254,9 +262,15 @@ export class AppModel extends Monobehiver {
modelId: modelName, modelId: modelName,
modelUrl: modelUrl, modelUrl: modelUrl,
modelControlType: modelControlType, modelControlType: modelControlType,
drag: drag drag: drag,
transform: transform
}); });
// 应用 transform
if (transform) {
this.applyTransform(modelName, transform);
}
// 配置拖拽功能 // 配置拖拽功能
if (drag) { if (drag) {
this.mainApp.appModelDrag?.configureDrag(modelName, drag); this.mainApp.appModelDrag?.configureDrag(modelName, drag);
@ -283,7 +297,7 @@ export class AppModel extends Monobehiver {
EventBridge.modelLoadProgress({ loaded: 0, total, progress: 0, percentage: 0 }); EventBridge.modelLoadProgress({ loaded: 0, total, progress: 0, percentage: 0 });
for (let i = 0; i < models.length; i++) { for (let i = 0; i < models.length; i++) {
const { modelId, modelUrl, modelControlType, drag } = models[i]; const { modelId, modelUrl, modelControlType, drag, transform } = models[i];
const result = await this.loadSingleModel(modelUrl, (event) => { const result = await this.loadSingleModel(modelUrl, (event) => {
this.emitProgress(i, total, modelUrl, event); this.emitProgress(i, total, modelUrl, event);
@ -298,9 +312,15 @@ export class AppModel extends Monobehiver {
modelId: modelId, modelId: modelId,
modelUrl: modelUrl, modelUrl: modelUrl,
modelControlType: modelControlType, modelControlType: modelControlType,
drag: drag drag: drag,
transform: transform
}); });
// 应用 transform
if (transform) {
this.applyTransform(modelId, transform);
}
// 配置拖拽功能 // 配置拖拽功能
if (drag) { if (drag) {
this.mainApp.appModelDrag?.configureDrag(modelId, drag); this.mainApp.appModelDrag?.configureDrag(modelId, drag);
@ -426,7 +446,8 @@ export class AppModel extends Monobehiver {
modelConfig.modelId, modelConfig.modelId,
modelConfig.modelUrl, modelConfig.modelUrl,
modelConfig.modelControlType, modelConfig.modelControlType,
modelConfig.drag modelConfig.drag,
modelConfig.transform
); );
} }
@ -591,4 +612,59 @@ export class AppModel extends Monobehiver {
mesh.scaling.z = scale.z; mesh.scaling.z = scale.z;
}); });
} }
/**
* 将模型放置到指定的放置区域
* @param modelId 模型ID
* @param zoneInfo 放置区域信息
* @param offsetDistance 距离墙面的偏移距离默认0.1,正数向外)
*/
placeToZone(modelId: string, zoneInfo: any, offsetDistance: number = 0): void {
const meshes = this.modelDic.Get(modelId);
if (!meshes?.length) {
console.warn(`Model not found: ${modelId}`);
return;
}
// 计算放置位置:中心点 + 法线方向的偏移
const targetPosition = zoneInfo.center.add(zoneInfo.normal.scale(offsetDistance));
// 计算旋转角度:让模型面向墙面(法线的反方向)
const targetDirection = zoneInfo.normal.scale(-1);
const angle = Math.atan2(targetDirection.x, targetDirection.z);
this.getModelTransformTargets(meshes).forEach(mesh => {
// 设置位置
mesh.position.copyFrom(targetPosition);
// 设置旋转只旋转Y轴让模型面向墙面
if (mesh.rotationQuaternion) {
mesh.rotationQuaternion = Quaternion.FromEulerAngles(0, angle, 0);
} else {
mesh.rotation.set(0, angle, 0);
}
});
}
/**
* 应用 transform 到模型
* @param modelId 模型ID
* @param transform 变换信息
*/
private applyTransform(modelId: string, transform: ModelTransform): void {
// 应用位置
if (transform.position) {
this.setPosition(modelId, transform.position);
}
// 应用旋转(角度制)
if (transform.rotation) {
this.setRotation(modelId, transform.rotation, true);
}
// 应用缩放
if (transform.scale) {
this.setScale(modelId, transform.scale);
}
}
} }

View File

@ -92,6 +92,12 @@ class AppRay extends Monobehiver {
const zones = this.mainApp.appDropZone.getPlacementZones(); const zones = this.mainApp.appDropZone.getPlacementZones();
const clickedZone = zones.find(zone => zone.mesh === pickInfo.pickedMesh); const clickedZone = zones.find(zone => zone.mesh === pickInfo.pickedMesh);
if (clickedZone) { if (clickedZone) {
// 计算该放置区域的目标位置和旋转
const offsetDistance = 0.1;
const targetPosition = clickedZone.center.add(clickedZone.normal.scale(offsetDistance));
const targetDirection = clickedZone.normal.scale(-1);
const angle = Math.atan2(targetDirection.x, targetDirection.z);
EventBridge.dropZoneClick({ EventBridge.dropZoneClick({
wallName: clickedZone.wallName, wallName: clickedZone.wallName,
index: clickedZone.index, index: clickedZone.index,
@ -99,7 +105,24 @@ class AppRay extends Monobehiver {
width: clickedZone.width, width: clickedZone.width,
height: clickedZone.height, height: clickedZone.height,
normal: clickedZone.normal, normal: clickedZone.normal,
mesh: clickedZone.mesh mesh: clickedZone.mesh,
transform: {
position: {
x: targetPosition.x,
y: targetPosition.y,
z: targetPosition.z
},
rotation: {
x: 0,
y: angle * 180 / Math.PI, // 转换为角度
z: 0
},
scale: {
x: 1,
y: 1,
z: 1
}
}
}); });
return; return;
} }

View File

@ -55,4 +55,21 @@ export type DropZoneClickPayload = {
height: number; height: number;
normal: any; normal: any;
mesh: any; mesh: any;
transform: {
position: {
x: number;
y: number;
z: number;
};
rotation: {
x: number;
y: number;
z: number;
};
scale: {
x: number;
y: number;
z: number;
};
};
}; };

View File

@ -176,6 +176,22 @@ export class KernelAdapter {
*/ */
scale: (options: { modelId: string; vector3: { x: number; y: number; z: number } }): void => { scale: (options: { modelId: string; vector3: { x: number; y: number; z: number } }): void => {
this.mainApp.appModel.setScale(options.modelId, options.vector3); this.mainApp.appModel.setScale(options.modelId, options.vector3);
},
/**
* 将模型放置到指定的放置区域
* @param options 放置配置 { modelId: string, zoneInfo: any, offsetDistance?: number }
* @example
* // 监听放置区域点击,将模型放置到该区域
* kernel.on('dropzone:click', (zoneInfo) => {
* kernel.transform.placeToZone({
* modelId: "myModel",
* zoneInfo: zoneInfo,
* offsetDistance: 0.1 // 可选,距离墙面的偏移距离
* });
* });
*/
placeToZone: (options: { modelId: string; zoneInfo: any; offsetDistance?: number }): void => {
this.mainApp.appModel.placeToZone(options.modelId, options.zoneInfo, options.offsetDistance);
} }
}; };