Shader & GLSL · Sözdizimi & türler
Vec types (GLSL vektör tipleri)
İlgili sayıları tek pakette taşı — xyz, rgb, uv
Grafik shader’larında aynı anlama gelen sayılar çoğu zaman ayrı ayrı float değil,
vektör olarak paketlenir: vec2, vec3,
vec4. Konum (xyz), renk (rgba), doku
koordinatı (uv) veya clip uzayı (vec4 ile w) bu tiplerle taşınır — GPU hem bellek düzenini hem matematik işlemlerini
buna göre optimize eder.
Bu sayfa vektör türlerinin sözdizimine odaklanır: yapıcılar, bileşen erişimi,
swizzle, yaygın kullanım eşlemeleri ve kısa vektör matematiği. Değişken
bildirimi ve kapsam
Variables
konusundadır; float / int genel çerçevesi ve mat4 özeti
GLSL giriş · tipler
sayfasında — burada matrisleri yalnızca vektörle nasıl çarpıldığına değiniriz.
Geometri tamponlarında position kanalı üç bileşenli dizidir (
itemSize = 3);
shader tarafında bu veri vec3 veya vec4 olarak okunur. Operatör ve
yerleşik fonksiyon ayrıntısı
Operators ve
Built-in
functions
konularına bırakılır.
Neden vektör tipi?
GLSL’de «vektör tipi» seçmek, yalnızca sözdizimi tercihi değildir — GPU’nun veriyi register içinde nasıl paketleyeceğini ve hangi yerleşik işlemlerin geçerli olacağını belirler. Bu bölüm, vec2 / vec3 / vec4 ayrıntılarına geçmeden önce «neden paket halinde taşıyoruz?» sorusuna kısa cevap verir.
Aynı paket, farklı anlam
Üç eksenli konum için üç ayrı float (px, py,
pz) tutmak yerine tek bir vec3 yazmak hem okunabilirliği artırır
hem de dot, cross, normalize gibi işlemlerin
doğrudan uygulanmasını sağlar — ayrıntılı liste
vektör matematiği
bölümünde. Renk için vec3 (RGB) veya şeffaflıkla vec4 (RGBA); 2B
doku için vec2 (UV) — matematiksel yapı «N adet float yan yana», anlamsal
yorum bağlama bağlıdır.
Buffer tarafında da aynı fikir görülür: position attribute’u üçlü dizidir,
shader’da vec3 olarak okunur (
itemSize). CPU’daki Vector3 (
Vektör
mantığı) ile isim benzerliği vardır; GLSL tarafında
vec3 shader register’ıdır.
Boyut uyumu ve broadcast
Vektör tipleri skalerlerle serbestçe «karışmaz» — her ifadenin boyutu tanımlıdır.
vec3 + float çoğu profilde geçerlidir: skaler her bileşene eklenir (
broadcast). Örneğin position + uOffset düşünülebilir;
uOffset tek sayıysa üç eksene de uygulanır.
Buna karşılık vec3 + vec2 çoğu zaman derleme hatası verir —
boyutlar uyuşmaz. Benzer şekilde vec4 bekleyen bir fonksiyona vec3
vermek de hataya gider; gerekirse yapıcı veya swizzle ile açıkça genişletirsiniz (
yapıcılar,
swizzle). Bu disiplin,
tip zorunluluğu
ile uyumludur; operatör kuralları
Operators
konusunda ayrıntılandırılır.
Vec2, Vec3,
Vec4
GLSL’de vec son eki, kaç adet float bileşeninin tek register’da
paketlendiğini söyler: vec2 iki, vec3 üç, vec4 dört.
Aşağıda her boyutun sahne ve shader’daki tipik rolü özetlenir; yapıcı ve swizzle ayrıntıları
§3–5’te kalır.
Tür adı = bileşen sayısı
Bileşen sayısı tür adında yazar — ayrı bir «uzunluk» alanı taşımazsınız; derleyici
vec3 ifadesini gördüğünde üç kayan nokta bekler. Hangi veri kanalında kaç
bileşen gittiği, shader girişinde de aynı sayıyla bildirilir:
attribute vec3 position, uniform vec2 uResolution,
varying vec2 vUv gibi. Bu eşleşme,
Uniforms
& varyings
konusunun özüdür; burada yalnızca «boyut seçimi» tarafını netleştiriyoruz.
vec2 — iki bileşen
İki bileşenli paket, düzlemde çalışan her şey için doğal türdür. En yaygın örnek doku
koordinatıdır: UV eksenleri (u, v) genelde
vec2 olarak taşınır; vertex shader’da uv attribute’undan okunur,
fragment tarafına varying vec2 vUv ile aktarılır (
GLSL · varying,
ilk örnek).
Aynı tür 2B ofsetler, ekran çözünürlüğünün yalnızca genişlik–yükseklik çifti (
uResolution.xy), gradyan yönü veya «iki skaleri birlikte taşı» durumlarında
da görülür. Fragment shader’da doku örneklemek için çoğu zaman elinizdeki koordinat
vec2’dir — üçüncü bir eksen gerekmez.
vec3 — üç bileşen
Üç bileşen, 3B uzayın «doğal» boyutudur. Model (veya dünya) uzayında konum
position.xyz, yüzey yönü normal, düz RGB renk veya ışık yönü
vektörü tipik olarak vec3 ile ifade edilir. Buffer’da itemSize 3
olan attribute kanalları vertex shader’da vec3 olarak okunur — tampon
düzenine kısa köprü
§1
ve
itemSize
konusundadır.
Renk şeffaflık gerektirmiyorsa vec3 yeterlidir; alpha kanalı eklenecekse
vec4’e geçilir. Konum ile renk aynı türde paketlense de anlamları farklıdır —
karıştırmamak için isimlendirme (baseColor, lightDir) ve
uniform/varying bildirimleri net kalmalıdır.
vec4 — dört bileşen
Dört bileşen, hem 3B+ek bilgi hem de grafik boru hattının zorunlu çıktı formatını
kapsar. Homojen koordinat (x, y, z,
w) perspektif projeksiyonda w ile bölme yapılana kadar dördüncü
bileşeni taşır; vertex shader’ın standart çıktısı
gl_Position her zaman vec4’tür (
GLSL · vertex aşaması).
Fragment tarafında vec4 çoğunlukla RGBA rengi (
gl_FragColor veya out vec4) temsil eder; bazen de «üç vektör +
tek skaler» paketi olarak kullanılır (örneğin yön + yoğunluk). vec3’ten
vec4’e geçerken dördüncü bileşeni bilinçli atamak gerekir —
yapıcılar
bölümündeki
vec4(vec3, float) kalıbı bu boşluğu kapatır.
Yapıcılar ve kısaltmalar
vec2 uv = vec2(0.5, 0.25);
vec3 red = vec3(1.0, 0.0, 0.0);
vec4 white = vec4(1.0);
vec3 fromVec4 = vec3(vColor.rgb);
vec4 promoted = vec4(vUv, 0.0, 1.0);
Tek skaler vererek tüm bileşenleri doldurma (vec3(1.0)) yaygındır. Daha küçük
vektörden büyüğe geçiş: vec4(vec3, float) veya swizzle + yapıcı birleşimi.
Tür dönüşümü için float(), int() skalerde olduğu gibi vektör
yapıcılarına da uygulanabilir (vec3(intVec)).
Bileşen erişimi: .xyzw ve
.rgba
Vektör değişkeni bellekte sıralı float bileşenlerinden oluşur; GLSL bunlara
nokta notasyonuyla erişmenizi sağlar. Bu bölüm tek bileşen ve
isimlendirme aileleri (.xyzw / .rgba) üzerinde
durur; birden fazla harfle alt vektör türetmek (
vUv.yx, color.bgra) bir sonraki
§5 · Swizzle
konusundadır.
Tek bileşen: nokta notasyonu
En basit erişim, tek harfle okumaktır: position.x, normal.y,
color.a. Sonuç her zaman float’tır — vektörden bir skaler
«çıkarır»,
türü değiştirmez. Örneğin clip uzayına yakın bir noktada perspektif için
gl_Position.w kullanılır; fragment tarafında alpha testi için
baseColor.a okunabilir.
Bileşen sırası yapıcıyla verdiğiniz sırayla aynıdır (
§3 · yapıcılar): ilk argüman
.x / .r, ikincisi .y / .g … Bu sayfa
boyunca vec3 / vec4 rolleri
§2’de özetlendi; burada «hangi harf
hangi
kanal?» sorusuna odaklanıyoruz.
.xyzw ve .rgba /
.stpq
GLSL, aynı fiziksel bileşenlere iki (üç) paralel isimlendirme ailesi tanır. Bunları aynı vektörde karıştırmak derleme hatası değildir — anlam bağlamına bağlı bir okuma kolaylığıdır:
xyzw: Konum, yön, clip uzayı, genel 3B/4B geometri — «eksen» veya «bileşen indeksi» okuması.position.xyz,lightDir.xybu aileye yakışır.rgba: Renk kanalları — kırmızı, yeşil, mavi, alpha.vColor.rgb,texel.afragment shader’da sık görülür.stpq: Doku / örnekleme bağlamında alternatif kanal adları (.s,.t…); pratikte çoğu ekipuvveyargbaile kalır,stpqdaha çok eski veya API dokümantasyonunda karşılaşılır.
Özet tablo (aynı vec4 için):
// 1. bileşen 2. 3. 4.
// .x .y .z .w ≡ .r .g .b .a ≡ .s .t .p .q
Aynı bileşen, farklı harf — tutarlılık
vColor.r ile vColor.x aynı birinci bileşendir; derleyici için
fark yoktur, yalnızca okuyanın zihnindeki model değişir — biri «kırmızı kanal», diğeri «ilk
eksen». Karışık aile örneği:
vec4 p = vec4(1.0, 2.0, 3.0, 1.0); float u = p.x; float v = p.g;
geçerlidir; p.x ile p.r yine aynı değeri verir.
Ekip çalışmasında dosya veya proje genelinde tek aileyi tercih etmek
(konum shader’ında çoğunlukla xyz, renk shader’ında rgba)
diff’leri
okunur kılar. Çok harfli permütasyonlar ve atama kuralları
swizzle
bölümünde; kısa hatırlatma ayrıca
GLSL giriş · altın kurallar
listesindedir — burada yalnızca «harf = kanal indeksi, aile = yorum» ayrımını
netleştiriyoruz.
Swizzle: yeniden sıralama ve alt vektör
Swizzle, aynı kaynaktan yeni bir vektör (veya skaler) türetmektir —
tek harfli erişim
§4’ün çok bileşenli uzantısıdır.
vUv.yx UV’yi ters çevirir, normal.xyz dörtlü paketten
vec3 kesiti alır, color.bgra kanalları permüte eder. GLSL’in en
sık kullanılan sözdizimi özelliklerinden biridir; prosedürel desen ve maske kodunda satır
sayısını ciddi azaltır.
vec4 c = texture2D(uMap, vUv);
vec3 rgb = c.rgb;
float a = c.a;
vec2 rg = c.rg;
vec3 bump = c.agb; // okuma: kanallar yeniden seçilir
Kurallar ve tuzaklar
Swizzle’ın gücü, okuma tarafındaki esnekliktir; yazma (atama) tarafında ise kanal çakışmasına karşı sıkı kurallar vardır. Aşağıdaki dört başlık günlük shader hatalarının çoğunu önler.
Çıktı boyutu
Seçtiğiniz harf sayısı, sonuç türünü doğrudan belirler: .xy →
vec2, .xyz → vec3, tek harf → float.
Kaynak vec4 olsa bile position.xy yalnızca iki bileşenli bir
alt vektördür — boyut «kaynak türüyle aynı kalır» diye bir kural yoktur.
Bu kural, §2’deki boyut disipliniyle
uyumludur: swizzle sonrası elinizdeki türü bir sonraki işleme (ör. dot,
mix) verirken bileşen sayısını bilinçli seçmiş olursunuz.
Tekrar ve genişletme
Aynı harfi birden fazla seçmek okuma tarafında geçerlidir: normal.xxx
vec3 üretir — bir skaleri üç eksene «yaymak» (genişletme) için kullanılır.
vec3(n.xxx) gibi kalıplar, tek bileşenli bir girdiyi üç bileşenli bir türe
taşımak istediğinizde yapıcıyla birlikte görülür.
Tekrar, okuma tarafında serbest olsa da atama tarafında farklı kurallara tabidir (aşağıdaki
bölüm); vColor.xyx = … gibi yazımlar bu yüzden reddedilir.
Atama kısıtı (l-value)
Swizzle sol tarafta — yani yazılacak hedefte — kullanılacaksa kurallar sıkıdır. Örneğin
vColor.rg = vec2(1.0, 0.0); çoğu profilde mümkündür: yalnızca kırmızı ve yeşil
kanallara yazar, mavi ve alpha dokunulmaz kalır.
Örtük çakışan kanallara yazmak geçersizdir: vColor.xyx = vec3(1.0); birinci ve
üçüncü hedefin ikisi de x kanalına işaret ettiği için derleyici reddeder —
hangi
değerin kalacağı belirsizdir. Okuma tarafında böyle bir belirsizlik yoktur;
vec3 v = vColor.xyx; her üç bileşene de aynı x değerini kopyalar.
vColor.rg = vec2(1.0, 0.0); // çoğu zaman geçerli
// vColor.xyx = vec3(1.0); // geçersiz: çakışan yazma hedefi
Karışık isimlendirme ailesi
.xy ile .rg aynı fiziksel bileşenlere denk gelir; fark yalnızca
okuma kolaylığıdır (
§4 · isim aileleri).
Okuma swizzle’ında .xgr gibi harf ailelerini karıştırmak da çoğu GLSL
sürümünde geçerlidir — örneğin c.agb dört kanallı bir dokudan permütasyon
üretir.
Yine de ekip içinde tek aileyi sürdürmek diff okunurluğunu artırır; karışık yazım «mümkün» olsa bile her satırda zihinsel çeviri gerektirir. Atama tarafında aile seçimi değil, kanal çakışması asıl hatayı üretir.
Kısa swizzle hatırlatması ayrıca GLSL giriş · altın kurallar listesindedir; bu sayfa shader pratiğindeki dört kurala odaklanır.
Vektör matematiği (özet)
Vektörler skaler gibi +, - ile toplanır; * ve
/ çoğu bağlamda bileşen bazında uygulanır (broadcast kuralları
Operators
konusunda). §1’de «paket» olarak seçtiğiniz vec3 artık bu yerleşiklerle
geometri ve renk hesabına girer — tam API listesi
Built-in
functions
sayfasına bırakılır; burada shader pratiğinde en sık beş fonksiyon özetlenir.
Length — uzunluk
Length(v) vektörün Öklid uzunluğunu tek bir float olarak döndürür.
Mesafe karşılaştırması, hız büyüklüğü veya «bu normal çok kısa mı?» kontrolü için
kullanılır.
Girdi vec2, vec3 veya vec4 olabilir; sonuç her zaman
skalerdir — boyut uyumu
§1 ile uyumludur.
Normalize — birim yön
Normalize(v), vektörü aynı yönde tutup uzunluğu 1 yapar — ışık yönü, bakış
vektörü veya yüzey normali girdiğinde sık görülür. Matematiksel olarak
v / length(v) düşüncesine denktir.
Sıfır vektörde bölme tanımsızdır; üretim shader’larında pratikte
v / max(length(v), 1e-6) veya benzeri küçük epsilon koruması görülür. Aksi
halde
bazı GPU’larda NaN üreten pikseller oluşabilir.
Dot — iç çarpım
Dot(a, b) iki vektörün iç çarpımını verir (skaler). Lambert tarzı aydınlatmada
klasik kalıp float ndotl = max(dot(normal, lightDir), 0.0); şeklindedir —
yüzey normali ile ışık yönü ne kadar hizalı, parlaklık o kadar yüksek. Aynı işlem, bir
vektörün başka bir yön üzerindeki projeksiyon fikrine de bağlanır.
a ve b aynı boyutta olmalıdır (vec3 ile
vec3 gibi); farklı boyutlar derleme hatasıdır.
Cross — çapraz çarpım
cross(a, b) yalnızca vec3 ile tanımlıdır; sonuç yine
vec3’tür ve her iki girdiye de dik bir vektör üretir. İki kenar vektöründen
yüzey normali türetmek veya teğet uzayında üçüncü eksen bulmak için kullanılır — normal
haritalama ve geometri shader’larında sık görülür.
Sıra önemlidir: cross(a, b) ile cross(b, a) zıt yönlüdür; elinizle
sağ kuralına göre hangi yönü istediğinizi kontrol edin.
Mix — karışım / geçiş
mix(a, b, t), a ile b arasında doğrusal geçiş yapar:
t == 0.0 tamamen a, t == 1.0 tamamen b.
Renk karışımı
(mix(baseColor, highlight, mask)) veya vektör interpolasyonu için
kullanılır; a ve b aynı vektör türünde olmalıdır.
t skaler olabileceği gibi vektör de olabilir — örneğin
mix(colorA, colorB, vUv.x) yatay gradyan,
mix(vec3(0.0), vec3(1.0), vec3(t)) ise kanal başına farklı ağırlık verir.
smoothstep ile birlikte yumuşak geçişler prosedürel desenlerin temelidir;
ayrıntı
Built-in
functions
konusuna bırakılır.
Three.js Vector3 API’si (
Vektör
mantığı) CPU tarafındaki karşılıktır — shader’da karşılık vec3 ve bu
yerleşiklerdir; matris çarpımı
§7’de özetlenir.
Vektör ve matris: mat4 * vec4
Bu sayfa boyunca vektörleri paketleme, swizzle ve yerleşiklerle işledik; vertex shader’da
onlar çoğu zaman matris çarpımının girdisi veya çıktısı olur. §2’de
gl_Position’ın vec4 olduğu söylenmişti — burada bu dörtlünün
mat4 zinciriyle nasıl üretildiğine odaklanıyoruz. Matris yapıcıları ve
mat2 / mat3 tanımları
GLSL giriş · matris
konusundadır; burada vektör–matris köprüsü özetlenir.
Vertex dönüşüm zinciri
Three.js ve benzeri motorlarda konum, önce model–view, sonra projeksiyon ile clip uzayına taşınır. Tipik satır:
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
position attribute’u çoğu zaman vec3’tür; homojen koordinat için
dördüncü bileşen 1.0 ile
yapıcı
veya vec4(position, 1.0) kalıbıyla eklenir. Çarpım sırası ve uniform isimleri
sahneye göre değişir; önemli olan «mat4 * vec4 → vec4» boyut
uyumudur. Örnek akış
GLSL · vertex aşaması
ve
ilk örnek
kodunda görülür; projectionMatrix gibi matrisler
uniform
olarak gelir.
Column-major düzen
GPU tarafında matrisler sütun öncelikli (column-major) saklanır;
GLSL’de mat4 * vec4 yazımı bu düzenle uyumludur. JavaScript’te
Matrix4 elemanlarını elle shader’a yazarken satır/sütun karışıklığı sık hata
kaynağıdır — vektör paketini doğru seçmek yetmez, matrisin bellek düzeni de eşleşmelidir.
Bu bölüm matris çarpımının cebirsel kanıtına girmez; «shader’da neden
vec4 gerekir?» sorusuna pratik cevap verir. Teorik matris özeti yukarıdaki
GLSL giriş bağlantısındadır.
Normal taşıma: mat3 ve
normalMatrix
Konum mat4 ile taşınırken yüzey normali çoğu zaman ayrı bir lineer dönüşüm
ister — ölçek veya perspektif içeren tam mat4 normali bozabilir. Three.js
normalMatrix (mat3) uniform’ı bu iş için sağlanır; shader’da yerel
normal üzerinde çarpılır:
vec3 worldNormal = normalize(normalMatrix * normal);
Burada girdi ve çıktı vec3’tür — §6’daki normalize yine devreye
girer. Aydınlatmada dot(normal, lightDir) hesaplanmadan önce normalin doğru
uzayda ve birim uzunlukta olduğundan emin olun; normal haritası ve TBN uzayı ileri konularda
ele alınır.
Boyut uyumu özeti
mat4 * vec4 geçerlidir; mat4 * vec3 çoğu zaman derleme hatasıdır
— önce vec4’e yükseltin. mat3 * vec3 normal ve renk yönü gibi
saf 3B vektörler içindir. Vektör–vektör kuralları
§1
ile aynı disiplin: tür adındaki boyut, çarpımda da korunur veya bilinçli genişletilir.
Holodepth notu
Yeni bir efekt yazarken her «paket» için türü bilinçli seçin: UV → vec2, renk
→ vec3 veya vec4, dünya normali → vec3. Uzun ifadeyi
tek satırda bırakmak yerine vec2 uv2 = vUv * 2.0; ve
float band = smoothstep(0.2, 0.8, uv2.y); gibi ara vektörler hem hatayı
bulmayı kolaylaştırır hem swizzle hatalarını azaltır.