Cube-Map-Filterung, Image-based Lighting

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Cube-Map-Filterung, Image-based Lighting

Beitrag von Krishty »

Wir hatten hier mal einen Faden über Image-based Lighting, in dem eXile sich darüber aufgeregt hatte, dass Cube-Map-Generatoren zu viel Banding ausspucken. Ich habe das Thema aufgegriffen weil ich eine Pipeline für meine Projekte brauche, und schreibe deshalb gerade an einem kleinen (Compute Shader-beschleunigten) Tool, das es hoffentlich besser macht.

Hier ist jedenfalls ein Schnappschuss von meinem Test-Sample-Muster weil das ganz interessant aussieht:
14-02-06 sample pattern.png
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von Krishty »

… und hier haben wir direkt die erste Katastrophe: Die Kanten der Cube Map werden nicht richtig gefiltert. Filtermodus steht auf D3D11_TEXTURE_ADDRESS_CLAMP; ich sehe aber die Unterseite der Fläche durchschimmern. Wat do?
14-02-06 edge seam.png
Nachtrag: Die Fehler sind aber nicht durchgängig, sondern nur an zwei gegenüberliegenden Flächen. Ich werde nochmal prüfen ob ich nicht irgendwo beim GPU-Upload eine Pixelzeile in den Sand gesetzt habe.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von Krishty »

Um von hier weiterzumachen:
eXile hat geschrieben:
mOfl hat geschrieben:Runterzuladen ist das ganze hier: http://code.google.com/p/cubemapgen/dow ... en-1_5.zip. Auch für andere Cube-Map-Zwecke ist das Tool wirklich hilfreich.
Vielen Dank für den Link! Ich kannte zwar schon das Tool, wusste aber noch nicht, dass der Code veröffentlicht wurde.

Aber irgendwie ist das doch Mist: Ich habe die Powerlines-Cubemap genommen, und die mal durchgejagt. Das ist das Ergebnis:
Bild
Banding. Ja, Banding. Egal in welchem Format (8-bit RGBA, 8-bit RGB, 16-bit RGBA, float16 RGBA, float32 RGBA). Liegt also wohl nicht an deren Berechnung, sondern einfach nur daran, dass das am Ende in 8 Bit auf dem Monitor anzeigt wird / werden soll (die benachbarten Bänder unterschieden sich um genau 1 in genau einer Komponente). Kann irgendjemand Ratschläge liefern? Only Dithering for the win?
Ich gebe mal meinen Versuch zum Besten:
14-02-06 powerlines lightmap.png
Meine ist rechtshändig; kann sein, dass AMDs linkshändig ist. Jedenfalls: Warum sieht die nun anders aus? Ich habe durchweg mit 32-Bit-Gleitkommazahlen im linearen Farbraum gearbeitet. Für jeden Pixel wurden 2000 auf der Hemisphäre (nicht auf dem Würfel) gleichverteilte Punkte in Betracht gezogen und nach Kosinus gewichtet. Das Mip Mapping, das ich dabei benutzt habe, wurde ebenfalls linear durchgeführt. Auch das Dithering während der sRGB-Konvertierung fand im linearen Farbraum statt. Ideen?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von eXile »

Krishty hat geschrieben:Jedenfalls: Warum sieht die nun anders aus? Ich habe durchweg mit 32-Bit-Gleitkommazahlen im linearen Farbraum gearbeitet. Für jeden Pixel wurden 2000 auf der Hemisphäre (nicht auf dem Würfel) gleichverteilte Punkte in Betracht gezogen und nach Kosinus gewichtet. Das Mip Mapping, das ich dabei benutzt habe, wurde ebenfalls linear durchgeführt. Auch das Dithering während der sRGB-Konvertierung fand im linearen Farbraum statt. Ideen?
Ich hoffe ich kann diese Frage zum Teil beantworten. Ich habe damals nicht die Gamma-Einstellung überprüft, weil ich damals dachte, dass das industry-proven™ Tool es schon selbständig hinkriegt, dass beim Laden und Schreiben von PNGs korrekt zwischen den Farbräumen umgewandelt wird – da man ja nicht voraussetzen kann, dass jeder in dieser industry auch Farbräume versteht. Pustekuchen. Man muss den „Eingabe-“ und den „Ausgabe-Gamma“ manuell in der GUI setzen. Das habe ich damals nicht gemacht.

