Blender의 컴포 지터에서 Multilayer EXR 파일을 어떻게 회전합니까?

Nov 18 2020

이미지 회전은 사소한 작업 인 것처럼 보이지만 Blender에서 Multilayer EXR 형식 파일로 작업 할 때이 문제에 직면합니다.

그런데 왜?

내 archvis 씬을 애니메이션으로 설정하는 것이 편리하다는 것을 알게되어 다른 스틸의 오브젝트를 변경하고 모든 카메라 앵글을 한 번에 애니메이션으로 렌더링 할 수 있습니다. 때때로 동일한 내부의 가로 및 세로 방향 이미지가 필요하고 작은 스크립트를 사용하여 X 및 Y 해상도 치수를 빠르게 전환 한 다음 프레임이 완료되면 카메라를 회전하여 일부 프레임이 회전 된 상태로 렌더링되도록합니다. 그러면 일련의 이미지를 합성하는 것이 매우 편리합니다.

최근에 몇 번의 배치로 장면을 렌더링 한 후 8K 파노라마 이미지 1 개, 가로 방향의 4K 거실 이미지 5 개, 그중 하나가 회전 된 상태의 4K 거실 이미지, 모두 세로 방향 인 계단 이미지 5 개가 순서대로 나오고 놀랍게도 컴 포지 팅 방향과 해상도의 차이에도 불구하고 모든 이미지를 한 번에 하나의 시퀀스로 수행하고 파일 출력 노드가있는 파일로 해당 시퀀스의 올바른 해상도와 방향으로 출력 할 수 있습니다. 이제 저는 동일한 순서로 다른 방향을 가질 수 있다는 것을 알고 있습니다.

지금까지했던 것처럼 출력 만 회전하는 대신 합성하면서 항상 올바르게 회전 된 모든 이미지를 볼 수 있다면 훨씬 더 놀랍습니다.

파일 시퀀스에서 회전이 필요한 렌더링 된 모든 Multilayer EXR 파일을 회전해야합니다.

내가 시도한 것

Multilayer EXR의 모든 출력을 Python으로 File Output 노드에 연결하고 Compositor 노드를 삽입하여 자동으로 편집하는 데 문제가 없으므로 한 레이어에서 작동하는 모든 솔루션이 편리하지만 컴포 지터에서 이미지를 지금까지 회전 할 수 없습니다. 회전하면 이미지가 원래 크기로 잘 리기 때문입니다.

질문

멀티 레이어 EXR의 모든 레이어를 회전하고 블렌더의 합성기 노드를 사용하여 회전 된 치수의 이미지로 출력하는 것이 가능합니까?

아래에 설명 된 내 솔루션과 답변에 Cryptomatte에 문제가 있습니다. 나는 그러한 문제없이 해결책을 찾기 위해 현상금을 시작하고 있습니다. Python으로 솔루션을 생각하기 시작했지만 Blender에서 어떻게 간단하고 사용하기 쉬운 지 모르겠습니다 ...

답변

3 lemon Dec 09 2020 at 22:26

cryptomattes 정보

문제는 회전 때문이 아니라 노드 위의 알파 때문입니다.

일반 컬러 이미지가됩니다.

다음과 같이 노드 그룹을 변경하는 경우 :

이를 통해 고려하지 않고 마스크에서 이미지 크기를 유지할 수 있지만 (0 곱하기) 회전 된 cryptomatte 값이 추가됩니다.

간단한 테스트 케이스 파일 :

2 MartynasŽiemys Nov 19 2020 at 17:05

이 솔루션에는 문제가 있습니다. 답변 끝 부분을 참조하십시오.

Brockmann이 지적했듯이 내가 찾지 못한 회전 이미지에 대해 매우 유사한 질문이 있습니다. 그것은 합성기의 이미지 크기가 어떤 것과 혼합되면 첫 번째 노드에서 상속된다는 것을 설명합니다. 마스크를 선택하지 않은 마스크 노드는 치수를 완벽하게 설정하는 데 사용됩니다.

따라서 Multilayer EXR 파일을 회전하려면 모든 레이어를 회전해야하며 Python을 사용하여 패널을 만드는 작은 애드온은 다음과 같습니다.

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()

이것이 Cryptomatte에서 작동하지 않는 것으로 밝혀졌습니다.

회전 프로세스는 Cryptomatte 값의 정밀도를 엉망으로 만들어 잘못된 마스크 가장자리를 만듭니다.

1 GordonBrinkmann Nov 18 2020 at 21:55

Render Result는 EXR의 치수 나 방향을 고려하지 않기 때문에 원하는 결과에 따라 답이 달라집니다. 간단한 방법은 EXR이 예를 들어 1920 x 1080 인 경우 Render Dimensions를 1920 x 1920으로 설정하는 것입니다. 이렇게하면 이미지가 항상 맞고 잘리지 않습니다. 50 %와 같은 다른 비율로 렌더링 하려면 Render Size> Fit로 설정된 Rotate Node 뒤에 Scale Node를 배치해야합니다 .

렌더링 된 이미지의 종횡비를 16 : 9로 유지하려면 두 가지 방법이 있습니다.

  1. EXR은 가능한 한 많은 공간을 채워야합니다 (0 °에서 1920 x 1080, 90 °에서 608 x 1080).
  2. 치수는 동일하게 유지되어야합니다 (0 °에서 1080 x 608, 90 °에서 608 x 1080).

어느 쪽이든 Render Size> FitRelative> X = Y = 9/16 = 0.5625로 설정된 두 번째 Scale Node가있는 위에서 설명한 Scale Node가 필요합니다 .

옵션 1의 경우 Relative 노드 를 비활성화 하거나 회전이 0 °이면 X = Y = 1로 설정해야합니다. 90 ° 또는 -90 °의 경우 X = Y = 0.5625로 활성화해야합니다.

옵션 2의 경우 0 ° 또는 90 °에 관계없이 활성화 된 상태로 두지 만이 경우 앞에서 언급했듯이 EXR은 이미지를 가로로 채우지 않습니다.

회전 값에 따라 상대 노드 를 자동으로 비활성화하는 노드 설정을 만들었습니다 . 이미지를 참조하십시오. 시퀀스를 렌더링하고 회전을위한 키 프레임을 설정하려는 경우 노드를 수동으로 비활성화 할 필요가 없습니다. 렌더 치수의 종횡비는 드라이버가 계산합니다.