Shader Nedir?
Shader, JavaScript tarafında değil; doğrudan GPU üzerinde çalışan küçük bir programdır.
Aynı talimat, GPU’nun binlerce çekirdeğinde paralel şekilde binlerce verteks/piksele
uygulanır.
Bu sayfada vertex/fragment ayrımını, "neden shader?" motivasyonunu, GLSL değişken
türlerini (uniform/attribute/varying) ve shader’ı sezgisel bir "filtre" gibi okumayı
kısa ama sağlam bir çekirdeğe oturtacağız.
Shader Piksellerin ve Köşelerin Küçük Programı
Shader, Three.js (JavaScript) tarafında değil; doğrudan GPU üzerinde çalışan küçük bir programcıktır. GPU’nun binlerce çekirdeği, senin yazdığın bu tek programı aynı anda binlerce veri noktasına uygular.
Buradaki sezgi "ordu" metaforudur: CPU planı kurar, GPU ise aynı talimatı paralel uygular. Shader, o talimatın kendisidir. Bu yüzden shader yazmak, bazen "tek satır matematikle milyonlarca pikseli yönetmek" gibi hissedilir.
Vertex Shader (İskeletçi)Vertex shader, her bir köşe noktasının (vertex) ekranda nereye düşeceğine karar verir. Döndürme/taşıma/ölçekleme gibi dönüşümler bu aşamada "köşe düzeyinde" gerçekleşir; yani modelin iskeletini hareket ettiren el burasıdır.
Fragment Shader (Boyacı)Fragment shader ise piksellerin hangi renkte olacağını belirler. Işık, gölge, yansıma ve doku (texture) gibi "görüntünün derisi" burada üretilir. Özetle: vertex "nerede?", fragment "ne renk?" sorusunu cevaplar.
Bu iki rolü pipeline içinde yan yana koyarsak resim daha netleşir: önce vertex shader "köşeleri" ekran uzayına taşır; sonra GPU bu köşelerden üçgenleri oluşturur ve ekranı piksellere böler; en sonda fragment shader her piksel için renk/ışık kararını verir. Yani shader’lar, geometrinin şekliyle görüntünün rengini iki ayrı aşamada yönetir.
Paralellik sezgisini doğru kurmak da önemli: "binlerce çekirdek" demek, her şeyin bedava olduğu anlamına gelmez. Shader içinde pahalı işlemler (çok fazla doku okuma, karmaşık dallanmalar, aşırı iterasyon) arttıkça, her piksele uygulanan maliyet büyür. Bu yüzden shader tasarımı; hem estetik hem de performans dengesi demektir.
Three.js pratiği: Hazır materyaller (MeshStandardMaterial vb.) aslında "önceden yazılmış shader paketleri" gibidir. Özel bir efekt istediğinde ise çoğu zaman uniform üzerinden zaman/mouse gibi parametreler gönderip, fragment tarafında rengi, vertex tarafında şekli manipüle edersin. GPU vs CPU iş bölümü için GPU vs CPU sayfası da iyi bir tamamlayıcıdır.
Bağlantı: Shader fikri, Canvas vs WebGL sayfasındaki boru hattının (pipeline) "programlanabilir" kısmıdır.
Neden Shader Kullanıyoruz? Kişiselleştirilmiş Gerçeklik
Three.js bize hazır materyaller sunar (ör. MeshStandardMaterial). Ama "eriyen metal", "dalgalanan deniz" veya "parazitli hologram" gibi standart dışı efektler, çoğu zaman shader seviyesinde kişiselleştirme ister.
Burada kilit avantaj donanım hızıdır: milyonlarca pikselin rengini JavaScript ile tek tek hesaplamak, main thread’i boğar. Shader ise bu işi GPU’nun paralel gücüyle her karede çok daha verimli yapar.
Yaratıcılık sezgisi: Elinde piksellerin rengini belirleyen bir formül varsa, rengi zamana, konuma veya mouse hareketine bağlayabilirsin. Shader, "renk = f(zaman, konum)" gibi bir filtre düşüncesini gerçek zamanlı sanata çevirir.
Hazır materyallerin gücü, "genel kullanım" için dengeli olmalarıdır; ama tam bu yüzden sınırları da vardır. Örneğin özel bir scanline efekti, hologram paraziti, ekran uzayı (screen-space) gradyanı veya objenin yüzeyinde zamanla akan bir desen istediğinde; materyal ayarları yeterli gelmeyebilir. Shader, burada "kendi görsel dilini" yazmana izin verir.
Bu kişiselleştirme genelde uniform üzerinden akar: time gönderir dalgayı yürütürsün, mouse gönderir etkileşimli parazit üretirsin, bir color gönderir sahnenin atmosferini tek hamlede değiştirirsin. Yani shader, "parametreleri knob gibi çevirip" görüntüyü gerçek zamanda şekillendirdiğin bir kontrol paneline dönüşür.
Ne zaman yazmalı? Eğer hedefin "fiziksel olarak doğru" bir materyalden çok, stil ve his üretmekse shader doğru yerdir. Ama sadece standart metal/roughness ayarı yapıyorsan, önce hazır materyallerle ilerlemek daha hızlı ve daha güvenlidir.
GLSL 3 Temel Değişken Kapısı
Shader yazarken JavaScript değil, GLSL (OpenGL Shading Language) kullanılır. Three.js’ten shader’a veri taşırken temel olarak üç kanal düşünürsün.
Uniforms: Herkes İçin AynıUniform, tüm pikseller/vertexler için aynı olan veridir: zaman, mouse konumu, ışık rengi gibi "global knob"’lar. Uniform değişince, shader’ın ürettiği dünya bir anda "ruh hali" değiştirir.
Attributes: Vertex’e ÖzelAttribute, her vertex’e özel veridir: konum (position), normal, vertex rengi gibi. Yani "iskeletin ham verisi" attribute’larla akar; vertex shader bu veriyi şekillendirir.
Varyings: Vertex’ten Fragment’e Yumuşak GeçişVarying, vertex shader’dan çıkıp fragment shader’a taşınan ve piksel aralarında "interpolated" (yumuşatılmış) verilerdir. Böylece vertex düzeyinde hesapladığın bir değeri, piksellere düzgün bir gradyan gibi yayarsın.
Mini sezgi: Uniform "herkese aynı not", attribute "her askere özel bilgi", varying ise "vertex’ten piksele akan yumuşak mesaj" gibidir.
Bu üç kapıyı, "veri yolu" gibi düşün: CPU tarafında (JavaScript) sen sahnenin durumunu değiştirirsin; GPU tarafında (GLSL) bu durum, doğru kanallardan akarak görüntüye dönüşür. Uniform, her kare güncellenebilen global kontrol düğmeleridir; attribute, geometriyle birlikte gelen "ham hamur"; varying ise bu hamuru piksel seviyesine taşırken arayı yumuşatan köprüdür.
Three.js tarafında attribute’lar çoğu zaman BufferGeometry üstünde yaşar: position/normal/uv gibi diziler GPU’ya bir kez yüklenir ve vertex shader’da okunur. Bu yüzden "modelin şeklini" değiştirmek istiyorsan attribute ve vertex tarafında düşünürsün; "renk/ışık hissini" değiştirmek istiyorsan fragment tarafı daha baskındır.
Uniform’lar ise en "canlı" kanaldır: time gibi bir değeri her tick’te güncellersin ve shader aynı geometri üzerinde akıp giden bir efekt üretir. Bu yaklaşım, render loop ve rAF ritmiyle birlikte okunur; çünkü uniform güncelleme sıklığı, görüntünün akıcılığını doğrudan etkiler.
Interpolasyon notu: Varying’ler piksel aralarında otomatik yumuşatılır; bu, gradyanlar için harikadır ama "keskin sınır" istediğin durumlarda beklenmedik sonuçlar verebilir. Böyle anlarda "keskinlik" kararını fragment tarafında (ör. threshold/step) kurmak daha kontrollü hissettirir.
Sezgisel Bakış Matematiksel Bir Filtre
Shader’a bakarken onu "karmaşık formül yığını" olarak değil, bir filtre olarak düşün: girişte zaman ve konum vardır, çıkışta renk/ışık vardır. Karmaşıklık, sadece bu filtrenin ne kadar detaylı yazıldığıyla ilgilidir.
Bu bakış açısı, shader yazmayı da sadeleştirir: "Hangi parametreyi oynarsam hangi görsel duygu çıkar?" sorusuna odaklanırsın. Yani shader, matematiği estetik bir kontrol paneline çevirir.
Filtre sezgisini bir adım daha netleştirelim: girdi çoğu zaman \((x,y)\) gibi ekran/UV koordinatları, \((x,y,z)\) gibi dünya verileri, time gibi bir uniform ve belki bir texture örneklemesidir. çıktı ise genelde tek bir şeydir: o pikselin rengi (ve bazen derinliğe dair kararlar). Yani "bir pikselin kaderi", birkaç girdinin matematikle yoğrulmasıdır.
Bu yüzden shader geliştirirken pratik bir yöntem şudur: tek bir parametre seç (ör. time), onu yavaşça değiştir ve görüntünün nasıl "nefes aldığını" izle. Sonra ikinci parametreyi ekle (ör. UV), deseni mekâna bağla. En son etkileşim ekle (ör. mouse), filtreyi "canlı" hale getir. Böyle ilerlediğinde karmaşık efektler bile katman katman anlaşılır olur.
Debug sezgisi: Shader’da bir şey ters gidiyorsa, önce "görselleştir": hesapladığın bir değeri doğrudan renge map et (ör. gri ton, sıcak-soğuk renk). Bu, matematiksel hatayı bulmanın en hızlı yoludur; çünkü shader’da console yok, ama renk var.
🚀 HoloDepth Lab: Shader SimülatörüMatematiğin nasıl sanata dönüştüğünü görmek ister misin? Lab’de küçük shader dokunuşlarıyla dalga, renk karışımı ve vertex distortion gibi efektleri canlı olarak manipüle edebilirsin.
GPU Ordularına Emir Verin
Matematiğin piksellere nasıl dönüştüğünü canlı izleyin. Kürenin şeklini Vertex Shader ile bozun, rengini ve dokusunu Fragment Shader ile anlık olarak yeniden kodlayın.
Vertex tarafında formu bük, fragment tarafında rengi/dokuyu değiştir. Küçük parametre dokunuşlarının GPU’da nasıl büyüdüğünü gör.