Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Werner <stefan.werner@tangent-animation.com>2020-03-05 14:05:42 +0300
committerStefan Werner <stefan.werner@tangent-animation.com>2020-03-05 14:21:38 +0300
commit51e898324de30c0985a80e5bc067358b5ccedbfc (patch)
tree5efddead1b7ca5655f1d6d2422b59e7da51fe271 /intern/cycles/render
parent4ccbbd308060f0330472828b317c59e054c9ee7b (diff)
Adaptive Sampling for Cycles.
This feature takes some inspiration from "RenderMan: An Advanced Path Tracing Architecture for Movie Rendering" and "A Hierarchical Automatic Stopping Condition for Monte Carlo Global Illumination" The basic principle is as follows: While samples are being added to a pixel, the adaptive sampler writes half of the samples to a separate buffer. This gives it two separate estimates of the same pixel, and by comparing their difference it estimates convergence. Once convergence drops below a given threshold, the pixel is considered done. When a pixel has not converged yet and needs more samples than the minimum, its immediate neighbors are also set to take more samples. This is done in order to more reliably detect sharp features such as caustics. A 3x3 box filter that is run periodically over the tile buffer is used for that purpose. After a tile has finished rendering, the values of all passes are scaled as if they were rendered with the full number of samples. This way, any code operating on these buffers, for example the denoiser, does not need to be changed for per-pixel sample counts. Reviewed By: brecht, #cycles Differential Revision: https://developer.blender.org/D4686
Diffstat (limited to 'intern/cycles/render')
-rw-r--r--intern/cycles/render/buffers.cpp21
-rw-r--r--intern/cycles/render/film.cpp14
-rw-r--r--intern/cycles/render/film.h2
-rw-r--r--intern/cycles/render/integrator.cpp20
-rw-r--r--intern/cycles/render/integrator.h3
-rw-r--r--intern/cycles/render/session.cpp4
-rw-r--r--intern/cycles/render/session.h3
7 files changed, 67 insertions, 0 deletions
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp
index 41e1b73fdac..19d3f00bf82 100644
--- a/intern/cycles/render/buffers.cpp
+++ b/intern/cycles/render/buffers.cpp
@@ -260,6 +260,22 @@ bool RenderBuffers::get_pass_rect(
return false;
}
+ float *sample_count = NULL;
+ if (name == "Combined") {
+ int sample_offset = 0;
+ for (size_t j = 0; j < params.passes.size(); j++) {
+ Pass &pass = params.passes[j];
+ if (pass.type != PASS_SAMPLE_COUNT) {
+ sample_offset += pass.components;
+ continue;
+ }
+ else {
+ sample_count = buffer.data() + sample_offset;
+ break;
+ }
+ }
+ }
+
int pass_offset = 0;
for (size_t j = 0; j < params.passes.size(); j++) {
@@ -420,6 +436,11 @@ bool RenderBuffers::get_pass_rect(
}
else {
for (int i = 0; i < size; i++, in += pass_stride, pixels += 4) {
+ if (sample_count && sample_count[i * pass_stride] < 0.0f) {
+ scale = (pass.filter) ? -1.0f / (sample_count[i * pass_stride]) : 1.0f;
+ scale_exposure = (pass.exposure) ? scale * exposure : scale;
+ }
+
float4 f = make_float4(in[0], in[1], in[2], in[3]);
pixels[0] = f.x * scale_exposure;
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index 172ea3dd31b..48d9c97e0fb 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -183,6 +183,13 @@ void Pass::add(PassType type, vector<Pass> &passes, const char *name)
case PASS_CRYPTOMATTE:
pass.components = 4;
break;
+ case PASS_ADAPTIVE_AUX_BUFFER:
+ pass.components = 4;
+ break;
+ case PASS_SAMPLE_COUNT:
+ pass.components = 1;
+ pass.exposure = false;
+ break;
case PASS_AOV_COLOR:
pass.components = 4;
break;
@@ -311,6 +318,7 @@ NODE_DEFINE(Film)
SOCKET_BOOLEAN(denoising_clean_pass, "Generate Denoising Clean Pass", false);
SOCKET_BOOLEAN(denoising_prefiltered_pass, "Generate Denoising Prefiltered Pass", false);
SOCKET_INT(denoising_flags, "Denoising Flags", 0);
+ SOCKET_BOOLEAN(use_adaptive_sampling, "Use Adaptive Sampling", false);
return type;
}
@@ -482,6 +490,12 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
kfilm->pass_stride;
have_cryptomatte = true;
break;
+ case PASS_ADAPTIVE_AUX_BUFFER:
+ kfilm->pass_adaptive_aux_buffer = kfilm->pass_stride;
+ break;
+ case PASS_SAMPLE_COUNT:
+ kfilm->pass_sample_count = kfilm->pass_stride;
+ break;
case PASS_AOV_COLOR:
if (!have_aov_color) {
kfilm->pass_aov_color = kfilm->pass_stride;
diff --git a/intern/cycles/render/film.h b/intern/cycles/render/film.h
index 95e54cb54d8..aae8fb404b0 100644
--- a/intern/cycles/render/film.h
+++ b/intern/cycles/render/film.h
@@ -81,6 +81,8 @@ class Film : public Node {
CryptomatteType cryptomatte_passes;
int cryptomatte_depth;
+ bool use_adaptive_sampling;
+
bool need_update;
Film();
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index f289e11fe14..ee1aa5988bf 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -27,6 +27,7 @@
#include "kernel/kernel_types.h"
#include "util/util_foreach.h"
+#include "util/util_logging.h"
#include "util/util_hash.h"
CCL_NAMESPACE_BEGIN
@@ -69,6 +70,9 @@ NODE_DEFINE(Integrator)
SOCKET_INT(volume_samples, "Volume Samples", 1);
SOCKET_INT(start_sample, "Start Sample", 0);
+ SOCKET_FLOAT(adaptive_threshold, "Adaptive Threshold", 0.0f);
+ SOCKET_INT(adaptive_min_samples, "Adaptive Min Samples", 0);
+
SOCKET_BOOLEAN(sample_all_lights_direct, "Sample All Lights Direct", true);
SOCKET_BOOLEAN(sample_all_lights_indirect, "Sample All Lights Indirect", true);
SOCKET_FLOAT(light_sampling_threshold, "Light Sampling Threshold", 0.05f);
@@ -178,6 +182,22 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->sampling_pattern = sampling_pattern;
kintegrator->aa_samples = aa_samples;
+ if (aa_samples > 0 && adaptive_min_samples == 0) {
+ kintegrator->adaptive_min_samples = max(4, (int)sqrtf(aa_samples));
+ VLOG(1) << "Cycles adaptive sampling: automatic min samples = "
+ << kintegrator->adaptive_min_samples;
+ }
+ else {
+ kintegrator->adaptive_min_samples = max(4, adaptive_min_samples);
+ }
+ if (aa_samples > 0 && adaptive_threshold == 0.0f) {
+ kintegrator->adaptive_threshold = max(0.001f, 1.0f / (float)aa_samples);
+ VLOG(1) << "Cycles adaptive sampling: automatic threshold = "
+ << kintegrator->adaptive_threshold;
+ }
+ else {
+ kintegrator->adaptive_threshold = adaptive_threshold;
+ }
if (light_sampling_threshold > 0.0f) {
kintegrator->light_inv_rr_threshold = 1.0f / light_sampling_threshold;
diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h
index 32d84c27072..9930e907aea 100644
--- a/intern/cycles/render/integrator.h
+++ b/intern/cycles/render/integrator.h
@@ -75,6 +75,9 @@ class Integrator : public Node {
bool sample_all_lights_indirect;
float light_sampling_threshold;
+ int adaptive_min_samples;
+ float adaptive_threshold;
+
enum Method {
BRANCHED_PATH = 0,
PATH = 1,
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 4231403e39a..6bf2160f9fa 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -1103,6 +1103,10 @@ void Session::render(bool with_denoising)
task.need_finish_queue = params.progressive_refine;
task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH;
+ task.adaptive_sampling.use = (scene->integrator->sampling_pattern == SAMPLING_PATTERN_PMJ) &&
+ scene->dscene.data.film.pass_adaptive_aux_buffer;
+ task.adaptive_sampling.min_samples = scene->dscene.data.integrator.adaptive_min_samples;
+
/* Acquire render tiles by default. */
task.tile_types = RenderTile::PATH_TRACE;
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index 7f3614ccb19..8053e46b12e 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -56,6 +56,7 @@ class SessionParams {
int denoising_start_sample;
int pixel_size;
int threads;
+ bool adaptive_sampling;
bool use_profiling;
@@ -89,6 +90,7 @@ class SessionParams {
denoising_start_sample = 0;
pixel_size = 1;
threads = 0;
+ adaptive_sampling = false;
use_profiling = false;
@@ -117,6 +119,7 @@ class SessionParams {
progressive == params.progressive && experimental == params.experimental &&
tile_size == params.tile_size && start_resolution == params.start_resolution &&
pixel_size == params.pixel_size && threads == params.threads &&
+ adaptive_sampling == params.adaptive_sampling &&
use_profiling == params.use_profiling &&
display_buffer_linear == params.display_buffer_linear &&
cancel_timeout == params.cancel_timeout && reset_timeout == params.reset_timeout &&