b°wide hat der Community einen Node-Pack zur Verfügung gestellt, der neben vielen Verwendungszwecken zur Reduktion von Cycles Rauschen im Compositor benutzt werden kann. Herunterladen könnt ihr ihn hier. Es bedarf vieler Klicks diese Node Group zu benutzen, zunächst muss man alle Channels aktivieren und dann alle In- und Outputs verbinden, hier gibt es eine one-click-solution.

In diesem Artikel möchte ich mich auf die höchsteffektive Node Group konzentrieren, die mithilfe des Bilateral Blurs Rauschen aus Renderings mit wenig Qualitätsverlust stark reduzieren. Ich gehe allerdings davon aus, dass ein paar grundlegende Vorgehensweisen in Python schon bekannt sind, falls das nicht der Fall sein sollte, schaut euch bitte ein paar der ARewO Entwicklungstutorials an, bei denen ich auf Level 0 ansetze.
Hier ist das komplette Script, danach die Erklärung:

  1. import bpy
  2.  
  3. bpy.context.scene.render.layers["RenderLayer"].use_pass_combined = True
  4. bpy.context.scene.render.layers["RenderLayer"].use_pass_z = True
  5. bpy.context.scene.render.layers["RenderLayer"].use_pass_ambient_occlusion = True
  6. bpy.context.scene.render.layers["RenderLayer"].use_pass_diffuse_direct = True
  7. bpy.context.scene.render.layers["RenderLayer"].use_pass_diffuse_indirect = True
  8. bpy.context.scene.render.layers["RenderLayer"].use_pass_diffuse_color = True
  9. bpy.context.scene.render.layers["RenderLayer"].use_pass_glossy_direct = True
  10. bpy.context.scene.render.layers["RenderLayer"].use_pass_glossy_indirect = True
  11. bpy.context.scene.render.layers["RenderLayer"].use_pass_glossy_color = True
  12. bpy.context.scene.render.layers["RenderLayer"].use_pass_transmission_direct = True
  13. bpy.context.scene.render.layers["RenderLayer"].use_pass_transmission_indirect = True
  14. bpy.context.scene.render.layers["RenderLayer"].use_pass_transmission_color = True
  15. bpy.context.scene.render.layers["RenderLayer"].use_pass_subsurface_direct = True
  16. bpy.context.scene.render.layers["RenderLayer"].use_pass_subsurface_indirect = True
  17. bpy.context.scene.render.layers["RenderLayer"].use_pass_subsurface_color = True
  18. bpy.context.scene.render.layers["RenderLayer"].use_pass_emit = True
  19. bpy.context.scene.render.layers["RenderLayer"].use_pass_environment = True
  20. bpy.context.scene.render.layers["RenderLayer"].use_pass_normal = True
  21.  
  22. # get the components
  23. nt = bpy.context.scene.node_tree
  24. render = nt.nodes['Render Layers']
  25. reduce_noise = nt.nodes['Group']
  26.  
  27. # store all relevant (not hidden) sockets
  28. list_out = [n.name for n in render.outputs]
  29. list_in = [n.name for n in reduce_noise.inputs if not n.hide]
  30.  
  31. for socket in list_in: #list of names -> strings
  32.     if socket.startswith('SSS'): # He used SSS instead of Subsurface, so we have to fix that.
  33.         reduce_noise.inputs[socket].name = socket.replace('SSS', 'Subsurface')
  34.         connection = socket.replace('SSS', 'Subsurface')
  35.     else: # for all others we just leave it
  36.         connection = socket
  37.     
  38.     if connection in list_out:
  39.         #now that all out and inputs have the same name, we can link them by name
  40.         nt.links.new(render.outputs[connection], reduce_noise.inputs[connection])

Setup:
Zunächst braucht ihr die Blenddatei in der diese Node Groups gespeichert sind, ladet sie mit dem Link oben herunter und speichert sie auf der Festplatte. Dann öffnet die Datei in der Rauschen reduziert werden soll und geht auf File -> Append (SHIFT + F1). Im Menu navigiert zur b°wide Datei, klickt sie an und geht in das Verzeichnis NodeTree. Dort sind alle Node Groups gespeichert und ihr könnt die PassCombineDenoiser  mit einem Doppelklick auswählen. Danach geht in das Compositor Layout oder öffnet den Node Editor in einem Fenster. In den Compositing Nodes stellt Use Nodes an (1). Dann SHIFT + A -> Group -> PassCombineDenoiser.

Das erstellt eine Node Group mit einer Menge Inputs. Wir haben aber nur 3 Outputs in der Render Layer  Node, also müssen wir das ändern. Im Render Layer Tab des Properties Window geht zu Passes und erweitert diese Option (2).
Bevor wir jetzt alle nötigen Passes aktivieren schauen wir uns an, was genau passiert, wenn wir einen dieser Passes anklicken. Dazu müssen wir mit der Maus über den Rand direkt unter der Info Leiste gehen und diese herunterziehen (3). Nach der Python Console ist diese Vorgehensweise der beste Freund des Blender Python Anfängers. Wenn wir jetzt also beispielsweise den Haken beim AO Pass setzen, kann man dort lesen:

  1. bpy.context.scene.render.layers["RenderLayer"].use_pass_ambient_occlusion = True

