Skip to content

Instantly share code, notes, and snippets.

@jeremybep
Last active March 9, 2023 20:58
Show Gist options
  • Save jeremybep/902b3ffc4ac63ca4f896724f1bce67fd to your computer and use it in GitHub Desktop.
Save jeremybep/902b3ffc4ac63ca4f896724f1bce67fd to your computer and use it in GitHub Desktop.
Foundry nuke - les metadonnees EXR

Préambule

On en trouve partout, que ce soit dans une photo prise avec votre smartphone. Dans une recherche internet, page web...image sortie d’un moteur d’un moteur de rendu...ect Je ne vais pas trop m’éparpiller, mais dans l’idée les metadonnées permettent d’avoir des données en relation à votre documents (ou fichier). On peut en rajouter comme en soustraire.

Ces metadonnées, peuvent être une date, une coordonnée gps, le format de l’image...ect Mais attention tous les formats d’images ne permettent pas d’embarquer se que l’on veut. Je vais surtout vous parler de l’exr mais sachez qu’il existes des normes comme : EXIF, IPTC, XMP pour les autres formats.

Certains formats ont des restrictions, quand une donnée ne peut pas être inscrite dans les metadonnées souvent un fichier dit «sideCar» est généré (sous forme d’un XML) à coté de votre document/fichier.

Alors à quel moment ça devient utile ?

Disons que ça peut-être utile à n’importe quelle étape.

Pour faire simple je vais vous donner des exemples :

  • Si vous utilisez un outil de tracking, vous pouvez venir récupérer le renderTime.
  • Si vous automatiser des tâches, vous pouvez construire/monter un fichier, une comp, une scène...dès réceptions de la dernière frame rendu.
  • Un FastChecking après le rendu.
  • Récupérer des infos du moteur de rendu pour les réinjecter dans un second renderer (comp 2.5D).
  • Récupérer les données pour créer une camera
  • ect, ect…

Au final ça peut servir à tous les départements.

Les champs de metadonnées

Via l’utilisation de l’exr beaucoup de logiciels 3D, moteurs de rendu intègrent par défaut des champs de metadonnées.

Certaines sont implémentées et/ou typées par le logiciel 3D, d’autres sont implémentées par le moteur de rendu utilisé. Il arrive aussi d'avoir un RAW ou un exr baké et une beauty lors d'un rendu, ces deux exr n'auront pas les mêmes metadonnées. Le RAW ou exr baké devrait avoir toutes les infos du renderer, l'autre (Beauty) plutôt issus du buffer du logiciel 3D.

Il sont généralement rangé par Tag ID, puis par Tag Name pour finir avec la valeur. exr/arnold/stats/time/render 3.22217

