holodepth

Shader & GLSL · Sözdizimi & türler

Uniforms & varyings

CPU ile GPU arasındaki veri sözleşmesi

Shader içindeki yerel değişkenler yalnızca o invokasyon içinde yaşar ( Variables). Gerçek sahne verisi — zaman, matrisler, köşe tamponları, vertex’ten fragment’e taşınan UV — ise uniform, attribute ve varying (veya in / out) ile bildirilir. Bu sayfa, GLSL sözdizimi serisinin «dış dünya köprüsü» katmanıdır.

Tür seçimi (vec3, sampler2D …) Vec types ve yerleşik çağrılar (texture2D, dot …) Built-in functions konusundadır; burada kimin ne zaman okuduğu ve Three.js tarafında nasıl beslendiği öne çıkar.

Genel panorama ve draw call çerçevesi GLSL giriş · depolama bölümündedir — burada shader dosyasındaki bildirim sözdizimi ve sık hatalar sabitlenir.

Neden uniform ve varying?

Three.js sahnesinde konum, renk veya zamanı JavaScript ile değiştirirsiniz: mesh.position.set(...), material.uniforms.uTime.value = t gibi satırlar CPU tarafında kalır. Shader dosyası ise GPU’da çalışır; aynı bilgiyi orada uniform, attribute veya varying (veya GLSL ES 3.00’da in / out) anahtar sözcükleriyle okursunuz. İki dünya arasındaki bağ, isim ve türün bire bir eşleşmesine dayanır — buna Holodepth’te kısaca sözleşme denir.

Sözleşme kırıldığında davranış her zaman aynı değildir. Tür veya operatör uyumsuzluğu çoğu zaman shader derlemesinde hata verir ( Operators · hatalar). Yanlış uniform adı ise programı derletebilir ama değeri bağlamaz: ekranda sessizce yanlış renk, donmuş animasyon veya siyah kare görürsünüz. Bu yüzden özel materyal yazarken önce «hangi isim, hangi tür, hangi taraftan besleniyor?» sorusunu netleştirmek, doğrudan GLSL satırı yazmaktan önce gelir.

Shader içinde hesapladığınız ara sonuçlar ( Variables · yerel) her vertex veya fragment invokasyonunda yeniden üretilir; sahne verisi dışarıdan gelir. Uniform, attribute ve varying bu dış veriyi dosyada görünür kılar — rol ayrımı ve «kim nerede okur?» tablosu bir sonraki bölümde; burada yalnızca «neden ayrı bir katman var?» sorusuna odaklanıyoruz.

Üç karar sorusu

Yeni bir değer shader’a eklenecekse, bildirim yazmadan önce şu üç soruyu sırayla sorun. Çoğu tasarım hatası bu sırayı atlayınca ortaya çıkar; cevaplar doğrudan anahtar sözcüğe map edilir.

  1. Bu değer tek bir çizim çağrısı (draw call) boyunca her köşede ve her pikselde aynı mı? Örnek: geçen süre, ekran çözünürlüğü, ışık rengi, projectionMatrix. Evet ise → uniform.
  2. Değer köşeden köşeye değişiyor mu? Örnek: model uzayındaki konum, UV, vertex rengi. Evet ise → attribute (yalnızca vertex shader girişi).
  3. Vertex aşamasında bilinen bir şey, fragment aşamasında da gerekli mi? Örnek: enterpolasyonlu UV, dünya uzayı normali. Evet ise → varying veya in·out çifti; vertex’te yazılır, fragment’te okunur.

Üç sorunun cevabı da «hayır» ise değer büyük olasılıkla yerel değişkendir: float edge = smoothstep(0.45, 0.55, vUv.x); gibi bir satır dışarıdan veri almaz, yalnızca o invokasyonda hesaplanır. Attribute’u fragment’te okumaya çalışmak veya zamanı varying ile taşımak gibi karışıklıklar bu ayrımı netleştirince kaybolur.

Çizim çağrısıyla ilişki

renderer.render(scene, camera) her karede birden fazla mesh çizer; her mesh + materyal kombinasyonu GPU’ya ayrı bir çağrı gönderir. Uniform değerleri o çağrı süresince sabitlenir — aynı üçgende köşe A ile köşe B aynı uTime değerini görür. Sonraki mesh’e geçildiğinde modelMatrix yeniden bağlanabilir. Draw call ve depolama sınıflarının genel tablosu GLSL giriş · depolama bölümündedir; bu sayfada çağrı kavramı yalnızca «uniform neden çağrı başına sabit?» sorusunu cevaplamak için anımsatılır.

