1# Fusion uses negative Z values for the depth buffer, while Blender denotes
2# this with positive values. For "Depth Merge" and other nodes to work
3# correctly, Blender's output must be flipped. I am unaware of how to do
4# this in Blender itself, hence this simple post processor.
5import OpenEXR
6import Imath
7import numpy as np
8import argparse
9import os
10
11Z_FLIPPED_METADATA_KEY = "zBufferFlipped"
12
13def invert_z_buffer(exr_input_path):
14 exr_file = OpenEXR.InputFile(exr_input_path)
15
16 header = exr_file.header()
17 channels = header['channels'];
18 part_names = channels.keys()
19
20 if Z_FLIPPED_METADATA_KEY in header:
21 print(f"Skipping {exr_input_path}")
22 exr_file.close()
23 return
24
25 processed_parts = {}
26
27 for part_name in part_names:
28 pixel_type = header['channels'][part_name].type
29 if pixel_type == Imath.PixelType(Imath.PixelType.HALF):
30 dtype = np.float16
31 elif pixel_type == Imath.PixelType(Imath.PixelType.FLOAT):
32 dtype = np.float32
33 else:
34 raise ValueError(f"Unsupported pixel type {pixel_type} for channel {part_name}.")
35
36 channel_data = exr_file.channel(part_name, pixel_type)
37 channel_data_array = np.frombuffer(channel_data, dtype=dtype)
38
39 if "Depth.Z" in part_name:
40 channel_data_array = -channel_data_array
41
42 processed_parts[part_name] = channel_data_array.tobytes()
43
44 header[Z_FLIPPED_METADATA_KEY] = 1
45
46 exr_output = OpenEXR.OutputFile(exr_input_path, header)
47
48 exr_output.writePixels(processed_parts)
49
50 exr_file.close()
51 exr_output.close()
52
53 print(f"Processed: {exr_input_path}")
54
55if __name__ == "__main__":
56 parser = argparse.ArgumentParser(description="Invert the Z-buffer in multipart EXR files.")
57
58 parser.add_argument('exr_files', nargs='+', help="List of EXR files to process.")
59
60 args = parser.parse_args()
61
62 for exr_file in args.exr_files:
63 if os.path.exists(exr_file):
64 invert_z_buffer(exr_file)
65 else:
66 print(f"File not found: {exr_file}")