[PYTHON] Berühren Sie den neuesten physikbasierten Renderer Mitsuba2 (3) Differenzierbares Rendering

Was ist Mitsuba2?

Ein kostenloser physikbasierter Renderer für Akademiker. Es gibt neue Funktionen wie differenzierbares Rendering und polarisiertes Rendering. Andere verwandte Artikel, die ich geschrieben habe, sind wie folgt.

Es wird davon ausgegangen, dass Mitsuba2 installiert wurde.

Was ist differenzierbares Rendern?

Es ist ein Rendering, das differenzielle Informationen so weitergeben kann, wie sie sind. Wenn der Rendering-Algorithmus die Funktion $ f (x) $ ist, die Eingabeszene $ x $ ist und das Rendering-Ergebnis $ y $ ist, gilt Folgendes.

y = f(x)

In einem teilbaren Renderer wird diese Funktion $ f $ differenziert, um $ \ frac {dy} {dx} $ zu erhalten. So ändern Sie $ x $, um das gewünschte Rendering-Ergebnis $ y $ zu erhalten Sie werden automatisch gefragt, was zu tun ist. Dies bedeutet, dass Sie das komplizierte umgekehrte Problem in CG lösen können, dh das inverse Rendering, das in der Vergangenheit schwierig war.

autodiff.jpg

Trotzdem denke ich, dass es schwierig ist, sich sofort vorzustellen, was man damit machen kann, also werde ich es anhand eines konkreten Beispiels erklären.

Verdichtungsdesign

Betrachten Sie ein Beispiel für die Projektion von RGB-Licht durch eine Glasscheibe auf eine Wand. Es ist ein Bild von Sandwichglas zwischen Projektor und Wand. caustic.jpg

Geben Sie zu diesem Zeitpunkt das Bild, das Sie projizieren möchten, im Voraus als $ y $ an. Dann wird die feine Form (Höhenprofil) $ x $ der Glasscheibe, die die Brechung realisiert, um das gewünschte Bild (Zielbild) $ y $ zu erhalten, automatisch durch die Gradientenmethode (SGD, Adam usw.) optimiert. Ich kann. In der Vergangenheit mussten solche Probleme heuristisch optimiert werden, indem die Schleife des optischen Systemdesigns → Auswertung → Rückmeldung gedreht oder eine spezielle optische Software mit verschiedenen Einschränkungen verwendet wurde. Mit diesem Framework können Sie einfach und universell optimieren.

Reflexionsoptimierung

Das Reflexionsvermögen des Objekts (BSDF-Parameter) kann ebenfalls optimiert werden, um das gewünschte Bild zu erreichen. Die folgende Abbildung zeigt, wie das Reflexionsvermögen der linken Wand, die ein Parameter der Szene ist, mit dem Bild ganz rechts als Zielbild $ y $ optimiert wird. inv_render0.jpg

Rot ist der wahre Wert an der linken Wand, aber Sie können sehen, dass selbst wenn Sie das Reflexionsvermögen mit einem geeigneten Wert initialisieren, es schließlich zum wahren Wert konvergiert (das Bild ist grob, weil die Anzahl der Proben gering ist). Wenn Sie jedes Mal genug Samples erstellen, wird für das differenzierbare Rendern viel Rechenzeit benötigt, sodass Sie die Anzahl der Samples während der Optimierung nicht wesentlich erhöhen. Eine solche automatische Optimierung des Reflexionsvermögens und der BSDF-Parameter war aufgrund der Auswirkungen der gegenseitigen Reflexion traditionell ein sehr schwieriges Problem. In der vorhandenen Forschung habe ich es also geschafft, es durch Hinzufügen einer großen Einschränkung zu lösen, aber in der differenzierbaren Darstellung kann es direkt mit der einfachen Methode gelöst werden.

Lichtquellenoptimierung

Das Reflexionsvermögen von Objekten und BSDF-Parametern ist für jedes Basisobjekt einheitlich, und die Anzahl der Parameter ist gering, so dass dies als einfaches Problem angesehen werden kann. Das differenzierbare Rendering von Mitsuba2 kann nicht nur einzelne Skalarwerte wie das Reflexionsvermögen, sondern auch hochdimensionale Daten wie die Umgebungslichtkarte automatisch optimieren. Die folgende Abbildung ist ein Beispiel für die Konvergenz zum wahren Wert, selbst wenn die Lichtquelle ordnungsgemäß initialisiert wurde. inv_render1.jpg

Oben ist die Umgebungslichtquellenkarte $ x $ und unten das Rendering-Ergebnis. Sie können sehen, dass sich die Lichtquellenkarte, die anfangs einheitlich und reinweiß war, ändert und sich das gerenderte Ergebnis dem Zielbild $ y $ nähert. Es wird nur ein Bildbeispiel angegeben, was bedeutet, dass dieselbe geeignete Lichtquelle ohne die Einstellung des Erstellers automatisch eingestellt werden kann.