Sessiz hatalar ve isim listesi

Varying eksikliği çoğu zaman program link aşamasında patlar; uniform ismi yanlışsa hata görünmeyebilir. Materyal başına kısa bir liste tutmak — uniform adları, attribute kanalları, varying çiftleri — diff okunurluğunu artırır. Sık görülen kalıplar §7’de toplanır; seri sonunda Holodepth notu üç sütunlu planı özetler.

Üç rol: yerel değişkenden farkı

Önceki bölüm «hangi anahtar sözcüğü seçmeliyim?» sorusuna cevap verir; burada seçimin arkasındaki rol sabitlenir: veri shader’ın içinde mi üretiliyor, CPU’dan mı geliyor, yoksa vertex’ten fragment’e mi taşınıyor? Variables · arayüz bölümünde yerel/global ile arayüz ayrımı tanıtılmıştı — burada aynı ayrımı üç isimle somutlaştırıyoruz; bildirim örnekleri ve Three.js köprüsü sonraki bölümlerde kalır.

Kısa kural: float t = 0.5; gibi yerel veya global shader değişkenleri programın kendi hesabıdır; uniform, attribute ve varying ise dış dünyayla veya pipeline aşamaları arasıyla konuşan katmandır. JavaScript’teki BufferAttribute ile shader’daki attribute vec3 position; aynı isimle eşleşir ama farklı katmanlardadır — tampon yapısı Attributes & buffer’lar konusunda, shader tarafındaki bildirim bu sayfada.

Kim, nerede okur?

Aşağıdaki özet, materyal yazarken «bu değişken hangi dosyada geçer?» sorusuna hızlı cevap verir. Derin enterpolasyon ve doku örneği §5 ile §3–§4’te açılır; genel draw call tablosu GLSL giriş · depolama bölümündedir.

  • uniform — Vertex ve fragment shader’da okunabilir; tek bir çizim çağrısı boyunca değişmez. Zaman (uniform float uTime;), dönüşüm ( uniform mat4 projectionMatrix;), doku tutamacı ( uniform sampler2D uMap;) bu gruptadır. Aynı üçgenin tüm köşeleri ve tüm pikselleri aynı uTime değerini görür.
  • attribute — Yalnızca vertex shader girişi; her invokasyon bir köşeyi temsil eder. Konum (attribute vec3 position;), UV
    ( attribute vec2 uv;), normal gibi kanallar GPU tamponundan gelir. Fragment shader bu isimlere erişemez; ihtiyaç varsa değer önce varying ile taşınır.
  • varying — Vertex’te yazılır, fragment’te aynı isim ve türle okunur; aradaki değerler rasterizer tarafından enterpolasyonla karıştırılır. Tipik kalıp: varying vec2 vUv; — vertex’te vUv = uv;, fragment’te texture2D(uMap, vUv). Enterpolasyonun sezgisi ve perspektif notu §5’te kalır.

Yerel değişkenle karıştırmayın

Üç rol, yerel değişkenin yapamadığı işleri üstlenir. Örneğin fragment’te vec3 lit = baseColor * ndotl; yalnızca o pikselde hesaplanır; komşu piksel bu lit değerini görmez. Buna karşılık uniform vec3 uLightColor; tüm fragment’lerde ortaktır ama fragment içinde uLightColor = … ile yeniden atanamaz — uniform salt okunur giriştir.

«Köşedeki UV’yi fragment’te kullanmak» isteği de yerel değişkenle çözülmez: attribute doğrudan fragment’te yoktur; vertex’te vUv = uv; yazıp varying ile aktarmak gerekir. Zamanı veya ışık rengini varying ile taşımak yerine uniform kullanmak genelde doğrudur — değer zaten çağrı boyunca sabittir ( §1 · üç soru).

Global shader değişkeni de her invokasyonda paylaşılan «program hafızası» değildir; paralel GPU çalışması nedeniyle güvenilir paylaşım için uniform veya doku kullanılır. Her kare değişen sabitler için global yerine uniform tercih edin ( Variables · global).

