diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 1e41525..8806661 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -252,6 +252,17 @@ static void xml_read_integrator(const XMLReadState& state, pugi::xml_node node) xml_read_int(&integrator->subsurface_samples, node, "subsurface_samples"); xml_read_int(&integrator->volume_samples, node, "volume_samples"); } + + /* Metropolis Path Path */ + bool metropolis = false; + xml_read_bool(&metropolis, node, "metropolis"); + + if(metropolis) { + integrator->method = Integrator::METROPOLIS_PATH; + xml_read_float(&integrator->image_mutation_range, "image_mutation_range"); + xml_read_float(&integrator->large_mutation_chance, "large_mutation_chance"); + xml_read_int(&integrator->max_consecutive_rejects, "max_consecutive_rejects"); + } /* Bounces */ xml_read_int(&integrator->min_bounce, node, "min_bounce"); diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py index 9991fdb..1d6f25a 100644 --- a/intern/cycles/blender/addon/presets.py +++ b/intern/cycles/blender/addon/presets.py @@ -56,6 +56,9 @@ class AddPresetSampling(AddPresetBase, Operator): preset_values = [ "cycles.samples", + "cycles.max_consecutive_rejects", + "cycles.image_mutation_range", + "cycles.large_mutation_chance", "cycles.preview_samples", "cycles.aa_samples", "cycles.preview_aa_samples", diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 5adcbc6..7eac837 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -106,6 +106,7 @@ enum_sampling_pattern = ( enum_integrator = ( ('BRANCHED_PATH', "Branched Path Tracing", "Path tracing integrator that branches on the first bounce, giving more control over the number of light and material samples"), ('PATH', "Path Tracing", "Pure path tracing integrator"), + ('METROPOLIS_PATH', "Metropolis Path Tracing", "Path tracing integrator with Metropolis sampling"), ) @@ -170,6 +171,26 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): default=False, ) + + cls.max_consecutive_rejects = IntProperty( + name="Max. consecutive rejects", + description="Number of rejected mutations before the next mutation is forced to be accepted", + min=1, max=10000, + default=512, + ) + cls.image_mutation_range = FloatProperty( + name="Image mutation range", + description="Range of the pixel position mutation", + min=0.0, max=10.0, + default=0.1, + ) + cls.large_mutation_chance = FloatProperty( + name="Large mutation chance", + description="Chance that a large mutation (new sample) is made instead of mutating the old one", + min=0.0, max=1.0, + default=0.4, + ) + cls.aa_samples = IntProperty( name="AA Samples", description="Number of antialiasing samples to render for each pixel", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 0b107de..a9e555a 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -56,6 +56,10 @@ def draw_samples_info(layout, cscene): aa = cscene.samples if cscene.use_square_samples: aa = aa * aa + elif integrator == 'METROPOLIS_PATH': + aa = cscene.samples + if cscene.use_square_samples: + aa = aa * aa else: aa = cscene.aa_samples d = cscene.diffuse_samples @@ -113,6 +117,13 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): row.prop(cscene, "progressive", text="") row.prop(cscene, "use_square_samples") + if cscene.progressive == 'METROPOLIS_PATH': + mrow = layout.row() + mrow.label("Metropolis:") + mrow.prop(cscene, "max_consecutive_rejects", text="Max. consecutive rejects") + mrow.prop(cscene, "image_mutation_range", text="Max. consecutive rejects") + mrow.prop(cscene, "large_mutation_chance", text="Chance of large mutation") + split = layout.split() col = split.column() @@ -127,6 +138,12 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): sub.label(text="Samples:") sub.prop(cscene, "samples", text="Render") sub.prop(cscene, "preview_samples", text="Preview") + elif cscene.progressive == 'METROPOLIS_PATH': + col = split.column() + sub = col.column(align=True) + sub.label(text="Samples:") + sub.prop(cscene, "samples", text="Render") + sub.prop(cscene, "preview_samples", text="Preview") else: sub.label(text="AA Samples:") sub.prop(cscene, "aa_samples", text="Render") diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 14e9f27..65dfb42 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -196,6 +196,10 @@ void BlenderSync::sync_integrator() integrator->method = (Integrator::Method)get_enum(cscene, "progressive"); + integrator->max_consecutive_rejects = get_int(cscene, "max_consecutive_rejects"); + integrator->image_mutation_range = get_float(cscene, "image_mutation_range"); + integrator->large_mutation_chance = get_float(cscene, "large_mutation_chance"); + int diffuse_samples = get_int(cscene, "diffuse_samples"); int glossy_samples = get_int(cscene, "glossy_samples"); int transmission_samples = get_int(cscene, "transmission_samples"); diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index bd309e3..3c689d3 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -33,6 +33,7 @@ CCL_NAMESPACE_BEGIN class Progress; class RenderTile; +class Session; /* Device Types */ diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 76123fe..6ed50a9 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -16,6 +16,7 @@ #include #include +#include #include "device.h" #include "device_intern.h" @@ -24,6 +25,7 @@ #include "kernel_compat_cpu.h" #include "kernel_types.h" #include "kernel_globals.h" +#include "kernel_random.h" #include "osl_shader.h" #include "osl_globals.h" @@ -37,9 +39,44 @@ #include "util_progress.h" #include "util_system.h" #include "util_thread.h" +#include "util_color.h" + + +#include "session.h" CCL_NAMESPACE_BEGIN +static float Mutate(const float x, const float randomValue) { + static const float s1 = 1.f / 512.f, s2 = 1.f / 16.f; + + const float dx = s1 / (s1 / s2 + fabsf(2.f * randomValue - 1.f)) - + s1 / (s1 / s2 + 1.f); + + if (randomValue < 0.5f) { + float mutatedX = x + dx; + return (mutatedX < 1.f) ? mutatedX : mutatedX - 1.f; + } else { + float mutatedX = x - dx; + return (mutatedX < 0.f) ? mutatedX + 1.f : mutatedX; + } +} + +static float MutateScaled(const float x, const float range, const float randomValue) { + static const float s1 = 32.f; + + const float dx = range / (s1 / (1.f + s1) + (s1 * s1) / (1.f + s1) * + fabsf(2.f * randomValue - 1.f)) - range / s1; + + float mutatedX = x; + if (randomValue < 0.5f) { + mutatedX += dx; + return (mutatedX < 1.f) ? mutatedX : (mutatedX - 1.f); + } else { + mutatedX -= dx; + return (mutatedX < 0.f) ? (mutatedX + 1.f) : mutatedX; + } +} + class CPUDevice : public Device { public: @@ -146,6 +183,14 @@ public: } }; + void clearPass(RenderTile *tile, KernelData *kd, float* buffer) { + for(int y = tile->y; y < tile->y + tile->h; y++) { + for(int x = tile->x; x < tile->x + tile->w; x++) { + *((ccl_global float4*)(buffer + (tile->offset + x + y*tile->stride)*kd->film.pass_stride)) = make_float4(0, 0, 0, 0); + } + } + } + void thread_path_trace(DeviceTask& task) { if(task_pool.canceled()) { @@ -256,13 +301,120 @@ public: else #endif { - for(int sample = start_sample; sample < end_sample; sample++) { + uint maxRejects = kg.__data.integrator.max_consecutive_rejects; + float largeMutationProbability = kg.__data.integrator.large_mutation_chance, imageMutationRange = kg.__data.integrator.image_mutation_range; + double sharedTotalLuminance = 0.0f, sharedSampleCount = 0.0f; + uint sampleSize = PRNG_BASE_NUM + kg.__data.integrator.max_bounce*PRNG_BOUNCE_NUM + 2; //2 for pixel + float *samples = new float[sampleSize]; + uint *sampleStamps = new uint[sampleSize]; + float weight = 0.0f; + uint consecRejects = 0; + uint stamp = 1, currentStamp = 1; + double currentLuminance = 0.0f; + float *currentSamples = new float[sampleSize]; + uint *currentSampleStamps = new uint[sampleSize]; + bool isLargeMutation = true, cooldown = true; + uint rng = lcg_init(kernel_globals.__data.integrator.seed); + + if (task.integrator_metropolis) { + for (int i = 0; i < sampleSize; i++) + sampleStamps[i] = 0; + if (start_sample == 0) clearPass(&tile, &kg.__data, render_buffer); + } + for(uint sample = start_sample; sample < end_sample; sample++) { if (task.get_cancel() || task_pool.canceled()) { if(task.need_finish_queue == false) break; } - for(int y = tile.y; y < tile.y + tile.h; y++) { + if (task.integrator_metropolis) { + for(uint i = 0; i < tile.w*tile.h; i++) { + for (uint j = 0; j < sampleSize; j++) { + uint sampleStamp = sampleStamps[j]; + float s; + if (sampleStamp == 0) { + s = lcg_step_float(&rng); + sampleStamp = 1; + } else s = samples[j]; + + + if ((j == 0) || (j == 1)) { + for (uint st = sampleStamp; st < stamp; ++st) + s = MutateScaled(s, imageMutationRange, lcg_step_float(&rng)); + } else { + for (uint st = sampleStamp; st < stamp; ++st) + s = Mutate(s, lcg_step_float(&rng)); + } + + samples[j] = s; + sampleStamps[j] = stamp; + } + + //Evaluate samples + float4 L = kernel_cpu_metropolis_path_trace(&kg, samples + 2, tile.offset, tile.stride, render_buffer, + (int) (samples[0]*tile.w) + tile.x, (int) (samples[1]*tile.h) + tile.y); + float newLuminance = linear_rgb_to_gray(L); + + if (isLargeMutation) { + sharedTotalLuminance += newLuminance; + sharedSampleCount += 1.0; + } + + const float meanIntensity = (sharedTotalLuminance > 0.0) ? (float) (sharedTotalLuminance / sharedSampleCount) : 1.f; + const float currentLargeMutationProbability = (cooldown) ? .5f : largeMutationProbability; + + //Accept sample? + float accProb; + if ((currentLuminance > 0.f) && (consecRejects < maxRejects)) accProb = min(1.0f, (float) (newLuminance / currentLuminance)); + else accProb = 1.f; + + const float newWeight = accProb + (isLargeMutation ? 1.0f : 0.0f); + weight += 1.0f - accProb; + + if ((accProb == 1.0f) || (lcg_step_float(&rng) < accProb)) { //Accept sample + const float norm = weight / (currentLuminance / meanIntensity + currentLargeMutationProbability); + if (norm > 0.f) + *((ccl_global float4*)(render_buffer + (tile.offset + (int) (samples[0]*tile.w) + tile.x + + ((int) (samples[1]*tile.h) + tile.y)*tile.stride)*kg.__data.film.pass_stride)) += L * norm; + + weight = newWeight; + currentStamp = stamp; + currentLuminance = newLuminance; + std::copy(samples, samples + sampleSize, currentSamples); + std::copy(sampleStamps, sampleStamps + sampleSize, currentSampleStamps); + consecRejects = 0; + } else { //Reject sample + const float norm = newWeight / (newLuminance / meanIntensity + currentLargeMutationProbability); + if (norm > 0.f) + *((ccl_global float4*)(render_buffer + (tile.offset + (int) (samples[0]*tile.w) + tile.x + + ((int) (samples[1]*tile.h) + tile.y)*tile.stride)*kg.__data.film.pass_stride)) += L * norm; + + stamp = currentStamp; + std::copy(currentSamples, currentSamples + sampleSize, samples); + std::copy(currentSampleStamps, currentSampleStamps + sampleSize, sampleStamps); + + ++consecRejects; + } + + if (cooldown) { //During cooldown, more large mutations are made + if (sharedSampleCount > tile.w*tile.h) { + cooldown = false; + isLargeMutation = (lcg_step_float(&rng) < currentLargeMutationProbability); + } else + isLargeMutation = (lcg_step_float(&rng) < .5f); + } else + isLargeMutation = (lcg_step_float(&rng) < currentLargeMutationProbability); + + if (isLargeMutation) { + stamp = 1; + std::fill(sampleStamps, sampleStamps + sampleSize, 0); + } else + ++stamp; + } + for(int y = tile.y; y < tile.y + tile.h; y++) + for(int x = tile.x; x < tile.x + tile.w; x++) + ((ccl_global float4*)(render_buffer + (tile.offset + x + y*tile.stride)*kg.__data.film.pass_stride))->w = sample + 1; //Override alpha + } else for(int y = tile.y; y < tile.y + tile.h; y++) { for(int x = tile.x; x < tile.x + tile.w; x++) { kernel_cpu_path_trace(&kg, render_buffer, rng_state, sample, x, y, tile.offset, tile.stride); diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h index c1bd39b..738c10f 100644 --- a/intern/cycles/device/device_task.h +++ b/intern/cycles/device/device_task.h @@ -65,6 +65,7 @@ public: bool need_finish_queue; bool integrator_branched; + bool integrator_metropolis; protected: double last_update_time; }; diff --git a/intern/cycles/kernel/kernel.cpp b/intern/cycles/kernel/kernel.cpp index 3fe1e80..37331f5 100644 --- a/intern/cycles/kernel/kernel.cpp +++ b/intern/cycles/kernel/kernel.cpp @@ -101,6 +101,10 @@ void kernel_cpu_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_s kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride); } +float4 kernel_cpu_metropolis_path_trace(KernelGlobals *kg, float* randomSamples, int offset, int stride, ccl_global float *buffer, float x, float y) { + return kernel_metropolis_path_trace(kg, randomSamples, offset, stride, buffer, x, y); +} + /* Film */ void kernel_cpu_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride) diff --git a/intern/cycles/kernel/kernel.h b/intern/cycles/kernel/kernel.h index 039dc79..498278e 100644 --- a/intern/cycles/kernel/kernel.h +++ b/intern/cycles/kernel/kernel.h @@ -42,6 +42,8 @@ void kernel_cpu_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *bu float sample_scale, int x, int y, int offset, int stride); void kernel_cpu_shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int i); +float4 kernel_cpu_metropolis_path_trace(KernelGlobals *kg, float* randomSamples, int offset, + int stride, ccl_global float *buffer, float x, float y); #ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 void kernel_cpu_sse2_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state, diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h index 887b1af..6cbfaa5 100644 --- a/intern/cycles/kernel/kernel_camera.h +++ b/intern/cycles/kernel/kernel_camera.h @@ -216,7 +216,7 @@ ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float /* Common */ -ccl_device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v, +ccl_device void camera_sample(KernelGlobals *kg, float x, float y, float filter_u, float filter_v, float lens_u, float lens_v, float time, Ray *ray) { /* pixel filter */ diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h index 512db9e..5890296 100644 --- a/intern/cycles/kernel/kernel_passes.h +++ b/intern/cycles/kernel/kernel_passes.h @@ -18,18 +18,21 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, int sample, float value) { + if (!buffer) return; ccl_global float *buf = buffer; *buf = (sample == 0)? value: *buf + value; } ccl_device_inline void kernel_write_pass_float3(ccl_global float *buffer, int sample, float3 value) { + if (!buffer) return; ccl_global float3 *buf = (ccl_global float3*)buffer; *buf = (sample == 0)? value: *buf + value; } ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, int sample, float4 value) { + if (!buffer) return; ccl_global float4 *buf = (ccl_global float4*)buffer; *buf = (sample == 0)? value: *buf + value; } @@ -37,6 +40,7 @@ ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, int sa ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global float *buffer, PathRadiance *L, ShaderData *sd, int sample, int path_flag, float3 throughput) { + if (!buffer) return; #ifdef __PASSES__ if(!(path_flag & PATH_RAY_CAMERA)) return; @@ -116,6 +120,7 @@ ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global fl ccl_device_inline void kernel_write_light_passes(KernelGlobals *kg, ccl_global float *buffer, PathRadiance *L, int sample) { + if (!buffer) return; #ifdef __PASSES__ int flag = kernel_data.film.pass_flag; diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 8460af8..6111670 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -1390,7 +1390,7 @@ ccl_device void kernel_path_trace(KernelGlobals *kg, /* accumulate result in output buffer */ kernel_write_pass_float4(buffer, sample, L); - path_rng_end(kg, rng_state, rng); + path_rng_end(kg, rng_state, &rng); } #ifdef __BRANCHED_PATH__ @@ -1422,9 +1422,26 @@ ccl_device void kernel_branched_path_trace(KernelGlobals *kg, /* accumulate result in output buffer */ kernel_write_pass_float4(buffer, sample, L); - path_rng_end(kg, rng_state, rng); + path_rng_end(kg, rng_state, &rng); } #endif +ccl_device float4 kernel_metropolis_path_trace(KernelGlobals *kg, float* randomSamples, int offset, int stride, ccl_global float *buffer, float x, float y) { + int index = offset + x + y*stride; + int pass_stride = kernel_data.film.pass_stride; + if (buffer) buffer += index*pass_stride; + + Ray ray; + camera_sample(kg, x, y, randomSamples[PRNG_FILTER_U], randomSamples[PRNG_FILTER_V], randomSamples[PRNG_LENS_U], randomSamples[PRNG_LENS_V], randomSamples[PRNG_TIME], &ray); + + float4 L; + if(ray.t != 0.0f) + L = kernel_path_integrate(kg, (RNG*) randomSamples, 1, ray, buffer); + else + L = make_float4(0.0f, 0.0f, 0.0f, 0.0f); + L.w = 1.f; + return L; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index ef39726..b61da00 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -100,6 +100,8 @@ ccl_device uint sobol_lookup(const uint m, const uint frame, const uint ex, cons ccl_device_inline float path_rng_1D(KernelGlobals *kg, RNG *rng, int sample, int num_samples, int dimension) { + if(kernel_data.integrator.metropolis) + return ((float*) rng)[dimension]; #ifdef __CMJ__ if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) { /* correlated multi-jittered */ @@ -131,6 +133,11 @@ ccl_device_inline float path_rng_1D(KernelGlobals *kg, RNG *rng, int sample, int ccl_device_inline void path_rng_2D(KernelGlobals *kg, RNG *rng, int sample, int num_samples, int dimension, float *fx, float *fy) { + if(kernel_data.integrator.metropolis) { + *fx = ((float*) rng)[dimension]; + *fy = ((float*) rng)[dimension + 1]; + return; + } #ifdef __CMJ__ if(kernel_data.integrator.sampling_pattern == SAMPLING_PATTERN_CMJ) { /* correlated multi-jittered */ @@ -148,6 +155,11 @@ ccl_device_inline void path_rng_2D(KernelGlobals *kg, RNG *rng, int sample, int ccl_device_inline void path_rng_init(KernelGlobals *kg, ccl_global uint *rng_state, int sample, int num_samples, RNG *rng, int x, int y, float *fx, float *fy) { + if (kernel_data.integrator.metropolis) { + *fx = ((float*) rng)[PRNG_FILTER_U]; + *fy = ((float*) rng)[PRNG_FILTER_V]; + return; + } #ifdef __SOBOL_FULL_SCREEN__ uint px, py; uint bits = 16; /* limits us to 65536x65536 and 65536 samples */ @@ -181,7 +193,7 @@ ccl_device_inline void path_rng_init(KernelGlobals *kg, ccl_global uint *rng_sta #endif } -ccl_device void path_rng_end(KernelGlobals *kg, ccl_global uint *rng_state, RNG rng) +ccl_device void path_rng_end(KernelGlobals *kg, ccl_global uint *rng_state, RNG* rng) { /* nothing to do */ } @@ -190,14 +202,14 @@ ccl_device void path_rng_end(KernelGlobals *kg, ccl_global uint *rng_state, RNG /* Linear Congruential Generator */ -ccl_device_inline float path_rng_1D(KernelGlobals *kg, RNG& rng, int sample, int num_samples, int dimension) +ccl_device_inline float path_rng_1D(KernelGlobals *kg, RNG* rng, int sample, int num_samples, int dimension) { /* implicit mod 2^32 */ - rng = (1103515245*(rng) + 12345); - return (float)rng * (1.0f/(float)0xFFFFFFFF); + *rng = (1103515245*(*rng) + 12345); + return (float)*rng * (1.0f/(float)0xFFFFFFFF); } -ccl_device_inline void path_rng_2D(KernelGlobals *kg, RNG& rng, int sample, int num_samples, int dimension, float *fx, float *fy) +ccl_device_inline void path_rng_2D(KernelGlobals *kg, RNG* rng, int sample, int num_samples, int dimension, float *fx, float *fy) { *fx = path_rng_1D(kg, rng, sample, num_samples, dimension); *fy = path_rng_1D(kg, rng, sample, num_samples, dimension + 1); @@ -219,10 +231,10 @@ ccl_device void path_rng_init(KernelGlobals *kg, ccl_global uint *rng_state, int } } -ccl_device void path_rng_end(KernelGlobals *kg, ccl_global uint *rng_state, RNG rng) +ccl_device void path_rng_end(KernelGlobals *kg, ccl_global uint *rng_state, RNG *rng) { /* store state for next sample */ - *rng_state = rng; + *rng_state = *rng; } #endif diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 77ecc2b..aa67316 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -17,6 +17,8 @@ #ifndef __KERNEL_TYPES_H__ #define __KERNEL_TYPES_H__ +#include + #include "kernel_math.h" #include "svm/svm_types.h" @@ -822,6 +824,12 @@ typedef struct KernelIntegrator { /* clamp */ float sample_clamp; + /* metropolis path */ + int metropolis; + int max_consecutive_rejects; + float image_mutation_range; + float large_mutation_chance; + /* branched path */ int branched; int aa_samples; diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index 1042a5c..5e08d5e 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -59,6 +59,9 @@ Integrator::Integrator() mesh_light_samples = 1; subsurface_samples = 1; volume_samples = 1; + max_consecutive_rejects = 512; + image_mutation_range = 0.1f; + large_mutation_chance = 0.4f; method = PATH; sampling_pattern = SAMPLING_PATTERN_SOBOL; @@ -117,6 +120,11 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene kintegrator->sample_clamp = (sample_clamp == 0.0f)? FLT_MAX: sample_clamp*3.0f; + kintegrator->metropolis = (method == METROPOLIS_PATH); + kintegrator->max_consecutive_rejects = max_consecutive_rejects; + kintegrator->image_mutation_range = image_mutation_range; + kintegrator->large_mutation_chance = large_mutation_chance; + kintegrator->branched = (method == BRANCHED_PATH); kintegrator->aa_samples = aa_samples; kintegrator->diffuse_samples = diffuse_samples; @@ -182,6 +190,9 @@ bool Integrator::modified(const Integrator& integrator) seed == integrator.seed && sample_clamp == integrator.sample_clamp && method == integrator.method && + max_consecutive_rejects == integrator.max_consecutive_rejects && + image_mutation_range == integrator.image_mutation_range && + large_mutation_chance == integrator.large_mutation_chance && aa_samples == integrator.aa_samples && diffuse_samples == integrator.diffuse_samples && glossy_samples == integrator.glossy_samples && diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h index cc4a28a..ca1cfb3 100644 --- a/intern/cycles/render/integrator.h +++ b/intern/cycles/render/integrator.h @@ -53,6 +53,10 @@ public: float sample_clamp; bool motion_blur; + int max_consecutive_rejects; + float image_mutation_range; + float large_mutation_chance; + int aa_samples; int diffuse_samples; int glossy_samples; @@ -64,7 +68,8 @@ public: enum Method { BRANCHED_PATH = 0, - PATH = 1 + PATH = 1, + METROPOLIS_PATH = 2 }; Method method; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 0805a68..8a4bc09 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -830,6 +830,7 @@ void Session::path_trace() task.update_progress_sample = function_bind(&Session::update_progress_sample, this); task.need_finish_queue = params.progressive_refine; task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH; + task.integrator_metropolis = scene->integrator->method == Integrator::METROPOLIS_PATH; device->task_add(task); } diff --git a/intern/cycles/util/util_color.h b/intern/cycles/util/util_color.h index 0cfa404..bca8318 100644 --- a/intern/cycles/util/util_color.h +++ b/intern/cycles/util/util_color.h @@ -218,6 +218,11 @@ ccl_device float linear_rgb_to_gray(float3 c) return c.x*0.2126f + c.y*0.7152f + c.z*0.0722f; } +ccl_device float linear_rgb_to_gray(float4 c) +{ + return c.x*0.2126f + c.y*0.7152f + c.z*0.0722f; +} + CCL_NAMESPACE_END #endif /* __UTIL_COLOR_H__ */