aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Frontend & UI

Three.js Animasyon: Canlı 3B Sahne Yapımı

Tarayıcıda gerçek zamanlı 3B grafik denince akla gelen ilk kütüphane Three.js'tir; bu yazıda Three.js animasyon mantığını sıfırdan kurarak dönen, ışık alan ve kullanıcı etkileşimine cevap veren canlı bir sahne yapacağız. Amaç sadece bir küp döndürmek değil, render döngüsünün nasıl çalıştığını, kareler arası zamanın neden önemli olduğunu ve sahneyi performanslı tutmanın yollarını anlamak. Sonunda elinizde tek bir HTML dosyasında çalışan, çerçeve düşürmeyen bir başlangıç şablonu olacak.

Three.js sahnesinin üç temel taşı

Her Three.js projesi üç nesne etrafında döner: Scene (sahne), Camera (kamera) ve Renderer (çizici). Sahne, görünür her şeyi tutan kapsayıcıdır. Kamera, bu sahneye hangi açıdan baktığımızı belirler. Renderer ise WebGL kullanarak sonucu bir <canvas> üzerine çizer.

  • Scene: nesneleri, ışıkları ve kameraları içeren grafik ağacının köküdür.
  • PerspectiveCamera: insan gözüne benzer şekilde uzaktaki nesneleri küçük gösteren, derinlik hissi veren kameradır.
  • WebGLRenderer: GPU üzerinde çalışır ve her karede sahneyi yeniden çizer.

Kütüphaneyi modül olarak içe aktarmak en temiz yöntemdir. Modern tarayıcılar import map ile CDN'den doğrudan ES modülü çekebilir.

<script type="importmap">
{
  "imports": {
    "three": "https://unpkg.com/three@0.160.0/build/three.module.js"
  }
}
</script>

<script type="module">
import * as THREE from 'three';
</script>

İlk sahneyi kurmak

Şimdi sahneyi, kamerayı ve renderer'ı oluşturalım. Kamera parametreleri sırayla şunlardır: görüş açısı (fov, derece), en-boy oranı, yakın kırpma ve uzak kırpma düzlemleri. Renderer'ı sayfaya eklemek için domElement özelliğini DOM'a koyarız.

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0b1020);

const camera = new THREE.PerspectiveCamera(
  60, window.innerWidth / window.innerHeight, 0.1, 100
);
camera.position.z = 4;

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);

setPixelRatio değerini 2 ile sınırlamak önemlidir: yüksek yoğunluklu ekranlarda piksel oranını kısıtlamak, çözünürlüğü makul tutarak GPU'yu rahatlatır ve mobilde ısınmayı azaltır.

Nesne, malzeme ve ışık

Three.js'te görünür bir nesne (mesh), bir geometri (şekil) ile bir malzemenin (yüzey görünümü) birleşiminden oluşur. MeshStandardMaterial fiziksel tabanlı bir malzemedir ve gerçekçi görünmek için ışığa ihtiyaç duyar; bu yüzden sahneye en az bir ışık eklemeden ekran kapkaranlık kalır.

