diff options
author | Brecht Van Lommel <brecht@blender.org> | 2021-10-24 15:19:19 +0300 |
---|---|---|
committer | Brecht Van Lommel <brecht@blender.org> | 2021-10-26 16:36:39 +0300 |
commit | d7d40745fa09061a3117bd3669c5a46bbf611eae (patch) | |
tree | 8dbaca086ecbb09aad62c25e9ece66332fe79af3 /intern/cycles/scene/jitter.cpp | |
parent | b698fe1e047e56e8ed67ba47464c0017d9c50eea (diff) |
Cycles: changes to source code folders structure
* Split render/ into scene/ and session/. The scene/ folder now contains the
scene and its nodes. The session/ folder contains the render session and
associated data structures like drivers and render buffers.
* Move top level kernel headers into new folders kernel/camera/, kernel/film/,
kernel/light/, kernel/sample/, kernel/util/
* Move integrator related kernel headers into kernel/integrator/
* Move OSL shaders from kernel/shaders/ to kernel/osl/shaders/
For patches and branches, git merge and rebase should be able to detect the
renames and move over code to the right file.
Diffstat (limited to 'intern/cycles/scene/jitter.cpp')
-rw-r--r-- | intern/cycles/scene/jitter.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/intern/cycles/scene/jitter.cpp b/intern/cycles/scene/jitter.cpp new file mode 100644 index 00000000000..e2162195ad8 --- /dev/null +++ b/intern/cycles/scene/jitter.cpp @@ -0,0 +1,281 @@ +/* + * Copyright 2019 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* This file is based on "Progressive Multi-Jittered Sample Sequences" + * by Per Christensen, Andrew Kensler and Charlie Kilpatrick. + * http://graphics.pixar.com/library/ProgressiveMultiJitteredSampling/paper.pdf + * + * Performance can be improved in the future by implementing the new + * algorithm from Matt Pharr in http://jcgt.org/published/0008/01/04/ + * "Efficient Generation of Points that Satisfy Two-Dimensional Elementary Intervals" + */ + +#include "scene/jitter.h" + +#include <math.h> +#include <vector> + +CCL_NAMESPACE_BEGIN + +static uint cmj_hash(uint i, uint p) +{ + i ^= p; + i ^= i >> 17; + i ^= i >> 10; + i *= 0xb36534e5; + i ^= i >> 12; + i ^= i >> 21; + i *= 0x93fc4795; + i ^= 0xdf6e307f; + i ^= i >> 17; + i *= 1 | p >> 18; + + return i; +} + +static float cmj_randfloat(uint i, uint p) +{ + return cmj_hash(i, p) * (1.0f / 4294967808.0f); +} + +class PMJ_Generator { + public: + static void generate_2D(float2 points[], int size, int rng_seed_in) + { + PMJ_Generator g(rng_seed_in); + points[0].x = g.rnd(); + points[0].y = g.rnd(); + int N = 1; + while (N < size) { + g.extend_sequence_even(points, N); + g.extend_sequence_odd(points, 2 * N); + N = 4 * N; + } + } + + protected: + PMJ_Generator(int rnd_seed_in) : num_samples(1), rnd_index(2), rnd_seed(rnd_seed_in) + { + } + + float rnd() + { + return cmj_randfloat(++rnd_index, rnd_seed); + } + + virtual void mark_occupied_strata(float2 points[], int N) + { + int NN = 2 * N; + for (int s = 0; s < NN; ++s) { + occupied1Dx[s] = occupied1Dy[s] = false; + } + for (int s = 0; s < N; ++s) { + int xstratum = (int)(NN * points[s].x); + int ystratum = (int)(NN * points[s].y); + occupied1Dx[xstratum] = true; + occupied1Dy[ystratum] = true; + } + } + + virtual void generate_sample_point( + float2 points[], float i, float j, float xhalf, float yhalf, int n, int N) + { + int NN = 2 * N; + float2 pt; + int xstratum, ystratum; + do { + pt.x = (i + 0.5f * (xhalf + rnd())) / n; + xstratum = (int)(NN * pt.x); + } while (occupied1Dx[xstratum]); + do { + pt.y = (j + 0.5f * (yhalf + rnd())) / n; + ystratum = (int)(NN * pt.y); + } while (occupied1Dy[ystratum]); + occupied1Dx[xstratum] = true; + occupied1Dy[ystratum] = true; + points[num_samples] = pt; + ++num_samples; + } + + void extend_sequence_even(float2 points[], int N) + { + int n = (int)sqrtf(N); + occupied1Dx.resize(2 * N); + occupied1Dy.resize(2 * N); + mark_occupied_strata(points, N); + for (int s = 0; s < N; ++s) { + float2 oldpt = points[s]; + float i = floorf(n * oldpt.x); + float j = floorf(n * oldpt.y); + float xhalf = floorf(2.0f * (n * oldpt.x - i)); + float yhalf = floorf(2.0f * (n * oldpt.y - j)); + xhalf = 1.0f - xhalf; + yhalf = 1.0f - yhalf; + generate_sample_point(points, i, j, xhalf, yhalf, n, N); + } + } + + void extend_sequence_odd(float2 points[], int N) + { + int n = (int)sqrtf(N / 2); + occupied1Dx.resize(2 * N); + occupied1Dy.resize(2 * N); + mark_occupied_strata(points, N); + std::vector<float> xhalves(N / 2); + std::vector<float> yhalves(N / 2); + for (int s = 0; s < N / 2; ++s) { + float2 oldpt = points[s]; + float i = floorf(n * oldpt.x); + float j = floorf(n * oldpt.y); + float xhalf = floorf(2.0f * (n * oldpt.x - i)); + float yhalf = floorf(2.0f * (n * oldpt.y - j)); + if (rnd() > 0.5f) { + xhalf = 1.0f - xhalf; + } + else { + yhalf = 1.0f - yhalf; + } + xhalves[s] = xhalf; + yhalves[s] = yhalf; + generate_sample_point(points, i, j, xhalf, yhalf, n, N); + } + for (int s = 0; s < N / 2; ++s) { + float2 oldpt = points[s]; + float i = floorf(n * oldpt.x); + float j = floorf(n * oldpt.y); + float xhalf = 1.0f - xhalves[s]; + float yhalf = 1.0f - yhalves[s]; + generate_sample_point(points, i, j, xhalf, yhalf, n, N); + } + } + + std::vector<bool> occupied1Dx, occupied1Dy; + int num_samples; + int rnd_index, rnd_seed; +}; + +class PMJ02_Generator : public PMJ_Generator { + protected: + void generate_sample_point( + float2 points[], float i, float j, float xhalf, float yhalf, int n, int N) override + { + int NN = 2 * N; + float2 pt; + do { + pt.x = (i + 0.5f * (xhalf + rnd())) / n; + pt.y = (j + 0.5f * (yhalf + rnd())) / n; + } while (is_occupied(pt, NN)); + mark_occupied_strata1(pt, NN); + points[num_samples] = pt; + ++num_samples; + } + + void mark_occupied_strata(float2 points[], int N) override + { + int NN = 2 * N; + int num_shapes = (int)log2f(NN) + 1; + occupiedStrata.resize(num_shapes); + for (int shape = 0; shape < num_shapes; ++shape) { + occupiedStrata[shape].resize(NN); + for (int n = 0; n < NN; ++n) { + occupiedStrata[shape][n] = false; + } + } + for (int s = 0; s < N; ++s) { + mark_occupied_strata1(points[s], NN); + } + } + + void mark_occupied_strata1(float2 pt, int NN) + { + int shape = 0; + int xdivs = NN; + int ydivs = 1; + do { + int xstratum = (int)(xdivs * pt.x); + int ystratum = (int)(ydivs * pt.y); + size_t index = ystratum * xdivs + xstratum; + assert(index < NN); + occupiedStrata[shape][index] = true; + shape = shape + 1; + xdivs = xdivs / 2; + ydivs = ydivs * 2; + } while (xdivs > 0); + } + + bool is_occupied(float2 pt, int NN) + { + int shape = 0; + int xdivs = NN; + int ydivs = 1; + do { + int xstratum = (int)(xdivs * pt.x); + int ystratum = (int)(ydivs * pt.y); + size_t index = ystratum * xdivs + xstratum; + assert(index < NN); + if (occupiedStrata[shape][index]) { + return true; + } + shape = shape + 1; + xdivs = xdivs / 2; + ydivs = ydivs * 2; + } while (xdivs > 0); + return false; + } + + private: + std::vector<std::vector<bool>> occupiedStrata; +}; + +static void shuffle(float2 points[], int size, int rng_seed) +{ + if (rng_seed == 0) { + return; + } + + constexpr int odd[8] = {0, 1, 4, 5, 10, 11, 14, 15}; + constexpr int even[8] = {2, 3, 6, 7, 8, 9, 12, 13}; + + int rng_index = 0; + for (int yy = 0; yy < size / 16; ++yy) { + for (int xx = 0; xx < 8; ++xx) { + int other = (int)(cmj_randfloat(++rng_index, rng_seed) * (8.0f - xx) + xx); + float2 tmp = points[odd[other] + yy * 16]; + points[odd[other] + yy * 16] = points[odd[xx] + yy * 16]; + points[odd[xx] + yy * 16] = tmp; + } + for (int xx = 0; xx < 8; ++xx) { + int other = (int)(cmj_randfloat(++rng_index, rng_seed) * (8.0f - xx) + xx); + float2 tmp = points[even[other] + yy * 16]; + points[even[other] + yy * 16] = points[even[xx] + yy * 16]; + points[even[xx] + yy * 16] = tmp; + } + } +} + +void progressive_multi_jitter_generate_2D(float2 points[], int size, int rng_seed) +{ + PMJ_Generator::generate_2D(points, size, rng_seed); + shuffle(points, size, rng_seed); +} + +void progressive_multi_jitter_02_generate_2D(float2 points[], int size, int rng_seed) +{ + PMJ02_Generator::generate_2D(points, size, rng_seed); + shuffle(points, size, rng_seed); +} + +CCL_NAMESPACE_END |