GLSL ES 3.00: in ve out

WebGL2 ve GLSL ES 3.00 shader’larında varying yerine vertex’te out vec2 vUv;, fragment’te in vec2 vUv; yazılır; anlam değişmez, yalnızca sözdizimi ayrışır. Attribute tarafında in vec3 position; gibi girişler de aynı nesneyi ifade eder — Three.js hâlâ buffer attribute isimlerini eşleştirir.

Holodepth örnekleri çoğu zaman klasik attribute / varying çiftini gösterir; WebGL2 projelerinde karşılığı bire bir çevrilebilir. flat niteliği, perspektif enterpolasyon ve varyings’in sınırları GLSL giriş · varying ile §5’te işlenir — burada yalnızca «aynı köprü, farklı anahtar sözcük» notu yeterlidir.

Uniform

§2’de uniform’ın vertex ve fragment’te okunabildiği ve çizim çağrısı boyunca sabit kaldığı özetlendi. Bu bölümde odak, shader dosyasında nasıl bildirildiği ve Three.js tarafında nasıl beslendiğidir — attribute ve varying §4–§5’e bırakılır.

Pratikte uniform, «bu mesh bu materyalle çizilirken herkesin gördüğü ortak parametre» demektir: geçen süre (uTime), tuval boyutu (uResolution), ışık rengi, kamera ve model matrisleri (projectionMatrix, modelMatrix), doku tutamacı ( sampler2D uMap). Köşe başına değişen konum veya UV burada değildir; onlar attribute ve ardından varying ile gelir. Draw call çerçevesi §1’de; Three.js’te material.uniforms kalıbı §6’da tamamlanır.

Bildirim ve tür

Bildirim kalıbı sabittir: uniform + tür + isim + ;. Örnekler: uniform float uTime;, uniform vec2 uResolution;, uniform mat4 modelMatrix;, uniform sampler2D uDiffuse;. Tür seçimi Vec types kurallarıyla aynıdır — shader tarafında kaç bileşen beklediğiniz, JavaScript’te gönderdiğiniz değerin şekliyle eşleşmelidir.

Skaler ve vektörlerde Three.js çoğu zaman karşılık gelen sınıfları kabul eder: uniform float ↔ sayı, uniform vec2Vector2 veya iki elemanlı dizi, uniform vec3Vector3. Bileşen sayısı uyuşmazsa derleme veya bağlama aşamasında hata alırsınız ( boyut uyumu, Operators · hatalar). Renk için uniform vec3 ile uniform vec4 karıştırmak sık görülen bir tuzaktır — alpha kanalı gerekiyorsa dörtlü tür seçin.

uniform mat4 vertex shader’da konum taşımada kullanılır; ifade projectionMatrix * modelViewMatrix * vec4(position, 1.0) hem matris uniform’larına hem de mat4 × vec4 kuralına dayanır ( Operators · matris). Matris uniform’larının ayrıntılı listesi aşağıda; önce fragment tarafında zaman ve doku ile çalışan kısa örneğe bakın.

uniform float uTime;
uniform vec2 uResolution;
uniform sampler2D uDiffuse;

void main() {
  vec2 uv = gl_FragCoord.xy / uResolution;
  float pulse = 0.5 + 0.5 * sin(uTime);
  vec4 tex = texture2D(uDiffuse, uv);
  gl_FragColor = vec4(tex.rgb * pulse, tex.a);
}

Matris uniform’ları

Three.js standart materyalleri modelViewMatrix, projectionMatrix, normalMatrix gibi isimleri otomatik bağlar; özel shader yazarken aynı isimleri kullanmak en az sürtünmeyi verir. Vertex shader’da gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); satırı bu uniform’lara dayanır — isimleri shader’da değiştirirseniz materyal veya onBeforeCompile tarafında da güncellemeniz gerekir. Normal dönüşümü için normalMatrix ayrı bir uniform olarak gelir; vektör matematiği Built-in · vektör ile birlikte kullanılır.

sampler2D ve doku

sampler2D bir uniform türüdür: GPU’ya hangi dokunun bağlanacağını söyler, piksel verisinin kendisi değildir. Fragment’te örnekleme texture2D(uDiffuse, vUv) şeklinde yapılır — texture2D sözdizimi Built-in · doku konusundadır. Burada kritik nokta isim eşleşmesidir: uniforms.uDiffuse = { value: myTexture } ↔ shader’daki uniform sampler2D uDiffuse;. UV çoğu zaman varying ile gelir ( §5); tam ekran efektlerinde bazen gl_FragCoord / uResolution ile de hesaplanır.

