holodepth

Shader & GLSL · Vertex / fragment

Coordinate spaces

Konum hangi uzayda?

Vertex / fragment serisinin son konusu: gl_Position yazılmadan önce konumun hangi uzaylardan geçtiği. Veri akışı taşıyıcıları ve adımları kurdu; Interpolation varying’lerin raster’da nasıl karıştığını anlattı — burada odak konum ve normalin matris zinciri.

Three.js çoğu projede modelViewMatrix ve projectionMatrix uniform’larını otomatik besler; özel materyalde hangi uzayda hesap yaptığınızı bilmek zorunludur. Matris çarpımı kuralları Operators ve mat4 türü Vec types konusundadır; bu sayfa uzay isimleri ve shader’daki tipik zinciri sabitler.

Genel koordinat sezgisi ByteOmi · koordinat sistemleri ve Matrix nedir? köprülerinde; aşağıdaki §1–§8 vertex shader bakışıyla ilerler.

Neden Koordinat Uzayları?

Aynı sahne içinde «konum» birden fazla anlama gelir. mesh.position nesneyi sahne grafiğinde taşır; attribute vec3 position; geometry’nin yerel köşe koordinatıdır. Vertex shader bu ikisini matrislerle birleştirip gl_Position üretir — uzay karışınca model yerinde durur, uçar veya iç içe geçer ( Veri akışı · akış hataları).

Fragment shader çoğu ışık hesabını «dünya» veya «görüntü» uzayında yapar; bu yüzden normal çoğu zaman vertex’te dönüştürülüp varying ile taşınır. UV ve renk enterpolasyonu Interpolation konusunda kalır; burada yalnızca konum / normal uzayı.

Bu sayfa ne anlatır, ne anlatmaz?

Anlatır: model → view → clip zinciri; Three.js matris uniform’ları; gl_Position satırı; normalMatrix; uzaya özel hatalar. Anlatmaz: tam matris türevi ve perspektif projeksiyon formülü (ByteOmi / matematik köprüleri); varying bildirimi derinliği; pipeline donanım tablosu ( Shader pipeline).

Seri içindeki yer

Vertex / fragment serisi burada kapanır: Veri akışıShader pipelineInterpolation → Coordinate spaces (bu sayfa). Önce «veri nereye akar?», sonra donanım, sonra karışım, en son «konum hangi uzayda çarpılıyor?».

Uzay Zinciri: Model → View → Clip

Vertex shader’da tek bir köşe noktası, birkaç uzaydan geçerek ekrana giden üçgenin parçası olur. Zinciri ezberlemek yerine her adımda «şimdi hangi soruya cevap veriyorum?» diye okuyun — Holodepth isimleri Three.js ile uyumludur; özel materyalde de aynı uniform adları görülür.

Dört Kapı: Local → World → View → Clip

  • Local / model — «Köşe mesh’in kendi gövdesinde nerede?» attribute vec3 position; geometry tamponundan gelir; ölçek ve şekil burada tanımlıdır ( §3).
  • World — «Sahnedeki mutlak yer neresi?» Three.js mesh.position / rotation / scale bu dönüşümü günceller; shader’da modelMatrix uniform’u köşeyi dünya uzayına taşır.
  • View / eye — «Kamera nereden bakıyor?» viewMatrix dünya noktasını kamera önüne alır. Pratikte çoğu örnek modelViewMatrix kullanır — iki adımı tek uniform’da birleştirir: modelViewMatrix = viewMatrix * modelMatrix ( §4).
  • Clip — «Ekran / derinlik testine uygun koordinat nedir?» projectionMatrix perspektif veya ortografik projeksiyon uygular; vertex çıkışı gl_Position bu uzaya yakındır. Sonrasında raster ve enterpolasyon ( Interpolation · raster) devreye girer — konum ve UV ayrı kanallardır.

Tipik Satır: gl_Position

En sık görülen kalıp: gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

Okuma yönü sağdan sola düşünülür: önce vec4(position, 1.0) homojen köşe (yerel uzay), sonra modelViewMatrix ile kamera önüne, en son projectionMatrix ile clip’e. Matrisler solda, vektör sağda kalır — GLSL’de mat4 * vec4 sırası Operators konusundadır.