Überhaupt stellen sich ja da einem beim Begriff Gamma in diesem Zusammenhang die Nackenhaare auf. Es ist ja nur näherungsweise richtig, das durch eine Gamma-Kurve zu transformieren. Man braucht ja eigentlich die sRGB-Transformation, welche bekanntermaßen ein lineares Teilstück beinhaltet. So weit wollen wir aber mal bei einem industry-proven™ Tool nicht gehen.

Darüber hinaus enthielt die damals von mir verwendete Version dieses industry-proven™ Tools einen Bug:
http://code.google.com/p/cubemapgen/downloads/detail?name=ModifiedCubeMapGen-1_5.zip hat geschrieben:CubeMapGen-1_5 win32 release MT binaries (This version use incorrect cosine power filtering, use version above please)
Wie dem auch sei. Ich habe nun einfach mal zum Testen eine Cubemap gebaut, welche nur aus einem hochaufgelösten Schachbrettmuster auf allen Faces besteht.
  • Einstellungen 1:
    • Input Degamma: 1
    • RGB Output Gamma: 1
    • [x] Irradiance cubemap
    • Resultat: Alle Pixelwerte (127, 127, 127)
  • Einstellungen 2:
    • Input Degamma: 2.2
    • RGB Output Gamma: 2.2
    • [x] Irradiance cubemap
    • Resultat: Alle Pixelwerte (186, 186, 186)
Letzteres ist also ungefähr das, was man bei einer korrekten sRGB-Transformation (Nomenklatur von hier)\($$C_{srgb}\Big(0.5 \cdot \big(C_{linear}(0) + C_{linear}(1)\big)\Big) \cdot 255 \approx 187.51$$\)herausbekommt.

Zum Testen habe ich auch noch mal die Powerline-Cubemap von damals auf beiden Einstellungen durchgejagt.
  • Einstellungen 1:
    Bild
  • Einstellungen 2:
    Bild
Du kannst ja auch mal testen, was bei dir herauskommt, wenn du auf alle Faces beispielsweise ein 256×256 Schachbrettmuster legst.
Und da das alles so schön war, habe ich auch mal Floyd-Steinberg-Dithering am Ende im GIMP drüberlaufen lassen:
  • Einstellungen 1:
    Bild
  • Einstellungen 2:
    Bild
Zuletzt geändert von Krishty am 07.02.2014, 16:53, insgesamt 1-mal geändert.
Grund: Bilder aus dem Showroom ausgeschlossen
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von Krishty »

Danke für den Tipp mit dem Schachbrett – da hätte ich selber drauf kommen müssen!

Ich bin so weit, dass ich es auf die Kosinus-Normalisierung festnageln kann. Wenn ich das Kosinus über die Hemisphäre integriere, kommt ein Faktor != 1 heraus – darum ist meine Cube Map zu dunkel. Hat dieses Integral zufällig einen Namen?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von Krishty »

Okay; ich hab’s. Ich normalisiere nun nicht mehr über die Anzahl der Samples, sondern über die Summe aller Kosinuswerte. Damit erreiche ich quasi die gleiche Helligkeit wie das AMD-Tool (57 / 52 / 42 an der Oberkante der Z-Fläche; mit dem AMD-Tool sind es 57 / 53 / 43).

Aber ist diese Normalisierung nicht nur dafür da, den Wertebereich der Textur voll auszunutzen, und müsste beim Benutzen der Cube Map wieder herausgerechnet werden?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von Krishty »

So sieht die falsch gefilterte Cubemap aus:
14-02-07 cube mip 6.png
14-02-07 cube mip 6.png (2.42 KiB) 3757 mal betrachtet
Das ist aus meiner Datei extrahiert; ich kann noch nicht dafür bürgen dass die Daten auch exakt so auf der GPU landen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von CodingCat »

Krishty hat geschrieben:Okay; ich hab’s. Ich normalisiere nun nicht mehr über die Anzahl der Samples, sondern über die Summe aller Kosinuswerte. Damit erreiche ich quasi die gleiche Helligkeit wie das AMD-Tool (57 / 52 / 42 an der Oberkante der Z-Fläche; mit dem AMD-Tool sind es 57 / 53 / 43).