Güncelleme sırası

Uniform değeri çizimden önce yazılmalıdır: material.uniforms.uTime.value = clock.getElapsedTime(); satırı renderer.render(...) çağrısından önce çalışır. Sonradan yapılan atama çoğu zaman bir sonraki karede görünür. «Hareket yok» şikâyetinde önce doğru materyal örneğine ve isim yazımına bakın ( §7). Aynı Vector3 veya doku referansını birden fazla materyal paylaşıyorsa beklenmedik yan etki olabilir — gerekirse her materyale ayrı { value: … } nesnesi verin.

İsimlendirme: u öneki

Holodepth ve Three.js örneklerinde u öneki uniform’ları ayırt eder ( Variables · isimlendirme). Zorunlu değil; tutarlılık diff okunurluğunu artırır.

Attribute

§3 çizim çağrısı boyunca sabit veriyi anlattı; attribute ise köşe başına değişen tampon verisidir. Yalnızca vertex shader’da okunur — her GPU invokasyonu bir köşeyi temsil eder. Fragment shader’da attribute bildiremezsiniz; piksel başına farklı değer ihtiyacı §5 ile çözülür.

Three.js tarafında kanal adı ile shader ismi bire bir eşleşmelidir: geometry.setAttribute('uv', uvAttribute) ↔ shader’da attribute vec2 uv;. JavaScript’teki BufferAttribute GPU tamponunu doldurur; shader’daki attribute satırı o tamponun vertex girişidir. Tampon oluşturma, güncelleme ve itemSize Attributes & buffer’lar konusundadır — burada yalnızca «isim ve tür sözleşmesi» sabitlenir.

Standart kanallar

BufferGeometry ve glTF export’ları çoğu mesh’te aynı kanal isimlerini kullanır. Özel geometri yazarken de bu isimlere uymak, Three.js ve örnek shader’larla uyumu kolaylaştırır.

  • position — Model (veya lokal) uzayda köşe konumu; shader’da genelde attribute vec3 position;. gl_Position hesabına girer; uniform matrislerle birlikte kullanılır ( §3 · matris).
  • uv — Doku koordinatı; attribute vec2 uv;. Fragment’te doğrudan yoktur — vertex’te vUv = uv; yazılıp varying ile taşınır; doku örnekleme §5 ve Built-in · doku ile birleşir.
  • normal — Yüzey normali; attribute vec3 normal;. Işık için çoğu zaman vNormal = normalMatrix * normal; ile görüş uzayına çevrilip varying olarak gönderilir ( Built-in · vektör).

Renk, teğet (tangent) veya özel veri kanalları da aynı mantıkla eklenir: geometry’de isim, shader’da uygun attribute vecN türü. Kanal başına bileşen sayısı itemSize ile shader türü uyumlu olmalıdır — üç sayı gönderip attribute vec2 okumak beklenmedik sonuç üretir ( Attributes · itemSize, Vec types).

Fragment’te okunamaz

texture2D(uMap, uv) fragment shader’da geçersizdir; doğru zincir attribute vec2 uv → vertex’te vUv = uv → fragment’te
texture2D(uMap, vUv). Attribute’u «her pikselde farklı UV» sanmak sık başlangıç hatasıdır — köşeler farklıdır, piksel değerleri rasterizer enterpolasyonu ile varying üzerinden gelir ( §2 · üç rol).

Aşağıdaki vertex.glsl örneği üç standart kanalı uniform matrislerle birleştirir; vUv ve vNormal fragment dosyanızda aynı isimle bildirilmelidir.

attribute vec3 position;
attribute vec2 uv;
attribute vec3 normal;

varying vec2 vUv;
varying vec3 vNormal;

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

Varying ve enterpolasyon

§4 attribute’ların yalnızca vertex’te okunduğunu gördük; fragment’in ihtiyaç duyduğu köşe verisi varying (veya GLSL ES 3.00’da out / in) ile taşınır. Vertex shader’da atadığınız değer, fragment shader’da aynı isim ve türle okunur; aradaki adımı GPU’nun rasterizer’ı doldurur.

