آموزش جامع Three.js
کتابخانه WebGL برای ساخت گرافیک سهبعدی تعاملی در مرورگر — بدون نیاز به دانش OpenGL.
📚معرفی و ساختار پایه
Three.js یک لایه انتزاعی روی WebGL است که ساخت صحنههای سهبعدی را در مرورگر آسان میکند. هر صحنه Three.js از سه عنصر اصلی تشکیل میشود:
- Scene — ظرف اصلی که همه اشیاء در آن قرار میگیرند
- Camera — دوربین که صحنه را از زاویهای خاص نگاه میکند
- Renderer — موتور رندر که صحنه را روی canvas نقاشی میکند
// ۱. ساختار پایه const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, innerWidth/innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(innerWidth, innerHeight); document.body.appendChild(renderer.domElement); // canvas // ۲. ساخت Mesh const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshStandardMaterial({ color: 0x88ce02 }); const cube = new THREE.Mesh(geometry, material); scene.add(cube); camera.position.set(0, 0, 3); // ۳. حلقه انیمیشن function animate() { requestAnimationFrame(animate); cube.rotation.x += 0.01; cube.rotation.y += 0.01; renderer.render(scene, camera); } animate();
🔷Geometry و Mesh
Geometry شکل هندسی است و Mesh ترکیب Geometry + Material. Three.js شکلهای آماده زیادی دارد.
new THREE.BoxGeometry(w, h, d) // جعبه new THREE.SphereGeometry(r, wSeg, hSeg) // کره new THREE.CylinderGeometry(rTop, rBot, h) // استوانه new THREE.TorusGeometry(r, tube, rSeg, tSeg) // حلقه new THREE.ConeGeometry(r, h, seg) // مخروط new THREE.PlaneGeometry(w, h) // صفحه new THREE.TorusKnotGeometry(r, tube) // گره توروس // موقعیت، چرخش، مقیاس mesh.position.set(x, y, z); mesh.rotation.set(rx, ry, rz); // رادیان mesh.scale.set(sx, sy, sz);
🎨Material
Material ظاهر سطح Mesh را تعریف میکند. انتخاب درست Material تأثیر زیادی بر عملکرد و ظاهر دارد.
// MeshBasicMaterial — بدون نور، سریعترین new THREE.MeshBasicMaterial({ color: 0xff0000 }); // MeshStandardMaterial — PBR، واقعیترین new THREE.MeshStandardMaterial({ color: 0x88ce02, roughness: 0.4, // 0=براق، 1=کدر metalness: 0.6 // 0=پلاستیک، 1=فلز }); // MeshPhongMaterial — براق کلاسیک new THREE.MeshPhongMaterial({ color: 0x3498db, shininess: 100 }); // MeshNormalMaterial — رنگ بر اساس جهت new THREE.MeshNormalMaterial(); // wireframe new THREE.MeshBasicMaterial({ color: 0x88ce02, wireframe: true });
| Material | نور لازم | کاربرد |
|---|---|---|
| MeshBasicMaterial | خیر | UI، debug، کارتهای رنگی |
| MeshLambertMaterial | بله | سطوح کدر، بهینه |
| MeshPhongMaterial | بله | پلاستیک، شیشه براق |
| MeshStandardMaterial | بله | PBR واقعی — پیشنهادی |
| MeshNormalMaterial | خیر | debug نرمالها |
| MeshDepthMaterial | خیر | سایه، depth effects |
💡نور (Lighting)
بدون نور، Materialهایی که به نور نیاز دارند (Standard، Lambert، Phong) کاملاً سیاه هستند.
// AmbientLight — نور محیطی یکنواخت scene.add(new THREE.AmbientLight(0xffffff, 0.4)); // DirectionalLight — نور جهتدار (مثل خورشید) const dirLight = new THREE.DirectionalLight(0xffffff, 1); dirLight.position.set(5, 10, 7); scene.add(dirLight); // PointLight — نور نقطهای (مثل لامپ) const ptLight = new THREE.PointLight(0xff8800, 2, 10); ptLight.position.set(0, 3, 0); scene.add(ptLight); // SpotLight — نور مخروطی (مثل نورافکن) const spot = new THREE.SpotLight(0xffffff, 1); spot.angle = Math.PI / 6; spot.penumbra = 0.2; scene.add(spot);
| نور | ویژگی |
|---|---|
| AmbientLight | نور یکنواخت بدون جهت — برای روشنایی کلی |
| DirectionalLight | نور موازی از یک جهت — مانند خورشید |
| PointLight(color, intensity, distance) | نور نقطهای در همه جهات |
| SpotLight | نور مخروطی با angle و penumbra |
| HemisphereLight(sky, ground) | نور آسمان + زمین — طبیعیترین ambient |
🎬انیمیشن و حرکت
حلقه انیمیشن با requestAnimationFrame پیادهسازی میشود. برای زمانبندی دقیق از Clock استفاده کنید.
const clock = new THREE.Clock(); function animate() { requestAnimationFrame(animate); const t = clock.getElapsedTime(); // ثانیه از شروع // چرخش cube.rotation.y = t * 0.5; // حرکت موجی cube.position.y = Math.sin(t) * 0.5; // مقیاس نبضی const s = 1 + Math.sin(t * 2) * 0.1; cube.scale.set(s, s, s); renderer.render(scene, camera); } animate();
🎥Camera و کنترل
Three.js دو نوع اصلی دوربین دارد. برای کنترل تعاملی OrbitControls پیشنهاد میشود.
// PerspectiveCamera — منظر واقعی (پیشنهادی) const cam = new THREE.PerspectiveCamera( 75, // fov درجه w / h, // aspect ratio 0.1, 1000 // near, far ); cam.position.set(0, 2, 5); cam.lookAt(0, 0, 0); // OrthographicCamera — بدون تغییر اندازه با فاصله new THREE.OrthographicCamera(left, right, top, bottom, near, far); // تغییر اندازه پنجره window.addEventListener('resize', () => { cam.aspect = innerWidth / innerHeight; cam.updateProjectionMatrix(); renderer.setSize(innerWidth, innerHeight); });
📷Texture
Texture تصاویر را روی سطح Mesh نقشه میکشد. TextureLoader برای بارگذاری و اعمال استفاده میشود.
const loader = new THREE.TextureLoader(); // بارگذاری texture const texture = loader.load('brick.jpg', () => { renderer.render(scene, camera); // رندر بعد از لود }); // اعمال روی material const mat = new THREE.MeshStandardMaterial({ map: texture, // رنگ اصلی normalMap: normTex, // جزئیات سطح roughnessMap: roughTex // نقشه زبری }); // تکرار texture texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.repeat.set(4, 4); // ۴×۴ تکرار // Cube map (محیط ۳۶۰) const cubeMap = new THREE.CubeTextureLoader() .load([px, nx, py, ny, pz, nz]); scene.background = cubeMap;
texture.minFilter = THREE.LinearFilter برای جلوگیری از mipmapهای اضافی استفاده کنید.
🌓Shadow
سایهها در Three.js باید صریحاً فعال شوند — هم روی renderer، هم روی نور، هم روی Mesh.
// ۱. فعالسازی روی Renderer renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; // نرمتر // ۲. نور باید سایه بسازد dirLight.castShadow = true; dirLight.shadow.mapSize.set(2048, 2048); // کیفیت dirLight.shadow.camera.far = 50; // ۳. اشیاء — سایه انداز و سایهپذیر cube.castShadow = true; // این شیء سایه میاندازد floor.receiveShadow = true; // این شیء سایه میپذیرد // کلی — همه بسازند/بپذیرند scene.traverse(obj => { if (obj.isMesh) { obj.castShadow = true; obj.receiveShadow = true; } });
🔍Raycasting — تعامل با اشیاء
Raycaster یک پرتو از دوربین به صحنه میفرستد و اشیاء برخوردی را تشخیص میدهد — پایه تعامل موس و کلیک در Three.js.
const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); window.addEventListener('mousemove', e => { // تبدیل موقعیت موس به فضای normalized (-1 تا 1) mouse.x = (e.clientX / innerWidth) * 2 - 1; mouse.y = -(e.clientY / innerHeight) * 2 + 1; }); function animate() { requestAnimationFrame(animate); raycaster.setFromCamera(mouse, camera); const hits = raycaster.intersectObjects(scene.children); if (hits.length > 0) { hits[0].object.material.color.set(0xff0000); // hover } renderer.render(scene, camera); }
🔥ذرات (Particles) و چیتشیت
سیستم ذرات با Points و BufferGeometry پیادهسازی میشود — بهینهترین راه برای هزاران نقطه.
const count = 5000; const positions = new Float32Array(count * 3); for (let i = 0; i < count * 3; i++) positions[i] = (Math.random() - 0.5) * 10; const geo = new THREE.BufferGeometry(); geo.setAttribute('position', new THREE.BufferAttribute(positions, 3)); const mat = new THREE.PointsMaterial({ size: 0.05, color: 0x88ce02, transparent: true, opacity: 0.8 }); scene.add(new THREE.Points(geo, mat));
📄 چیتشیت سریع
| عملیات | کد |
|---|---|
| صحنه پایه | new Scene() + Camera + WebGLRenderer |
| Mesh | new Mesh(geometry, material) |
| موقعیت | mesh.position.set(x,y,z) |
| چرخش | mesh.rotation.y += 0.01 |
| زمان | clock.getElapsedTime() |
| نور محیطی | new AmbientLight(0xffffff, 0.4) |
| نور جهتدار | new DirectionalLight(0xffffff, 1) |
| texture | new TextureLoader().load('img.jpg') |
| سایه | renderer.shadowMap.enabled = true |
| کلیک/hover | new Raycaster().intersectObjects(...) |
| ذرات | new Points(bufferGeo, PointsMaterial) |
| حذف از صحنه | scene.remove(mesh); mesh.geometry.dispose() |
- از
BufferGeometryبه جای Geometry استفاده کنید - اشیاء ثابت را
mesh.matrixAutoUpdate = falseکنید - Geometryها و Materialهای استفادهنشده را
.dispose()کنید - از
renderer.setPixelRatio(Math.min(devicePixelRatio, 2))استفاده کنید
🚀زمین بازی کد (Playground)
صحنهٔ سهبعدی Three.js را همینجا بساز و زنده ببین. هندسه، متریال و انیمیشن را تغییر بده و ▶ اجرا را بزن. نسخهٔ r134 آفلاین بارگذاری میشود.