gl_Position taşıyıcı değildir; varying değildir — vertex’in zorunlu konum çıkışıdır ( Veri akışı · vertex çıkışı). Tam çarpım sırası, w bileşeninin perspektif bölünmesi ve NDC ayrıntısı ileride bu bölümde derinleştirilecek; şimdilik «her matris bir uzay kapısı» yeterlidir.

Ayrı Matrisler Ne Zaman?

modelMatrix ve viewMatrix’i ayrı kullanmak, dünya uzayında ışık / gölge veya nesne bazlı efekt yazarken gerekebilir — örneğin fragment’te dünya konumu için modelMatrix * vec4(position, 1.0) ayrı hesaplanır. Yalnızca standart mesh çizimi için modelViewMatrix + projectionMatrix çoğu zaman yeterlidir.

Genel vertex rolü GLSL giriş · vertex aşaması bölümünde de özetlenir. Aşağıdaki §3 yerel position attribute’unu, §4 Three.js uniform setini, §5 örnek kodu açar.

Yerel köşe: attribute position

§2 zincirinin ilk kapısı buradadır: vertex shader’a giren position, henüz sahne veya kamera görmeyen yerel köşe koordinatıdır. Matrisler bu değeri dünya / görüntü / clip’e taşır — attribute içinde «dünya konumu» saklanmaz.

Geometry tamponu ve isim sözleşmesi

Attribute vec3 position; shader bildirimidir; veri BufferGeometry üzerindeki position attribute tamponundan gelir. İsimler eşleşmelidir — Three.js’te farklı kanal adı kullanırsanız shader’a ulaşmaz ( Uniforms · attribute, Attributes & buffer’lar).

Her vertex invokasyonu tampondan bir köşe satırı okur; değer draw call boyunca attribute olarak sabitlenir, uniform gibi paylaşılmaz
( Veri akışı · taşıyıcılar). Köşeden köşeye farklı position normaldir — mesh’in şekli burada kodlanır.

Nesne dönüşümü ≠ köşe koordinatı

Sık karışıklık: mesh.position (ve rotation, scale) tüm nesneyi sahne grafiğinde taşır; position attribute’u ise geometry’nin kendi gövdesindeki noktadır. Sahne tarafında nesneyi hareket ettirirsiniz; shader’da bunun karşılığı modelMatrix uniform’udur — attribute’a mesh.position yazılmaz ( Veri akışı · akış hataları, §8).

Vertex’te doğru kalıp: gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);position yerel kalır, dönüşüm matrislerle gelir. Nesneyi shader içinde position + vec3(...) ile kaydırmak yerine ya sahne grafiğini ya da modelMatrix uniform’unu güncelleyin
( §4).

Kaynak: DCC export ve procedural mesh

Blender, Maya vb. export edilen mesh’ler köşeleri genelde model / yerel uzayda getirir — bu yüzden import sonrası mesh.position ile sahneye yerleştirirsiniz. Three.js PlaneGeometry, BoxGeometry, SphereGeometry de aynı mantıkla köşeleri yerel uzayda üretir; merkez ve boyut parametreleri geometry oluşturulurken tampona yazılır.

Özel tampon ( Custom buffer geometry) yazarken de «bu array hangi uzayda?» sorusunu baştan netleştirin — çoğu zaman yerel mesh uzayıdır; dünya koordinatı attribute’a gömülmez, modelMatrix ile taşınır.

Sonraki adımlar

Vertex shader’ın işi: bu yerel noktayı §2 zinciriyle dünya / görüntü / clip’e taşımak ve gl_Position yazmak. Normal ve UV ayrı attribute kanallarıdır; konumla aynı uzayda olmak zorunda değildir — normal normalMatrix ile ayrı dönüştürülür (§6). Aşağıdaki §4, matris uniform setini; §5 standart vertex örneğini gösterir.

Matris uniform’ları (Three.js)