Ci-dessous plusieurs exemple de metadonnées issus de différent renderer.

  • Arnold
{exr/CameraFilmApertureHorizontal 1}
{exr/CameraFilmApertureVertical 0.540541}
{exr/CameraFocalLength 0.972222}
{exr/arnold/AA_samples 1}
{exr/arnold/auto_transparency_depth 5}
{exr/arnold/bounds_max_x 1997}
{exr/arnold/bounds_max_y 1079}
{exr/arnold/bounds_min_x 0}
{exr/arnold/bounds_min_y 0}
{exr/arnold/diffuse_depth 0}
{exr/arnold/diffuse_samples 1}
{exr/arnold/glossy_depth 0}
{exr/arnold/glossy_samples 1}
{exr/arnold/host/hw "1 x Intel(R) Core(TM) i7-4930K CPU @ 3.40GHz (6 cores, 12 logical) with 32708MB"}
{exr/arnold/host/name jeremy-win}
{exr/arnold/host/os "Windows 8 Professional (version 6.2, build 9200)"}
{exr/arnold/reflection_depth 2}
{exr/arnold/refraction_depth 2}
{exr/arnold/refraction_samples 1}
{exr/arnold/sss_samples 1}
{exr/arnold/stats/date "Sat Oct 08 21:10:41 2016"}
{exr/arnold/stats/geo/curve_segments 0}
{exr/arnold/stats/geo/triangles 1.37102e+06}
{exr/arnold/stats/memory/peak 1919.18}
{exr/arnold/stats/memory/start 1642.72}
{exr/arnold/stats/rays/all/pixel 5.96652}
{exr/arnold/stats/rays/all/total 1.37055e+07}
{exr/arnold/stats/rays/camera/pixel 0.999053}
{exr/arnold/stats/rays/camera/total 2.29489e+06}
{exr/arnold/stats/time/render 3.22217}
{exr/arnold/stats/time/setup 0.446054}
{exr/arnold/texture_max_memory_MB 2048}
{exr/arnold/threads 12}
{exr/arnold/total_depth 5}
{exr/arnold/version "Arnold 4.2.14.3 windows icc-14.0.2 oiio-1.5.24 rlm-12.0.2 2016/08/08 12:32:59"}
{exr/arnold/volume_depth 0}
{exr/arnold/volume_samples 1}
{exr/capDate "2016:10:08 21:10:41"}
{exr/compression 3}
{exr/compressionName "Zip (16 scanlines)"}
{exr/dataWindow 0,0,1997,1079}
{exr/displayWindow 0,0,1997,1079}
{exr/pixelAspectRatio 1}
{exr/screenWindowCenter 0,0}
{exr/screenWindowWidth 1}
{exr/type scanlineimage}
{exr/worldToCamera 0.736098,0.0323383,0.676103,0,-0.676875,0.0351669,0.735258,0,-5.58794e-07,0.998859,-0.0477752,0,735.447,-153.407,-740.001,1}
{exr/worldToNDC 1.4313,0.116328,0.676103,0.676103,-1.31615,0.126503,0.735258,0.735258,-1.08654e-06,3.59312,-0.0477752,-0.0477752,1430.04,-551.84,-740.001,-740.001}
{input/bitsperchannel "16-bit half float"}
{input/ctime "2016-10-08 21:10:45"}
{input/filename /media/nuke/metadata/arnold/test.exr}
{input/filereader exr}
{input/filesize 4791683}
{input/frame 1}
{input/height 1080}
{input/mtime "2016-10-08 21:10:45"}
{input/width 1998}
  • 3dsmax raw
{exr/cameraAperture 36}
{exr/cameraFarClip 3.40282e+038}
{exr/cameraFarRange 1000}
{exr/cameraFov 54.4322}
{exr/cameraNearClip 0}
{exr/cameraNearRange 0}
{exr/cameraProjection 0}
{exr/cameraTargetDistance 14325.7}
{exr/cameraTransform 0.736098,-0.676875,-5.60656e-007,0,0.0323382,0.0351668,0.998858,0,-0.676102,-0.735257,0.0477752,0,-36.8621,1023.88,118.706,1}
{exr/compression 3}
{exr/compressionName "Zip (16 scanlines)"}
{exr/dataWindow 0,0,1997,1079}
{exr/displayWindow 0,0,1997,1079}
{exr/gamma 1}
{exr/pixelAspectRatio 1}
{exr/screenWindowCenter 0,0}
{exr/screenWindowWidth 1}
{exr/type scanlineimage}
{input/bitsperchannel "16-bit half float"}
{input/ctime "2016-10-08 21:12:13"}
{input/filename /media/nuke/metadata/3dsmax/test.exr}
{input/filereader exr}
{input/filesize 2709574}
{input/frame 1}
{input/height 1080}
{input/mtime "2016-10-08 21:12:13"}
{input/width 1998}
  • V-Ray raw
{exr/cameraAperture 36}
{exr/cameraFNumber 8}
{exr/cameraFarClip 1e+30}
{exr/cameraFarRange 1000}
{exr/cameraFocalLength 40}
{exr/cameraFov 48.3494}
{exr/cameraNearClip 0}
{exr/cameraNearRange 0}
{exr/cameraProjection 0}
{exr/cameraTargetDistance 636.642}
{exr/cameraTransform -0.46523,0.885084,0.0136567,0,0.879455,0.463915,-0.106495,0,-0.100593,-0.0375343,-0.994219,0,545.379,360.62,-17.7607,1}
{exr/compression 3}
{exr/compressionName "Zip (16 scanlines)"}
{exr/dataWindow 0,0,1279,719}
{exr/displayWindow 0,0,1279,719}
{exr/pixelAspectRatio 1}
{exr/screenWindowCenter 0,0}
{exr/screenWindowWidth 1}
{exr/type scanlineimage}
{input/bitsperchannel "16-bit half float"}
{input/ctime "2016-10-18 20:54:39"}
{input/filename /media/nuke/metadata/vray/test.exr}
{input/filereader exr}
{input/filesize 10950672}
{input/frame 1}
{input/height 720}
{input/mtime "2013-12-08 14:42:03"}
{input/width 1280}
  • Corona raw
{exr/compression 3}
{exr/compressionName "Zip (16 scanlines)"}
{exr/corona.ch.BEAUTY 1}
{exr/corona.ch.CESSENTIAL_Direct 1}
{exr/corona.ch.CESSENTIAL_Indirect 1}
{exr/corona.ch.CESSENTIAL_Reflect 1}
{exr/corona.ch.CESSENTIAL_Refract 1}
{exr/corona.ch.CGeometry_WorldPosition 1}
{exr/corona.ch.CMasking_Mask 1}
{exr/corona.ch.CMasking_WireColor 1}
{exr/corona.ch.CShading_RawReflect.reflect 1}
{exr/corona.ch.CShading_RawRefract.refract 1}
{exr/corona.ch.CShading_Shadows 1}
{exr/corona.ch.CShading_SourceColor.diffuse 1}
{exr/corona.ch.CTAO 1}
{exr/corona.ch.Denoised 1}
{exr/corona.ch.Hybrid 1}
{exr/corona.ch.SqrBeauty 1}
{exr/corona.ch.SqrHybrid 1}
{exr/corona.ch.SqrVisibleDiffuse 1}
{exr/corona.ch.SqrVisibleNormals 1}
{exr/corona.ch.VisibleDiffuse 1}
{exr/corona.ch.VisibleNormals 1}
{exr/corona.colorMapping.gamma 2.2}
{exr/corona.colorMapping.tm 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}
{exr/corona.colorMapping.whitepoint 1}
{exr/corona.customMetadata "1633636962 53562967 25 357158"}
{exr/corona.isCoronaExr 1}
{exr/corona.renderstamp "Corona Renderer | Intel(R) Core(TM) i7-4930K CPU @ 3.40GHz | Time: 0:06:06 | Passes: 25 | Primitives: 3\\xa0081\\xa0515 | Rays/s: 4\\xa0563\\xa0831"}
{exr/corona.stats.passes 25}
{exr/corona.stats.raysPerSample 30.4994}
{exr/corona.stats.raysPerSecond 4563831}
{exr/corona.stats.time 366953}
{exr/dataWindow 0,0,1919,1079}
{exr/displayWindow 0,0,1919,1079}
{exr/pixelAspectRatio 1}
{exr/screenWindowCenter 0,0}
{exr/screenWindowWidth 1}
{exr/type scanlineimage}
{input/bitsperchannel "32-bit float"}
{input/ctime "2016-10-18 20:50:14"}
{input/filename /media/nuke/metadata/corona/test.exr}
{input/filereader exr}
{input/filesize 118642774}
{input/frame 1}
{input/height 1080}
{input/mtime "2016-05-29 23:18:04"}
{input/width 1920}
  • Redshift raw
{exr/RSCameraAperture 1.417320,0.797591}
{exr/RSCameraAspect 1.777000}
{exr/RSCameraDOFRadius 1.000000}
{exr/RSCameraFOV 54.432102}
{exr/RSCameraFStop 8.000000}
{exr/RSCameraFarPlane 10000.000000}
{exr/RSCameraNearPlane 0.100000}
{exr/RSCameraShift 0.000000,0.000000}
{exr/RSCameraShutterRatio 100.000000}
{exr/RSCameraTransform -0.638894,0.012540,0.769192,0.000000,0.104471,0.992019,0.070602,0.000000,0.762168,-0.125465,0.635105,0.000000,-28.530312,11.208566,-139.894714,1.000000}
{exr/RSVersion 2.0.66}
{exr/capDate "2016:10:14 12:23:30"}
{exr/chunkCount 34}
{exr/compression 3}
{exr/compressionName "Zip (16 scanlines)"}
{exr/dataWindow 0,0,959,539}
{exr/displayWindow 0,0,959,539}
{exr/name subimage00}
{exr/pixelAspectRatio 1}
{exr/screenWindowCenter 0,0}
{exr/screenWindowWidth 1}
{exr/type scanlineimage}
{input/bitsperchannel "32-bit float"}
{input/ctime "2016-10-18 20:50:34"}
{input/filename /media/nuke/metadata/redshift/test.exr}
{input/filereader exr}
{input/filesize 13621424}
{input/frame 1}
{input/height 540}
{input/mtime "2016-10-18 20:49:01"}
{input/width 960}
Lecture et traitement des metadaonnées :