const geometry = new THREE.IcosahedronGeometry(1, 0);
const material = new THREE.MeshStandardMaterial({
  color: 0x4f9dde,
  roughness: 0.3,
  metalness: 0.6,
  flatShading: true,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

const keyLight = new THREE.DirectionalLight(0xffffff, 2);
keyLight.position.set(3, 4, 5);
scene.add(keyLight);
scene.add(new THREE.AmbientLight(0x404060, 1.5));

Burada bir yönlü ışık (güneş gibi yönlü, keskin gölgeli) ve bir ortam ışığı (her yöne eşit, gölgeleri yumuşatan dolgu) birlikte kullanıyoruz. Bu ikili, basit ama dengeli bir aydınlatma verir.

Render döngüsü ve zaman tabanlı animasyon

Animasyonun kalbi render döngüsüdür. requestAnimationFrame tarayıcıya "bir sonraki çizime hazır olduğunda beni çağır" der; bu genellikle saniyede 60 kez, ekranın yenileme hızıyla senkron olur. Naif yaklaşımda her karede sabit bir değer eklenir, ama bu yanlıştır: 60 Hz ekranda yavaş, 144 Hz ekranda hızlı döner. Doğrusu, geçen süreyle (delta) çarpmaktır.

const clock = new THREE.Clock();

function animate() {
  requestAnimationFrame(animate);

  const delta = clock.getDelta(); // saniye cinsinden geçen süre
  mesh.rotation.y += delta * 0.8;  // saniyede 0.8 radyan
  mesh.rotation.x += delta * 0.3;

  renderer.render(scene, camera);
}
animate();

THREE.Clock kareler arasında geçen gerçek süreyi verir. Dönüş hızını bu değerle çarpınca animasyon, ekranın yenileme hızından bağımsız olarak her cihazda aynı hızda akar. Bu, profesyonel ile amatör arasındaki en görünür farklardan biridir.

Pencere boyutuna uyum ve etkileşim

Kullanıcı pencereyi yeniden boyutlandırınca görüntü bozulmasın diye kamerayı ve renderer'ı güncellemeliyiz. Kameranın en-boy oranı değiştiğinde updateProjectionMatrix çağrısı şarttır.

window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

Etkileşim için en hızlı yol resmi OrbitControls eklentisidir; fareyle sahneyi döndürmeyi, yakınlaştırmayı sağlar. Onu da import map'e ekleyip controls.update()'i döngüye koymanız yeterli. Daha hafif bir his isterseniz fare konumunu kameranın hafif bir kaydırmasına bağlayabilirsiniz (parallax etkisi).

Performans ve temizlik ipuçları

  • Sekme arka plandayken durdurun: sayfa görünmezken requestAnimationFrame zaten yavaşlar, ama ağır sahnelerde document.hidden kontrolüyle döngüyü tamamen durdurmak pili korur.
  • Geometri ve malzemeyi tekrar kullanın: aynı şekilden yüzlerce kopya gerekiyorsa InstancedMesh tek çizim çağrısıyla hepsini çizer.
  • Bellek sızıntısına dikkat: bir nesneyi kalıcı olarak kaldırırken geometry.dispose() ve material.dispose() çağırın; GPU belleği otomatik boşalmaz.
  • Gölgeleri ölçülü kullanın: gerçek zamanlı gölge haritaları pahalıdır; ihtiyaç yoksa kapalı tutun.

Sık Sorulan Sorular

Three.js öğrenmek için WebGL bilmem gerekir mi?

Hayır. Three.js, WebGL'in karmaşık shader ve buffer detaylarını soyutlar; başlangıç için JavaScript ve temel 3B kavramları (koordinat, vektör, kamera) yeterlidir. İleride özel shader yazmak istediğinizde WebGL bilgisi avantaj sağlar ama zorunlu değildir.

Animasyonum bazı bilgisayarlarda neden çok hızlı dönüyor?

Büyük olasılıkla dönüşü sabit bir sayı ile artırıyorsunuz. Yüksek yenileme hızlı (120/144 Hz) ekranlarda döngü daha sık çalışır ve hareket hızlanır. Çözüm, hareketi clock.getDelta() ile çarpmak, yani zaman tabanlı animasyon kullanmaktır.

Three.js mobil cihazlarda iyi çalışır mı?

Evet, ama dikkatli olmak gerekir. setPixelRatio'yu sınırlayın, çokgen sayısını düşük tutun, ağır post-processing efektlerinden kaçının ve gölgeleri kısıtlayın. Bu önlemlerle orta seviye telefonlarda bile akıcı 3B sahneler çalıştırabilirsiniz.

Tarayıcıda canlı bir 3B deneyim mi hayal ediyorsunuz? Ürün konfigüratöründen interaktif arka plana kadar Three.js tabanlı sahneler tasarlayıp performanslı şekilde hayata geçiriyorum. Projenizi konuşmak için benimle iletişime geçin.

Bu kategorideki tüm yazılar →

Devamı için