🏗️ 부재 구성
-
-
- 가시설4 (H-빔)
- 52개
-
-
- h-pile2 (기초파일)
- 244개, H-400×400×8000mm
-
-
- 토류판 (흙막이판)
- 240개, PL-700×360×14mm
-
-
- H-PILE (파일)
- 26개
-
-
- 스터럿 (버팀목)
- 26개
-
+
+
가시설4 52개
+
h-pile2 244개
+
토류판 240개
+
H-PILE 26개
+
스터럿 26개
-
🎨 범례
-
+
H-빔
@@ -300,19 +222,11 @@
-
⌨️ 조작
-
- 마우스:
- • 좌클릭 드래그 = 회전
- • 휠 스크롤 = 확대/축소
-
- 화면:
- • 3D 배치 확인
- • 부재 형상 검증
- • 구조 파악
-
+ 좌클릭 드래그: 회전
+ 우클릭 드래그: 이동
+ 휠: 확대/축소
@@ -328,8 +242,6 @@
scene.background = new THREE.Color(0x1a3a52);
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 500000);
- // 부재 중심을 향하도록 설정 (정확한 좌표 범위)
- // 중심: (-216, -2554), 폭: 1373, 높이: 552
camera.position.set(-216, -2554, 3000);
camera.lookAt(-216, -2554, 0);
@@ -350,6 +262,26 @@
const hemis = new THREE.HemisphereLight(0x87ceeb, 0x333333, 0.4);
scene.add(hemis);
+ // 추가 조명
+ const pointLight = new THREE.PointLight(0xffffff, 0.8, 10000);
+ pointLight.position.set(500, 500, 500);
+ scene.add(pointLight);
+
+ // OrbitControls (먼저 초기화!)
+ const controls = new THREE.OrbitControls(camera, canvas);
+ controls.target.set(-216, -2554, 0);
+ controls.autoRotate = false;
+ controls.enableDamping = true;
+ controls.dampingFactor = 0.05;
+ controls.enableZoom = true;
+ controls.zoomSpeed = 1.0;
+ controls.enablePan = true;
+ controls.panSpeed = 0.5;
+ controls.update();
+
+ console.log('=== 3D 뷰어 초기화 ===');
+ console.log('✓ OrbitControls 준비 완료');
+
// 재질
const getMaterial = (type) => {
const colors = {
@@ -362,133 +294,15 @@
return new THREE.MeshStandardMaterial({ color, roughness: 0.7, metalness: 0.2 });
};
- const DISPLAY_SCALE = 0.01; // mm → cm (1:100)
+ const DISPLAY_SCALE = 0.01;
- // 디버깅 정보 추가
- console.log('=== 3D 뷰어 초기화 ===');
- console.log('카메라 위치:', camera.position);
- console.log('카메라 타겟:', controls.target);
-
- // 배경 밝게 변경해서 테스트
- scene.background = new THREE.Color(0x1a3a52);
- console.log('배경색 설정 완료');
-
- // 샘플 부재 추가 (테스트용)
- console.log('샘플 부재 생성 중...');
- const testGeometry = new THREE.BoxGeometry(4, 4, 80); // 400×400×8000mm → 4×4×80
- const testMaterial = new THREE.MeshStandardMaterial({
- color: 0x7ed321,
- roughness: 0.7,
- emissive: 0x2d5a2d
- });
- const testMesh = new THREE.Mesh(testGeometry, testMaterial);
- testMesh.position.set(0, -2554, 100); // 부재 중심 좌표
+ // 샘플 부재 (테스트용)
+ const testGeo = new THREE.BoxGeometry(4, 4, 80);
+ const testMat = new THREE.MeshStandardMaterial({ color: 0x7ed321, roughness: 0.7, emissive: 0x2d5a2d });
+ const testMesh = new THREE.Mesh(testGeo, testMat);
+ testMesh.position.set(0, -2554, 100);
scene.add(testMesh);
- console.log('✓ 샘플 부재 @ (0, -2554, 100) - 녹색');
-
- // 추가 조명
- const testLight = new THREE.PointLight(0xffffff, 1.0, 10000);
- testLight.position.set(500, 500, 500);
- scene.add(testLight);
- console.log('✓ 테스트 조명 추가됨');
-
- // stats.json 로드 및 부재 생성
- console.log('stats.json 로드 시작...');
- fetch('gasiseol-correct-v2-stats.json')
- .then(r => {
- console.log('응답 상태:', r.status);
- return r.json();
- })
- .then(data => {
- console.log('📊 JSON 파싱 완료');
- console.log('총 부재:', data.totalParts);
- console.log('배치 부재:', data.parts.length);
-
- let addedCount = 0;
- // 각 부재를 3D 메시로 생성
- data.parts.forEach((part, idx) => {
- let geometry;
- const { blockType, type, spec, position, volume } = part;
-
- // 부재 타입별 3D 형상 생성
- if (type === 'Pile') {
- // H-PILE 형상 (H-beam 박스)
- geometry = new THREE.BoxGeometry(
- 400 * DISPLAY_SCALE,
- 400 * DISPLAY_SCALE,
- 8000 * DISPLAY_SCALE
- );
- } else if (type === 'Panel') {
- // 판재 - 규격에서 가로×세로×두께 추출
- let w = 700, h = 360, d = 14;
- if (spec && spec.includes('×')) {
- const match = spec.match(/PL\.-(\d+)×(\d+)×(\d+)/);
- if (match) {
- w = parseInt(match[1]);
- h = parseInt(match[2]);
- d = parseInt(match[3]);
- }
- }
- geometry = new THREE.BoxGeometry(
- w * DISPLAY_SCALE,
- h * DISPLAY_SCALE,
- d * DISPLAY_SCALE
- );
- } else if (type === 'H-Beam') {
- // H-빔 - H-400×400×13×21
- let w = 400, h = 400, d = 6000;
- if (spec && spec.includes('H-')) {
- const match = spec.match(/H-(\d+)×(\d+)/);
- if (match) {
- w = parseInt(match[1]);
- h = parseInt(match[2]);
- }
- }
- geometry = new THREE.BoxGeometry(
- w * DISPLAY_SCALE,
- h * DISPLAY_SCALE,
- d * DISPLAY_SCALE
- );
- } else if (type === 'Strut') {
- // 버팀목 - 200×200×4000
- geometry = new THREE.BoxGeometry(
- 200 * DISPLAY_SCALE,
- 200 * DISPLAY_SCALE,
- 4000 * DISPLAY_SCALE
- );
- } else {
- geometry = new THREE.BoxGeometry(
- 300 * DISPLAY_SCALE,
- 300 * DISPLAY_SCALE,
- 3000 * DISPLAY_SCALE
- );
- }
-
- const mesh = new THREE.Mesh(geometry, getMaterial(type));
- mesh.position.set(position.x, position.y, position.z);
- mesh.userData = { blockType, type, spec, volume };
-
- scene.add(mesh);
- addedCount++;
-
- if (addedCount <= 3 || addedCount % 100 === 0) {
- console.log(`[${addedCount}] ${blockType} @ (${position.x.toFixed(0)}, ${position.y.toFixed(0)}, ${position.z})`);
- }
- });
-
- console.log('✅ ' + addedCount + '개 부재 씬에 추가됨');
-
- // UI 업데이트
- document.getElementById('totalParts').textContent = data.totalParts + '개';
- document.getElementById('totalVolume').textContent = Math.round(data.totalVolume).toLocaleString() + ' m³';
- document.getElementById('loadingMsg').style.display = 'none';
-
- console.log('✅ 3D 모델 생성 완료');
- })
- .catch(err => {
- console.error('❌ 로드 오류:', err);
- document.getElementById('loadingMsg').innerHTML = '❌ 부재 데이터 로드 실패
' + err.message;
- });
+ console.log('✓ 샘플 부재 추가됨');
// 그리드 & 축
const gridHelper = new THREE.GridHelper(3000, 20, 0x444444, 0x222222);
@@ -498,18 +312,56 @@
const axisHelper = new THREE.AxesHelper(500);
scene.add(axisHelper);
- // OrbitControls로 카메라 제어
- const controls = new THREE.OrbitControls(camera, canvas);
- controls.target.set(-216, -2554, 0); // 부재 중심을 타겟으로
- controls.autoRotate = false;
- controls.autoRotateSpeed = 2;
- controls.enableDamping = true;
- controls.dampingFactor = 0.05;
- controls.enableZoom = true;
- controls.zoomSpeed = 1.0;
- controls.enablePan = true;
- controls.panSpeed = 0.5;
- controls.update();
+ // stats.json 로드
+ console.log('stats.json 로드 시작...');
+ fetch('gasiseol-correct-v2-stats.json')
+ .then(r => {
+ console.log('응답:', r.status);
+ return r.json();
+ })
+ .then(data => {
+ console.log('✓ JSON 파싱 완료');
+ console.log('총 부재:', data.totalParts);
+
+ let count = 0;
+ data.parts.forEach(part => {
+ let geometry;
+ const { blockType, type, spec, position, volume } = part;
+
+ if (type === 'Pile') {
+ geometry = new THREE.BoxGeometry(4, 4, 80);
+ } else if (type === 'Panel') {
+ geometry = new THREE.BoxGeometry(7, 3.6, 0.14);
+ } else if (type === 'H-Beam') {
+ geometry = new THREE.BoxGeometry(4, 4, 60);
+ } else if (type === 'Strut') {
+ geometry = new THREE.BoxGeometry(2, 2, 40);
+ } else {
+ geometry = new THREE.BoxGeometry(3, 3, 30);
+ }
+
+ const mesh = new THREE.Mesh(geometry, getMaterial(type));
+ mesh.position.set(position.x, position.y, position.z);
+ scene.add(mesh);
+ count++;
+
+ if (count <= 3 || count % 100 === 0) {
+ console.log(`[${count}] ${blockType} @ (${position.x.toFixed(0)}, ${position.y.toFixed(0)})`);
+ }
+ });
+
+ console.log('✓ ' + count + '개 부재 추가됨');
+
+ document.getElementById('totalParts').textContent = data.totalParts + '개';
+ document.getElementById('totalVolume').textContent = Math.round(data.totalVolume).toLocaleString() + ' m³';
+ document.getElementById('loadingMsg').style.display = 'none';
+
+ console.log('✅ 완료!');
+ })
+ .catch(err => {
+ console.error('❌ 오류:', err);
+ document.getElementById('loadingMsg').innerHTML = '❌ 로드 실패
' + err.message;
+ });
// 렌더링
function animate() {
@@ -519,7 +371,7 @@
}
animate();
- // 윈도우 리사이징
+ // 리사이징
window.addEventListener('resize', () => {
const newWidth = canvas.clientWidth;
const newHeight = canvas.clientHeight;