Jetzt müssen wir noch die restlichen notwendigen Passes anwählen. Keine Sorge, das müssen wir nur einmal machen, bei jedem weiteren Importieren wird das Skript das für uns übernehmen. In dem Python Information Fenster könnt ihr mit B alles auswählen, was wir brauchen (alles was use_pass_ enthält). Mit der Maus immernoch über dem blau markierten Text STRG + C drücken und einen Text Editor öffnen oder zum Window Preset Scripting wechseln. Dort auf New (4) klicken, damit wir ein Skript beginnen können. Als erstes schreiben wir: 

  1. import bpy

Danach fügen wir den Code ein, den wir eben kopiert haben (STRG + V). Jetzt macht unser Skript dasselbe wie das, was wir eben per Hand getan haben, schon eine große Hilfe, aber da geht noch mehr. Zuerst erstellen wir ein paar Variablen, die es anderen oder uns später erleichtern nachzuvollziehen, was wir getan haben, also die Lesbarkeit verbessern:

  1. nt = bpy.context.scene.node_tree
  2. render = nt.nodes['Render Layers']
  3. reduce_noise = nt.nodes['Group']

Man kann sich den node_tree als Verzeichnis vorstellen, die Dateien, die wir daraus verwenden sind die Variablen: render, welche die Node im Nodetree enthält, die  'Render Layers' heißt und reduce_noise. Die nächsten Zeilen sind etwas komplizierter. Man könnte auch eine For-Schleife verwenden, um durch die Attribute der In- und Outputs zu gehen, aber diese Weise ist die Python übliche.

  1. list_out = [n.name for n in render.outputs]
  2. list_in = [n.name for n in reduce_noise.inputs if not n.hide]

Erklärung: Wenn wir alle Namen der Outputs in einer Liste speichern möchten, geht das nicht mit render.outputs.names weil outputs eine Liste ist und nur die Einzelnen Objekte der Liste einen Namen haben. Wir benutzen [] um zu zeigen, dass das Ergebnis eine Liste sein wird. Das n ist eine temporäre Variable, die alle Outputs einen nach dem anderen annimmt, denn jetzt können wir mit n.name sagen, dass wir den Namen des Outputs wollen. For also für alle render.outputs. Das gibt uns ein Array von allen Namen der outputs der oben deklarierten Variable render enthält. Die nächste Zeile tut dasselbe, mit der kleinen Einschränkung: wir wollen nur die Inputs in der Liste, die nicht versteckt sind, also ihre Eigenschaft n.hide nicht wahr ist. Das ist nur eine Vorsichtsmaßnahme, falls es automatisch generierte, oder eben versteckte und damit nicht benutzte Inputs geben sollte.

Jetzt möchten wir mit den Elementen in diesen Listen auch etwas anstellen. Um Python zu sagen, dass wir eine Liste abarbeiten wollen und zwar jedes einzeln schreibt man:

  1. for socket in list_in:

Die Variable socket wird in jedem Zyklus einen anderen Wert annehmen, nämlich den Namen, der gerade betrachtet wird. Wir müssen alle Zeilen einrücken, die zur Schleife gehören, so zeigt man Python, wann die Schleife vorbei ist. Wahrscheinlich habt ihr schon gesehen, dass die meisten Inputs den gleichen Namen wie die Outputs haben, mit Außnahme der letzten 3, dort steht statt 'Subsuface' 'SSS'. Das verhindert zwar, dass wir die Sockets einfach mit F verbinden können und verlangt ein paar Zeilen mehr in unserem Skript, aber es hat mich trotzdem gefreut, weil es dadurch noch ein wenig mehr Sinn macht, diese Schritte tatsächlich zu skripten und nicht jedesmal per Hand macht. Außerdem können wir uns noch ein wenig mehr Code betrachten.

  1.     if socket.startswith('SSS'): # Er hat SSS statt Subsurface benutzt also: reparieren.
  2.         reduce_noise.inputs[socket].name = socket.replace('SSS', 'Subsurface')
  3.         connection = socket.replace('SSS', 'Subsurface')

Eins der großartigen Dinge an Python ist: Selbst wenn man keine Ahnung von Code hat, kann man doch einigermaßen erraten, was gerade passiert. Wenn also der Socket (wir erinnern uns, das ist ein Name, also String) mit 'SSS' anfängt, soll das 'SSS' durch 'Subsurface' ersetzt werden. Dann erstellen wir eine weitere Variable, die ebenfalls den ersetzten String enthält. Die Variable socket selbst zu ersetzen kann problematisch sein, da sie von der Schleife zugewiesen wird, also lieber auf Nummer sicher. 

  1.     else: # für alle anderen lassen wir alles wie's ist.
  2.         connection = socket
  3.     if connection in list_out:
  4.         nt.links.new(render.outputs[connection], reduce_noise.inputs[connection])

Jetzt haben also alle zusammengehörigen In- und Outputs den selben Namen und wir können sie nach Namen verbinden. Es ist wichtig, dass man beachtet, dass die Verbindung (link) nicht teil der In- und Outputs ist, was auf den 1. Blick vielleicht logisch erscheinen mag, sondern Teil des Nodetrees selber. Deshalb nt.links.new. nt war ja der gesamte Nodetree der Szene s.o.