bc-model-viewer 1.7.18 → 1.7.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>相机切换演示 - Bc-model-viewer</title>
|
|
8
|
+
<link rel="stylesheet" href="common-styles.css">
|
|
9
|
+
<style>
|
|
10
|
+
.camera-info {
|
|
11
|
+
margin-top: 15px;
|
|
12
|
+
padding: 12px;
|
|
13
|
+
background: rgba(102, 126, 234, 0.1);
|
|
14
|
+
border-radius: 6px;
|
|
15
|
+
border-left: 3px solid #667eea;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.camera-info-label {
|
|
19
|
+
font-size: 12px;
|
|
20
|
+
color: #666;
|
|
21
|
+
margin-bottom: 4px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.camera-info-value {
|
|
25
|
+
font-size: 16px;
|
|
26
|
+
font-weight: 600;
|
|
27
|
+
color: #667eea;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.camera-params {
|
|
31
|
+
margin-top: 15px;
|
|
32
|
+
padding: 12px;
|
|
33
|
+
background: rgba(255, 255, 255, 0.05);
|
|
34
|
+
border-radius: 6px;
|
|
35
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.camera-param-group {
|
|
39
|
+
margin-bottom: 12px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.camera-param-group:last-child {
|
|
43
|
+
margin-bottom: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.camera-param-label {
|
|
47
|
+
display: flex;
|
|
48
|
+
justify-content: space-between;
|
|
49
|
+
align-items: center;
|
|
50
|
+
margin-bottom: 6px;
|
|
51
|
+
font-size: 12px;
|
|
52
|
+
color: rgba(255, 255, 255, 0.8);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.camera-param-value {
|
|
56
|
+
color: #4CAF50;
|
|
57
|
+
font-weight: 600;
|
|
58
|
+
font-size: 13px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.camera-param-input {
|
|
62
|
+
width: 100%;
|
|
63
|
+
height: 6px;
|
|
64
|
+
border-radius: 3px;
|
|
65
|
+
background: rgba(255, 255, 255, 0.2);
|
|
66
|
+
outline: none;
|
|
67
|
+
-webkit-appearance: none;
|
|
68
|
+
appearance: none;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.camera-param-input::-webkit-slider-thumb {
|
|
72
|
+
-webkit-appearance: none;
|
|
73
|
+
appearance: none;
|
|
74
|
+
width: 16px;
|
|
75
|
+
height: 16px;
|
|
76
|
+
border-radius: 50%;
|
|
77
|
+
background: #4CAF50;
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
|
80
|
+
transition: background 0.2s;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.camera-param-input::-webkit-slider-thumb:hover {
|
|
84
|
+
background: #45a049;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.camera-param-input::-moz-range-thumb {
|
|
88
|
+
width: 16px;
|
|
89
|
+
height: 16px;
|
|
90
|
+
border-radius: 50%;
|
|
91
|
+
background: #4CAF50;
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
border: none;
|
|
94
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
|
95
|
+
transition: background 0.2s;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.camera-param-input::-moz-range-thumb:hover {
|
|
99
|
+
background: #45a049;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.camera-type-badge {
|
|
103
|
+
display: inline-block;
|
|
104
|
+
padding: 4px 10px;
|
|
105
|
+
border-radius: 12px;
|
|
106
|
+
font-size: 12px;
|
|
107
|
+
font-weight: 600;
|
|
108
|
+
text-transform: uppercase;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.camera-type-perspective {
|
|
112
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
113
|
+
color: white;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.camera-type-orthographic {
|
|
117
|
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
118
|
+
color: white;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.info-text {
|
|
122
|
+
font-size: 12px;
|
|
123
|
+
color: rgba(255, 255, 255, 0.6);
|
|
124
|
+
line-height: 1.6;
|
|
125
|
+
margin-top: 10px;
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
128
|
+
</head>
|
|
129
|
+
|
|
130
|
+
<body>
|
|
131
|
+
<div id="container"></div>
|
|
132
|
+
<a href="index.html" class="back-button">返回示例列表</a>
|
|
133
|
+
<div class="demo">
|
|
134
|
+
<h2>📷 相机切换演示</h2>
|
|
135
|
+
<p>在透视相机和正交相机之间切换,体验不同的视图效果。</p>
|
|
136
|
+
|
|
137
|
+
<div class="control-group">
|
|
138
|
+
<button onclick="switchToPerspective()">切换到透视相机</button>
|
|
139
|
+
<button onclick="switchToOrthographic()" class="secondary">切换到正交相机</button>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<div class="camera-info">
|
|
143
|
+
<div class="camera-info-label">当前相机类型</div>
|
|
144
|
+
<div class="camera-info-value" id="cameraType">透视相机</div>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div class="camera-params" id="cameraParams">
|
|
148
|
+
<!-- 动态生成的相机参数控制 -->
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<div class="info-text">
|
|
152
|
+
<strong>透视相机:</strong>模拟人眼视角,近大远小,适合查看整体场景。<br>
|
|
153
|
+
<strong>正交相机:</strong>无透视变形,平行投影,适合查看精确尺寸。
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<script type="module">
|
|
158
|
+
|
|
159
|
+
import { Viewer } from '../../index.ts'
|
|
160
|
+
|
|
161
|
+
const container = document.getElementById('container')
|
|
162
|
+
|
|
163
|
+
// 实例化 Viewer 对象
|
|
164
|
+
const viewer = new Viewer(container, {
|
|
165
|
+
style: {
|
|
166
|
+
type: 1
|
|
167
|
+
},
|
|
168
|
+
load: {
|
|
169
|
+
cache: {
|
|
170
|
+
enabled: false,
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
gui: {
|
|
174
|
+
enabled: true
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
// 加载测试模型
|
|
179
|
+
try {
|
|
180
|
+
await viewer.loadZipAsync('./dgz/样板间.dgz')
|
|
181
|
+
console.log('模型加载成功')
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error('模型加载失败:', error)
|
|
184
|
+
alert('无法加载测试模型,请确保模型文件存在')
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 更新相机信息显示
|
|
188
|
+
function updateCameraInfo() {
|
|
189
|
+
const isPerspective = viewer.isPerspective();
|
|
190
|
+
const cameraTypeElement = document.getElementById('cameraType');
|
|
191
|
+
const cameraParamsElement = document.getElementById('cameraParams');
|
|
192
|
+
|
|
193
|
+
if (cameraTypeElement) {
|
|
194
|
+
if (isPerspective) {
|
|
195
|
+
cameraTypeElement.innerHTML = '<span class="camera-type-badge camera-type-perspective">透视相机</span>';
|
|
196
|
+
} else {
|
|
197
|
+
cameraTypeElement.innerHTML = '<span class="camera-type-badge camera-type-orthographic">正交相机</span>';
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// 更新相机参数控制
|
|
202
|
+
if (cameraParamsElement) {
|
|
203
|
+
if (isPerspective) {
|
|
204
|
+
const fov = viewer.camera.fov || 45;
|
|
205
|
+
cameraParamsElement.innerHTML = `
|
|
206
|
+
<div class="camera-param-group">
|
|
207
|
+
<div class="camera-param-label">
|
|
208
|
+
<span>视野角度 (FOV)</span>
|
|
209
|
+
<span class="camera-param-value" id="fovValue">${fov}°</span>
|
|
210
|
+
</div>
|
|
211
|
+
<input
|
|
212
|
+
type="range"
|
|
213
|
+
class="camera-param-input"
|
|
214
|
+
min="10"
|
|
215
|
+
max="120"
|
|
216
|
+
step="1"
|
|
217
|
+
value="${fov}"
|
|
218
|
+
oninput="updateFOV(this.value)"
|
|
219
|
+
/>
|
|
220
|
+
</div>
|
|
221
|
+
`;
|
|
222
|
+
} else {
|
|
223
|
+
// 计算当前 viewSize(基于 orthographicCamera 的 zoom)
|
|
224
|
+
const orthoCamera = viewer.orthographicCamera;
|
|
225
|
+
const zoom = orthoCamera ? orthoCamera.zoom : 1;
|
|
226
|
+
// 估算 viewSize(实际值需要根据 boxSize 计算)
|
|
227
|
+
const estimatedViewSize = 10 / zoom;
|
|
228
|
+
|
|
229
|
+
cameraParamsElement.innerHTML = `
|
|
230
|
+
<div class="camera-param-group">
|
|
231
|
+
<div class="camera-param-label">
|
|
232
|
+
<span>视图大小 (View Size)</span>
|
|
233
|
+
<span class="camera-param-value" id="viewSizeValue">${estimatedViewSize.toFixed(1)}</span>
|
|
234
|
+
</div>
|
|
235
|
+
<input
|
|
236
|
+
type="range"
|
|
237
|
+
class="camera-param-input"
|
|
238
|
+
min="1"
|
|
239
|
+
max="50"
|
|
240
|
+
step="0.5"
|
|
241
|
+
value="${estimatedViewSize}"
|
|
242
|
+
oninput="updateViewSize(this.value)"
|
|
243
|
+
/>
|
|
244
|
+
</div>
|
|
245
|
+
`;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// 切换到透视相机
|
|
251
|
+
function switchToPerspective() {
|
|
252
|
+
viewer.toggleCamera('perspective');
|
|
253
|
+
updateCameraInfo();
|
|
254
|
+
console.log('已切换到透视相机');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// 切换到正交相机
|
|
258
|
+
function switchToOrthographic() {
|
|
259
|
+
viewer.toggleCamera('orthographic');
|
|
260
|
+
updateCameraInfo();
|
|
261
|
+
console.log('已切换到正交相机');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// 更新 FOV(仅透视相机)
|
|
265
|
+
function updateFOV(value) {
|
|
266
|
+
if (!viewer.isPerspective()) return;
|
|
267
|
+
|
|
268
|
+
const fov = parseFloat(value);
|
|
269
|
+
viewer.camera.fov = fov;
|
|
270
|
+
viewer.camera.updateProjectionMatrix();
|
|
271
|
+
|
|
272
|
+
const fovValueElement = document.getElementById('fovValue');
|
|
273
|
+
if (fovValueElement) {
|
|
274
|
+
fovValueElement.textContent = `${fov}°`;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// 更新 ViewSize(仅正交相机)
|
|
279
|
+
function updateViewSize(value) {
|
|
280
|
+
if (viewer.isPerspective()) return;
|
|
281
|
+
|
|
282
|
+
const viewSize = parseFloat(value);
|
|
283
|
+
viewer.updateOrthographicCamera(viewSize);
|
|
284
|
+
|
|
285
|
+
const viewSizeValueElement = document.getElementById('viewSizeValue');
|
|
286
|
+
if (viewSizeValueElement) {
|
|
287
|
+
viewSizeValueElement.textContent = viewSize.toFixed(1);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// 暴露函数到全局
|
|
292
|
+
window.viewer = viewer;
|
|
293
|
+
window.switchToPerspective = switchToPerspective;
|
|
294
|
+
window.switchToOrthographic = switchToOrthographic;
|
|
295
|
+
window.updateFOV = updateFOV;
|
|
296
|
+
window.updateViewSize = updateViewSize;
|
|
297
|
+
|
|
298
|
+
// 初始更新一次
|
|
299
|
+
updateCameraInfo();
|
|
300
|
+
|
|
301
|
+
// 监听窗口大小变化,更新相机信息
|
|
302
|
+
window.addEventListener('resize', () => {
|
|
303
|
+
setTimeout(updateCameraInfo, 100);
|
|
304
|
+
});
|
|
305
|
+
</script>
|
|
306
|
+
|
|
307
|
+
</body>
|
|
308
|
+
|
|
309
|
+
</html>
|
|
310
|
+
|
package/examples/index.html
CHANGED
|
@@ -280,7 +280,7 @@
|
|
|
280
280
|
<body>
|
|
281
281
|
<div class="container">
|
|
282
282
|
<header>
|
|
283
|
-
<h1>🚀
|
|
283
|
+
<h1>🚀 model-viewer</h1>
|
|
284
284
|
<p>3D 模型查看器示例导航</p>
|
|
285
285
|
</header>
|
|
286
286
|
|
|
@@ -423,6 +423,17 @@
|
|
|
423
423
|
<a href="PositionCameraTool.html" class="link-button">查看示例 →</a>
|
|
424
424
|
</div>
|
|
425
425
|
|
|
426
|
+
<div class="example-card" data-name="相机切换" data-desc="透视正交切换">
|
|
427
|
+
<h3><span class="icon">📷</span>相机切换</h3>
|
|
428
|
+
<div class="description">演示在透视相机和正交相机之间切换。透视相机模拟人眼视角,正交相机无透视变形,适合查看精确尺寸。</div>
|
|
429
|
+
<div class="tags">
|
|
430
|
+
<span class="tag tag-tool">相机工具</span>
|
|
431
|
+
<span class="tag tag-feature">透视相机</span>
|
|
432
|
+
<span class="tag tag-feature">正交相机</span>
|
|
433
|
+
</div>
|
|
434
|
+
<a href="ToggleCamera.html" class="link-button">查看示例 →</a>
|
|
435
|
+
</div>
|
|
436
|
+
|
|
426
437
|
<div class="example-card" data-name="框选放大" data-desc="选择缩放">
|
|
427
438
|
<h3><span class="icon">🔍</span>框选放大工具</h3>
|
|
428
439
|
<div class="description">演示如何使用框选工具来放大查看模型的特定区域。框选范围越小,放大倍数越大,适合查看细节。</div>
|