Wie drehe ich eine mehrschichtige EXR-Datei in Blenders Compositor?

Nov 18 2020

Es scheint, dass das Drehen eines Bildes eine triviale Aufgabe ist. Ich habe jedoch dieses Problem, wenn ich mit Dateien im EXR-Format im Mehrschichtbereich in Blender arbeite.

Aber wieso?

Ich finde es praktisch, meine Archvis-Szenen als Animationen einzurichten, damit ich Objekte in verschiedenen Standbildern ändern und alle Kamerawinkel gleichzeitig als Animation rendern kann. Manchmal benötige ich Bilder im Quer- und Hochformat desselben Interieurs und verwende ein kleines Skript, um schnell die Abmessungen der X- und Y-Auflösung zu wechseln und die Kamera zu drehen, wenn ich mit dem Einrahmen fertig bin, sodass einige Frames gedreht werden. Es ist dann sehr praktisch für mich, eine Folge von Bildern zusammenzusetzen.

Kürzlich habe ich eine Szene in wenigen Stapeln gerendert und am Ende 1 8K-Panoramabild, 5 4K-Wohnzimmerbilder im Querformat mit einem von ihnen gedreht und 5 Bilder von Treppen, die alle in einer Sequenz im Hochformat sind, und zu meiner Überraschung, wenn Compositing Ich kann das mit allen Bildern gleichzeitig als eine Sequenz tun, trotz des Unterschieds in Ausrichtung und Auflösung, und sie in Dateien mit Dateiausgabeknoten mit der richtigen Auflösung und Ausrichtung aus dieser einen Sequenz ausgeben. Jetzt weiß ich also, dass ich in derselben Sequenz, die amüsiert, unterschiedliche Orientierungen haben kann.

Es wäre noch erstaunlicher, wenn ich beim Zusammensetzen immer alle Bilder sehen könnte, die korrekt gedreht wurden, anstatt nur die Ausgabe zu drehen, wie ich es bisher getan habe.

Ich müsste alle gerenderten Multilayer-EXR-Dateien drehen, die in meiner Dateisequenz gedreht werden müssen.

Was ich versucht habe

Ich habe keine Probleme damit, jede Ausgabe eines Multilayer EXR mit dem Dateiausgabeknoten mit Python zu verbinden und auch Compositor-Knoten einzufügen, um sie automatisch zu bearbeiten, sodass jede Lösung, die für eine Ebene funktioniert, für mich praktisch ist. Ich kann das Bild jedoch nicht so weit im Compositor drehen weil das Bild beim Drehen auf die ursprünglichen Abmessungen zugeschnitten wird:

Die Frage

Ist es möglich, jede Ebene einer Multilayer-EXR zu drehen und auf einem Bild mit gedrehten Abmessungen sowie mit Blender's Compositor-Knoten auszugeben, wenn dies der Fall ist - wie?

Meine unten beschriebene Lösung und Antwort haben Probleme mit Cryptomatte. Ich beginne ein Kopfgeld in der Hoffnung, eine Lösung ohne diese Probleme zu finden. Ich fange an, über eine Lösung mit Python nachzudenken, habe aber keine Ahnung, wie einfach und leicht die Verwendung von Blender sein würde ...

Antworten

3 lemon Dec 09 2020 at 22:26

Über Kryptomatten

Das Problem ist nicht auf die Rotation zurückzuführen, sondern auf den Alpha-Over-Knoten:

was zu einem einfarbigen Bild führt.

Wenn Sie die Knotengruppe folgendermaßen ändern:

Dies ermöglicht es, die Bildgröße von der Maske fernzuhalten, ohne sie zu berücksichtigen (multipliziert mit 0), fügt jedoch die gedrehten Kryptomatenwerte hinzu.

Eine einfache Testfalldatei:

2 MartynasŽiemys Nov 19 2020 at 17:05

Diese Lösung hat Probleme - siehe das Ende der Antwort.

Wie Brockmann betonte, gibt es eine sehr ähnliche Frage zu rotierenden Bildern, die ich nicht gefunden habe. Es erklärt irgendwie, dass Bilddimensionen im Compositor vom ersten Knoten geerbt werden, wenn er mit etwas gemischt wird. Der Maskenknoten ohne ausgewählte Maske dient zum perfekten Einstellen der Abmessungen:

Um eine mehrschichtige EXR-Datei zu drehen, müssten alle Ebenen gedreht werden, und mit Python würde das Erstellen eines Bedienfelds in einem kleinen Addon ungefähr so ​​aussehen:

bl_info = {
    "name": "Nodes",
    "author": "Martynas Žiemys",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "Compositor -> n panel -> Node Tools",
    "description": "",
    "warning": "",
    "doc_url": "",
    "category": "Compositor",
}

import bpy
from bpy.types import Panel, Operator
from mathutils import Vector
from math import radians

