[PYTHON] Touchez le dernier moteur de rendu basé sur la physique Mitsuba2 (3) Rendu différenciable

Qu'est-ce que Mitsuba2

Un moteur de rendu basé sur la physique gratuit pour les universitaires. Il existe de nouvelles fonctionnalités telles que le rendu différenciable et le rendu polarisé. D'autres articles connexes que j'ai écrits sont les suivants.

On suppose que Mitsuba2 a été installé.

Qu'est-ce que le rendu différenciable?

C'est un rendu qui peut propager des informations différentielles telles quelles. Lorsque l'algorithme de rendu est la fonction $ f (x) $, la scène d'entrée est $ x $ et le résultat du rendu est $ y $, ce qui suit est valable.

y = f(x)

Dans un rendu divisible, cette fonction $ f $ est différenciée pour obtenir $ \ frac {dy} {dx} $, alors comment changer $ x $ pour obtenir le résultat de rendu souhaité $ y $ Il vous demandera automatiquement quoi faire. Cela signifie que vous pouvez résoudre le problème inverse compliqué en CG, c'est-à-dire le rendu inverse, qui était difficile dans le passé.

autodiff.jpg

Cela dit, je pense qu'il est difficile d'imaginer immédiatement ce que vous pouvez en faire, alors je vais l'expliquer à l'aide d'un exemple concret.

Conception à condensation

Prenons un exemple de projection de lumière RVB sur un mur à travers un panneau de verre. C'est une image de verre en sandwich entre le projecteur et le mur. caustic.jpg

À ce stade, donnez à l'avance l'image que vous souhaitez projeter en tant que $ y $. Ensuite, la forme fine (profil de hauteur) $ x $ du panneau de verre qui réalise la réfraction pour obtenir l'image souhaitée (image cible) $ y $ est automatiquement optimisée par la méthode du gradient (SGD, Adam, etc.). Je peux. Dans le passé, ces problèmes devaient être optimisés de manière heuristique en faisant tourner la boucle de conception du système optique → évaluation → rétroaction, ou en utilisant un logiciel optique dédié avec diverses restrictions. Vous pouvez facilement et universellement optimiser avec ce cadre.

Optimisation de la réflectivité

La réflectance de l'objet (paramètre BSDF) peut également être optimisée pour répondre à l'image souhaitée. La figure ci-dessous montre comment optimiser la réflectance du mur gauche, qui est un paramètre de la scène, avec l'image la plus à droite comme image cible $ y $. inv_render0.jpg

