d8a80f6272
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해 끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은 과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업. 도구: Datacollect/scripts/link_reconcile_apply.mjs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.4 KiB
6.4 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-threejs | Three.js | 10_Wiki/Topics | verified | self |
|
none | A | 0.9 | applied |
|
2026-05-10 | pending |
|
Three.js
매 한 줄
"매 web 의 de-facto 3D library — WebGL/WebGPU 의 high-level wrapper". 매 scene graph + materials + lights + cameras + loaders. 2026 r170+ — WebGPURenderer stable, TSL (Three Shading Language), node-based materials. React 통합은
@react-three/fiber.
매 핵심
매 core entities
- Scene: 매 graph root.
- Camera: Perspective / Orthographic.
- Renderer: WebGLRenderer / WebGPURenderer.
- Mesh = Geometry + Material.
- Light: Ambient / Directional / Point / Spot.
매 render loop
requestAnimationFrame→ update → renderer.render(scene, camera).- 매 r3f 는 자동 loop.
매 응용
- Product configurator (3D customization).
- Data visualization (graph, scatter).
- WebXR (VR/AR).
- Game / interactive art.
💻 패턴
Vanilla minimal
import * as THREE from 'three';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75, window.innerWidth / window.innerHeight, 0.1, 1000,
);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
const geo = new THREE.BoxGeometry(1, 1, 1);
const mat = new THREE.MeshStandardMaterial({ color: 0x6699ff });
const cube = new THREE.Mesh(geo, mat);
scene.add(cube);
scene.add(new THREE.AmbientLight(0xffffff, 0.4));
const dir = new THREE.DirectionalLight(0xffffff, 1);
dir.position.set(5, 5, 5);
scene.add(dir);
renderer.setAnimationLoop(() => {
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
});
WebGPU renderer (r170+)
import * as THREE from 'three/webgpu';
import { color, normalLocal } from 'three/tsl';
const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init();
const mat = new THREE.MeshBasicNodeMaterial();
mat.colorNode = color('#6699ff').mul(normalLocal.length());
React Three Fiber
import { Canvas, useFrame } from '@react-three/fiber';
import { OrbitControls, Environment } from '@react-three/drei';
import { useRef } from 'react';
import type { Mesh } from 'three';
function Box() {
const ref = useRef<Mesh>(null);
useFrame((_, dt) => {
if (ref.current) ref.current.rotation.y += dt;
});
return (
<mesh ref={ref}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="#6699ff" />
</mesh>
);
}
export default function App() {
return (
<Canvas camera={{ position: [3, 3, 3] }}>
<Environment preset="city" />
<Box />
<OrbitControls />
</Canvas>
);
}
GLTF model loading
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
const draco = new DRACOLoader();
draco.setDecoderPath('https://www.gstatic.com/draco/v1/decoders/');
const loader = new GLTFLoader();
loader.setDRACOLoader(draco);
const gltf = await loader.loadAsync('/model.glb');
scene.add(gltf.scene);
// r3f
import { useGLTF } from '@react-three/drei';
function Model() {
const { scene } = useGLTF('/model.glb');
return <primitive object={scene} />;
}
Postprocessing
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
composer.addPass(new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
0.8, 0.4, 0.85,
));
renderer.setAnimationLoop(() => composer.render());
Instanced rendering (10k+ objects)
const count = 10_000;
const mesh = new THREE.InstancedMesh(geo, mat, count);
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
dummy.position.set(
(Math.random() - 0.5) * 100,
(Math.random() - 0.5) * 100,
(Math.random() - 0.5) * 100,
);
dummy.updateMatrix();
mesh.setMatrixAt(i, dummy.matrix);
}
scene.add(mesh);
Disposal (memory)
function dispose(obj: THREE.Object3D) {
obj.traverse((child) => {
if ((child as THREE.Mesh).isMesh) {
const m = child as THREE.Mesh;
m.geometry.dispose();
const mats = Array.isArray(m.material) ? m.material : [m.material];
mats.forEach((mat) => mat.dispose());
}
});
}
WebXR (VR)
renderer.xr.enabled = true;
import { VRButton } from 'three/addons/webxr/VRButton.js';
document.body.appendChild(VRButton.createButton(renderer));
매 결정 기준
| 상황 | Approach |
|---|---|
| 매 React app | @react-three/fiber + drei |
| 매 vanilla / lib | three.js direct |
| 매 GPU compute / advanced shader | WebGPURenderer + TSL |
| 매 game | Babylon.js / PlayCanvas (more game-oriented) |
| 매 declarative UI integration | r3f (preferred) |
기본값: 매 React → r3f + drei. 매 그 외 → three.js + addons.
🔗 Graph
🤖 LLM 활용
언제: 매 scene scaffold, 매 shader translate, 매 r3f component generation. 언제 X: 매 production shader optimization — 매 hand-tune 필요.
❌ 안티패턴
- Forgetting dispose: 매 GPU memory leak.
new THREE.Xin render loop: 매 GC pressure.- No
setPixelRatio: 매 retina blurry. - Many individual meshes: 매 instancing 의 사용.
- Direct DOM rerender on every frame: 매 r3f 의 자동 loop 무시.
🧪 검증 / 중복
- Verified (three.js r170 docs, react-three/fiber docs, mrdoob, 2026).
- 신뢰도 A.
🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Three.js r170 with WebGPU, TSL, r3f, instancing |