Ca fait un paquet d’info tout de même, bien sur il faut en avoir l’utilité et certaines sont quasi inutiles… Au lieu de partir sur plusieurs exemples, je vais m’attarder sur une étape, qui consiste à baker les données de la caméra (de votre scene 3D) dans Nuke via les metadonnées. Chose qui m’a donné pas mal de file à retordre sur quelques moteurs de rendu. Car comme vous allez le voir il n’y a pas qu’une recette, mais plusieurs en fonction de.

Je ne vais pas faire tous les moteur de rendu non plus, mais dans l’ensemble c’est presque pareil. Oui presque…:)

Les coordonnées camera :

Suivant les moteurs de rendus on obtient des champs complètements différents et donc pas forcement applicable à tous les sauces. Ces metadonnées sont en fait des coordonnées, ici elle sont disposées à être injectées dans une matrice 4x4. La ou ça peut différer, c’est de la manière dont les coordonnées sont rangées (x,y,z,w). Pour bien comprendre le fonctionnement des matrices (de manière générale) mais aussi pour la suite du chapitre, je vous invite à lire cet excellent article matrices en Français. Les vecteurs

Mais également, pour la mise en application des Matrices sous Nuke, l’article suivant : the nuke.math Python module to do Vector and Matrix operations

Prenons l’exemple d'Arnold ci-dessus, on retrouve :
{exr/worldToCamera 0.736098,0.0323383,0.676103,0,-0.676875,0.0351669,0.735258,0,-5.58794e-07,0.998859,-0.0477752,0,735.447,-153.407,-740.001,1}
{exr/worldToNDC 1.4313,0.116328,0.676103,0.676103,-1.31615,0.126503,0.735258,0.735258,-1.08654e-06,3.59312,-0.0477752,-0.0477752,1430.04,-551.84,-740.001,-740.001}
  • WorldToCamera : Une matrice qui transforme les points 3D du monde, aux coordonnées de la caméra. Les infos sont rangées de gauche à droite. Les coordonnées indiquent le placement de la camera. Le Z indique la direction de la camera.

  • WorldToNDC : Une matrice qui transforme les points 3D du monde en une normalisation des coordonnées. Normalized Device Coordinate (NDC)