Le rouge est la vraie valeur sur le mur de gauche, mais vous pouvez voir que même si vous initialisez la réflectance avec une valeur appropriée, elle converge finalement vers la vraie valeur (l'image est grossière car le nombre d'échantillons est petit, Si vous échantillonnez suffisamment à chaque fois, le calcul du rendu différentiable prendra beaucoup de temps, vous n'augmenterez donc pas beaucoup le nombre d'échantillons lors de l'optimisation). Une telle optimisation automatique de la réflectance et des paramètres BSDF a traditionnellement été un problème très difficile en raison des effets de la réflexion mutuelle. Donc, dans la recherche existante, j'ai réussi à le résoudre en ajoutant une grosse restriction, mais dans le rendu différenciable, il peut être résolu directement par la méthode simple.

Optimisation de la source lumineuse

La réflectance des objets et les paramètres BSDF sont uniformes pour chaque objet de base, et le nombre de paramètres est petit, il peut donc être considéré comme un problème simple. Le rendu différenciable de Mitsuba2 peut optimiser automatiquement non seulement des valeurs scalaires uniques telles que la réflectance, mais également des données de haute dimension telles que la carte de lumière ambiante. La figure ci-dessous est un exemple de convergence vers la valeur vraie même si la source lumineuse est correctement initialisée. inv_render1.jpg

Le haut est la carte de source lumineuse d'environnement $ x $, et le bas est le résultat du rendu. Vous pouvez voir que la carte de source de lumière, qui était initialement d'un blanc uniforme et pur, change et le résultat rendu se rapproche de l'image cible $ y $. Un seul exemple d'image est donné, ce qui signifie que la même source de lumière appropriée peut être réglée automatiquement sans l'ajustement du créateur.

En principe, le volume et la forme peuvent être automatiquement optimisés. Cependant, la forme etc. n'a pas encore été mise en œuvre. Selon l'auteur, il sera bientôt implémenté (https://github.com/mitsuba-renderer/mitsuba2/issues/26). Je pense que vous devriez vérifier GitHub fréquemment.

Déplacer le rendu différenciable

La formule a préparé l'exemple de code pour optimiser la réflectance et la source de lumière mentionnées dans l'exemple ci-dessus, alors déplaçons-le.

Comme je l'ai écrit dans Introduction, il est nécessaire d'avoir un environnement GPU pour effectuer un rendu différentiel. De plus, la variante spécifiée dans mistuba.conf doit contenir au moins une configuration divisible. Tout d'abord, je pense que gpu_autodiff_rgb est bien.

Ce qui suit décrit la procédure pour Windows. Je pense que c'est presque la même chose pour Linux. Le rendu GPU ne fonctionne pas sur MacOS. De la même manière que Move from Python, transmettez d'abord le PATH au module mitsuba dans le répertoire racine, puis accédez à l'exemple de code de docs \ examples \ 10_inverse_rendering \ Bouge toi

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

Optimisation de la réflectivité

Tout d'abord, essayons d'optimiser la réflectance. Mettez les données au travail.

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

Comme mentionné précédemment, veuillez mettre la cbox des données ci-dessus sous 10_inverse_rendering pour chaque répertoire. Si vous exécutez ce qui suit et que les images sont générées l'une après l'autre, l'opération réussit.

python invert_cbox.py

Je vais vous expliquer le contenu du code. J'ai ajouté un commentaire en japonais.

#Exemple de rendu inversé simple: rendre l'image cible de la Cornell Box,
#Optimiser l'un des paramètres de la scène (réflectivité du mur gauche) à l'aide d'un rendu divisible et d'une optimisation basée sur le gradient

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

#Chargez la Cornell Box
Thread.thread().file_resolver().append('cbox')
scene = load_file('cbox/cbox.xml')

#Trouver des paramètres de scène différenciables
params = traverse(scene)

#Supprimez tous les paramètres sauf celui que vous souhaitez différencier
params.keep(['red.reflectance.value'])

#Imprimer la valeur actuelle et générer une sauvegarde
param_ref = Color3f(params['red.reflectance.value'])
print(param_ref)

#Rendre l'image cible (sans utiliser encore de dérivés)
image_ref = render(scene, spp=8)
crop_size = scene.sensors()[0].film().crop_size()
write_bitmap('out_ref.png', image_ref, crop_size)

#Changer le mur gauche en blanc (par défaut)
params['red.reflectance.value'] = [.9, .9, .9]
params.update()

#Sélectionnez Adam comme méthode d'optimisation des paramètres
opt = Adam(params, lr=.2)

time_a = time.time()

#Nombre d'itérations
iterations = 100

for it in range(iterations):
    #Effectuer un rendu différenciable de la scène
    image = render(scene, optimizer=opt, unbiased=True, spp=1)
    write_bitmap('out_%03i.png' % it, image, crop_size)

    #Prendre la perte (MSE entre l'image rendue et l'image cible)
    ob_val = ek.hsum(ek.sqr(image - image_ref)) / len(image)

    #Propagation inverse de l'erreur au paramètre d'entrée
    ek.backward(ob_val)

    #Effectuer des étapes de dégradé
    opt.step()

    #Sort le résultat de la comparaison de la réflectance avec la valeur de Ground Truth
    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()

#Sortie du temps de calcul moyen pour chaque itération
print()
print('%f ms per iteration' % (((time_b - time_a) * 1000) / iterations))

Optimisation de la source lumineuse

Ensuite, optimisez la carte des sources lumineuses. Téléchargez les exemples de données ici et décompressez-les (http://mitsuba-renderer.org/scenes/bunny.zip). C'est un lapin en métal entouré d'un environnement de type musée, et je pense qu'il contient des fichiers de maillage et des fichiers de description de scène.

Procédez comme suit pour commencer à optimiser la source lumineuse.

python invert_bunny.py

J'expliquerai également le contenu du code avec des commentaires.

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

#scène(bunny)Lis
Thread.thread().file_resolver().append('bunny')
scene = load_file('bunny/bunny.xml')

#Trouver des paramètres de scène différenciables
params = traverse(scene)

#Faire une sauvegarde
param_res = params['my_envmap.resolution']
param_ref = Float(params['my_envmap.data'])

#Supprimez tous les paramètres sauf celui que vous souhaitez différencier
params.keep(['my_envmap.data'])

#Rendre l'image cible (sans utiliser encore de dérivés)
image_ref = render(scene, spp=16)
crop_size = scene.sensors()[0].film().crop_size()
write_bitmap('out_ref.png', image_ref, crop_size)

#Changé en une carte d'éclairage unifiée de l'environnement blanc
params['my_envmap.data'] = ek.full(Float, 1.0, len(param_ref))
params.update()

#Sélectionnez Adam comme méthode d'optimisation des paramètres
opt = Adam(params, lr=.02)

time_a = time.time()

#Nombre d'itérations
iterations = 100

for it in range(iterations):
    #Effectuer un rendu différenciable de la scène
    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]))

    #Prendre la perte (MSE entre l'image rendue et l'image cible)
    ob_val = ek.hsum(ek.sqr(image - image_ref)) / len(image)

    #Propagation inverse de l'erreur au paramètre d'entrée
    ek.backward(ob_val)

    #Effectuer des étapes de dégradé
    opt.step()

    #Sortie du résultat de la comparaison de la carte des sources lumineuses environnementales avec la valeur de Ground Truth
    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()

#Sortie du temps de calcul moyen pour chaque itération
print()
print('%f ms per iteration' % (((time_b - time_a) * 1000) / iterations))

my_envmap.data est le paramètre de la carte de source lumineuse d'environnement, qui est un bitmap RGBA 125K (unidimensionnel). Ses paramètres de 125K peuvent être optimisés en même temps.

Comme vous pouvez le voir en comparant les deux exemples de codes ci-dessus, en modifiant les paramètres que vous souhaitez dériver, vous pouvez optimiser avec presque le même code, et vous pouvez voir qu'il peut être décrit de manière très générale.

Résumé

Nous avons résumé les principes, les applications et l'exécution d'un exemple de code pour le rendu différenciable nouvellement activé dans Mitsuba2. Le rendu inverse, qui était difficile en tant que problème inverse dans le passé, peut maintenant être résolu avec une description très concise (dans de nombreux cas), donc je pense personnellement que c'est une technologie révolutionnaire.

La prochaine fois, je présenterai la fonction nouvellement ajoutée du rendu polarisé.

c'est tout.

Recommended Posts

Touchez le dernier moteur de rendu basé sur la physique Mitsuba2 (3) Rendu différenciable
Touchez le dernier moteur de rendu basé sur la physique Mitsuba2 (2) Passer de Python