class OutputRotatedMultilayer(Operator):
    """Make multilayer EXR file output for all outputs of active image node rotated"""
    bl_idname = "node.multilayer_output_rotated"
    bl_label = "Multilayer Output Rotated"

    @classmethod
    def poll(cls, context):
        image_node_active = False
        if context.scene.node_tree.nodes.active is not None:
            image_node_active = (context.scene.node_tree.nodes.active.type in {"IMAGE","R_LAYERS"})
        return image_node_active

    def execute(self, context):
        if "RotateImage" not in bpy.data.node_groups:
            rotate = bpy.data.node_groups.new('RotateImage', 'CompositorNodeTree')
            rotate.inputs.new('NodeSocketColor','Image')
            rotate.outputs.new('NodeSocketColor','Image')
            out = rotate.nodes.new('NodeGroupOutput')
            out.location = (200,0)
            input = rotate.nodes.new('NodeGroupInput')
            input.location = (-400,0)
            mask = rotate.nodes.new('CompositorNodeMask')
            mask.location = (-200,200)
            mask.use_feather = 0
            mask.size_source = 'FIXED'
            mask.size_x = 3600
            mask.size_y = 2400
            mix = rotate.nodes.new('CompositorNodeAlphaOver')
            mix.location = (0,25)
            mix.hide = 1
            rot = rotate.nodes.new('CompositorNodeRotate')
            rot.location = (-200,-50)
            rot.filter_type = 'NEAREST'
            rot.inputs[1].default_value= radians(90)
            rotate.links.new(out.inputs[0], mix.outputs[0])
            rotate.links.new(rot.inputs[0], input.outputs[0])
            rotate.links.new(mix.inputs[1], mask.outputs[0])
            rotate.links.new(mix.inputs[2], rot.outputs[0])
            
        width = context.scene.node_tree.nodes.active.width
        active = context.scene.node_tree.nodes.active
        tree = context.scene.node_tree
        links = tree.links 
        output = tree.nodes.new('CompositorNodeOutputFile')  
        output.location = active.location + Vector((500,0))
        output.format.file_format = 'OPEN_EXR_MULTILAYER'
        output.format.color_depth = '32'
        output.format.color_mode = 'RGBA'
        output.format.compression = 15
        output.layer_slots.clear()
        for i,every_slot in enumerate(active.outputs):
            if active.type == "R_LAYERS":
                if every_slot.enabled:
                    output.layer_slots.new( name = every_slot.name )
                    g = tree.nodes.new('CompositorNodeGroup')
                    g.node_tree = bpy.data.node_groups["RotateImage"]
                    g.hide = 1 
                    g.location = (-100,i*50)
                    links.new(active.outputs[i], g.inputs[0])
                    links.new(g.outputs[0], output.inputs[every_slot.name])
            else:
                output.layer_slots.new( name = every_slot.name )
                g = tree.nodes.new('CompositorNodeGroup')
                g.node_tree = bpy.data.node_groups["RotateImage"]
                g.hide = 1 
                g.location = active.location + Vector((200,i*-33))
                links.new(active.outputs[i], g.inputs[0])
                links.new(g.outputs[0], output.inputs[every_slot.name])
                
                
        return {'FINISHED'}

class NODE_PT_node_tools(Panel):
    bl_space_type = 'NODE_EDITOR'
    bl_region_type = 'UI'
    bl_category = "Node Tools"
    bl_label = "Node Tools"

    @classmethod
    def poll(cls, context):
        space = context.space_data
        return space.type == 'NODE_EDITOR'

    def draw(self, context):
        layout = self.layout
        col = layout.column()
        col.operator("node.multilayer_output_rotated")
        
def register():
    bpy.utils.register_class(OutputRotatedMultilayer)
    bpy.utils.register_class(NODE_PT_node_tools)


def unregister():
    bpy.utils.unregister_class(OutputRotatedMultilayer)
    bpy.utils.unregister_class(NODE_PT_node_tools)


if __name__ == "__main__":
    register()

Es stellt sich heraus, dass dies bei Cryptomatte nicht funktioniert

Der Rotationsprozess beeinträchtigt die Genauigkeit der Cryptomatte-Werte und führt zu falschen Maskenkanten:

1 GordonBrinkmann Nov 18 2020 at 21:55

Da das Renderergebnis die Abmessungen oder die Ausrichtung des EXR nicht berücksichtigt, hängt die Antwort davon ab, welches Ergebnis Sie erzielen möchten. Der einfache Weg wäre, wenn die EXR beispielsweise 1920 x 1080 ist, die Renderabmessungen auf 1920 x 1920 einzustellen. Auf diese Weise passt das Bild immer und wird in keiner Weise zugeschnitten. Wenn Sie mit einem anderen Prozentsatz wie 50% rendern möchten, sollten Sie einen Skalierungsknoten nach dem Drehknoten platzieren, der auf Rendergröße> Anpassen eingestellt ist .

Wenn Sie das Seitenverhältnis des gerenderten Bildes bei 16: 9 halten möchten, gibt es zwei Möglichkeiten:

  1. Die EXR sollte so viel Platz wie möglich ausfüllen (1920 x 1080 bei 0 °, 608 x 1080 bei 90 °) oder
  2. Die Abmessungen sollten gleich bleiben (1080 x 608 bei 0 °, 608 x 1080 bei 90 °).

In beiden Fällen benötigen Sie den oben beschriebenen Skalierungsknoten mit Rendergröße> Anpassen und einen zweiten Skalierungsknoten, der auf Relativ> X = Y = 9/16 = 0,5625 eingestellt ist .

Für die Option 1 müssen Sie den relativen Knoten deaktivieren oder X = Y = 1 setzen, wenn die Drehung 0 ° beträgt. Für 90 ° oder -90 ° müssen Sie es mit X = Y = 0,5625 aktivieren.

Für Option 2 lassen Sie es einfach aktiviert, egal ob 0 ° oder 90 °, aber wie bereits erwähnt, füllt die EXR das Bild in diesem Fall nicht horizontal aus.

Ich habe ein Knoten-Setup mit automatischer Deaktivierung des relativen Knotens gemäß dem Rotationswert erstellt (siehe Abbildung). Die Idee ist, wenn Sie eine Sequenz rendern und Keyframes für die Rotation festlegen möchten, müssen Sie Knoten nicht manuell deaktivieren. Das Seitenverhältnis der Renderdimensionen wird von den Treibern berechnet.