§3 yerel position attribute’unu tanımladı; bu bölüm onu uzaylar arası taşıyan mat4 uniform’larını shader dosyasında nasıl okuyacağınızı sabitler. Başlıkta «Three.js» geçmesi, Holodepth örneklerindeki isim sözleşmesi içindir — kamera kurulumu, Camera API’si veya Matrix4 JavaScript ayrıntısı bu sayfada yoktur; odak GLSL tarafındaki uzay zinciridir.

ShaderMaterial ve çoğu built-in materyal, vertex shader’a aşağıdaki matris uniform’larını otomatik enjekte eder — GLSL dosyasında isimler bire bir aynıdır. Sizin işiniz motorun matrisi nasıl hesapladığını ezberlemek değil; vertex satırında hangi uniform’un hangi uzay kapısını kapattığını bilmektir.

ModelMatrix — Nesne → Dünya

uniform mat4 modelMatrix; yerel position attribute’unu ( §3) dünya uzayına taşır. Sahne grafiğinde nesneyi taşıdığınızda güncellenen dönüşüm burada okunur; köşe tamponuna eklenmez.

Vertex’te dünya konumu gerekiyorsa: vec4 worldPos = modelMatrix * vec4(position, 1.0); — sonrasında varying veya ayrı hesap ile fragment’e taşınabilir. Standart çizimde bu adım çoğu zaman modelViewMatrix içinde gizlidir.

ViewMatrix — Dünya → Kamera

uniform mat4 viewMatrix; dünya uzayındaki noktayı kamera / görüntü uzayına alır. Tek başına konum satırında daha seyrek görülür; pratikte modelViewMatrix model ve view adımlarını birleştirir.

Ayrı kullanım, kamera ve nesne dönüşümlerini shader içinde farklı kombinlemek istediğiniz özel efektlerde anlamlıdır; günlük materyal yazımında ikinci plandadır.

ModelViewMatrix — Birleşik Model + View

uniform mat4 modelViewMatrix;, kabaca viewMatrix * modelMatrix çarpımının hazır halidir — konum için en sık kullanılan uniform’dur. Tipik çarpım: modelViewMatrix * vec4(position, 1.0) ( §2 · gl_Position).

«Önce model sonra view» mantığı bu tek matriste paketlenmiştir; vertex’te ayrı ayrı çarpmak yerine motorun gönderdiği birleşik değeri okumak hem kısadır hem hatası azaltır.

ProjectionMatrix — Görüntü → Clip

uniform mat4 projectionMatrix; kamera önündeki noktayı clip uzayına yakın temsile projekte eder — perspektif veya ortografik kamera ayarına bağlıdır. Vertex’te genelde son çarpandır; çıktı gl_Position’dır ve raster buna göre aday piksel seçer.

Tam satır: gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); — projeksiyon «ekran perspektifi» katmanıdır; UV veya renk bu matristen geçmez.

NormalMatrix — Normal İçin Ayrı Yol

uniform mat3 normalMatrix; konum matrisinin kopyası değildir; attribute vec3 normal; yön vektörlerini dönüştürmek için türetilmiştir. Türü mat3’tür — normal §6’daki kalıpta ( §6) kullanılır.

Konum için normalMatrix, view için modelViewMatrix kullanmak yaygın bir karışıklıktır; her attribute kendi uzay dönüşümünü izler.

Draw Call Boyunca Sabit; Enterpolasyon Yok

Tüm matris uniform’ları draw call başına bir kez bağlanır — aynı mesh çizimindeki her köşe ve fragment invokasyonu aynı projectionMatrix, aynı modelViewMatrix değerini görür. Raster köşeler arasında matris karıştırmaz ( Interpolation · uniform karışmaz).

Uniform bildirim kuralları Uniforms · uniform konusundadır. Kamera veya nesne hareket ettiyse matrisler bir sonraki render öncesi güncellenmiş olmalıdır ( Veri akışı · draw call öncesi).

Tekrar Çarpım Tuzağı

