Blender  V2.93
jitter.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* This file is based on "Progressive Multi-Jittered Sample Sequences"
18  * by Per Christensen, Andrew Kensler and Charlie Kilpatrick.
19  * http://graphics.pixar.com/library/ProgressiveMultiJitteredSampling/paper.pdf
20  *
21  * Performance can be improved in the future by implementing the new
22  * algorithm from Matt Pharr in http://jcgt.org/published/0008/01/04/
23  * "Efficient Generation of Points that Satisfy Two-Dimensional Elementary Intervals"
24  */
25 
26 #include "render/jitter.h"
27 
28 #include <math.h>
29 #include <vector>
30 
32 
33 static uint cmj_hash(uint i, uint p)
34 {
35  i ^= p;
36  i ^= i >> 17;
37  i ^= i >> 10;
38  i *= 0xb36534e5;
39  i ^= i >> 12;
40  i ^= i >> 21;
41  i *= 0x93fc4795;
42  i ^= 0xdf6e307f;
43  i ^= i >> 17;
44  i *= 1 | p >> 18;
45 
46  return i;
47 }
48 
49 static float cmj_randfloat(uint i, uint p)
50 {
51  return cmj_hash(i, p) * (1.0f / 4294967808.0f);
52 }
53 
55  public:
56  static void generate_2D(float2 points[], int size, int rng_seed_in)
57  {
58  PMJ_Generator g(rng_seed_in);
59  points[0].x = g.rnd();
60  points[0].y = g.rnd();
61  int N = 1;
62  while (N < size) {
63  g.extend_sequence_even(points, N);
64  g.extend_sequence_odd(points, 2 * N);
65  N = 4 * N;
66  }
67  }
68 
69  protected:
70  PMJ_Generator(int rnd_seed_in) : num_samples(1), rnd_index(2), rnd_seed(rnd_seed_in)
71  {
72  }
73 
74  float rnd()
75  {
76  return cmj_randfloat(++rnd_index, rnd_seed);
77  }
78 
79  virtual void mark_occupied_strata(float2 points[], int N)
80  {
81  int NN = 2 * N;
82  for (int s = 0; s < NN; ++s) {
83  occupied1Dx[s] = occupied1Dy[s] = false;
84  }
85  for (int s = 0; s < N; ++s) {
86  int xstratum = (int)(NN * points[s].x);
87  int ystratum = (int)(NN * points[s].y);
88  occupied1Dx[xstratum] = true;
89  occupied1Dy[ystratum] = true;
90  }
91  }
92 
93  virtual void generate_sample_point(
94  float2 points[], float i, float j, float xhalf, float yhalf, int n, int N)
95  {
96  int NN = 2 * N;
97  float2 pt;
98  int xstratum, ystratum;
99  do {
100  pt.x = (i + 0.5f * (xhalf + rnd())) / n;
101  xstratum = (int)(NN * pt.x);
102  } while (occupied1Dx[xstratum]);
103  do {
104  pt.y = (j + 0.5f * (yhalf + rnd())) / n;
105  ystratum = (int)(NN * pt.y);
106  } while (occupied1Dy[ystratum]);
107  occupied1Dx[xstratum] = true;
108  occupied1Dy[ystratum] = true;
109  points[num_samples] = pt;
110  ++num_samples;
111  }
112 
113  void extend_sequence_even(float2 points[], int N)
114  {
115  int n = (int)sqrtf(N);
116  occupied1Dx.resize(2 * N);
117  occupied1Dy.resize(2 * N);
118  mark_occupied_strata(points, N);
119  for (int s = 0; s < N; ++s) {
120  float2 oldpt = points[s];
121  float i = floorf(n * oldpt.x);
122  float j = floorf(n * oldpt.y);
123  float xhalf = floorf(2.0f * (n * oldpt.x - i));
124  float yhalf = floorf(2.0f * (n * oldpt.y - j));
125  xhalf = 1.0f - xhalf;
126  yhalf = 1.0f - yhalf;
127  generate_sample_point(points, i, j, xhalf, yhalf, n, N);
128  }
129  }
130 
131  void extend_sequence_odd(float2 points[], int N)
132  {
133  int n = (int)sqrtf(N / 2);
134  occupied1Dx.resize(2 * N);
135  occupied1Dy.resize(2 * N);
136  mark_occupied_strata(points, N);
137  std::vector<float> xhalves(N / 2);
138  std::vector<float> yhalves(N / 2);
139  for (int s = 0; s < N / 2; ++s) {
140  float2 oldpt = points[s];
141  float i = floorf(n * oldpt.x);
142  float j = floorf(n * oldpt.y);
143  float xhalf = floorf(2.0f * (n * oldpt.x - i));
144  float yhalf = floorf(2.0f * (n * oldpt.y - j));
145  if (rnd() > 0.5f) {
146  xhalf = 1.0f - xhalf;
147  }
148  else {
149  yhalf = 1.0f - yhalf;
150  }
151  xhalves[s] = xhalf;
152  yhalves[s] = yhalf;
153  generate_sample_point(points, i, j, xhalf, yhalf, n, N);
154  }
155  for (int s = 0; s < N / 2; ++s) {
156  float2 oldpt = points[s];
157  float i = floorf(n * oldpt.x);
158  float j = floorf(n * oldpt.y);
159  float xhalf = 1.0f - xhalves[s];
160  float yhalf = 1.0f - yhalves[s];
161  generate_sample_point(points, i, j, xhalf, yhalf, n, N);
162  }
163  }
164 
165  std::vector<bool> occupied1Dx, occupied1Dy;
168 };
169 
171  protected:
173  float2 points[], float i, float j, float xhalf, float yhalf, int n, int N) override
174  {
175  int NN = 2 * N;
176  float2 pt;
177  do {
178  pt.x = (i + 0.5f * (xhalf + rnd())) / n;
179  pt.y = (j + 0.5f * (yhalf + rnd())) / n;
180  } while (is_occupied(pt, NN));
181  mark_occupied_strata1(pt, NN);
182  points[num_samples] = pt;
183  ++num_samples;
184  }
185 
186  void mark_occupied_strata(float2 points[], int N) override
187  {
188  int NN = 2 * N;
189  int num_shapes = (int)log2f(NN) + 1;
190  occupiedStrata.resize(num_shapes);
191  for (int shape = 0; shape < num_shapes; ++shape) {
192  occupiedStrata[shape].resize(NN);
193  for (int n = 0; n < NN; ++n) {
194  occupiedStrata[shape][n] = false;
195  }
196  }
197  for (int s = 0; s < N; ++s) {
198  mark_occupied_strata1(points[s], NN);
199  }
200  }
201 
202  void mark_occupied_strata1(float2 pt, int NN)
203  {
204  int shape = 0;
205  int xdivs = NN;
206  int ydivs = 1;
207  do {
208  int xstratum = (int)(xdivs * pt.x);
209  int ystratum = (int)(ydivs * pt.y);
210  size_t index = ystratum * xdivs + xstratum;
211  assert(index < NN);
212  occupiedStrata[shape][index] = true;
213  shape = shape + 1;
214  xdivs = xdivs / 2;
215  ydivs = ydivs * 2;
216  } while (xdivs > 0);
217  }
218 
219  bool is_occupied(float2 pt, int NN)
220  {
221  int shape = 0;
222  int xdivs = NN;
223  int ydivs = 1;
224  do {
225  int xstratum = (int)(xdivs * pt.x);
226  int ystratum = (int)(ydivs * pt.y);
227  size_t index = ystratum * xdivs + xstratum;
228  assert(index < NN);
229  if (occupiedStrata[shape][index]) {
230  return true;
231  }
232  shape = shape + 1;
233  xdivs = xdivs / 2;
234  ydivs = ydivs * 2;
235  } while (xdivs > 0);
236  return false;
237  }
238 
239  private:
240  std::vector<std::vector<bool>> occupiedStrata;
241 };
242 
243 static void shuffle(float2 points[], int size, int rng_seed)
244 {
245  /* Offset samples by 1.0 for faster scrambling in kernel_random.h */
246  for (int i = 0; i < size; ++i) {
247  points[i].x += 1.0f;
248  points[i].y += 1.0f;
249  }
250 
251  if (rng_seed == 0) {
252  return;
253  }
254 
255  constexpr int odd[8] = {0, 1, 4, 5, 10, 11, 14, 15};
256  constexpr int even[8] = {2, 3, 6, 7, 8, 9, 12, 13};
257 
258  int rng_index = 0;
259  for (int yy = 0; yy < size / 16; ++yy) {
260  for (int xx = 0; xx < 8; ++xx) {
261  int other = (int)(cmj_randfloat(++rng_index, rng_seed) * (8.0f - xx) + xx);
262  float2 tmp = points[odd[other] + yy * 16];
263  points[odd[other] + yy * 16] = points[odd[xx] + yy * 16];
264  points[odd[xx] + yy * 16] = tmp;
265  }
266  for (int xx = 0; xx < 8; ++xx) {
267  int other = (int)(cmj_randfloat(++rng_index, rng_seed) * (8.0f - xx) + xx);
268  float2 tmp = points[even[other] + yy * 16];
269  points[even[other] + yy * 16] = points[even[xx] + yy * 16];
270  points[even[xx] + yy * 16] = tmp;
271  }
272  }
273 }
274 
275 void progressive_multi_jitter_generate_2D(float2 points[], int size, int rng_seed)
276 {
277  PMJ_Generator::generate_2D(points, size, rng_seed);
278  shuffle(points, size, rng_seed);
279 }
280 
281 void progressive_multi_jitter_02_generate_2D(float2 points[], int size, int rng_seed)
282 {
283  PMJ02_Generator::generate_2D(points, size, rng_seed);
284  shuffle(points, size, rng_seed);
285 }
286 
unsigned int uint
Definition: BLI_sys_types.h:83
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
void mark_occupied_strata(float2 points[], int N) override
Definition: jitter.cpp:186
bool is_occupied(float2 pt, int NN)
Definition: jitter.cpp:219
void mark_occupied_strata1(float2 pt, int NN)
Definition: jitter.cpp:202
void generate_sample_point(float2 points[], float i, float j, float xhalf, float yhalf, int n, int N) override
Definition: jitter.cpp:172
float rnd()
Definition: jitter.cpp:74
int num_samples
Definition: jitter.cpp:166
std::vector< bool > occupied1Dx
Definition: jitter.cpp:165
static void generate_2D(float2 points[], int size, int rng_seed_in)
Definition: jitter.cpp:56
virtual void generate_sample_point(float2 points[], float i, float j, float xhalf, float yhalf, int n, int N)
Definition: jitter.cpp:93
PMJ_Generator(int rnd_seed_in)
Definition: jitter.cpp:70
void extend_sequence_even(float2 points[], int N)
Definition: jitter.cpp:113
void extend_sequence_odd(float2 points[], int N)
Definition: jitter.cpp:131
std::vector< bool > occupied1Dy
Definition: jitter.cpp:165
virtual void mark_occupied_strata(float2 points[], int N)
Definition: jitter.cpp:79
static float cmj_randfloat(uint i, uint p)
Definition: jitter.cpp:49
void progressive_multi_jitter_02_generate_2D(float2 points[], int size, int rng_seed)
Definition: jitter.cpp:281
static void shuffle(float2 points[], int size, int rng_seed)
Definition: jitter.cpp:243
static CCL_NAMESPACE_BEGIN uint cmj_hash(uint i, uint p)
Definition: jitter.cpp:33
void progressive_multi_jitter_generate_2D(float2 points[], int size, int rng_seed)
Definition: jitter.cpp:275
#define CCL_NAMESPACE_END
#define floorf(x)
#define sqrtf(x)
params N