Ganz technisch fwidth(p)
ist definiert als
fwidth(p) := abs(dFdx(p)) + abs(dFdy(p))
Und dFdx(p)
/ dFdy(p)
sind die partiellen Ableitungen des Wertes p
in Bezug auf die x
und y
Bildschirmabmessungen. Sie geben an, wie sich der Wert von p
verhält, wenn ein Pixel nach rechts ( x
) oder ein Pixel nach oben ( y
) verschoben wird .
Wie können sie nun praktisch berechnet werden? Nun, wenn Sie die Werte der Nachbarpixel kennen p
, können Sie diese Ableitungen einfach als direkte endliche Differenzen berechnen, als Näherung für ihre tatsächlichen mathematischen Ableitungen (die möglicherweise überhaupt keine exakte analytische Lösung haben):
dFdx(p) := p(x+1) - p(x)
Aber jetzt fragen Sie sich vielleicht, woher wir überhaupt die Werte von p
(die im Shader-Programm auch willkürlich berechnet werden können) für die benachbarten Pixel kennen. Wie berechnen wir diese Werte, ohne dass ein erheblicher Overhead entsteht, indem wir die gesamte Shader-Berechnung zwei (oder drei) Mal durchführen?
Weißt du was? Diese Nachbarwerte werden sowieso berechnet, da für das Nachbarpixel auch ein Fragment-Shader ausgeführt wird. Alles, was Sie benötigen, ist der Zugriff auf diesen benachbarten Fragment-Shader-Aufruf, wenn er für das benachbarte Pixel ausgeführt wird. Aber es ist noch einfacher, weil diese Nachbarwerte genau zur gleichen Zeit berechnet werden.
Moderne Rasterizer bezeichnen Fragment-Shader in größeren Kacheln mit mehr als einem benachbarten Pixel. Im kleinsten Fall wäre dies ein 2 × 2-Pixelraster. Und für jeden solchen Pixelblock wird der Fragment-Shader für jedes Pixel aufgerufen, und diese Aufrufe werden in perfekt parallelen Verriegelungsschritten ausgeführt, so dass alle Berechnungen für jedes dieser Pixel im Block in genau derselben Reihenfolge und genau zur gleichen Zeit ausgeführt werden (Das ist auch der Grund, warum Verzweigungen im Fragment-Shader vermieden werden sollten, auch wenn sie nicht tödlich sind, da jeder Aufruf eines Blocks jeden Zweig untersuchen müsste, den mindestens einer der Aufrufe einnimmt, selbst wenn er nur wegwirft die Ergebnisse danach, wie auch in den Antworten auf diese verwandte Frage angesprochen). Ein Fragment-Shader kann also theoretisch jederzeit auf die Fragment-Shader-Werte seiner Nachbarpixel zugreifen. Und während Sie keinen direkten Zugriff auf diese Werte verfügen, haben Sie Zugriff auf Werte von ihnen berechnet, wie die Ableitungsfunktionen dFdx
, dFdy
, fwidth
, ...
dFdx(p) = p(x1) - p(x)
, dannx1
kann das entweder sein(x+1)
oder(x-1)
, je nach Position des Pixelsx
im Quad. In beiden Fällenx1
muss sich die Wellenfront in derselben Verzerrung wie befindenx
. Hab ich recht?