diff --git a/viewer/index.html b/viewer/index.html index 5f8216b..ef5b0b4 100644 --- a/viewer/index.html +++ b/viewer/index.html @@ -28,6 +28,11 @@ html,body{margin:0;height:100%;background:var(--bg);color:var(--fg);font-family:

대산2터널 본선 3D 모델

측점 4+745 ~ 5+480 · 단위 m
+

구간 보기 (측점)

+ +
+ 4+745 +

지보패턴 (라이닝·굴착 여유대)

굴착 여유대

@@ -107,11 +112,11 @@ Promise.all([ const c = META_BY_ID[o.name]; o.userData = { id: o.name, group: c ? c.group : '', pattern: c && c.pattern ? c.pattern : null, from: c ? c.from_sta : null, to: c ? c.to_sta : null, label: c ? c.label : o.name }; - o.geometry.computeVertexNormals(); // GLB normals from the exporter are not reliable for shading + o.geometry = o.geometry.toNonIndexed(); // flat shading: one normal per triangle, no smoothing + o.geometry.computeVertexNormals(); const rgb = c && c.color ? c.color : [200, 200, 200]; o.material = new THREE.MeshStandardMaterial({ color: new THREE.Color(rgb[0] / 255, rgb[1] / 255, rgb[2] / 255), - roughness: 0.75, metalness: 0.0, side: THREE.DoubleSide }); - if (o.userData.group === '굴착면') { o.material.transparent = true; o.material.opacity = 0.55; o.material.depthWrite = false; } + roughness: 0.8, metalness: 0.0, side: THREE.DoubleSide, flatShading: true }); meshes.push(o); }); const box = new THREE.Box3().setFromObject(root); @@ -126,14 +131,23 @@ Promise.all([ }; const overview = () => viewFrom(c, d * 0.75); const focusStation = (sta) => { + sta = Math.max(4745, Math.min(5480, sta)); const bb = new THREE.Box3(); let any = false; for (const m of meshes) { - if (m.userData.group === '라이닝' && m.userData.from <= sta && sta < m.userData.to) { bb.union(new THREE.Box3().setFromObject(m)); any = true; } + const u = m.userData; + if (!m.visible || u.from == null) continue; + if (u.to < sta - 15 || u.from > sta + 15) continue; + bb.union(new THREE.Box3().setFromObject(m)); any = true; } if (!any) return; const cc = bb.getCenter(new THREE.Vector3()), ss = bb.getSize(new THREE.Vector3()); - viewFrom(cc, Math.max(ss.x, ss.y, ss.z) * 2.2 + 12); + viewFrom(cc, Math.max(ss.x, ss.y, ss.z) * 0.9 + 25); + staEl.value = String(sta); staLabel.textContent = fmtSta(sta); }; + const staEl = document.getElementById('sta'), staLabel = document.getElementById('staLabel'); + staEl.addEventListener('input', () => focusStation(Number(staEl.value))); + document.getElementById('prev').addEventListener('click', () => focusStation(Number(staEl.value) - 5)); + document.getElementById('next').addEventListener('click', () => focusStation(Number(staEl.value) + 5)); document.getElementById('viewAll').addEventListener('click', overview); document.getElementById('viewStart').addEventListener('click', () => focusStation(4745)); overview();