Grundsätzlich können Volumen und Form automatisch optimiert werden. Die Form usw. wurde jedoch noch nicht implementiert. Laut dem Autor wird es bald implementiert (https://github.com/mitsuba-renderer/mitsuba2/issues/26). Ich denke, Sie sollten GitHub häufig überprüfen.

Verschieben Sie differenzierbares Rendering

Die Formel hat den Beispielcode zur Optimierung des Reflexionsvermögens und der im obigen Beispiel erwähnten Lichtquelle vorbereitet. Verschieben wir ihn also.

Wie ich in Einführung geschrieben habe, ist eine GPU-Umgebung erforderlich, um ein differenzielles Rendern durchzuführen. Außerdem muss die in "mistuba.conf" angegebene Variante mindestens eine teilbare Konfiguration enthalten. Zunächst denke ich, dass "gpu_autodiff_rgb" in Ordnung ist.

Im Folgenden wird die Vorgehensweise für Windows beschrieben. Ich denke, dass es für Linux fast dasselbe ist. GPU-Rendering funktioniert unter MacOS nicht. Übergeben Sie wie Von Python verschieben zuerst den PATH an das Mitsuba-Modul im Stammverzeichnis und wechseln Sie dann zum Beispielcode von docs \ examples \ 10_inverse_rendering \ Bewegung

mitsuba2> setpath.bat
mitsuba2> cd docs\examples\10_inverse_rendering\
mitsuba2\docs\examples\10_inverse_rendering>

Reflexionsoptimierung

Versuchen wir zunächst, das Reflexionsvermögen zu optimieren. Bringen Sie die Daten zur Arbeit.

git clone https://github.com/mitsuba-renderer/mitsuba-data.git

Wie bereits erwähnt, setzen Sie bitte die cbox der oben genannten Daten für jedes Verzeichnis unter "10_inverse_rendering". Wenn Sie Folgendes ausführen und Bilder nacheinander generiert werden, ist dies erfolgreich.

python invert_cbox.py

Ich werde den Inhalt des Codes erklären. Ich habe einen Kommentar auf Japanisch hinzugefügt.

#Einfaches Reverse-Rendering-Beispiel: Rendern Sie das Zielbild der Cornell Box.
#Optimieren Sie einen der Szenenparameter (Reflexionsvermögen der linken Wand) mithilfe von teilbarem Rendering und gradientenbasierter Optimierung

import enoki as ek
import mitsuba
mitsuba.set_variant('gpu_autodiff_rgb')

from mitsuba.core import Thread, Color3f
from mitsuba.core.xml import load_file
from mitsuba.python.util import traverse
from mitsuba.python.autodiff import render, write_bitmap, Adam
import time

#Laden Sie die Cornell Box
Thread.thread().file_resolver().append('cbox')
scene = load_file('cbox/cbox.xml')

#Finden Sie differenzierbare Szenenparameter
params = traverse(scene)

#Verwerfen Sie alle Parameter außer dem, den Sie unterscheiden möchten
params.keep(['red.reflectance.value'])

#Drucken Sie den aktuellen Wert und erstellen Sie ein Backup
param_ref = Color3f(params['red.reflectance.value'])
print(param_ref)

#Rendern Sie das Zielbild (verwenden Sie noch keine Derivate).
image_ref = render(scene, spp=8)
crop_size = scene.sensors()[0].film().crop_size()
write_bitmap('out_ref.png', image_ref, crop_size)

#Ändern Sie die linke Wand in Weiß (Standard)
params['red.reflectance.value'] = [.9, .9, .9]
params.update()

#Wählen Sie Adam als Methode zur Parameteroptimierung
opt = Adam(params, lr=.2)

time_a = time.time()

#Anzahl der Iterationen
iterations = 100

for it in range(iterations):
    #Führen Sie ein differenzierbares Rendern der Szene durch
    image = render(scene, optimizer=opt, unbiased=True, spp=1)
    write_bitmap('out_%03i.png' % it, image, crop_size)

    #Verlust nehmen (MSE zwischen gerendertem Bild und Zielbild)
    ob_val = ek.hsum(ek.sqr(image - image_ref)) / len(image)

    #Setzen Sie den Fehler auf den Eingabeparameter zurück
    ek.backward(ob_val)

    #Führen Sie Verlaufsschritte durch
    opt.step()

    #Gibt das Ergebnis des Vergleichs des Reflexionsvermögens mit dem Wert der Grundwahrheit aus
    err_ref = ek.hsum(ek.sqr(param_ref - params['red.reflectance.value']))
    print('Iteration %03i: error=%g' % (it, err_ref[0]), end='\r')

time_b = time.time()

#Geben Sie die durchschnittliche Berechnungszeit für jede Iteration aus
print()
print('%f ms per iteration' % (((time_b - time_a) * 1000) / iterations))

Lichtquellenoptimierung

Optimieren Sie als Nächstes die Lichtquellenkarte. Laden Sie die Beispieldaten hier herunter und entpacken Sie sie (http://mitsuba-renderer.org/scenes/bunny.zip). Es ist ein Metallhase, der von einer musealen Umgebung umgeben ist, und ich denke, er enthält Netzdateien und Szenenbeschreibungsdateien.

Gehen Sie wie folgt vor, um die Lichtquelle zu optimieren.

python invert_bunny.py

Ich werde auch den Inhalt des Codes mit Kommentaren erklären.

import enoki as ek
import mitsuba
mitsuba.set_variant('gpu_autodiff_rgb')

from mitsuba.core import Float, Thread
from mitsuba.core.xml import load_file
from mitsuba.python.util import traverse
from mitsuba.python.autodiff import render, write_bitmap, Adam
import time

#Szene(bunny)Lesen
Thread.thread().file_resolver().append('bunny')
scene = load_file('bunny/bunny.xml')

#Finden Sie differenzierbare Szenenparameter
params = traverse(scene)

#Mach ein Backup
param_res = params['my_envmap.resolution']
param_ref = Float(params['my_envmap.data'])

#Verwerfen Sie alle Parameter außer dem, den Sie unterscheiden möchten
params.keep(['my_envmap.data'])

#Rendern Sie das Zielbild (verwenden Sie noch keine Derivate).
image_ref = render(scene, spp=16)
crop_size = scene.sensors()[0].film().crop_size()
write_bitmap('out_ref.png', image_ref, crop_size)

#Geändert zu einer einheitlichen weißen Umgebungsbeleuchtungskarte
params['my_envmap.data'] = ek.full(Float, 1.0, len(param_ref))
params.update()

#Wählen Sie Adam als Methode zur Parameteroptimierung
opt = Adam(params, lr=.02)

time_a = time.time()

#Anzahl der Iterationen
iterations = 100

for it in range(iterations):
    #Führen Sie ein differenzierbares Rendern der Szene durch
    image = render(scene, optimizer=opt, unbiased=True, spp=1)
    write_bitmap('out_%03i.png' % it, image, crop_size)
    write_bitmap('envmap_%03i.png' % it, params['my_envmap.data'],
                 (param_res[1], param_res[0]))

    #Verlust nehmen (MSE zwischen gerendertem Bild und Zielbild)
    ob_val = ek.hsum(ek.sqr(image - image_ref)) / len(image)

    #Setzen Sie den Fehler auf den Eingabeparameter zurück
    ek.backward(ob_val)

    #Führen Sie Verlaufsschritte durch
    opt.step()

    #Geben Sie das Ergebnis des Vergleichs der Umgebungslichtquellenkarte mit dem Wert von Ground Truth aus
    err_ref = ek.hsum(ek.sqr(param_ref - params['my_envmap.data']))
    print('Iteration %03i: error=%g' % (it, err_ref[0]), end='\r')

time_b = time.time()

#Geben Sie die durchschnittliche Berechnungszeit für jede Iteration aus
print()
print('%f ms per iteration' % (((time_b - time_a) * 1000) / iterations))

my_envmap.data ist der Parameter der Umgebungslichtquellenzuordnung, bei der es sich um eine 125K-RGBA-Bitmap (eindimensional) handelt. Die 125K-Parameter können gleichzeitig optimiert werden.

Wie Sie durch Vergleichen der beiden oben genannten Beispielcodes sehen können, können Sie durch Ändern der Parameter, die Sie ableiten möchten, mit fast demselben Code optimieren und sehen, dass er sehr allgemein beschrieben werden kann.

Zusammenfassung

Wir haben die Prinzipien, Anwendungen und Ausführung von Beispielcode für das neu aktivierte differenzierbare Rendering in Mitsuba2 zusammengefasst. Inverses Rendern, das in der Vergangenheit als umgekehrtes Problem schwierig war, kann jetzt (in vielen Fällen) mit einer sehr präzisen Beschreibung gelöst werden. Ich persönlich halte es daher für eine revolutionäre Technologie.

Nächstes Mal werde ich die neu hinzugefügte Funktion des polarisierten Renderns vorstellen.

das ist alles.

Recommended Posts

Berühren Sie den neuesten physikbasierten Renderer Mitsuba2 (3) Differenzierbares Rendering
Berühren Sie den neuesten physikbasierten Renderer Mitsuba2 (2) Move from Python