Blender의 컴포 지터에서 Multilayer EXR 파일을 어떻게 회전합니까?
이미지 회전은 사소한 작업 인 것처럼 보이지만 Blender에서 Multilayer EXR 형식 파일로 작업 할 때이 문제에 직면합니다.
그런데 왜?
내 archvis 씬을 애니메이션으로 설정하는 것이 편리하다는 것을 알게되어 다른 스틸의 오브젝트를 변경하고 모든 카메라 앵글을 한 번에 애니메이션으로 렌더링 할 수 있습니다. 때때로 동일한 내부의 가로 및 세로 방향 이미지가 필요하고 작은 스크립트를 사용하여 X 및 Y 해상도 치수를 빠르게 전환 한 다음 프레임이 완료되면 카메라를 회전하여 일부 프레임이 회전 된 상태로 렌더링되도록합니다. 그러면 일련의 이미지를 합성하는 것이 매우 편리합니다.
최근에 몇 번의 배치로 장면을 렌더링 한 후 8K 파노라마 이미지 1 개, 가로 방향의 4K 거실 이미지 5 개, 그중 하나가 회전 된 상태의 4K 거실 이미지, 모두 세로 방향 인 계단 이미지 5 개가 순서대로 나오고 놀랍게도 컴 포지 팅 방향과 해상도의 차이에도 불구하고 모든 이미지를 한 번에 하나의 시퀀스로 수행하고 파일 출력 노드가있는 파일로 해당 시퀀스의 올바른 해상도와 방향으로 출력 할 수 있습니다. 이제 저는 동일한 순서로 다른 방향을 가질 수 있다는 것을 알고 있습니다.
지금까지했던 것처럼 출력 만 회전하는 대신 합성하면서 항상 올바르게 회전 된 모든 이미지를 볼 수 있다면 훨씬 더 놀랍습니다.
파일 시퀀스에서 회전이 필요한 렌더링 된 모든 Multilayer EXR 파일을 회전해야합니다.
내가 시도한 것
Multilayer EXR의 모든 출력을 Python으로 File Output 노드에 연결하고 Compositor 노드를 삽입하여 자동으로 편집하는 데 문제가 없으므로 한 레이어에서 작동하는 모든 솔루션이 편리하지만 컴포 지터에서 이미지를 지금까지 회전 할 수 없습니다. 회전하면 이미지가 원래 크기로 잘 리기 때문입니다.

질문
멀티 레이어 EXR의 모든 레이어를 회전하고 블렌더의 합성기 노드를 사용하여 회전 된 치수의 이미지로 출력하는 것이 가능합니까?
아래에 설명 된 내 솔루션과 답변에 Cryptomatte에 문제가 있습니다. 나는 그러한 문제없이 해결책을 찾기 위해 현상금을 시작하고 있습니다. Python으로 솔루션을 생각하기 시작했지만 Blender에서 어떻게 간단하고 사용하기 쉬운 지 모르겠습니다 ...
답변
cryptomattes 정보
문제는 회전 때문이 아니라 노드 위의 알파 때문입니다.

일반 컬러 이미지가됩니다.
다음과 같이 노드 그룹을 변경하는 경우 :

이를 통해 고려하지 않고 마스크에서 이미지 크기를 유지할 수 있지만 (0 곱하기) 회전 된 cryptomatte 값이 추가됩니다.
간단한 테스트 케이스 파일 :
이 솔루션에는 문제가 있습니다. 답변 끝 부분을 참조하십시오.
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 값의 정밀도를 엉망으로 만들어 잘못된 마스크 가장자리를 만듭니다.

Render Result는 EXR의 치수 나 방향을 고려하지 않기 때문에 원하는 결과에 따라 답이 달라집니다. 간단한 방법은 EXR이 예를 들어 1920 x 1080 인 경우 Render Dimensions를 1920 x 1920으로 설정하는 것입니다. 이렇게하면 이미지가 항상 맞고 잘리지 않습니다. 50 %와 같은 다른 비율로 렌더링 하려면 Render Size> Fit로 설정된 Rotate Node 뒤에 Scale Node를 배치해야합니다 .
렌더링 된 이미지의 종횡비를 16 : 9로 유지하려면 두 가지 방법이 있습니다.
- EXR은 가능한 한 많은 공간을 채워야합니다 (0 °에서 1920 x 1080, 90 °에서 608 x 1080).
- 치수는 동일하게 유지되어야합니다 (0 °에서 1080 x 608, 90 °에서 608 x 1080).
어느 쪽이든 Render Size> Fit 과 Relative> 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은 이미지를 가로로 채우지 않습니다.
회전 값에 따라 상대 노드 를 자동으로 비활성화하는 노드 설정을 만들었습니다 . 이미지를 참조하십시오. 시퀀스를 렌더링하고 회전을위한 키 프레임을 설정하려는 경우 노드를 수동으로 비활성화 할 필요가 없습니다. 렌더 치수의 종횡비는 드라이버가 계산합니다.

