WebGL · Shader sistemi · Vertex
WebGL: Vertex shader (geometri ve konum katmanı)
Vertex shader, pipeline’ın ilk aktif hesaplama istasyonudur. Buffer’lardan gelen ham noktaları alır, onları sahne/kamera/projeksiyon sözleşmesine göre dönüştürür ve geometriyi “ekrana gidecek hat” üzerine yerleştirir. Bu katman, sahnedeki her noktanın nerede olacağını belirler.
Bu sayfa GLSL syntax dersi değildir. Hedef, vertex shader’ın rolünü, uzay dönüşümü yolculuğunu (local → world → view → clip) ve veri girişlerini (attribute/uniform/varying) netleştirmektir.
Vertex nedir? (geometrinin yapı taşı)
Her 3D model, uzaydaki çok sayıda noktanın (vertex) birleşiminden oluşur. Tek bir vertex sadece bir koordinattır; ama vertex’ler bir ağ (mesh) oluşturacak şekilde bağlandığında yüzeyler ve hacimler ortaya çıkar.
WebGL/GPU açısından vertex’i “yalnızca bir nokta” gibi değil, çoğu zaman bir veri paketi gibi düşünmek daha doğrudur: pozisyonun yanında normal, UV, vertex rengi gibi ek alanlar da taşır. Bu alanlar, vertex shader’ın geometriyi doğru konumlandırması ve bir sonraki aşamaya anlamlı bilgi taşıması için ham girdidir.
- Vertex ağları: Noktalar, üçgenler/çizgiler gibi primitive’lerle bağlanır ve geometriyi oluşturur.
- Topoloji (bağlantı kuralı): Hangi vertex’in hangisiyle birleşip üçgen oluşturacağı, çoğu zaman indeks (index buffer) ile tarif edilir. Yani “yüzey”, koordinatlardan çok bağlantı bilgisidir.
- Modelin ham hâli: Shader çalışmadan önce “model”, GPU belleğinde sadece sayı dizileridir. Vertex shader bu sayılara konumlandırma anlamı katar.
Sezgi: vertex’ler tuğla gibidir; mesh ise o tuğlaların hangi sırayla dizileceğini söyleyen plandır. Vertex shader, bu planı “ekrana gidecek geometri” hâline getiren ilk mühendislik katmanıdır.
Vertex shader ne yapar? (konum hesaplayıcı)
Vertex shader, gönderdiğiniz her verteksi “tek tek” ele alır — ama GPU’nun paralel doğası sayesinde bu, aynı anda çok sayıda verteks üzerinde yürür. Her yürütmenin ana görevi, o verteks için nihai ekran yolculuğunu başlatacak konumu üretmektir.
Buradaki ana fikir, “sahneyi” değil, tek bir verteksi düşündüğünüzde netleşir: vertex shader’ın her çalıştırılışı, bir verteks girdisi alır; onu matrisler ve kurallar üzerinden dönüştürür; sonra pipeline’a “bu verteks buraya düştü” diye raporlar. Aynı kural, tüm vertekslere uygulanır.
- Bireysel işleme: Program, her vertex için bir kez çalıştırılır.
- Yeni konum tayini: Orijinal veriyi alır, dönüşümleri uygular ve “nerede?” cevabını üretir.
- Ek veri üretimi: Sadece konum değil; fragment tarafında işe yarayacak bazı değerler de hazırlanabilir (ör. UV aktarımı, vertex rengi, aydınlatma için ara katsayılar). Bu veriler varying olarak taşınır.
Sezgi: vertex shader “geometriyi taşır”; fragment shader “görüntüyü kurar”. Bu yüzden vertex tarafı, pipeline’ın geri kalanına doğru, düzgün ve tutarlı bir başlangıç koşulu sağlar.
Coordinate space yolculuğu (uzay dönüşümleri)
Bu sayfanın kalbi, bir noktanın “ham veri” hâlinden “ekran koordinatı” hâline gelene kadar geçtiği duraklardır. Aynı vertex, farklı uzaylarda farklı sayılarla temsil edilir; amaç, onu kamera ve projeksiyon sözleşmesine göre doğru uzaya taşımaktır.
- Local / model space: Nesnenin kendi merkezine göre koordinatlar.
- World space: Nesnenin sahne içindeki konum/rotasyon/ölçekle yerleştirildiği uzay.
- View space: Her şeyin kamera merkezli olarak yeniden ifade edildiği uzay.
- Clip space: Görüş hacmine göre sıkıştırılmış uzay; pratikte ekrana giden sınırların tanımlandığı alan (sonrasında NDC’ye indirgenir).
Clip space’ten sonra iki küçük ama kritik adım daha vardır:
- Perspective divide → NDC: GPU,
gl_Position’ı \(w\) bileşenine bölerek koordinatları NDC’ye indirger (yaklaşık \([-1, 1]\)). Bu adım, perspektifin “yakın büyük, uzak küçük” etkisinin geometrik temelidir. - Viewport dönüşümü: NDC, ekrandaki piksel koordinatlarına eşlenir. Yani “matematiksel uzay” artık “ekran ızgarası”na oturur.
Sezgi: vertex shader’ın işi yalnızca bir matris çarpımı değildir; o, bir verteksi “kamera sözleşmesine uygun bir koordinat diline” çevirir. Böylece pipeline’ın geri kalanı, geometriyi güvenle piksel dünyasına taşıyebilir.
Space stage
Matrix stack
gl_Position builderActive vertex data
Shader kodu (secondary)
gl_Position = Projection * View * Model * vec4(position, 1.0);
Matris transform mantığı
Vertex shader, bu yolculuğu çoğu zaman üç temel matrisle kurar: Model (nesneyi dünyaya), View (dünyayı kameraya), Projection (3D derinliği 2D ekrana) taşır. Özetle vertex shader, her nokta için bu matris zincirini uygular ve koordinatı bir sonraki aşamanın anlayacağı forma sokar.
Buradaki matrisler, “geometriyi taşımak” için birer sözleşmedir:
- Model matrix: Nesnenin kendi uzayındaki koordinatları sahneye yerleştirir (konum/rotasyon/ölçek).
- View matrix: Dünyayı kameranın bakışına göre yeniden ifade eder; yani “kamerayı taşıdım” yerine “dünyayı kameraya göre ters taşıdım” gibi düşünebilirsiniz.
- Projection matrix: Görüş hacmini (frustum) clip space’e taşır ve perspektif derinlik etkisini kurar.
Bu zincirin amacı, vertex’i “rasterization’ın anlayacağı” forma sokmaktır. Matrisler matematiksel olarak ağır görünse de burada tek hedef vardır: sahnedeki konumu, kamera sözleşmesiyle uyumlu hâle getirmek.
gl_Position (nihai çıktı)
Her vertex shader’ın tek zorunluluğu vardır: gl_Position değerini üretmek.
Bu değer GPU’ya “bu verteks clip space’te nereye düşüyor?” bilgisini verir. Bu konumlar
sayesinde
üçgenler kurulur; bir sonraki aşamada fragment shader bu yüzeyleri boyamaya başlar.
gl_Position bir vec4’tür ve dördüncü bileşen (\(w\)) rastgele
bir ek
sayı değildir: biraz sonra yapılacak perspective divide adımının
parçasıdır.
GPU, clip space’ten NDC’ye geçerken \(x/w\), \(y/w\), \(z/w\) hesaplar; bu yüzden vertex
shader’ın
ürettiği değer, “ekran geometrisinin kaderini” belirler.
Sezgi: gl_Position doğru değilse, pipeline’ın geri kalanı doğru çalışsa bile
görüntü
doğru olamaz. Çünkü rasterization, fragment’leri üretmek için önce bu konumu referans alır.
Veri tipleri (vertex perspektifi)
Vertex shader’ın “girdi dili” üç kanalla kurulur: bazı veriler her verteks için değişir, bazıları tüm çizim boyunca sabittir, bazıları ise vertex’ten çıkıp yüzeye yayılır. Bu ayrım, hem doğru sonuç hem de doğru zihinsel model için kritiktir.
- Attribute: Vertex shader’a özeldir; vertex başına değişen veridir (konum, normal, UV). Kaynağı buffer’lardır ve layout (stride/offset) sözleşmesiyle doğru okunur.
- Uniform: Draw boyunca sabit kalan veridir (matrisler, zaman, kamera parametreleri). “Sabit” demek “hiç değişmez” değil; draw süresince sabit, kareler arasında güncellenebilir demektir.
- Varying: Vertex shader’dan çıkıp fragment shader’a taşınan köprü veridir (ör. “yükseklik katsayısı” gibi). Rasterization bu veriyi üçgenin içine interpolasyonla yayar, böylece fragment tarafı yüzey boyunca pürüzsüz bir giriş alır.
Mini sezgi: attribute “ham malzeme”, uniform “kontrol paneli”, varying ise “yüzeye yayılmış bilgi”dir. Vertex shader bu üç kanalı doğru kurarsa, fragment shader’ın eline tutarlı bir yüzey dili verir.
Vertex manipulation: 3D deformasyon
Vertex shader yalnızca “yerleştirmek” ile kalmaz; geometriyi aktif olarak şekillendirebilir. Bu katman, 3D manipülasyonun doğal yuvasıdır: bir verteksin konumunu değiştirdiğiniz an, yüzeyin formunu değiştirmiş olursunuz.
Önemli sınır: vertex shader yeni verteks “icat etmez”; yalnızca mevcut verteksleri taşır. Yani topoloji (kaç üçgen var, nasıl bağlılar) aynı kalır; değişen şey bu topolojinin uzaydaki şeklidir. Bu yüzden vertex shader ile yapılan deformasyonlar, hızlı ve güçlüdür ama “detay” üretmek için ek teknikler gerekir.
- Displacement: Bir dokuya veya katsayıya göre noktaları itmek/çekmek.
- Wave effect: Matematiksel dalga ile yüzeyi dalgalandırmak.
- Deformasyon: Dinamik şekil değiştirmeler ve animasyon altyapıları için temel fikirleri kurmak.
Vertex manipülasyonunun pratik sonucu şudur: yalnızca konum değil, yüzeyin “hissi” de değişir. Çünkü normal gibi aydınlatma girdileri, geometri değişince anlamını yitirebilir. Bu yüzden bazı deformasyonlarda, normal’ı da uygun bir uzayda yeniden ele almak gerekir (detaylar aydınlatma/GLSL sayfalarında).
Not: burada “nasıl kodlanır?”ı değil, vertex shader’ın geometri üzerinde yetki alanını sabitliyoruz.
Clip space & clipping
Üretilen gl_Position clip space sınırlarının dışındaysa, GPU o noktayı ve o
noktaya
bağlı yüzey parçalarını otomatik olarak keser (clipping). Bu, ekran dışında kalan bölgelerin
boşuna “piksel üretimi”ne taşınmamasını sağlayan temel bir sözleşmedir.
Clipping’i “görüş hacmi güvenliği” gibi düşünebilirsiniz: kamera frustum’ünün dışına taşan kısımlar, rasterization’a girmeden önce kırpılır. Buradaki kritik detay, kesmenin sadece “tamamen atma” olmadığıdır: bir üçgen kısmen dışarıdaysa, GPU o üçgeni sınır düzlemlerine göre kesip içeride kalan parçayı tutabilir.
- Clip vs cull: Culling genelde “tamamen dışarıda” olanları eler; clipping ise sınırı kesen primitifleri “yeniden şekillendirir”.
- Neden burada? Çünkü bu aşamada geometri artık clip space/NDC sözleşmesine yakındır; “ekran sınırı” matematiksel olarak nettir.
Sonuç: vertex shader doğru bir gl_Position ürettiğinde, GPU geri kalanını
disiplinli
şekilde yürütür: görünmeyeni kırpar, görüneni piksel dünyasına taşır.
En güçlü anlatım
Vertex shader “nerede?” sorusunu cevaplar. Fragment shader ise “nasıl görünecek?” sorusunu.
Three.js bağlantısı (tek paragraf)
Three.js’te bir objenin pozisyonu/rotasyonu/ölçeği gibi dönüşümler, altta vertex shader’ın çalıştığı dönüşüm zincirine karşılık gelir. Siz üst katmanda bir objeyi döndürdüğünüzde, pratikte vertex shader’ın kullandığı model/view/projection sözleşmesinin girdileri güncellenmiş olur.