Özel uniform eklerken «bu matris hangi uzayı birleştiriyor?» sorusunu sorun. Sık hatalar:

  • projectionMatrix * projectionMatrix * … — projeksiyon iki kez uygulanır.
  • modelViewMatrix varken ayrıca modelMatrix ile tekrar çarpmak — dünya adımı iki kez işlenir.
  • Konum için normalMatrix kullanmak — yanlış uzay; normal §6’daki kalıpta kalır.

Güvenli yol: Three.js’in verdiği isimleri ve §2’deki tek satırlık kalıbı kopyalayıp yalnızca ihtiyaç duyduğunuz ek uniform’ları (zaman, doku) eklemek.

Ayrı Model + View Ne Zaman?

Shader’da modelMatrix ve viewMatrix’i ayrı tutmak, dünya uzayında hesap gerektiğinde anlamlıdır — örneğin vertex’te
vec4 worldPos = modelMatrix * vec4(position, 1.0); yazıp varying ile fragment’e taşımak. Yalnızca «mesh’i ekrana çiz» hedefi için modelViewMatrix + projectionMatrix yeterlidir ( §2 · ayrı matrisler).

RawShaderMaterial Notu

RawShaderMaterial kullanıyorsanız bu matris uniform’ları otomatik gelmez — vertex shader’da bildirmeniz ve JavaScript tarafında beslemeniz gerekir. Holodepth vertex / fragment örnekleri varsayılan Three.js isim setini gösterir; motor API’si GLSL giriş (Three.js) konusundadır, burada yalnızca «shader’da hangi isim, hangi uzay?» sabitlenir.

Aşağıdaki §5, bu uniform’ların tamamını içeren standart vertex örneğini gösterir.

Örnek: Standart Vertex Konumu

Aşağıdaki kalıp, konum uzayını tek satırda toplar. UV taşıma Interpolation · UV örneği ile birleştirildiğinde tam materyal iskeleti oluşur.

attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;

varying vec2 vUv;
varying vec3 vNormal;