Üçgen çizildikten sonra köşe değerleri iç noktalara enterpolasyonla karıştırılır: bir köşede kırmızı, karşıda mavi renk taşıyorsanız yüzey ortasında mor ton görürsünüz. UV, normal veya özel veri için de aynı mantık geçerlidir — «köşede keskin, yüzeyde yumuşak» geçişlerin çoğu varying + enterpolasyon kombinasyonundan gelir. Zaman veya ışık rengi gibi çağrı boyunca sabit veriler buraya değil, uniform ile gelir ( §1 · üç soru).

Çift taraflı bildirim

Vertex ve fragment dosyalarında aynı bildirim satırı gerekir — örneğin her iki tarafta da varying vec2 vUv;. Vertex’te vUv = uv; yazılır; fragment’te yalnızca okunur. İsim veya tür uyuşmazlığı (vec2 vs vec3) program link aşamasında hata verir; bu, uniform ismindeki sessiz hatadan farklı olarak genelde konsolda görünür ( §1 · sessiz hatalar).

in / out sözdizimi §2’de özetlendi; WebGL2’de vertex’te out vec2 vUv;, fragment’te in vec2 vUv; çifti aynı köprüdür. Three.js özel materyallerinde klasik varying yazımı yaygındır.

Perspektif enterpolasyon

WebGL, clip uzayından sonra UV ve renk gibi varyings için perspektif düzeltmeli enterpolasyon uygular. Eğik 3B yüzeylerde doku hafif «akıyor» gibi görünebilir; bu çoğu zaman hata değil, beklenen davranışa yakındır. Tam ekran 2B quad veya ortografik sahnelerde fark nadiren hissedilir. Üçgen başına tek değer taşımak isteyen kanallar için flat niteliği ve sınırlar GLSL giriş · varying bölümündedir — burada yalnızca «köşe → piksel karışımı» sezgisi yeterlidir.

Normal, UV ve doku zinciri

varying vec3 vNormal fragment’te genelde normalize(vNormal) ile ışık hesabına girer; vertex tarafında çoğu zaman
vNormal = normalMatrix * normal; yazılır ( §4 · vertex örneği, Built-in · vektör). varying vec2 vUv ise doku örneklemesi için kullanılır: fragment’te texture2D(uMap, vUv)uMap uniform’ı §3’te, texture2D Built-in · doku konusundadır. Varying üzerinde swizzle ve tür kuralları Vec types / Operators ile aynıdır; yeni tür eklemeden önce kanalın gerçekten vertex’te üretilip fragment’e taşınması gerektiğini doğrulayın.

Aşağıdaki fragment örneği yalnızca vUv ve doku uniform’ını gösterir; tam vertex + fragment çifti GLSL giriş · ilk örnek ile §4 vertex kodunu birleştirin.

varying vec2 vUv;
uniform sampler2D uMap;

void main() {
  vec4 albedo = texture2D(uMap, vUv);
  gl_FragColor = albedo;
}

Three.js köprüsü

§3–§5 shader dosyasında uniform, attribute ve varying bildirimlerini işledi; bu bölüm aynı sözleşmenin Three.js tarafındaki karşılığını toplar. Standart materyaller (MeshStandardMaterial vb.) çoğu matris ve ışık uniform’ını sizin adınıza günceller — kaynak kodu görmezsiniz ama aynı köprü mantığı geçerlidir. Tam kontrol için ShaderMaterial veya mevcut materyale küçük eklemeler için onBeforeCompile kullanırsınız; her iki yolda da shader’daki isimler JavaScript tarafıyla bire bir eşleşmelidir.

Genel ShaderMaterial panoraması ve ilk bağlama adımları GLSL giriş (Three.js) bölümündedir — burada yalnızca uniform / attribute / varying’in nereden yazıldığı özetlenir; GLSL sözdizimi serisinin pratik kapanışı sayılır.

Uniform nesnesi

ShaderMaterial oluştururken uniforms anahtarı bir sözlük bekler; her giriş { value: … } sarmalayıcısı ister — doğrudan uTime: 0 yazmak çalışmaz. Kare döngüsünde çoğu zaman uniforms.uTime.value = t; ile güncellersiniz; atama renderer.render öncesinde olmalıdır ( §3 · güncelleme sırası). Skaler, Vector2 / Vector3, Matrix4 ve Texture örnekleri shader türüyle eşleşmelidir ( §3 · bildirim ve tür).

Aynı uniforms nesnesini materyale verip döngüde .value alanlarını değiştirmek yaygın bir kalıptır — aşağıdaki örnek bunu gösterir. Paylaşılan referanslar (tek Vector3 örneği) beklenmedik yan etki verebilir; gerekirse materyal başına ayrı { value: new THREE.Vector3() } kullanın.

import * as THREE from 'three';

const uniforms = {
  uTime: { value: 0 },
  uResolution: { value: new THREE.Vector2() },
  uMap: { value: null },
};

const material = new THREE.ShaderMaterial({
  uniforms,
  vertexShader: document.getElementById('vs').textContent,
  fragmentShader: document.getElementById('fs').textContent,
});

function animate() {
  uniforms.uTime.value = performance.now() * 0.001;
  renderer.render(scene, camera);
}

Geometry attribute’ları

BufferGeometry üzerinde tanımladığınız kanal adları, vertex shader’daki attribute isimleriyle eşleşir: geometry.setAttribute('uv', …)attribute vec2 uv;. BoxGeometry gibi hazır geometriler çoğu zaman position, uv ve normal kanallarını zaten içerir — özel shader yazarken bu isimlere uymak en az sürtünmeyi verir. Tampon doldurma, güncelleme ve itemSize Attributes & buffer’lar konusundadır; shader tarafındaki eşleşme kuralı §4’te sabitlendi.

mesh.position veya mesh.rotation JavaScript nesne dönüşümüdür; shader’daki attribute vec3 position köşe tamponudur — ikisi farklı katmandadır. Model hareketini genelde uniform matrisler (modelMatrix, modelViewMatrix) taşır; köşe konumları geometri tamponunda kalır.

Varying sizin sorumluluğunuzda

Three.js, ShaderMaterial için otomatik vUv veya vNormal üretmez. Vertex ve fragment shader kaynaklarınızda aynı varying (veya WebGL2’de out / in) satırlarını siz yazarsınız; vertex’te atama, fragment’te okuma ( §5, §4 · vertex örneği). Enterpolasyon tamamen GPU pipeline’ında olur — JavaScript’te «varying güncelle» diye bir API yoktur.

onBeforeCompile

Mevcut MeshPhysicalMaterial gibi bir materyalin shader kaynağı derlenmeden hemen önce değiştirilmek istendiğinde material.onBeforeCompile = (shader) => { … } kullanılır. Küçük bir renk karışımı veya ek uniform eklemek için uygundur; callback içinde shader.uniforms.uMyEffect = { value: 1.0 }; yazılır ve GLSL parçası kaynağa enjekte edilir — shader’da yine uniform float uMyEffect; bildirimi gerekir. Varying veya attribute eklemediğiniz sürece Three.js mevcut köprüyü korur; yeni köprü kanalları yine sizin shader metninizde tanımlanmalıdır.

Tam ekran efekt, çok dosyalı GLSL veya sıfırdan pipeline için ayrı ShaderMaterial çoğu zaman daha okunaklıdır. İki yolu aynı projede karıştırırken uniform isimlerinin çakışmadığından emin olun.

Son hatırlatma: döngüdeki yerel let t = … veya const color = … değişkenleri GPU’ya otomatik gitmez — shader’a veri yalnızca material.uniforms, geometry.attributes ve kendi yazdığınız vertex/fragment çifti üzerinden akar. Karışıklık çoğu zaman «JS’te değişkeni güncelledim ama shader görmüyor» şikâyetinde ortaya çıkar ( §7).

Sık hatalar

Bu sayfa boyunca uniform, attribute ve varying ayrı ayrı tanıtıldı; sahada hata çoğu zaman «yanlış katmana veri koymak» veya «isim/tür sözleşmesini kırmak» şeklinde görünür. Bazıları derleme veya link aşamasında patlar; uniform ismi gibi bazıları ise programı çalıştırıp sessizce yanlış sonuç üretir ( §1 · sessiz hatalar). Aşağıdaki başlıklar teşhis sırasına yakın bir kontrol listesi sunar — her madde ilgili bölüme link verir, aynı metni tekrar etmez.

İsim uyumsuzluğu