Aber ist diese Normalisierung nicht nur dafür da, den Wertebereich der Textur voll auszunutzen, und müsste beim Benutzen der Cube Map wieder herausgerechnet werden?
Die Summe der Kosinusgewichte ist in diesem Fall N/2, die Normierung entspricht also einer Multiplikation des arithmetischen Mittels mit 2, die wiederum richtig ist, aber die Erklärung dauert etwas länger:

Beginnen wir bei der Monte-Carlo-Integration, denn am Ende willst du ja diffuse Beleuchtung haben, was wiederum der Lösung folgendes Rendering-Integrals entspricht (Reflektanz r der Oberfläche konstanter Farbwert mit Komponenten zwischen 0 und 1, l einfallendes Licht):
\($$\int_\Omega{\frac{r}{\pi} l(\omega) \cos(\omega) d\omega}$$\)

Nun wollen wir das Integral durch Abtastung lösen. Dazu interpretieren wir das Integral um in die Berechnung eines (kontinuierlichen) Erwartungswertes. Dann ziehen wir mit einer bestimmten Wahrscheinlichkeitsdichte p "zufällig" N Richtungen. Mit steigendem N konvergiert nach dem Gesetz der großen Zahlen das Stichprobenmittel gegen den Erwartungswert:

\(\begin{align*}\int_\Omega{\frac{r}{\pi} l(\omega) \cos(\omega) d\omega} &= \int_\Omega{\frac{r}{\pi} l(\omega) \cos(\omega) \frac{p(\omega)}{p(\omega)} d\omega} \\
&= \operatorname{Erwartungswert}(\frac{r}{\pi} l(\omega) \cos(\omega) \frac{1}{p(\omega)}) \\
&\approx \operatorname{Stichprobenmittel} \\
&= \frac{1}{N} \sum_{\omega_i \in \Omega}^N {\frac{r}{\pi} l(\omega) \cos(\omega) \frac{1}{p(\omega)}}\end{align*}\)


Da wir hier die ganze Zeit von gleichverteilten Stichproben reden, ist p = konstant = 1/2pi. Es ergibt sich:

\($$\frac{1}{N} \sum_{\omega_i \in \Omega}^N {\frac{r}{\pi} l(\omega) \cos(\omega) \frac{1}{p(\omega)}} = \frac{1}{N} \sum_{\omega_i \in \Omega}^N {\frac{r}{\pi} l(\omega) \cos(\omega) \frac{1}{\frac{1}{2\pi}}} = \frac{1}{N} \sum_{\omega_i \in \Omega}^N {\frac{r}{\pi} l(\omega) \cos(\omega) 2\pi} = \frac{2}{N} \sum_{\omega_i \in \Omega}^N {r\ l(\omega) \cos(\omega)}$$\)

Zieht man nun die konstante Oberflächenreflektanz r raus, weil wir die später für jeden Oberflächenpunkt selbst bestimmen wollen, bleibt für die Einträge der gefilterten Cubemap:

\($$\frac{2}{N} \sum_{\omega_i \in \Omega}^N {l(\omega) \cos(\omega)}$$\)

Man beachte den Vorfaktor 2/N. Nun können wir uns anschauen, warum man diesen zufällig auch durch eine Normierung mit der Summe der Kosinusgewichte erhält:

\(\begin{align}\int_\Omega{\cos(\omega) d\omega} = \pi &= \frac{1}{N} \sum_{\omega_i \in \Omega}^N {\cos(\omega) \frac{1}{p(\omega)}} = \frac{1}{N} \sum_{\omega_i \in \Omega}^N {\cos(\omega) 2 \pi} \\
\pi &= 2 \pi \frac{1}{N} \sum_{\omega_i \in \Omega}^N {\cos(\omega)} \\
\frac{N}{2} &= \sum_{\omega_i \in \Omega}^N {\cos(\omega)}
\end{align}\)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von Krishty »

Zuerst einmal vielen vielen Danke für die Herleitung: Ich dachte, ich hätte an ganz anderer Stelle einen Fehler gemacht, dass ich alles mit 2 multiplizieren muss. Das beantwortet dann auch meinen Thread von vor fünf Jahren :)