Les coordonnées NDC sont en 2D, (0,0) et (1,1) correspond au haut-gauche et bas droit de la fenêtre.

Pour la mise en application, je vous invite à jeter un œil sur le script écrit par Deke Kincaid ancien Media and Entertainment OEM Development Manager chez the Foundry (et pas que :)

Prenons l’exemple de 3dsmax ci-dessus, on retrouve :
{exr/cameraTransform 0.736098,-0.676875,-5.60656e-007,0,0.0323382,0.0351668,0.998858,0,-0.676102,-0.735257,0.0477752,0,-36.8621,1023.88,118.706,1}

C’est une matrice bien plus simple à venir injecter. Il y a tout de même deux paramètres à prendre en compte, l’ordre de transformation et l’ordre de rotation. Par défaut dans Nuke les cameras sont en ZXY et SRT. Mais il ce peux que l’ordre des data ne soit pas rangées de gauche à droite et/ou lue aussi de gauche à droite…normalement il n’y a aucune raison, mais c’est bon de se le rappeler.

Attention tout de même si vous êtes sous 3Dsmax. C'est en Z-up et non en Y-up.

Donc pour pallier à ce problème vous pouvez passer par le ColorMatrix pour les layer RGB (normal, WPP) et injecter ce Flip.

$$\begin{bmatrix} 1 & 0 & 0 \\\ 0 & 0 & 1 \\\ 0 & -1 & 0 \end{bmatrix}$$

