1
This commit is contained in:
BIN
assets/卷帘大.glb
BIN
assets/卷帘大.glb
Binary file not shown.
BIN
assets/卷帘小.glb
BIN
assets/卷帘小.glb
Binary file not shown.
BIN
assets/小桌.glb
BIN
assets/小桌.glb
Binary file not shown.
BIN
assets/框架.glb
BIN
assets/框架.glb
Binary file not shown.
BIN
assets/百叶窗小.glb
BIN
assets/百叶窗小.glb
Binary file not shown.
297813
examples/index copy.js
Normal file
297813
examples/index copy.js
Normal file
File diff suppressed because one or more lines are too long
120
examples/index.js
Normal file
120
examples/index.js
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import { kernel } from './index copy.js';
|
||||||
|
|
||||||
|
// import { kernel } from 'https://sdk.zguiy.com/zt/assets/index.js';
|
||||||
|
|
||||||
|
// const config = {
|
||||||
|
// container: document.querySelector('#renderDom'),
|
||||||
|
// modelUrlList: ['/assets/model.glb'],
|
||||||
|
// env: { envPath: '/assets/hdr.env', intensity: 1.2, rotationY: 0.3, background: false },
|
||||||
|
// };
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
container: document.querySelector('#renderDom'),
|
||||||
|
modelUrlList: [],
|
||||||
|
env: { envPath: 'https://sdk.zguiy.com/resurces/hdr/hdr.env', intensity: 1.2, rotationY: 0.3, background: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
kernel.init(config);
|
||||||
|
kernel.model.add("卷帘大", "https://sdk.zguiy.com/resurces/model/框架.glb")
|
||||||
|
kernel.model.add("卷帘大", "https://sdk.zguiy.com/resurces/model/卷帘大.glb")
|
||||||
|
kernel.model.add("卷帘小", "https://sdk.zguiy.com/resurces/model/卷帘小.glb")
|
||||||
|
kernel.model.add("小桌", "https://sdk.zguiy.com/resurces/model/小桌.glb")
|
||||||
|
|
||||||
|
kernel.on('model:load:progress', (data) => {
|
||||||
|
console.log('模型加载事件', data);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
kernel.on('model:loaded', (data) => {
|
||||||
|
console.log('模型加载完成', data);
|
||||||
|
// 隐藏进度条
|
||||||
|
const progressContainer = document.getElementById('progress-container');
|
||||||
|
if (progressContainer) {
|
||||||
|
progressContainer.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
kernel.on('all:ready', (data) => {
|
||||||
|
console.log('所有模块加载完,', data);
|
||||||
|
kernel.material.apply({
|
||||||
|
target: 'Material__2',
|
||||||
|
attribute: 'alpha',
|
||||||
|
value: 0.5,
|
||||||
|
});
|
||||||
|
kernel.hotspot.render([
|
||||||
|
{
|
||||||
|
id: "h1",
|
||||||
|
type: 'hotspot',
|
||||||
|
name: "卷帘门",
|
||||||
|
meshName: "Valve_01",
|
||||||
|
icon: "https://bpic.588ku.com/element_pic/20/06/30/d1046b01afc0b9586844350d131f4daf.jpg!/fw/253/quality/90/unsharp/true/compress/true",
|
||||||
|
offset: [25, 25, 0],
|
||||||
|
radius: 20,
|
||||||
|
color: "#21c7ff",
|
||||||
|
payload: { type: "valve", code: "A" },
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// 存储当前选中的材质名和网格
|
||||||
|
let currentMaterialName = '';
|
||||||
|
let currentPickedMesh = null;
|
||||||
|
|
||||||
|
kernel.on('model:click', (data) => {
|
||||||
|
console.log('模型点击事件', data);
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
// DOM 2D转3D 示例:点击模型时显示信息框
|
||||||
|
if (data.pickedMesh && data.pickedPoint) {
|
||||||
|
const meshName = data.pickedMesh.name;
|
||||||
|
const position = data.pickedPoint; // 使用点击位置的坐标
|
||||||
|
currentMaterialName = data.materialName || ''; // 保存材质名
|
||||||
|
currentPickedMesh = data.pickedMesh; // 保存网格对象
|
||||||
|
|
||||||
|
console.log('点击位置的3D坐标:', position);
|
||||||
|
console.log('材质名:', currentMaterialName);
|
||||||
|
|
||||||
|
// 获取已创建的DOM元素
|
||||||
|
const infoDiv = document.getElementById('model-info-box');
|
||||||
|
|
||||||
|
// 更新信息内容
|
||||||
|
document.getElementById('info-name').textContent = `名称: ${meshName}`;
|
||||||
|
document.getElementById('info-position').textContent = `坐标: [${position.x.toFixed(2)}, ${position.y.toFixed(2)}, ${position.z.toFixed(2)}]`;
|
||||||
|
|
||||||
|
// 将DOM附加到点击的3D坐标(会自动显示)
|
||||||
|
kernel.domTo3D.attach('model-info', infoDiv, [position.x, position.y, position.z], { x: -2, y: -2 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 暴露到全局,供 index.html 使用
|
||||||
|
window.getCurrentMaterialName = () => currentMaterialName;
|
||||||
|
window.getCurrentPickedMesh = () => currentPickedMesh;
|
||||||
|
|
||||||
|
// 暴露 kernel 到全局,方便调试
|
||||||
|
|
||||||
|
|
||||||
|
kernel.on('hotspot:click', (data) => {
|
||||||
|
console.log('热点被点击:', data);
|
||||||
|
const { id, name } = data
|
||||||
|
if (name === "卷帘门") {
|
||||||
|
kernel.door.toggle({ upY: 28, downY: 0, speed: 12 });
|
||||||
|
|
||||||
|
// Y轴剖切,只作用于卷帘门网格,保留下方,剖掉上方
|
||||||
|
const clipHeight = 28; // 调整这个值找到合适的剖切高度
|
||||||
|
console.log('设置剖切:', clipHeight);
|
||||||
|
kernel.clipping.setY(clipHeight, true, ['Box005.001', 'Box006.001']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.kernel = kernel;
|
||||||
|
// 添加模型到场景
|
||||||
|
// await kernel.model.add('https://sdk.zguiy.com/resurces/model/百叶1.glb');
|
||||||
|
|
||||||
|
// 销毁模型
|
||||||
|
// kernel.model.destroy('car');
|
||||||
|
|
||||||
|
// 替换模型
|
||||||
|
// await kernel.model.replace('car', '/models/new-car.glb');
|
||||||
|
|
||||||
@ -21,6 +21,12 @@
|
|||||||
#app {
|
#app {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#canvas-container {
|
||||||
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +36,157 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#config-panel {
|
||||||
|
width: 320px;
|
||||||
|
background: rgba(30, 30, 45, 0.95);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: -2px 0 10px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#config-panel::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#config-panel::-webkit-scrollbar-track {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#config-panel::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-title {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 2px solid rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-category {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-header {
|
||||||
|
padding: 12px 15px;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
transition: background 0.3s;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-header:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-header.active {
|
||||||
|
background: rgba(76, 175, 80, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-arrow {
|
||||||
|
transition: transform 0.3s;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-arrow.expanded {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-content {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 0fr;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: grid-template-rows 0.3s ease, padding 0.3s ease;
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-content.expanded {
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-content>* {
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-item {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-label {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-group {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-btn:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border-color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-btn.selected {
|
||||||
|
background: rgba(76, 175, 80, 0.6);
|
||||||
|
border-color: #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-checkbox:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-checkbox input[type="checkbox"] {
|
||||||
|
margin-right: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-checkbox label {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/* 进度条样式 */
|
/* 进度条样式 */
|
||||||
#progress-container {
|
#progress-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -63,6 +220,8 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
|
<!-- 画布区域 -->
|
||||||
|
<div id="canvas-container">
|
||||||
<canvas id="renderDom"></canvas>
|
<canvas id="renderDom"></canvas>
|
||||||
<div id="progress-container" style="display: none;">
|
<div id="progress-container" style="display: none;">
|
||||||
<div id="progress-bar"></div>
|
<div id="progress-bar"></div>
|
||||||
@ -70,116 +229,304 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 配置面板 -->
|
||||||
|
<div id="config-panel">
|
||||||
|
<div class="config-title">选装选配</div>
|
||||||
|
|
||||||
|
<!-- 棚子尺寸 -->
|
||||||
|
<div class="config-category">
|
||||||
|
<div class="category-header" data-category="size">
|
||||||
|
<span class="category-title">棚子尺寸</span>
|
||||||
|
<span class="category-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="category-content">
|
||||||
|
<div class="option-group">
|
||||||
|
<button class="option-btn" data-option="size-1">3x3米</button>
|
||||||
|
<button class="option-btn" data-option="size-2">4x4米</button>
|
||||||
|
<button class="option-btn" data-option="size-3">5x5米</button>
|
||||||
|
<button class="option-btn" data-option="size-4">6x6米</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 棚子类型 -->
|
||||||
|
<div class="config-category">
|
||||||
|
<div class="category-header" data-category="type">
|
||||||
|
<span class="category-title">棚子类型</span>
|
||||||
|
<span class="category-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="category-content">
|
||||||
|
<div class="option-group">
|
||||||
|
<button class="option-btn" data-option="type-1">平顶</button>
|
||||||
|
<button class="option-btn" data-option="type-2">尖顶</button>
|
||||||
|
<button class="option-btn" data-option="type-3">弧形</button>
|
||||||
|
<button class="option-btn" data-option="type-4">异形</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 百叶 (单选) -->
|
||||||
|
<div class="config-category">
|
||||||
|
<div class="category-header" data-category="louver">
|
||||||
|
<span class="category-title">百叶</span>
|
||||||
|
<span class="category-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="category-content">
|
||||||
|
<div class="option-group">
|
||||||
|
<button class="option-btn" data-option="louver-1">百叶1</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-4">百叶4</button>
|
||||||
|
<button class="option-btn" data-option="louver-4">卷帘小</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 配色 -->
|
||||||
|
<div class="config-category">
|
||||||
|
<div class="category-header" data-category="color">
|
||||||
|
<span class="category-title">配色</span>
|
||||||
|
<span class="category-arrow">▼</span>
|
||||||
|
</div>
|
||||||
|
<div class="category-content">
|
||||||
|
<div class="option-group">
|
||||||
|
<button class="option-btn" data-option="color-1">白色</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-4">木色</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 模型信息框(用于2D转3D显示) -->
|
||||||
|
<div id="model-info-box" style="display: none;">
|
||||||
|
<div style="
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
min-width: 200px;
|
||||||
|
">
|
||||||
|
<div style="font-weight: bold; margin-bottom: 8px; color: #4CAF50;">模型信息</div>
|
||||||
|
<div id="info-name" style="margin-bottom: 5px;">名称: -</div>
|
||||||
|
<div id="info-position" style="margin-bottom: 10px; font-size: 12px; color: #666;">坐标: -</div>
|
||||||
|
|
||||||
|
<div style="display: flex; gap: 8px; margin-bottom: 8px;">
|
||||||
|
<button id="color-btn-1" style="
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
background: #FFFFFF;
|
||||||
|
color: #333;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
">白色</button>
|
||||||
|
<button id="color-btn-2" style="
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
background: #000000;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
">黑色</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="display: flex; gap: 8px;">
|
||||||
|
<button id="remove-model-btn" style="
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
background: #f44336;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
">移除</button>
|
||||||
|
<button id="close-info-btn" style="
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
background: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
">关闭</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="module" src="./index.js"></script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
// import { kernel } from './src/main.ts';
|
import { kernel } from './index copy.js';
|
||||||
|
|
||||||
import { kernel } from 'https://sdk.zguiy.com/zt/assets/index.js';
|
|
||||||
|
|
||||||
// const config = {
|
|
||||||
// container: document.querySelector('#renderDom'),
|
|
||||||
// modelUrlList: ['/assets/model.glb'],
|
|
||||||
// env: { envPath: '/assets/hdr.env', intensity: 1.2, rotationY: 0.3, background: false },
|
|
||||||
// };
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
container: document.querySelector('#renderDom'),
|
|
||||||
modelUrlList: ['https://sdk.zguiy.com/resurces/model/model.glb'],
|
|
||||||
env: { envPath: 'https://sdk.zguiy.com/resurces/hdr/hdr.env', intensity: 1.2, rotationY: 0.3, background: true },
|
|
||||||
};
|
|
||||||
|
|
||||||
kernel.init(config);
|
|
||||||
|
|
||||||
|
|
||||||
|
// ========== UI 交互逻辑 ==========
|
||||||
|
|
||||||
kernel.on('model:load:progress', (data) => {
|
// 折叠面板切换
|
||||||
console.log('模型加载事件', data);
|
document.querySelectorAll('.category-header').forEach(header => {
|
||||||
|
header.addEventListener('click', function () {
|
||||||
|
const content = this.nextElementSibling;
|
||||||
|
const arrow = this.querySelector('.category-arrow');
|
||||||
|
|
||||||
|
// 切换展开/收起状态
|
||||||
|
content.classList.toggle('expanded');
|
||||||
|
arrow.classList.toggle('expanded');
|
||||||
|
this.classList.toggle('active');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 单选按钮逻辑
|
||||||
|
document.querySelectorAll('.option-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', async function () {
|
||||||
|
const optionGroup = this.parentElement;
|
||||||
|
const category = this.closest('.config-category');
|
||||||
|
const categoryName = category.querySelector('.category-header').dataset.category;
|
||||||
|
|
||||||
const progress = data.progress || 0;
|
// 同一组内取消其他选中状态
|
||||||
const progressBar = document.getElementById('progress-bar');
|
optionGroup.querySelectorAll('.option-btn').forEach(b => {
|
||||||
const progressText = document.getElementById('progress-text');
|
b.classList.remove('selected');
|
||||||
const progressContainer = document.getElementById('progress-container');
|
});
|
||||||
|
|
||||||
if (progressContainer) {
|
// 选中当前按钮
|
||||||
progressContainer.style.display = 'block';
|
this.classList.add('selected');
|
||||||
|
|
||||||
|
// 触发自定义事件
|
||||||
|
const event = new CustomEvent('config:change', {
|
||||||
|
detail: {
|
||||||
|
category: categoryName,
|
||||||
|
value: this.dataset.option,
|
||||||
|
text: this.textContent
|
||||||
}
|
}
|
||||||
if (progressBar) {
|
});
|
||||||
progressBar.style.width = `${progress * 100}%`;
|
document.dispatchEvent(event);
|
||||||
|
|
||||||
|
console.log('配置变更:', {
|
||||||
|
category: categoryName,
|
||||||
|
value: this.dataset.option,
|
||||||
|
text: this.textContent
|
||||||
|
});
|
||||||
|
|
||||||
|
// 百叶模型替换逻辑
|
||||||
|
if (categoryName === "louver") {
|
||||||
|
const currentText = this.textContent;
|
||||||
|
const modelUrl = `https://sdk.zguiy.com/resurces/model/${currentText}.glb`;
|
||||||
|
console.log('替换百叶模型:', modelUrl);
|
||||||
|
try {
|
||||||
|
await kernel.model.replace('卷帘小', modelUrl);
|
||||||
|
console.log(`百叶模型已替换为 ${currentText}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`百叶模型替换失败:`, error);
|
||||||
}
|
}
|
||||||
if (progressText) {
|
}
|
||||||
progressText.textContent = `${Math.round(progress * 100)}%`;
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 多选复选框逻辑
|
||||||
|
document.querySelectorAll('.option-checkbox input[type="checkbox"]').forEach(checkbox => {
|
||||||
|
checkbox.addEventListener('change', async function () {
|
||||||
|
const category = this.closest('.config-category');
|
||||||
|
const categoryName = category.querySelector('.category-header').dataset.category;
|
||||||
|
const optionGroup = this.closest('.option-group');
|
||||||
|
const checked = this.checked;
|
||||||
|
|
||||||
|
// 获取当前组所有选中的值
|
||||||
|
const selectedValues = Array.from(
|
||||||
|
optionGroup.querySelectorAll('input[type="checkbox"]:checked')
|
||||||
|
).map(cb => ({
|
||||||
|
value: cb.dataset.option,
|
||||||
|
text: cb.nextElementSibling.textContent
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 触发自定义事件
|
||||||
|
const event = new CustomEvent('config:change', {
|
||||||
|
detail: {
|
||||||
|
category: categoryName,
|
||||||
|
values: selectedValues,
|
||||||
|
checked: this.checked,
|
||||||
|
currentValue: this.dataset.option
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.dispatchEvent(event);
|
||||||
|
|
||||||
|
console.log('配置变更(多选):', {
|
||||||
|
category: categoryName,
|
||||||
|
selectedValues: selectedValues,
|
||||||
|
checked: this.checked,
|
||||||
|
currentValue: this.dataset.option
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听配置变更事件(供外部使用)
|
||||||
|
document.addEventListener('config:change', function (e) {
|
||||||
|
// 这里可以根据配置变更来操作 3D 模型
|
||||||
|
// 例如:
|
||||||
|
// if (e.detail.category === 'size') {
|
||||||
|
// kernel.model.replace('shed', `/models/shed-${e.detail.value}.glb`);
|
||||||
|
// }
|
||||||
|
// if (e.detail.category === 'color') {
|
||||||
|
// kernel.material.apply({
|
||||||
|
// target: 'ShedMaterial',
|
||||||
|
// attribute: 'baseColor',
|
||||||
|
// value: getColorValue(e.detail.value)
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========== 模型信息框按钮事件 ==========
|
||||||
|
|
||||||
|
// 关闭按钮事件
|
||||||
|
document.getElementById('close-info-btn').addEventListener('click', () => {
|
||||||
|
kernel.domTo3D.detach('model-info');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 白色按钮事件
|
||||||
|
document.getElementById('color-btn-1').addEventListener('click', () => {
|
||||||
|
const materialName = window.getCurrentMaterialName();
|
||||||
|
if (materialName) {
|
||||||
|
console.log('切换为白色,材质名:', materialName);
|
||||||
|
kernel.material.color(materialName, '#FFFFFF');
|
||||||
|
} else {
|
||||||
|
console.log('没有选中材质');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 黑色按钮事件
|
||||||
|
document.getElementById('color-btn-2').addEventListener('click', () => {
|
||||||
kernel.on('model:loaded', (data) => {
|
const materialName = window.getCurrentMaterialName();
|
||||||
console.log('模型加载完成', data);
|
if (materialName) {
|
||||||
// 隐藏进度条
|
console.log('切换为黑色,材质名:', materialName);
|
||||||
const progressContainer = document.getElementById('progress-container');
|
kernel.material.color(materialName, '#000000');
|
||||||
if (progressContainer) {
|
} else {
|
||||||
progressContainer.style.display = 'none';
|
console.log('没有选中材质');
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
kernel.on('all:ready', (data) => {
|
|
||||||
console.log('所有模块加载完,', data);
|
|
||||||
kernel.material.apply({
|
|
||||||
target: 'Material__2',
|
|
||||||
attribute: 'alpha',
|
|
||||||
value: 0.5,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
kernel.hotspot.render([
|
|
||||||
{
|
|
||||||
id: "h1",
|
|
||||||
name: "卷帘门",
|
|
||||||
meshName: "Valve_01",
|
|
||||||
icon: "./btn_热点.png",
|
|
||||||
offset: [25, 25, 0],
|
|
||||||
radius: 20,
|
|
||||||
color: "#21c7ff",
|
|
||||||
payload: { type: "valve", code: "A" },
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
kernel.on('model:click', (data) => {
|
|
||||||
console.log('模型点击事件', data);
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
kernel.on('hotspot:click', (data) => {
|
|
||||||
console.log('热点被点击:', data);
|
|
||||||
const { id, name } = data
|
|
||||||
if (name === "卷帘门") {
|
|
||||||
kernel.door.toggle({ upY: 28, downY: 0, speed: 12 });
|
|
||||||
|
|
||||||
// Y轴剖切,只作用于卷帘门网格,保留下方,剖掉上方
|
|
||||||
const clipHeight = 28; // 调整这个值找到合适的剖切高度
|
|
||||||
console.log('设置剖切:', clipHeight);
|
|
||||||
kernel.clipping.setY(clipHeight, true, ['Box005.001', 'Box006.001']);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 移除按钮事件
|
||||||
// 添加模型到场景
|
document.getElementById('remove-model-btn').addEventListener('click', () => {
|
||||||
await kernel.model.add('/models/car.glb');
|
const pickedMesh = window.getCurrentPickedMesh();
|
||||||
|
if (pickedMesh) {
|
||||||
// 销毁模型
|
const meshName = pickedMesh.name;
|
||||||
kernel.model.destroy('car');
|
const success = kernel.model.remove(meshName);
|
||||||
|
if (success) {
|
||||||
// 替换模型
|
console.log('模型已移除');
|
||||||
await kernel.model.replace('car', '/models/new-car.glb');
|
// 关闭信息框
|
||||||
|
kernel.domTo3D.detach('model-info');
|
||||||
|
} else {
|
||||||
|
console.log('移除失败:未找到该网格所属的模型');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('没有选中的网格');
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
4
index.js
4
index.js
@ -10,12 +10,12 @@ import { kernel } from './src/main.ts';
|
|||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
container: document.querySelector('#renderDom'),
|
container: document.querySelector('#renderDom'),
|
||||||
modelUrlList: ['https://sdk.zguiy.com/resurces/model/框架.glb'],
|
modelUrlList: [],
|
||||||
env: { envPath: 'https://sdk.zguiy.com/resurces/hdr/hdr.env', intensity: 1.2, rotationY: 0.3, background: true },
|
env: { envPath: 'https://sdk.zguiy.com/resurces/hdr/hdr.env', intensity: 1.2, rotationY: 0.3, background: true },
|
||||||
};
|
};
|
||||||
|
|
||||||
kernel.init(config);
|
kernel.init(config);
|
||||||
|
kernel.model.add("卷帘大", "https://sdk.zguiy.com/resurces/model/框架.glb")
|
||||||
kernel.model.add("卷帘大", "https://sdk.zguiy.com/resurces/model/卷帘大.glb")
|
kernel.model.add("卷帘大", "https://sdk.zguiy.com/resurces/model/卷帘大.glb")
|
||||||
kernel.model.add("卷帘小", "https://sdk.zguiy.com/resurces/model/卷帘小.glb")
|
kernel.model.add("卷帘小", "https://sdk.zguiy.com/resurces/model/卷帘小.glb")
|
||||||
kernel.model.add("小桌", "https://sdk.zguiy.com/resurces/model/小桌.glb")
|
kernel.model.add("小桌", "https://sdk.zguiy.com/resurces/model/小桌.glb")
|
||||||
|
|||||||
@ -208,7 +208,7 @@ export class AppModel extends Monobehiver {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result.success && result.meshes) {
|
if (result.success && result.meshes) {
|
||||||
this.cloneMaterials(result.meshes, modelName);
|
// this.cloneMaterials(result.meshes, modelName);
|
||||||
this.modelDic.Set(modelName, result.meshes);
|
this.modelDic.Set(modelName, result.meshes);
|
||||||
|
|
||||||
// 更新 GameManager 的字典
|
// 更新 GameManager 的字典
|
||||||
|
|||||||
@ -745,12 +745,13 @@ export class GameManager extends Monobehiver {
|
|||||||
applyMaterial(target: string, attribute: string, value: number | string): void {
|
applyMaterial(target: string, attribute: string, value: number | string): void {
|
||||||
// 这里需要根据实际的材质管理逻辑实现
|
// 这里需要根据实际的材质管理逻辑实现
|
||||||
console.log(`Applying attribute ${attribute} to ${value}`);
|
console.log(`Applying attribute ${attribute} to ${value}`);
|
||||||
|
console.log(this.materialDic);
|
||||||
|
|
||||||
// 示例实现:根据目标和材质路径应用材质
|
// 示例实现:根据目标和材质路径应用材质
|
||||||
// 1. 查找目标网格
|
// 1. 查找目标网格
|
||||||
const targetMaterials: PBRMaterial[] = [];
|
const targetMaterials: PBRMaterial[] = [];
|
||||||
this.materialDic.Values().forEach(material => {
|
this.materialDic.Values().forEach(material => {
|
||||||
if (material.name.includes(target)) {
|
if (material.name === target) {
|
||||||
console.log(`${this.materialDic.Get(material.name)}`, material);
|
console.log(`${this.materialDic.Get(material.name)}`, material);
|
||||||
targetMaterials.push(material);
|
targetMaterials.push(material);
|
||||||
}
|
}
|
||||||
@ -769,8 +770,23 @@ export class GameManager extends Monobehiver {
|
|||||||
targetMaterials.forEach(material => {
|
targetMaterials.forEach(material => {
|
||||||
if (attribute === 'baseColor' && typeof value === 'string') {
|
if (attribute === 'baseColor' && typeof value === 'string') {
|
||||||
// 如果是 baseColor 且值是字符串(16进制颜色),转换为 Color3
|
// 如果是 baseColor 且值是字符串(16进制颜色),转换为 Color3
|
||||||
material.albedoColor = Color3.FromHexString(value);
|
const color = Color3.FromHexString(value);
|
||||||
console.log(`Applying baseColor ${value} to material: ${material.name}`);
|
|
||||||
|
console.log(`Before: albedoColor =`, material.albedoColor);
|
||||||
|
console.log(`Before: albedoTexture =`, material.albedoTexture);
|
||||||
|
|
||||||
|
material.albedoColor = color;
|
||||||
|
|
||||||
|
// 如果有纹理,颜色会作为纹理的乘法因子
|
||||||
|
if (material.albedoTexture) {
|
||||||
|
console.log(`Material ${material.name} has albedoTexture, color will tint the texture`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 强制刷新材质
|
||||||
|
material.markDirty();
|
||||||
|
|
||||||
|
console.log(`After: albedoColor =`, material.albedoColor);
|
||||||
|
console.log(`Applying baseColor ${value} to material: ${material.name}`, color);
|
||||||
} else if (material[attribute]) {
|
} else if (material[attribute]) {
|
||||||
material[attribute] = value;
|
material[attribute] = value;
|
||||||
console.log(`Applying attribute ${attribute} to ${value} to mesh: ${material.name}`);
|
console.log(`Applying attribute ${attribute} to ${value} to mesh: ${material.name}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user