📌 Ne Zaman Kullanılır?
- ✅ 3D web, ürün görselleştirme, interaktif deneyim, oyun, WebGL
- ⚠️ Performans yönetimi zor, öğrenme eğrisi yüksek
- ❌ 2D animasyon (CSS/Framer yeterli), basit grafik
Önerilen Kullanım: Three.js veya React Three Fiber + Blender modeller Alternatifler: Babylon.js, PlayCanvas, A-Frame (VR)
Three.js & React Three Fiber — 3D Web Rehberi
Three.js, tarayicida 3D sahne oluşturmak için en yaygin JavaScript kutuphanesidir. React Three Fiber (R3F) ise Three.js'i React icinde deklaratif olarak kullanmayi sağlar.
Temel Kavramlar
Sahne Yapisi
Bir Three.js sahnesi 3 temel bilesenden olusur:
javascript
import * as THREE from 'three';
// 1. Sahne (Scene) — tum nesneleri icerir
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);
// 2. Kamera (Camera) — bakis acisi
const camera = new THREE.PerspectiveCamera(
75, // FOV (goris acisi)
window.innerWidth / window.innerHeight, // Aspect ratio
0.1, // Near clipping plane
1000 // Far clipping plane
);
camera.position.set(0, 2, 5);
// 3. Renderer — sahneyi cizer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);Mesh = Geometry + Material
javascript
// Geometry (sekil)
const geometry = new THREE.BoxGeometry(1, 1, 1);
// Material (gorunum)
const material = new THREE.MeshStandardMaterial({
color: 0x3b82f6,
roughness: 0.4,
metalness: 0.6
});
// Mesh (geometry + material)
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);Animasyon Dongusu
javascript
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();Responsive (Pencere Boyutu Degisimi)
javascript
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});Geometri ve Mesh
Temel Geometriler
| Geometri | Açıklama | Parametreler |
|---|---|---|
| BoxGeometry | Kup/kutu | width, height, depth |
| SphereGeometry | Kure | radius, widthSegments, heightSegments |
| CylinderGeometry | Silindir | radiusTop, radiusBottom, height |
| PlaneGeometry | Duz yuzey | width, height |
| TorusGeometry | Halka | radius, tube, radialSegments |
| ConeGeometry | Koni | radius, height |
| RingGeometry | Halka yuzey | innerRadius, outerRadius |
BufferGeometry (Custom Geometri)
javascript
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
-1, -1, 0,
1, -1, 0,
0, 1, 0,
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));InstancedMesh (Performansli Cok Obje)
Ayni geometri ve materyali binlerce kez verimli render etme:
javascript
const count = 1000;
const mesh = new THREE.InstancedMesh(geometry, material, count);
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
dummy.position.set(
Math.random() * 20 - 10,
Math.random() * 20 - 10,
Math.random() * 20 - 10
);
dummy.updateMatrix();
mesh.setMatrixAt(i, dummy.matrix);
}
scene.add(mesh);Materials ve Shading
Material Turleri
| Material | Kullanım | Isik Gerekli |
|---|---|---|
| MeshBasicMaterial | Duz renk, isik yok | Hayir |
| MeshStandardMaterial | PBR, gercekci | Evet |
| MeshPhysicalMaterial | Cam, clearcoat, iridescence | Evet |
| MeshLambertMaterial | Hafif golgeleme, hızlı | Evet |
| MeshPhongMaterial | Parlak yuzeyler | Evet |
| ShaderMaterial | Custom GLSL shader | Ozel |
MeshStandardMaterial Parametreleri
javascript
const material = new THREE.MeshStandardMaterial({
color: 0x3b82f6, // Renk
roughness: 0.5, // 0 = ayna, 1 = mat
metalness: 0.5, // 0 = plastik, 1 = metal
map: diffuseTexture, // Diffuse texture
normalMap: normalTexture, // Normal map (yuzey detayi)
roughnessMap: roughTex, // Roughness map
envMap: envTexture, // Environment map (yansima)
transparent: true, // Saydamlik aktif
opacity: 0.8, // Saydamlik degeri
});Environment Map (HDRI)
javascript
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
new RGBELoader().load('/env.hdr', (texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture; // Tum materyallere yansima
scene.background = texture; // Arka plan
});Isiklandirma (Lighting)
Isik Turleri
| Isik | Açıklama | Kullanım |
|---|---|---|
| AmbientLight | Her yone esit isik (golge yok) | Genel aydinlatma |
| DirectionalLight | Paralel isik (gunes) | Dis mekan |
| PointLight | Noktasal (ampul) | Ic mekan |
| SpotLight | Konik (spot) | Sahne isigi |
| HemisphereLight | Gokyuzu + zemin renk gecisi | Dogal ortam |
| RectAreaLight | Dikdortgen yuzey isik | Studyo |
Three-Point Lighting
javascript
// Key light (ana isik)
const keyLight = new THREE.DirectionalLight(0xffffff, 1.5);
keyLight.position.set(5, 5, 5);
keyLight.castShadow = true;
scene.add(keyLight);
// Fill light (dolgu)
const fillLight = new THREE.DirectionalLight(0x8888ff, 0.5);
fillLight.position.set(-5, 3, 5);
scene.add(fillLight);
// Rim light (arka kenar)
const rimLight = new THREE.DirectionalLight(0xffffff, 0.8);
rimLight.position.set(0, 5, -5);
scene.add(rimLight);Golge (Shadow)
javascript
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Isik golge atar
keyLight.castShadow = true;
keyLight.shadow.mapSize.set(2048, 2048);
// Nesne golge atar
cube.castShadow = true;
// Zemin golge alir
floor.receiveShadow = true;Interaction (Etkilesim)
OrbitControls
javascript
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // Yumusak hareket
controls.dampingFactor = 0.05;
controls.maxPolarAngle = Math.PI / 2; // Asagi bakmayi sinirla
controls.minDistance = 2;
controls.maxDistance = 20;
// Animasyon dongusunde guncelle
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}Raycasting (Tikla ve Sec)
javascript
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
window.addEventListener('click', (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children);
if (intersects.length > 0) {
const selected = intersects[0].object;
selected.material.color.set(0xff0000); // Secilen nesneyi kirmizi yap
console.log('Secilen:', selected.name);
}
});Hover Efekti
javascript
window.addEventListener('mousemove', (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(meshes);
// Tum nesneleri sifirla
meshes.forEach(m => m.material.emissive.setHex(0x000000));
// Hover olan nesneyi parlat
if (intersects.length > 0) {
intersects[0].object.material.emissive.setHex(0x333333);
document.body.style.cursor = 'pointer';
} else {
document.body.style.cursor = 'default';
}
});Physics (Fizik) Entegrasyonu
Rapier (WASM, hızlı)
bash
npm install @dimforge/rapier3d-compatjavascript
import RAPIER from '@dimforge/rapier3d-compat';
await RAPIER.init();
const world = new RAPIER.World({ x: 0, y: -9.81, z: 0 }); // Yerekimi
// Zemin (static body)
const groundDesc = RAPIER.RigidBodyDesc.fixed();
const groundBody = world.createRigidBody(groundDesc);
const groundCollider = RAPIER.ColliderDesc.cuboid(10, 0.1, 10);
world.createCollider(groundCollider, groundBody);
// Kup (dynamic body)
const cubeDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(0, 5, 0);
const cubeBody = world.createRigidBody(cubeDesc);
const cubeCollider = RAPIER.ColliderDesc.cuboid(0.5, 0.5, 0.5);
world.createCollider(cubeCollider, cubeBody);
// Animasyon dongusunde fizik guncelle
function animate() {
requestAnimationFrame(animate);
world.step();
const pos = cubeBody.translation();
const rot = cubeBody.rotation();
cube.position.set(pos.x, pos.y, pos.z);
cube.quaternion.set(rot.x, rot.y, rot.z, rot.w);
renderer.render(scene, camera);
}Post-Processing
EffectComposer
javascript
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass';
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass';
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
// Bloom efekti (parlama)
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
0.5, // strength
0.4, // radius
0.85 // threshold
);
composer.addPass(bloomPass);
// Render dongusunde composer kullan
function animate() {
requestAnimationFrame(animate);
composer.render(); // renderer.render() yerine
}Diger Post-Processing Efektleri
| Efekt | Açıklama |
|---|---|
| Bloom | Parlak alanlarda isik tasmasi |
| SSAO | Ambient occlusion (koseler koyu) |
| DOF | Derinlik alani bulanikligi |
| Outline | Secilen nesne etrafinda kontur |
| FXAA/SMAA | Anti-aliasing |
| Film/Glitch | Stilize efektler |
Model Yukleme (GLTF/GLB)
GLTFLoader
javascript
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
// Draco decoder (sikistirilmis modeller icin)
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('/draco/');
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
gltfLoader.load(
'/models/product.glb',
(gltf) => {
const model = gltf.scene;
model.scale.set(1, 1, 1);
model.position.set(0, 0, 0);
scene.add(model);
// Animasyon varsa
if (gltf.animations.length > 0) {
const mixer = new THREE.AnimationMixer(model);
gltf.animations.forEach((clip) => mixer.clipAction(clip).play());
}
},
(progress) => {
console.log(`Yukleniyor: ${(progress.loaded / progress.total * 100).toFixed(0)}%`);
},
(error) => {
console.error('Model yuklenemedi:', error);
}
);Model Optimizasyon
| Yöntem | Açıklama | Arac |
|---|---|---|
| Draco compression | Mesh sikistirma (%80-90 kucultme) | gltf export ayari |
| Texture boyut | 512x512 veya 1024x1024 web için | Photoshop, Sharp |
| Polygon azaltma | Decimate modifier | Blender |
| gltf-transform | CLI ile optimize | npx @gltf-transform/cli |
| gltfpack | Mesh quantization | meshoptimizer |
React Three Fiber (R3F)
Temel Kullanım
bash
npm install @react-three/fiber @react-three/dreijsx
import { Canvas } from '@react-three/fiber';
import { OrbitControls, Environment } from '@react-three/drei';
function Box({ position, color }) {
const [hovered, setHovered] = useState(false);
const meshRef = useRef();
useFrame((state, delta) => {
meshRef.current.rotation.y += delta * 0.5;
});
return (
<mesh
ref={meshRef}
position={position}
onPointerOver={() => setHovered(true)}
onPointerOut={() => setHovered(false)}
>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'hotpink' : color} />
</mesh>
);
}
export default function Scene() {
return (
<Canvas camera={{ position: [0, 2, 5], fov: 75 }}>
<ambientLight intensity={0.5} />
<directionalLight position={[5, 5, 5]} />
<Box position={[-1.5, 0, 0]} color="blue" />
<Box position={[1.5, 0, 0]} color="green" />
<OrbitControls enableDamping />
<Environment preset="sunset" />
</Canvas>
);
}@react-three/drei Yardimci Bilesenler
| Bileşen | Açıklama |
|---|---|
| OrbitControls | Kamera kontrolu |
| Environment | HDRI ortam isigi |
| useGLTF | GLTF model yükleme hook |
| Text / Text3D | 3D yazi |
| Html | 3D sahne icinde HTML |
| Float | Yuzme animasyonu |
| ContactShadows | Zemin golge |
| PresentationControls | Sürüm modeli gosterim |
| Sparkles | Parlti efekti |
| Sky | Gokyuzu |
useGLTF ile Model Yukleme
jsx
import { useGLTF } from '@react-three/drei';
function Product() {
const { scene } = useGLTF('/models/product.glb');
return <primitive object={scene} scale={1} />;
}
// Preload (onceden yukle)
useGLTF.preload('/models/product.glb');R3F + Post-Processing
bash
npm install @react-three/postprocessingjsx
import { EffectComposer, Bloom, Vignette } from '@react-three/postprocessing';
function Scene() {
return (
<Canvas>
{/* ... sahne icerigi ... */}
<EffectComposer>
<Bloom intensity={0.5} luminanceThreshold={0.9} />
<Vignette offset={0.3} darkness={0.7} />
</EffectComposer>
</Canvas>
);
}R3F + Physics (@react-three/rapier)
bash
npm install @react-three/rapierjsx
import { Physics, RigidBody } from '@react-three/rapier';
function Scene() {
return (
<Canvas>
<Physics gravity={[0, -9.81, 0]}>
{/* Dusen kup */}
<RigidBody>
<mesh position={[0, 5, 0]}>
<boxGeometry />
<meshStandardMaterial color="blue" />
</mesh>
</RigidBody>
{/* Zemin (sabit) */}
<RigidBody type="fixed">
<mesh position={[0, -1, 0]}>
<boxGeometry args={[20, 0.2, 20]} />
<meshStandardMaterial color="gray" />
</mesh>
</RigidBody>
</Physics>
</Canvas>
);
}Vanilla Three.js vs R3F
| Özellik | Three.js (vanilla) | React Three Fiber |
|---|---|---|
| Yaklasim | Imperative | Declarative (JSX) |
| React entegrasyonu | Manuel | Dogal |
| State yönetimi | Manuel | React hooks |
| Ekosistem | three/examples | @react-three/drei |
| Performans | Biraz daha hızlı | Cok yakin |
| Öğrenme | Three.js bilgisi gerekli | React + Three.js |
| Ideal | Non-React proje | React proje |
Web Export ve Optimizasyon
Performans Hedefleri
| Metrik | Hedef | Açıklama |
|---|---|---|
| Dosya boyutu | < 5 MB | Model + texture toplam |
| Triangle sayisi | 10K - 100K | Sahne toplami |
| Texture boyutu | 512x512 - 1024x1024 | Web için yeterli |
| FPS | 60 FPS | Mobilde 30 FPS kabul edilebilir |
| Ilk yükleme | < 3 saniye | Lazy load kullan |
Optimizasyon Teknikleri
- InstancedMesh: Ayni objeyi binlerce kez verimli render
- LOD (Level of Detail): Uzaktaki nesneler için düşük polygon
- Frustum Culling: Kamera gorusunun disindaki nesneleri render etme (Three.js varsayılan)
- Texture Compression: KTX2 format (GPU compressed)
- Draco: Mesh boyutunu %80-90 azaltir
- Lazy loading: Modelleri gorunur oldugunda yükle
- dispose(): Kullanilmayan geometry, material, texture'lari temizle
dispose() ile Bellek Temizleme
javascript
// Sahne temizleme — mutlaka yapin, yoksa bellek sizintisi olur
function cleanup(scene) {
scene.traverse((child) => {
if (child.isMesh) {
child.geometry.dispose();
if (child.material.isMaterial) {
cleanMaterial(child.material);
}
}
});
}
function cleanMaterial(material) {
material.dispose();
// Texture'lari temizle
for (const key of Object.keys(material)) {
const value = material[key];
if (value && typeof value === 'object' && 'dispose' in value) {
value.dispose();
}
}
}model-viewer (Google — Kolay 3D Gosterim)
HTML tag ile 3D model gosterimi — JavaScript bilgisi gerektirmez:
html
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"></script>
<model-viewer
src="/models/product.glb"
alt="Urun 3D Model"
auto-rotate
camera-controls
shadow-intensity="1"
style="width: 100%; height: 400px;"
></model-viewer>Güvenlik
- Kullanici yuklenen 3D model riskleri: Kullanici yukledigi .glb/.gltf dosyaları zararli script icerebilir — sandbox'ta yukleyin, dosya boyutunu sinirlayin
- WebGL context loss: GPU kaynak yetersizliginde context kaybolabilir —
renderer.domElement.addEventListener('webglcontextlost', handler)ile yakalayip kullaniciya bildirin - Bellek sizintisi: dispose() cagirmazsaniz bellek surekli artar — sayfa degisimlerinde (React useEffect cleanup) mutlaka temizleyin
- Cross-origin: Texture ve modelleri farkli domain'den yuklerken CORS ayarlarina dikkat edin
İpuçları (Tips)
- dispose() her seyi temizle: Geometry, material, texture — ozellikle SPA'larda sayfa degisiminde
- Texture compression: KTX2 format GPU'da acilir, daha az bellek tuketir
- LOD kullan:
THREE.LODile uzaktaki nesneler için düşük poly versiyon - InstancedMesh: 100+ ayni obje varsa kesinlikle kullanin (1000x performans farki)
- Offscreen Canvas: Worker thread'de render — ana thread'i bloklamaz
- requestAnimationFrame: setInterval/setTimeout yerine her zaman bunu kullanin
- Stats.js: FPS, MS, MB monitor — geliştirme sırasında performans takibi
- Pixel ratio sinirla:
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))— 4K ekranlarda gereksiz render onleme - Blender export:
Ctrl+A > All Transformsuygula, sonra glTF/GLB export - React projede: R3F + drei kullanin — vanilla Three.js yerine cok daha temiz kod
Ilgili Rehberler
Frontend
- Frontend Genel Bakış
- JavaScript & TypeScript
- TypeScript Rehberi
- React Rehberi
- Next.js Rehberi
- Vue.js Rehberi
- CSS & Tailwind
- Web Performance