Dieser Fehler wäre damit ausgeräumt; und ein anderer ebenfalls (Texturausmaße fest in einen Shader geschrieben). Dennoch bleibt das Problem mit den Ecken der Cube Map:
14-02-07 edge errors.png
Die Farbsäume habe ich absichtlich hinzugefügt; die hellen Streifen sind aber nicht beabsichtigt. Ich versuche immernoch meine Texel zu prüfen, aber PIX mag mich nicht … :-(

Nachtrag: Es wird noch „besser“, wenn ich anisotrop filtere statt via SampleLevel():
bösequads.png
bösequads.png (8.45 KiB) 3630 mal betrachtet
So hatte ich die Textur in den Ecken aber nicht bestellt! Die Quads flimmern bei Bewegung auch wie Sau …

Noch einer: Wie gut funktioniert Texture Cube Filtering bei AMD? So gut:
14-02-07 cubemap anisotropic with LOD bias.png
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von eXile »

Ich dachte, man muss bei Monte-Carlo-Integration immer mit dem Volumen \($V$\) des Integrationsgebietes multiplizieren. D.h. man kriegt sofort für sämtliche BRDFs:\($$\begin{align}L_o(\boldsymbol{x},\boldsymbol{\omega_o})=&\int_{\Omega}f(\boldsymbol{x},\boldsymbol{\omega_i},\boldsymbol{\omega_o})\cdot L_{i}(\boldsymbol{x},\boldsymbol{\omega_i})\cdot\cos(\vartheta_{i})\,\mathrm{d}\boldsymbol{\omega_i}\\=&\lim_{N\to\infty}2\pi\cdot\frac{1}{N}\sum_{k=1}^{N}f(\boldsymbol{x},\boldsymbol{\omega_i}^{(k)},\boldsymbol{\omega_o})\cdot L_{i}(\boldsymbol{x},\boldsymbol{\omega_i}^{(k)})\cdot\boldsymbol{n}^{*}\boldsymbol{\omega_i}^{(k)}\end{align}$$\)Das „Volumen“ ist hier halt der Oberflächeninhalt einer Halbkugel, und das sind \($2\pi$\). Wir können im Folgenden das \($\boldsymbol{x}$\) komplett ignorieren, und einfach \($L_o(\boldsymbol{\omega_o})$\), \($f(\boldsymbol{\omega_i}, \boldsymbol{\omega_o})$\) und \($L_i(\boldsymbol{\omega_i})$\) wie bei Cat schreiben. Das ist auch absolut korrekt so, aber weil ich jetzt nicht alle meine Formeln ändern wollte, und das so näher an der Renderinggleichung bleibt, habe ich das mal dringelassen. Das \($\boldsymbol{x}$\) ist dann halt der Punkt, an der die Cubemap berechnet wird. Der ist logischerweise als Mittelpunkt der Cubemap konstant und spielt für die Berechnung keine Rolle. Auch ist bei mir \(${}^*$\) immer das Skalarprodukt.

Für eine diffuse BRDF \($$\begin{align}f(\boldsymbol{x},\boldsymbol{\omega_i},\boldsymbol{\omega_o})&=\frac{1}{\pi}\end{align}$$\)kriegt man das Gleiche was Cat bereits so schön vorgerechnet hat: \($$\begin{align}L_{o}(\boldsymbol{x},\boldsymbol{\omega_o})=&\int_{\Omega}\frac{1}{\pi}\cdot L_{i}(\boldsymbol{x},\boldsymbol{\omega_i})\cdot\cos(\vartheta_{i})\,\mathrm{d}\boldsymbol{\omega_i}\\=&\lim_{N\to\infty}2\pi\cdot\frac{1}{N}\sum_{k=1}^{N}\frac{1}{\pi}\cdot L_{i}(\boldsymbol{x},\boldsymbol{\omega_i}^{(k)})\cdot\cos(\vartheta_{i}^{(k)})\\=&\lim_{N\to\infty}\frac{2}{N}\sum_{k=1}^{N}L_{i}(\boldsymbol{x},\boldsymbol{\omega_i}^{(k)})\cdot\cos(\vartheta_{i}^{(k)})\\\Rightarrow L_{o}(\boldsymbol{\omega_o})\approx&\frac{2}{N}\sum_{k=1}^{N}L_{i}(\boldsymbol{\omega_i}^{(k)})\cdot\cos(\vartheta_{i}^{(k)})\end{align}$$\)Dabei sind \($\boldsymbol{\omega_i}^{(1)}$\), \($\boldsymbol{\omega_i}^{(2)}$\), ..., \($\boldsymbol{\omega_i}^{(N)}$\) der erste, zweite, ..., \($N$\)-te gesampelte Winkel bei der Monte-Carlo-Integration, und \($\vartheta_i^{(1)}$\), \($\vartheta_i^{(2)}$\), ..., \($\vartheta_i^{(N)}$\) die \($\vartheta$\)-Komponente desselben.

Wir haben also nun behandelt, was der Irradiance-Modus von CubeMapGen ausrechnet. Bleibt noch der Blinn-Phong-Modus. Im Blinn-Phong-Modus von CubeMapGen sollte der die Blinn-Phong-Formel \($$f(\boldsymbol{x},\boldsymbol{\omega_i},\boldsymbol{\omega_o})=\frac{\big(\boldsymbol{h}(\boldsymbol{\omega_i},\boldsymbol{\omega_o})^{*}\boldsymbol{\omega_i}\big)^{m}}{\boldsymbol{n}^{*}\boldsymbol{\omega_i}}\text{ mit }\boldsymbol{h}(\boldsymbol{\omega_i},\boldsymbol{\omega_o})=\frac{\boldsymbol{\omega_i}+\boldsymbol{\omega_o}}{\|\boldsymbol{\omega_i}+\boldsymbol{\omega_o}\|_{2}}$$\) nehmen (wobei \($\boldsymbol{h}$\) der Half-Way-Vektor ist). Dann können wir auch mal ausrechnen, was bei der Monte-Carlo-Integration berechnet werden sollte: \($$\begin{align}L_{o}(\boldsymbol{x},\boldsymbol{\omega_o})=&\int_{\Omega}f(\boldsymbol{x},\boldsymbol{\omega_i},\boldsymbol{\omega_o})\cdot L_{i}(\boldsymbol{x},\boldsymbol{\omega_i})\cdot\cos(\vartheta_{i})\,\mathrm{d}\boldsymbol{\omega_i}\\=&\int_{\Omega}\big(\boldsymbol{h}(\boldsymbol{\omega_i},\boldsymbol{\omega_o})^{*}\boldsymbol{\omega_i}\Big)^{\! m}\!\!\cdot L_{i}(\boldsymbol{x},\boldsymbol{\omega_i})\,\mathrm{d}\boldsymbol{\omega_i}\\=&\lim_{N\to\infty}2\pi\cdot\frac{1}{N}\sum_{k=1}^{N}\bigg(\boldsymbol{h}(\boldsymbol{\omega_i},\boldsymbol{\omega_o})^{*}\boldsymbol{\omega_i}^{(k)}\bigg)^{\!\! m}\!\!\cdot L_{i}(\boldsymbol{x},\boldsymbol{\omega_i}^{(k)})\\=&\lim_{N\to\infty}\frac{2\pi}{N}\sum_{k=1}^{N}\bigg(\!\Big(\!\frac{\boldsymbol{\omega_i}^{(k)}+\boldsymbol{\omega_o}}{\|\boldsymbol{\omega_i}^{(k)}+\boldsymbol{\omega_o}\|_{2}}\!\Big)^{*}\boldsymbol{\omega_i}^{(k)}\bigg)^{\!\! m}\!\!\cdot L_{i}(\boldsymbol{x},\boldsymbol{\omega_i}^{(k)})\\\Rightarrow L_{o}(\boldsymbol{\omega_{o}})\approx&\frac{2\pi}{N}\sum_{k=1}^{N}\bigg(\!\Big(\!\frac{\boldsymbol{\omega_i}^{(k)}+\boldsymbol{\omega_o}}{\|\boldsymbol{\omega_i}^{(k)}+\boldsymbol{\omega_o}\|_{2}}\!\Big)^{*}\boldsymbol{\omega_i}^{(k)}\bigg)^{\!\! m}\!\!\cdot L_{i}(\boldsymbol{\omega_i}^{(k)})\end{align}$$\)Zur mathematischen Aufheiterung: Und das Cubemap-Filtering oben ist ja schrecklich. :(
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von CodingCat »

eXile hat geschrieben:Ich dachte, man muss bei Monte-Carlo-Integration immer mit dem Volumen \($V$\) des Integrationsgebietes multiplizieren.
Sicher, aber wo wir schonmal dabei waren, sagt obige Herleitung hoffentlich mehr als "man muss". ;) Insbesondere sollte sie plausibel machen, wie/warum Monte Carlo Integration überhaupt funktioniert. Außerdem ergibt sich aus der darin frei wählbar eingeführten Sample-Wahrscheinlichkeitsdichte p ganz nebenbei auch noch gleich, wie und warum Importance Sampling funktioniert (salopp die bevorzugte Abtastung wichtiger Lichtrichtungen), inklusive der notwendigen Formelanpassungen bei nicht gleichmäßig verteilten Abtastrichtungen.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von Krishty »

SampleGrad(uvw, 16 * ddx(uvw), 16 * ddy(uvw))
14-02-08 ddx ddy 16.png
wat

uvw = normalize(uvw);
SampleGrad(uvw, 16 * ddx(uvw), 16 * ddy(uvw))

14-02-08 ddx ddy normalize.png
14-02-08 ddx ddy normalize.png (44.23 KiB) 3566 mal betrachtet
WTF

uvw = uvw / max(abs(uvw.x), max(abs(uvw.y), abs(uvw.z)));
SampleGrad(uvw, 16 * ddx(uvw), 16 * ddy(uvw))
14-02-08 ddx ddy max3.png
ARE YOU KIDDING ME

Heute abend wird ein anderer AMD-Treiber ausprobiert
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von CodingCat »

Achtung: Es ist anzunehmen, dass du ALLE Parameter skalieren musst, wenn du so das Mip-Level beinflussen willst. So stimmen die Koordinatensysteme der Richtung und der Ableitungen nicht mehr überein (irgendwie muss am Ende die Ableitung ja mit der übergebenen Richtung verrechnet werden!). Das ist eine Besonderheit von Cubemaps, weil dort noch eine Projektion vor dem eigentlichen Lookup erfolgt, die sich auch auf die Ableitungen auswirken muss (der Betrag des Vektors ist in diesem Fall nur für die zentrale Texturkoordinate irrelevant).
Zuletzt geändert von CodingCat am 09.02.2014, 14:13, insgesamt 1-mal geändert.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von Krishty »

Erstmal: Nvidia liefert hier völlig unterschiedliche Ergebnisse, die deutlich korrekter aussehen, aber leider auch starke Artefakte an den Kanten aufweisen. Ich habe dummerweise vergessen, Schnappschüsse zu machen; die werde ich später nachreichen.
CodingCat hat geschrieben:Achtung: Es ist anzunehmen, dass du ALLE Parameter skalieren musst, wenn du so das Mip-Level beinflussen willst. Andernfalls stimmen die Koordinatensysteme der Richtung und der Ableitungen nicht mehr überein (irgendwie muss am Ende die Ableitung ja mit der übergebenen Richtung verrechnet werden!). Das ist eine Besonderheit von Cubemaps, weil dort noch eine Projektion vor dem eigentlichen Lookup erfolgt, die sich auch auf die Ableitungen auswirken muss (der Betrag des Vektors ist in diesem Fall nur für die zentrale Texturkoordinate irrelevant).
Wartewarte, das verstehe ich nicht: Wenn ich die Koordinate mit dem selben Faktor skaliere wie die Gradienten (auf AMD wieder mit fehlerhafter Darstellung), dann wird überhaupt nicht skaliert. Das sieht mir danach aus, dass die XYZ-zu-Cube-Umrechnung (1 / max3(coord)) auf den Gradienten exakt wiederholt wird. Ist das nicht sinnfrei? Man muss doch den Sample-Verlauf in 3d ausrechnen und die Samples dann einzeln mit möglicherweise unterschiedlichen Regeln projezieren, weil sie auf unterschiedlichen Flächen liegen …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Cube-Map-Filterung, Image-based Lighting

Beitrag von Krishty »

Weil ich gefragt wurde, ob SampleBias() eine Alternative wäre:

Laut MSDN erlaubt SampleBias() nur eine Verschiebung des Mip-Levels um 0…1, was für mich deutlich zu wenig ist. Der Wert wird aber nicht geclampt und man kann frei und froh höhere Werte übergeben – das sieht dann aber dummerweise so aus (6.0f):
14-02-09 SampleBias 6.png
Dieses Auffächern sieht aber genau so aus wie die sinnlosen ddx()- / ddy()-Werte, die AMD ausspuckt. Es könnte gut sein, dass es auf Nvidia fehlerfrei funktioniert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Showroom - Aktuelle Arbeiten und Projekte

Beitrag von CodingCat »

Krishty hat geschrieben:Das sieht mir danach aus, dass die XYZ-zu-Cube-Umrechnung (1 / max3(coord)) auf den Gradienten exakt wiederholt wird. Ist das nicht sinnfrei? Man muss doch den Sample-Verlauf in 3d ausrechnen und die Samples dann einzeln mit möglicherweise unterschiedlichen Regeln projezieren, weil sie auf unterschiedlichen Flächen liegen …
Nein, das stimmt schon, hatte ich übersehen. Wenn man alles durchmultipliziert, kommt natürlich wieder exakt das Gleiche heraus, weil die skalierten Derivatives wieder die gleiche Richtungsänderung bewirken. Das führt mich nun aber zu dem Verdacht, dass du tatsächlich die Richtungsänderung manipulieren musst, d.h. die Richtungsänderung aus den Derivatives berechnen und dann den Winkel vervielfachen.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Cube-Map-Filterung, Image-based Lighting

Beitrag von Krishty »

Ich werde das heute abend probieren, sobald ich wieder an der Nvidia-Karte sitze. Dann prüfe ich auch als Erstes, ob SampleGrad(ddx, ddy) das gleiche Ergebnis liefert wie der eingebaute anisotrope Filter.

Ich spiele die ganze Zeit mit der Notlösung, SampleLevel() einzusetzen (weil es als einziges zuverlässig funktioniert) und das Mip-Level mit der Entfernung anzupassen. Damit ich nicht wieder von Hand mit ddx / ddy hantieren muss, wollte ich TextureCube.CalculateLevelOfDetailUnclamped() nutzen (kein D3D 10.0, yay). Hier ist das Mip-Level, das ich vorgeschlagen kriege (Radeon HD 4000):
14-02-09 CalculateLevelOfDetailUnclamped.png
Beachtet bitte die Artefakte an der Kante oben rechts, die Sprünge über die Kanten, und dass der Blickwinkel fast garnicht in das Ergebnis einfließt (flache Flächen flimmern furchtbar).

Und falls ihr meint, dass ich hier wieder nur Erbsen zähle, hier die Wirkung unter Einsatzbedingungen:
14-02-09 CalculateLevelOfDetailUnclamped error.png
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8239
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Cube-Map-Filterung, Image-based Lighting

Beitrag von Krishty »

SampleGrad(ddx(), ddy()) auf GeForce GTX 650 (ohne Skalierung):
14-02-09 SampleGrad ddx ddy GeForce GTX 650.png
14-02-09 SampleGrad ddx ddy GeForce GTX 650.png (95.02 KiB) 2294 mal betrachtet
Das ist zumindest nicht so offensichtlich kaputt wie das AMD-Ergebnis, aber … keine anisotrope Filterung (trotz 16-fach im Sampler); keine Filterung über Kanten hinweg; flimmern. Mistmistmistmist :(

Und hier CalculateLevelOfDetailUnclamped():
14-02-09 CalculateLevelOfDetailUnclamped.png
Besser als bei AMD, aber immernoch unbrauchbar. Und es ist nicht anisotrop. Wenn man den Vorschlag auf doppeltes Detail hochdreht kommt man gerade dahin dass es scharf ist, ziemlich flimmert, und die Kanten kaum auffallen. Produktionstauglich ist das aber nicht.

Was soll ich jetzt machen um Cubemaps pro Pixel unterschiedliches LOD zu verleihen? Anisotrope Filterung und Projektion im Shader selberschreiben? AMD abfackeln? Aufgeben?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten