The Book of Shaders by Patricio Gonzalez Vivo & Jen Lowe

Українська - Bahasa Indonesia - Tiếng Việt - 日本語 - 中文版 - 한국어 - Español - Portugues - Français - Italiano - Deutsch - Русский - Polski - Türkçe - English


Uniform'lar

Şimdiye kadar GPU'nun, her biri görüntünün toplamının bir kısmına renk atamaktan sorumlu olan çok sayıda paralel iş parçacığını nasıl yönettiğini gördük. Her paralel iş parçacığı diğerlerine kör olsa da, CPU'dan tüm iş parçacıklarına bazı girdiler gönderebilmemiz gerekir. Grafik kartının mimarisi nedeniyle bu girdiler tüm iş parçacıkları için eşit (uniform) olacak ve zorunlu olarak salt okunur (read only) olarak ayarlanacaktır. Başka bir deyişle, her iş parçacığı okuyabileceği ancak değiştiremeyeceği aynı verileri alır.

Bu girdilere uniform denir ve desteklenen çoğu türde gelirler: float, vec2, vec3, vec4, mat2, mat3, mat4, sampler2D ve samplerCube. Uniform'lar, varsayılan kayan nokta hassasiyetini atadıktan hemen sonra shader'ın en üstünde ilgili türle tanımlanır.

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;  // Tuval boyutu (genişlik,yükseklik)
uniform vec2 u_mouse;       // ekran piksellerinde fare konumu
uniform float u_time;       // Yüklemeden bu yana saniye cinsinden süre

Uniform'ları CPU ve GPU arasındaki küçük köprüler gibi hayal edebilirsiniz. İsimler uygulamadan uygulamaya değişecektir ancak bu örnek serisinde her zaman şunları iletiyorum: u_time (shader başladığından beri saniye cinsinden süre), u_resolution (shader'ın çizildiği pano boyutu) ve u_mouse (pano içindeki fare konumu piksel cinsinden). Bu değişkenin doğası hakkında açık olmak için uniform adından önce u_ koyma kuralını izliyorum, ancak her türlü uniform adı bulacaksınız. Örneğin ShaderToy.com aynı uniform'ları kullanır ancak şu isimlerle:

uniform vec3 iResolution;   // görüntü alanı çözünürlüğü (piksel cinsinden)
uniform vec4 iMouse;        // fare piksel koordinatları. xy: geçerli, zw: tıklama
uniform float iTime;        // shader oynatma süresi (saniye cinsinden)

Yeterince konuştuk, uniform'ları eylem halinde görelim. Aşağıdaki kodda, panodaki kırmızı miktarının geçişini canlandırmak için bir sinüs fonksiyonuyla birlikte u_time'ı - shader çalışmaya başladığından beri geçen saniye sayısını - kullanıyoruz.

Gördüğünüz gibi GLSL'in daha fazla sürprizi var. GPU, donanım hızlandırmalı açı, trigonometrik ve üstel fonksiyonlara sahiptir. Bu fonksiyonlardan bazıları şunlardır: sin(), cos(), tan(), asin(), acos(), atan(), pow(), exp(), log(), sqrt(), abs(), sign(), floor(), ceil(), fract(), mod(), min(), max() ve clamp().

Şimdi yukarıdaki kodla oynama zamanı.

gl_FragCoord

GLSL'in bize varsayılan bir çıktı olan vec4 gl_FragColor'ı vermesi gibi, bize varsayılan bir girdi olan vec4 gl_FragCoord'ı da verir; bu, aktif iş parçacığının üzerinde çalıştığı pikselin veya ekran parçasının ekran koordinatlarını tutar. vec4 gl_FragCoord ile bir iş parçacığının panonun neresinde çalıştığını biliriz. Bu durumda buna uniform demiyoruz çünkü iş parçacığından iş parçacığına farklı olacaktır, bunun yerine gl_FragCoord'a varying (değişen) denir.

Yukarıdaki kodda, parçanın koordinatını panonun toplam çözünürlüğüne bölerek normalize ediyoruz. Bunu yaparak değerler 0.0 ve 1.0 arasına gelecektir, bu da X ve Y değerlerini KIRMIZI ve YEŞİL kanala eşlemeyi kolaylaştırır.

Shader diyarında, değişkenlere güçlü renkler atamak ve onlardan bir anlam çıkarmaya çalışmak dışında hata ayıklama (debugging) için çok fazla kaynağımız yoktur. Bazen GLSL'de kodlamanın şişelerin içine gemi koymaya çok benzediğini keşfedeceksiniz. Aynı derecede zor, güzel ve tatmin edicidir.

Şimdi bu kod hakkındaki anlayışımızı deneme ve zorlama zamanı.

Bu alıştırmaları yaptıktan sonra yeni shader güçlerinizi başka nerede deneyebileceğinizi merak edebilirsiniz. Sonraki bölümde three.js, Processing ve openFrameworks'te kendi shader araçlarınızı nasıl yapacağınızı göreceğiz.