diff options
Diffstat (limited to 'intern')
-rw-r--r-- | intern/cycles/session/merge.cpp | 132 |
1 files changed, 112 insertions, 20 deletions
diff --git a/intern/cycles/session/merge.cpp b/intern/cycles/session/merge.cpp index 57dd6a67785..0a9ed37750b 100644 --- a/intern/cycles/session/merge.cpp +++ b/intern/cycles/session/merge.cpp @@ -35,12 +35,15 @@ enum MergeChannelOp { MERGE_CHANNEL_NOP, MERGE_CHANNEL_COPY, MERGE_CHANNEL_SUM, - MERGE_CHANNEL_AVERAGE + MERGE_CHANNEL_AVERAGE, + MERGE_CHANNEL_SAMPLES, }; struct MergeImagePass { /* Full channel name. */ string channel_name; + /* Pass name. */ + string name; /* Channel format in the file. */ TypeDesc format; /* Type of operation to perform when merging. */ @@ -51,6 +54,13 @@ struct MergeImagePass { int merge_offset; }; +struct SampleCount { + /* Total number of samples. */ + int total; + /* Buffer for actual number of samples rendered per pixel. */ + array<float> per_pixel; +}; + struct MergeImageLayer { /* Layer name. */ string name; @@ -58,6 +68,10 @@ struct MergeImageLayer { vector<MergeImagePass> passes; /* Sample amount that was used for rendering this layer. */ int samples; + /* Indicates if this layer has "Debug Sample Count" pass. */ + bool has_sample_pass; + /* Offset of the "Debug Sample Count" pass if it exists. */ + int sample_pass_offset; }; /* Merge Image */ @@ -84,6 +98,9 @@ static MergeChannelOp parse_channel_operation(const string &pass_name) string_startswith(pass_name, "Debug Render Time")) { return MERGE_CHANNEL_SUM; } + else if (string_startswith(pass_name, "Debug Sample Count")) { + return MERGE_CHANNEL_SAMPLES; + } else { return MERGE_CHANNEL_AVERAGE; } @@ -148,11 +165,11 @@ static bool parse_channels(const ImageSpec &in_spec, pass.offset = i; pass.merge_offset = i; - string layername, passname, channelname; + string layername, channelname; if (parse_channel_name( - pass.channel_name, layername, passname, channelname, multiview_channels)) { + pass.channel_name, layername, pass.name, channelname, multiview_channels)) { /* Channel part of a render layer. */ - pass.op = parse_channel_operation(passname); + pass.op = parse_channel_operation(pass.name); } else { /* Other channels are added in unnamed layer. */ @@ -208,6 +225,19 @@ static bool parse_channels(const ImageSpec &in_spec, return false; } + /* Check if the layer has "Debug Sample Count" pass. */ + auto sample_pass_it = find_if( + layer.passes.begin(), layer.passes.end(), [](const MergeImagePass &pass) { + return pass.name == "Debug Sample Count"; + }); + if (sample_pass_it != layer.passes.end()) { + layer.has_sample_pass = true; + layer.sample_pass_offset = distance(layer.passes.begin(), sample_pass_it); + } + else { + layer.has_sample_pass = false; + } + layers.push_back(layer); } @@ -298,9 +328,7 @@ static void merge_layer_render_time(ImageSpec &spec, spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time)); } -static void merge_channels_metadata(vector<MergeImage> &images, - ImageSpec &out_spec, - vector<int> &channel_total_samples) +static void merge_channels_metadata(vector<MergeImage> &images, ImageSpec &out_spec) { /* Based on first image. */ out_spec = images[0].in->spec(); @@ -323,7 +351,6 @@ static void merge_channels_metadata(vector<MergeImage> &images, int index = distance(out_spec.channelnames.begin(), channel); pass.merge_offset = index; - channel_total_samples[index] += layer.samples; /* First image wins for channels that can't be averaged or summed. */ if (pass.op == MERGE_CHANNEL_COPY) { pass.op = MERGE_CHANNEL_NOP; @@ -332,7 +359,6 @@ static void merge_channels_metadata(vector<MergeImage> &images, else { /* Add new channel. */ pass.merge_offset = out_spec.nchannels; - channel_total_samples.push_back(layer.samples); out_spec.channelnames.push_back(pass.channel_name); out_spec.channelformats.push_back(pass.format); @@ -376,7 +402,7 @@ static void alloc_pixels(const ImageSpec &spec, array<float> &pixels) static bool merge_pixels(const vector<MergeImage> &images, const ImageSpec &out_spec, - const vector<int> &channel_total_samples, + const unordered_map<string, SampleCount> &layer_samples, array<float> &out_pixels, string &error) { @@ -416,16 +442,36 @@ static bool merge_pixels(const vector<MergeImage> &images, out_pixels[out_offset] += pixels[offset]; } break; - case MERGE_CHANNEL_AVERAGE: - /* Weights based on sample metadata. Per channel since not + case MERGE_CHANNEL_AVERAGE: { + /* Weights based on sample count passes and sample metadata. Per channel since not * all files are guaranteed to have the same channels. */ - const int total_samples = channel_total_samples[out_offset]; - const float t = (float)layer.samples / (float)total_samples; - - for (; offset < num_pixels; offset += stride, out_offset += out_stride) { - out_pixels[out_offset] += t * pixels[offset]; + size_t sample_pass_offset = layer.sample_pass_offset; + const auto &samples = layer_samples.at(layer.name); + + for (size_t i = 0; offset < num_pixels; + offset += stride, sample_pass_offset += stride, out_offset += out_stride, i++) { + const float total_samples = samples.per_pixel[i]; + + float layer_samples; + if (layer.has_sample_pass) { + layer_samples = pixels[sample_pass_offset] * layer.samples; + } + else { + layer_samples = layer.samples; + } + + out_pixels[out_offset] += pixels[offset] * (1.0f * layer_samples / total_samples); + } + break; + } + case MERGE_CHANNEL_SAMPLES: { + const auto &samples = layer_samples.at(layer.name); + for (size_t i = 0; offset < num_pixels; + offset += stride, out_offset += out_stride, i++) { + out_pixels[out_offset] = 1.0f * samples.per_pixel[i] / samples.total; } break; + } } } } @@ -484,6 +530,49 @@ static bool save_output(const string &filepath, return ok; } +static void read_layer_samples(vector<MergeImage> &images, + unordered_map<string, SampleCount> &layer_samples) +{ + for (auto &image : images) { + const ImageSpec &in_spec = image.in->spec(); + + for (auto &layer : image.layers) { + bool initialize = (layer_samples.count(layer.name) == 0); + auto ¤t_layer_samples = layer_samples[layer.name]; + + if (initialize) { + current_layer_samples.total = 0; + current_layer_samples.per_pixel.resize(in_spec.width * in_spec.height); + std::fill( + current_layer_samples.per_pixel.begin(), current_layer_samples.per_pixel.end(), 0); + } + + if (layer.has_sample_pass) { + /* Load the "Debug Sample Count" pass and add the samples to the layer's sample count. */ + array<float> sample_count_buffer; + sample_count_buffer.resize(in_spec.width * in_spec.height); + image.in->read_image(0, + 0, + layer.sample_pass_offset, + layer.sample_pass_offset, + TypeDesc::FLOAT, + (void *)sample_count_buffer.data()); + + for (size_t i = 0; i < current_layer_samples.per_pixel.size(); i++) { + current_layer_samples.per_pixel[i] += sample_count_buffer[i] * layer.samples; + } + } + else { + /* Use sample count from metadata if there's no "Debug Sample Count" pass. */ + for (size_t i = 0; i < current_layer_samples.per_pixel.size(); i++) { + current_layer_samples.per_pixel[i] += layer.samples; + } + } + + current_layer_samples.total += layer.samples; + } + } +} /* Image Merger */ ImageMerger::ImageMerger() @@ -507,14 +596,17 @@ bool ImageMerger::run() return false; } + /* Load and sum sample count for each render layer. */ + unordered_map<string, SampleCount> layer_samples; + read_layer_samples(images, layer_samples); + /* Merge metadata and setup channels and offsets. */ ImageSpec out_spec; - vector<int> channel_total_samples; - merge_channels_metadata(images, out_spec, channel_total_samples); + merge_channels_metadata(images, out_spec); /* Merge pixels. */ array<float> out_pixels; - if (!merge_pixels(images, out_spec, channel_total_samples, out_pixels, error)) { + if (!merge_pixels(images, out_spec, layer_samples, out_pixels, error)) { return false; } |