Z technicznego punktu widzenia fwidth(p)
jest zdefiniowany jako
fwidth(p) := abs(dFdx(p)) + abs(dFdy(p))
I dFdx(p)
/ dFdy(p)
są częściowymi pochodnymi wartości p
w odniesieniu do wymiarów x
i y
ekranu. Oznacza to więc, jak p
zachowuje się wartość parametru, gdy przesuwa się jeden piksel w prawo ( x
) lub jeden piksel w górę ( y
).
Jak można je praktycznie obliczyć? Cóż, jeśli znasz wartości sąsiednich pikseli p
, możesz po prostu obliczyć te pochodne jako bezpośrednie różnice skończone jako przybliżenie ich rzeczywistych pochodnych matematycznych (które mogą nie mieć w ogóle dokładnego rozwiązania analitycznego):
dFdx(p) := p(x+1) - p(x)
Ale oczywiście teraz możesz zapytać, skąd w ogóle znamy wartości p
(które mogą być dowolną dowolnie obliczoną wartością w programie modułu cieniującego) dla sąsiednich pikseli? Jak obliczyć te wartości bez ponoszenia dużego obciążenia, wykonując obliczenia całego modułu cieniującego dwa (lub trzy) razy?
Cóż, wiesz co, te sąsiednie wartości są i tak obliczane, ponieważ dla sąsiedniego piksela uruchamiasz również moduł cieniujący fragmenty. Tak więc wszystko, czego potrzebujesz, to dostęp do wywołania tego modułu cieniującego fragmenty przy uruchomieniu dla sąsiedniego piksela. Ale jest to jeszcze łatwiejsze, ponieważ te sąsiednie wartości są również obliczane dokładnie w tym samym czasie.
Nowoczesne rasteryzatory nazywają shadery fragmentów w większych kafelkach więcej niż jednego sąsiedniego piksela. W najmniejszym przypadku byłaby to siatka pikseli 2x2. I dla każdego takiego bloku pikseli wywoływany jest moduł cieniujący fragmenty dla każdego piksela, a te wywołania przebiegają w idealnie równoległym kroku blokowania, dzięki czemu wszystkie obliczenia są wykonywane w dokładnie tej samej kolejności i w tym samym czasie dla każdego z tych pikseli w bloku (dlatego też rozgałęzienie w module cieniującym fragmenty, chociaż nie jest zabójcze, należy unikać, jeśli to możliwe, ponieważ każde wywołanie bloku musiałoby zbadać każdą gałąź, która jest pobierana przez co najmniej jedno wywołanie, nawet jeśli po prostu wyrzuca) wyniki później, jak podano również w odpowiedziach na to powiązane pytanie). Tak więc w dowolnym momencie moduł cieniujący fragment teoretycznie ma dostęp do wartości modułu cieniującego fragmentu sąsiednich pikseli. A gdy nie mają bezpośredniego dostępu do tych wartości, masz dostęp do wartościami obliczonymi z nich, podobnie jak funkcje pochodnych dFdx
, dFdy
, fwidth
, ...
dFdx(p) = p(x1) - p(x)
, tox1
może być albo,(x+1)
albo(x-1)
, w zależności od pozycji pikselax
w kwadracie. Tak czy inaczej,x1
musi być w tej samej warp / wavefront cox
. Mam rację?