void main() {
  vUv = uv;
  vNormal = normalize(normalMatrix * normal);
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

Normal: normalMatrix

Konum position ve modelViewMatrix ile clip’e gider ( §2, §5). Normal ayrı bir yoldur: attribute vec3 normal; yerel yüzey yönüdür; ışık ve yansıma hesapları çoğu zaman dünya veya görüntü uzayında yapılır — bu yüzden normalMatrix uniform’u ( §4 · normalMatrix) devreye girer.

Vertex Kalıbı: Dönüştür, Normalize Et, Taşı

Tipik satır: vNormal = normalize(normalMatrix * normal); — önce uzay dönüşümü, sonra birim uzunluk. normalize enterpolasyondan önce veya sonra tartışılır; pratikte vertex’te normalize edip varying ile göndermek yaygındır. Fragment’te dot(vNormal, lightDir) gibi hesaplar bu enterpolasyonlu yönü kullanır ( Interpolation, Built-in · vektör).

normal attribute’unu fragment’te doğrudan okuyamazsınız — akış attribute → varying → raster → varying ( Veri akışı · taşıyıcılar). Konum kanalı ile karıştırmayın; UV ayrı kanaldır.

Yerel Normal, Dünya Işığı

Fragment’te dot(normal, uLightDir) yazmak, yerel normali dünya uzayındaki ışık vektörüyle karşılaştırmaktır — sonuç yanlış veya kameraya bağlı «kayar» görünür. Işık yönü hangi uzaydaysa normal de o uzayda olmalıdır; vertex’te normalMatrix bu eşleştirmeyi sağlar.

Ters ölçek (scale negatif eksen) gibi durumlarda normalMatrix özellikle önemlidir — konum matrisinin üst 3×3’ünü kopyalamak yeterli değildir. Ayrıntılı türev (ters çevrim üst 3×3) ileride bu bölümde açılacak; şimdilik pratik kural: motorun gönderdiği uniform mat3 normalMatrix; değerini kullanın; elle modelMatrix ile aynı sanmayın.

Fragment’te Tüketim

vNormal enterpolasyonlu geldikten sonra fragment’te çoğu zaman tekrar normalize(vNormal) uygulanır — üçgen içi karışım uzunluğu bozulmuş olabilir. Işık modeli bu sayfada derinleştirilmez; uzay eşleşmesi sağlandıysa materyal formülünüz çalışır.

Clip Çıkışı ve Raster

§4 · projectionMatrix vertex’te son çarpandır; çıktı gl_Position’dır. Bu bölüm, konum zincirinin GPU’ya bıraktığı zorunlu çıkış ile raster / enterpolasyon arasındaki sınırı netleştirir — UV ve normal bu kanaldan gitmez.

gl_Position: Konum Çıkışı, Taşıyıcı Değil

gl_Position vertex shader’ın zorunlu çıkışıdır; attribute, uniform veya varying değildir ( Veri akışı · vertex çıkışı). Rasterizer hangi piksellerin üçgene aday olduğunu buna göre belirler — «ekran nerede?» sorusunun cevabı burada kodlanır.

vUv, vNormal ayrı varyings’lerdir; gl_Position onları taşımaz. Enterpolasyon yalnızca varying kanallarında çalışır ( Interpolation · girdi ve çıktı).

W Bileşeni ve Perspektif

gl_Position bir vec4’tür; w bileşeni perspektif bölünmede rol oynar. Derinlik testi ve perspektif enterpolasyon (UV’nin uzak köşede sıkışması gibi) bu değere bağlıdır — çoğu zaman hata değil, projeksiyonun doğal sonucudur ( Interpolation · perspektif).

Clip uzayı, NDC ve ekran pikseli dönüşümünün matematiği ileride bu bölümde derinleştirilecek. Shader yazarken §2’deki tek satırlık kalıbı doğru uygulamak çoğu uygulama için yeterlidir.

Raster Sonrası

gl_Position işlendikten sonra pipeline rasterize eder; fragment shader renk ve derinlik üretir — tam adım listesi Shader pipeline konusundadır. Uzay serisi burada kapanır; sonraki §8 yaygın karışıklıkları özetler.

Uzaya özel karışıklıklar

Aşağıdaki liste konum ve normal uzayı karışıklıklarını vurgular — doğru taşıyıcı ama yanlış uzay. «uv fragment’te yok» veya «varying unuttum» gibi akış hataları Interpolation · hatalar ve Veri akışı · hatalar bölümlerinde kalır.

  • mesh.position ile position attribute’unu aynı sanmak — biri sahne düğümü (→ modelMatrix), biri geometry köşesi (→ attribute). Düzeltme: sahne grafiğinde taşı veya §2 kalıbını kullan ( §3).
  • Normali dönüştürmeden dot(normal, lightDir) — yerel normal, dünya ışığı ile karşılaştırılır. Düzeltme:
    vNormal = normalize(normalMatrix * normal); ( §6).
  • Yanlış matrisle gl_Position — model kaybolur, devasa görünür veya ters döner. Düzeltme: §2’deki
    projectionMatrix * modelViewMatrix * vec4(position, 1.0) sırasını ve isimleri kopyalayın ( §4 · tekrar çarpım).
  • Matris çarpım sırasını ters yazmak — zincir bozulur. Düzeltme: Three.js uniform isimlerini olduğu gibi kullanın; elle yeniden sıralamayın.
  • Ölçekli veya aynalı ölçekte normalMatrix atlamak — aydınlatma yamuk, içe dönük görünür. Düzeltme: uniform mat3 normalMatrix; ( §4).
  • gl_Position ile varying karıştırmak — konum çıkışı ayrı kanal; UV/normal varying ile taşınır ( §7).

Hızlı Kontrol Listesi

Şüphede iki soru: (1) Bu vektör hangi uzayda tanımlı? (2) Hedef uzayda hangi matris / varying gerekli? Konum için §2 kalıbı; normal için §6 kalıbı; taşıyıcı zinciri için Veri akışı özeti. Vertex / fragment serisi bu sorularla kapanır — geniş GLSL bağlamı için GLSL giriş (Three.js).

Holodepth notu

Vertex / fragment serisi tamamlandı. Özel materyalde kağıda local → modelView → projection → gl_Position oklarını çizin; UV/normal için Interpolation sayfasına dönün. Geniş bağlam için GLSL giriş (Three.js).