Belirti: animasyon donuk, renk hep siyah veya varsayılan, doku görünmüyor — konsol bazen temiz. Tipik örnek: shader’da uniform float uTime;, JavaScript’te material.uniforms.time veya uTIME. WebGL eşleşmeyen ismi bağlamaz; değer sıfırda kalabilir. Büyük/küçük harf duyarlıdır; vertex ve fragment dosyaları da aynı yazımı ister.

Çözüm: materyal başına tek liste (uniform adları, attribute kanalları, varying çiftleri); shader ve uniforms sözlüğünde bire bir aynı string. onBeforeCompile içinde eklenen uniform’lar için hem shader.uniforms.uX hem GLSL bildirimi gerekir ( §6).

Varying tek tarafta veya tür uyumsuz

Belirti: program link hatası — «varying … not declared» benzeri mesajlar. Vertex’te varying vec2 vUv; varken fragment’te eksik satır veya vec3 yazmak en sık nedenlerdir. WebGL2’de out / in çiftinde de isim ve tür bire bir aynı olmalıdır ( §5 · çift bildirim).

Çözüm: iki shader dosyasını yan yana açın; varying listesini satır satır eşleştirin. Yeni kanal eklerken önce §1’deki üç soruyu sorun — gerçekten varying mi, yoksa uniform mu?

Attribute’u fragment’te kullanmak

Belirti: derleme hatası veya «uv undeclared» — fragment’te texture2D(uMap, uv) yazmak. uv yalnızca vertex shader girişidir ( §4). Doğru zincir: attribute vec2 uv → vertex’te vUv = uv → fragment’te texture2D(uMap, vUv).

İlgili karışıklık: zaman veya ışık rengini varying ile taşımaya çalışmak — çağrı boyunca sabit veriler uniform olmalıdır ( §1 · üç soru).

Tür ve boyut

Belirti: shader derlemesi reddedilir veya mesh garip deforme olur. Örnekler: uniform vec2’ye üç bileşen göndermek; shader’da vec3 + vec2 yazmak; tamponda itemSize: 2 iken attribute vec3 position; okumak. İlk ikisi Operators · hatalar ve Vec types · boyut konusundadır; üçüncüsü Attributes · itemSize ile §4’te özetlendi.

Çözüm: her kanal için «tampon kaç bileşen? shader hangi vecN? JS hangi sınıf?» üçlüsünü yazın; doku için sampler2D + Texture eşleşmesini §3 ile kontrol edin.

Güncelleme zamanı ve paylaşılan referans

Belirti: uniform «bir kare gecikmeli» veya iki materyal beklenmedik şekilde aynı rengi paylaşıyor. renderer.render çağrısından sonra yazılan uniforms.uTime.value çoğu zaman bir sonraki karede görünür ( §3 · güncelleme). İki ShaderMaterial aynı Vector3 veya Texture referansını paylaşıyorsa biri güncellendiğinde diğeri de değişir.

Çözüm: güncellemeyi render öncesine alın; paylaşım istemiyorsanız materyal başına { value: new THREE.Vector3() } veya dokunun kopyası. Yerel let değişkeni shader’a otomatik gitmez — veri yalnızca material.uniforms ve geometry attribute’ları üzerinden akar ( §6).

Hızlı teşhis sırası

Sorun çıktığında sırayla: (1) Konsolda derleme / link hatası var mı? (2) İsim listesi üç dosyada (JS, vertex, fragment) uyumlu mu? (3) Veri doğru katmanda mı — uniform / attribute / varying? (4) Tür ve itemSize eşleşiyor mu? (5) Uniform güncellemesi render öncesinde mi? Çoğu vaka bu beş adımda kapanır; kalan edge case’ler için GLSL giriş · depolama geniş tabloya bakın.

Holodepth notu

GLSL sözdizimi serisini bitirirken şu sırayı koruyun: tür ve paket (Vec types) → işlem (Operators) → yerleşik (Built-in) → veri köprüsü (bu sayfa). Yeni materyal yazarken önce kağıt üzerinde üç sütun çizin: uniform listesi, attribute listesi, varying listesi — sonra shader ve material.uniforms tarafını doldurun. §7’deki teşhis listesini projeye yapıştırıp ilk hatada işaretlemek, uzun debug oturumlarını kısaltır.