Pour la camera multiplier cette matrice pour faire une rotation autour du X.

$$\begin{bmatrix} 1 & 0 & 0 & 0 \\\ 0 & 0 & 1 & 0 \\\ 0 & -1 & 0 & 0 \\\ 0 & 0 & 0 & 1 \end{bmatrix}$$

Pour la mise en application, je vous met en lien un article de la doc The Foundry

Les paramètres de la camera

Pour bien baker une camera via les metadonnées il faut aussi connaître la taille du capteur (film back), la longeur de focal (focal length),le format de l’image (width, height). Ça simplifie les calculs.

La ou ça devient vite énervant, suivant le logiciel de 3D voir le moteur de rendu il y a amalgame sur la terminologie. On se retrouve avec des "horizontal aperture" voir même "Aperture" tout court qui correspond en fait à la taille du capteur, une longueur de focal exprimer en ratio, ect…

Ne pas oublier que 99,999 % du temps les valeurs sont exprimées en inch. Des fois, ...oui, des fois, la taille du capteur est exprimer en mm mais seulement pour la largeur (vu sous 3dsmax).

Logiquement il y a tous se qu’il faut dans les champs, pour reconstituer une camera dans Nuke.

Si il vous manque des valeurs à votre camera, n'hésitez pas à faire un tour sur cette base de données : VFX Camera Database Vous trouverez aussi les formules afin de calculer ce qu’il vous manque.

Metadonnées extraites de l'exr Arnold
{exr/CameraFilmApertureHorizontal 1}
{exr/CameraFilmApertureVertical 0.540541}
{exr/CameraFocalLength 0.972222}
{input/height 540}
{input/mtime "2016-10-18 20:49:01"}
{input/width 960}

Si vous passez par la case, "je convertit tout ça en mm et hop !" c’est rapé ;) Oui, prenons par exemple exr/CameraFocalLength : Arnold donne un ratio et non une longueur de focal en inch… Pour obtenir la bonne valeur, tout du moins en relation à votre longueur de capteur. Il faut multiplier ce ratio par la longueur du capteur exr/CameraFilmApertureHorizontal

Ensuite privilégiez des valeurs proches des cameras avec lesquels le rendu a été fait. Dans notre cas CameraFilmApertureHorizontal = 1, overrider plutôt cette valeur avec le FilmBack réel de la camera (ex : 35mm)

Concernant la hauteur du FilmBack, divisez le CameraFilmApertureVertical par la ratio de votre input Ce sera plus clair pour vous et pour le compositeur de retomber sur des valeurs identiques au fichier 3D lancé au rendu.

Donc pour les paramètres de la camera on devrait avoir quelque chose comme ça:

imageWidth = metaData['input/width']
imageHeight = metaData['input/height']
imageRatio = float(imageWidth) / float(imageHeight)
filmBackWidth = 35.0
filmBackHeight = filmBackWidth / imageRatio 
focalLengthMeta = metaData['exr/CameraFocalLength']
fov = filmBackWidth * focalLengthMeta

Et ces valeurs sont à venir injecter dans la camera : Note : au cas ou n'oubliez pas de faire une raz de l'outil avec : node["knob"].clearAnimated()

cam = nuke.toNode("votre_node_camera")
cam['haperture'].setValue( filmBackWidth )
cam['vaperture'].setValue( filmBackHeight )
cam['focal'].setValue( round(fov , 1) )

Voila pour les grandes lignes, ensuite rien ne vous empêche de rajouter aussi le fstop, la distance de focal, near, far. Mais aussi les settings lié au renderer dans Nuke, shutter, samples et cie...

Tips

Documentation OpenEXR

Script de bake pour des exr Vray

Script de bake pour des exr Redshift

Script de bake pour des exr Arnold

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment