Blender V4.3
voronoi.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
8
9/*
10 * SPDX-License-Identifier: MIT
11 * Original code is copyright (c) 2013 Inigo Quilez.
12 *
13 * Smooth Voronoi:
14 *
15 * - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
16 *
17 * Distance To Edge based on:
18 *
19 * - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm
20 * - https://www.shadertoy.com/view/ldl3W8
21 *
22 * With optimization to change -2..2 scan window to -1..1 for better performance,
23 * as explained in https://www.shadertoy.com/view/llG3zy.
24 */
25
26struct VoronoiParams {
27 float scale;
28 float detail;
29 float roughness;
30 float lacunarity;
31 float smoothness;
32 float exponent;
33 float randomness;
34 float max_distance;
38};
39
40struct VoronoiOutput {
41 float distance = 0.0f;
43 float4 position = zero_float4();
44};
45
46/* ***** Distances ***** */
47
48ccl_device float voronoi_distance(const float a, const float b)
49{
50 return fabsf(b - a);
51}
52
53template<typename T>
55{
56 if (params.metric == NODE_VORONOI_EUCLIDEAN) {
57 return distance(a, b);
58 }
59 else if (params.metric == NODE_VORONOI_MANHATTAN) {
60 return reduce_add(fabs(a - b));
61 }
62 else if (params.metric == NODE_VORONOI_CHEBYCHEV) {
63 return reduce_max(fabs(a - b));
64 }
65 else if (params.metric == NODE_VORONOI_MINKOWSKI) {
66 return powf(reduce_add(power(fabs(a - b), params.exponent)), 1.0f / params.exponent);
67 }
68 else {
69 return 0.0f;
70 }
71}
72
73/* **** 1D Voronoi **** */
74
75ccl_device float4 voronoi_position(const float coord)
76{
77 return make_float4(0.0f, 0.0f, 0.0f, coord);
78}
79
81{
82 float cellPosition = floorf(coord);
83 float localPosition = coord - cellPosition;
84
85 float minDistance = FLT_MAX;
86 float targetOffset = 0.0f;
87 float targetPosition = 0.0f;
88 for (int i = -1; i <= 1; i++) {
89 float cellOffset = i;
90 float pointPosition = cellOffset +
91 hash_float_to_float(cellPosition + cellOffset) * params.randomness;
92 float distanceToPoint = voronoi_distance(pointPosition, localPosition);
93 if (distanceToPoint < minDistance) {
94 targetOffset = cellOffset;
95 minDistance = distanceToPoint;
96 targetPosition = pointPosition;
97 }
98 }
99
100 VoronoiOutput octave;
101 octave.distance = minDistance;
102 octave.color = hash_float_to_float3(cellPosition + targetOffset);
103 octave.position = voronoi_position(targetPosition + cellPosition);
104 return octave;
105}
106
108 const float coord)
109{
110 float cellPosition = floorf(coord);
111 float localPosition = coord - cellPosition;
112
113 float smoothDistance = 0.0f;
114 float smoothPosition = 0.0f;
115 float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
116 float h = -1.0f;
117 for (int i = -2; i <= 2; i++) {
118 float cellOffset = i;
119 float pointPosition = cellOffset +
120 hash_float_to_float(cellPosition + cellOffset) * params.randomness;
121 float distanceToPoint = voronoi_distance(pointPosition, localPosition);
122 h = h == -1.0f ?
123 1.0f :
125 0.0f, 1.0f, 0.5f + 0.5f * (smoothDistance - distanceToPoint) / params.smoothness);
126 float correctionFactor = params.smoothness * h * (1.0f - h);
127 smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
128 correctionFactor /= 1.0f + 3.0f * params.smoothness;
129 float3 cellColor = hash_float_to_float3(cellPosition + cellOffset);
130 smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
131 smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
132 }
133
134 VoronoiOutput octave;
135 octave.distance = smoothDistance;
136 octave.color = smoothColor;
137 octave.position = voronoi_position(cellPosition + smoothPosition);
138 return octave;
139}
140
142{
143 float cellPosition = floorf(coord);
144 float localPosition = coord - cellPosition;
145
146 float distanceF1 = FLT_MAX;
147 float distanceF2 = FLT_MAX;
148 float offsetF1 = 0.0f;
149 float positionF1 = 0.0f;
150 float offsetF2 = 0.0f;
151 float positionF2 = 0.0f;
152 for (int i = -1; i <= 1; i++) {
153 float cellOffset = i;
154 float pointPosition = cellOffset +
155 hash_float_to_float(cellPosition + cellOffset) * params.randomness;
156 float distanceToPoint = voronoi_distance(pointPosition, localPosition);
157 if (distanceToPoint < distanceF1) {
158 distanceF2 = distanceF1;
159 distanceF1 = distanceToPoint;
160 offsetF2 = offsetF1;
161 offsetF1 = cellOffset;
162 positionF2 = positionF1;
163 positionF1 = pointPosition;
164 }
165 else if (distanceToPoint < distanceF2) {
166 distanceF2 = distanceToPoint;
167 offsetF2 = cellOffset;
168 positionF2 = pointPosition;
169 }
170 }
171
172 VoronoiOutput octave;
173 octave.distance = distanceF2;
174 octave.color = hash_float_to_float3(cellPosition + offsetF2);
175 octave.position = voronoi_position(positionF2 + cellPosition);
176 return octave;
177}
178
180 const float coord)
181{
182 float cellPosition = floorf(coord);
183 float localPosition = coord - cellPosition;
184
185 float midPointPosition = hash_float_to_float(cellPosition) * params.randomness;
186 float leftPointPosition = -1.0f + hash_float_to_float(cellPosition - 1.0f) * params.randomness;
187 float rightPointPosition = 1.0f + hash_float_to_float(cellPosition + 1.0f) * params.randomness;
188 float distanceToMidLeft = fabsf((midPointPosition + leftPointPosition) / 2.0f - localPosition);
189 float distanceToMidRight = fabsf((midPointPosition + rightPointPosition) / 2.0f - localPosition);
190
191 return min(distanceToMidLeft, distanceToMidRight);
192}
193
195 const float coord)
196{
197 float cellPosition = floorf(coord);
198 float localPosition = coord - cellPosition;
199
200 float closestPoint = 0.0f;
201 float closestPointOffset = 0.0f;
202 float minDistance = FLT_MAX;
203 for (int i = -1; i <= 1; i++) {
204 float cellOffset = i;
205 float pointPosition = cellOffset +
206 hash_float_to_float(cellPosition + cellOffset) * params.randomness;
207 float distanceToPoint = fabsf(pointPosition - localPosition);
208 if (distanceToPoint < minDistance) {
209 minDistance = distanceToPoint;
210 closestPoint = pointPosition;
211 closestPointOffset = cellOffset;
212 }
213 }
214
215 minDistance = FLT_MAX;
216 float closestPointToClosestPoint = 0.0f;
217 for (int i = -1; i <= 1; i++) {
218 if (i == 0) {
219 continue;
220 }
221 float cellOffset = i + closestPointOffset;
222 float pointPosition = cellOffset +
223 hash_float_to_float(cellPosition + cellOffset) * params.randomness;
224 float distanceToPoint = fabsf(closestPoint - pointPosition);
225 if (distanceToPoint < minDistance) {
226 minDistance = distanceToPoint;
227 closestPointToClosestPoint = pointPosition;
228 }
229 }
230
231 return fabsf(closestPointToClosestPoint - closestPoint) / 2.0f;
232}
233
234/* **** 2D Voronoi **** */
235
237{
238 return make_float4(coord.x, coord.y, 0.0f, 0.0f);
239}
240
242{
243 float2 cellPosition = floor(coord);
244 float2 localPosition = coord - cellPosition;
245
246 float minDistance = FLT_MAX;
247 float2 targetOffset = make_float2(0.0f, 0.0f);
248 float2 targetPosition = make_float2(0.0f, 0.0f);
249 for (int j = -1; j <= 1; j++) {
250 for (int i = -1; i <= 1; i++) {
251 float2 cellOffset = make_float2(i, j);
252 float2 pointPosition = cellOffset +
253 hash_float2_to_float2(cellPosition + cellOffset) * params.randomness;
254 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
255 if (distanceToPoint < minDistance) {
256 targetOffset = cellOffset;
257 minDistance = distanceToPoint;
258 targetPosition = pointPosition;
259 }
260 }
261 }
262
263 VoronoiOutput octave;
264 octave.distance = minDistance;
265 octave.color = hash_float2_to_float3(cellPosition + targetOffset);
266 octave.position = voronoi_position(targetPosition + cellPosition);
267 return octave;
268}
269
271 const float2 coord)
272{
273 float2 cellPosition = floor(coord);
274 float2 localPosition = coord - cellPosition;
275
276 float smoothDistance = 0.0f;
277 float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
278 float2 smoothPosition = make_float2(0.0f, 0.0f);
279 float h = -1.0f;
280 for (int j = -2; j <= 2; j++) {
281 for (int i = -2; i <= 2; i++) {
282 float2 cellOffset = make_float2(i, j);
283 float2 pointPosition = cellOffset +
284 hash_float2_to_float2(cellPosition + cellOffset) * params.randomness;
285 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
286 h = h == -1.0f ?
287 1.0f :
288 smoothstep(0.0f,
289 1.0f,
290 0.5f + 0.5f * (smoothDistance - distanceToPoint) / params.smoothness);
291 float correctionFactor = params.smoothness * h * (1.0f - h);
292 smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
293 correctionFactor /= 1.0f + 3.0f * params.smoothness;
294 float3 cellColor = hash_float2_to_float3(cellPosition + cellOffset);
295 smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
296 smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
297 }
298 }
299
300 VoronoiOutput octave;
301 octave.distance = smoothDistance;
302 octave.color = smoothColor;
303 octave.position = voronoi_position(cellPosition + smoothPosition);
304 return octave;
305}
306
308{
309 float2 cellPosition = floor(coord);
310 float2 localPosition = coord - cellPosition;
311
312 float distanceF1 = FLT_MAX;
313 float distanceF2 = FLT_MAX;
314 float2 offsetF1 = make_float2(0.0f, 0.0f);
315 float2 positionF1 = make_float2(0.0f, 0.0f);
316 float2 offsetF2 = make_float2(0.0f, 0.0f);
317 float2 positionF2 = make_float2(0.0f, 0.0f);
318 for (int j = -1; j <= 1; j++) {
319 for (int i = -1; i <= 1; i++) {
320 float2 cellOffset = make_float2(i, j);
321 float2 pointPosition = cellOffset +
322 hash_float2_to_float2(cellPosition + cellOffset) * params.randomness;
323 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
324 if (distanceToPoint < distanceF1) {
325 distanceF2 = distanceF1;
326 distanceF1 = distanceToPoint;
327 offsetF2 = offsetF1;
328 offsetF1 = cellOffset;
329 positionF2 = positionF1;
330 positionF1 = pointPosition;
331 }
332 else if (distanceToPoint < distanceF2) {
333 distanceF2 = distanceToPoint;
334 offsetF2 = cellOffset;
335 positionF2 = pointPosition;
336 }
337 }
338 }
339
340 VoronoiOutput octave;
341 octave.distance = distanceF2;
342 octave.color = hash_float2_to_float3(cellPosition + offsetF2);
343 octave.position = voronoi_position(positionF2 + cellPosition);
344 return octave;
345}
346
348 const float2 coord)
349{
350 float2 cellPosition = floor(coord);
351 float2 localPosition = coord - cellPosition;
352
353 float2 vectorToClosest = make_float2(0.0f, 0.0f);
354 float minDistance = FLT_MAX;
355 for (int j = -1; j <= 1; j++) {
356 for (int i = -1; i <= 1; i++) {
357 float2 cellOffset = make_float2(i, j);
358 float2 vectorToPoint = cellOffset +
359 hash_float2_to_float2(cellPosition + cellOffset) * params.randomness -
360 localPosition;
361 float distanceToPoint = dot(vectorToPoint, vectorToPoint);
362 if (distanceToPoint < minDistance) {
363 minDistance = distanceToPoint;
364 vectorToClosest = vectorToPoint;
365 }
366 }
367 }
368
369 minDistance = FLT_MAX;
370 for (int j = -1; j <= 1; j++) {
371 for (int i = -1; i <= 1; i++) {
372 float2 cellOffset = make_float2(i, j);
373 float2 vectorToPoint = cellOffset +
374 hash_float2_to_float2(cellPosition + cellOffset) * params.randomness -
375 localPosition;
376 float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
377 if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
378 float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
379 normalize(perpendicularToEdge));
380 minDistance = min(minDistance, distanceToEdge);
381 }
382 }
383 }
384
385 return minDistance;
386}
387
389 const float2 coord)
390{
391 float2 cellPosition = floor(coord);
392 float2 localPosition = coord - cellPosition;
393
394 float2 closestPoint = make_float2(0.0f, 0.0f);
395 float2 closestPointOffset = make_float2(0.0f, 0.0f);
396 float minDistance = FLT_MAX;
397 for (int j = -1; j <= 1; j++) {
398 for (int i = -1; i <= 1; i++) {
399 float2 cellOffset = make_float2(i, j);
400 float2 pointPosition = cellOffset +
401 hash_float2_to_float2(cellPosition + cellOffset) * params.randomness;
402 float distanceToPoint = distance(pointPosition, localPosition);
403 if (distanceToPoint < minDistance) {
404 minDistance = distanceToPoint;
405 closestPoint = pointPosition;
406 closestPointOffset = cellOffset;
407 }
408 }
409 }
410
411 minDistance = FLT_MAX;
412 float2 closestPointToClosestPoint = make_float2(0.0f, 0.0f);
413 for (int j = -1; j <= 1; j++) {
414 for (int i = -1; i <= 1; i++) {
415 if (i == 0 && j == 0) {
416 continue;
417 }
418 float2 cellOffset = make_float2(i, j) + closestPointOffset;
419 float2 pointPosition = cellOffset +
420 hash_float2_to_float2(cellPosition + cellOffset) * params.randomness;
421 float distanceToPoint = distance(closestPoint, pointPosition);
422 if (distanceToPoint < minDistance) {
423 minDistance = distanceToPoint;
424 closestPointToClosestPoint = pointPosition;
425 }
426 }
427 }
428
429 return distance(closestPointToClosestPoint, closestPoint) / 2.0f;
430}
431
432/* **** 3D Voronoi **** */
433
435{
436 return float3_to_float4(coord);
437}
438
440{
441 float3 cellPosition = floor(coord);
442 float3 localPosition = coord - cellPosition;
443
444 float minDistance = FLT_MAX;
445 float3 targetOffset = make_float3(0.0f, 0.0f, 0.0f);
446 float3 targetPosition = make_float3(0.0f, 0.0f, 0.0f);
447 for (int k = -1; k <= 1; k++) {
448 for (int j = -1; j <= 1; j++) {
449 for (int i = -1; i <= 1; i++) {
450 float3 cellOffset = make_float3(i, j, k);
451 float3 pointPosition = cellOffset + hash_float3_to_float3(cellPosition + cellOffset) *
452 params.randomness;
453 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
454 if (distanceToPoint < minDistance) {
455 targetOffset = cellOffset;
456 minDistance = distanceToPoint;
457 targetPosition = pointPosition;
458 }
459 }
460 }
461 }
462
463 VoronoiOutput octave;
464 octave.distance = minDistance;
465 octave.color = hash_float3_to_float3(cellPosition + targetOffset);
466 octave.position = voronoi_position(targetPosition + cellPosition);
467 return octave;
468}
469
471 const float3 coord)
472{
473 float3 cellPosition = floor(coord);
474 float3 localPosition = coord - cellPosition;
475
476 float smoothDistance = 0.0f;
477 float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
478 float3 smoothPosition = make_float3(0.0f, 0.0f, 0.0f);
479 float h = -1.0f;
480 for (int k = -2; k <= 2; k++) {
481 for (int j = -2; j <= 2; j++) {
482 for (int i = -2; i <= 2; i++) {
483 float3 cellOffset = make_float3(i, j, k);
484 float3 pointPosition = cellOffset + hash_float3_to_float3(cellPosition + cellOffset) *
485 params.randomness;
486 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
487 h = h == -1.0f ?
488 1.0f :
489 smoothstep(0.0f,
490 1.0f,
491 0.5f + 0.5f * (smoothDistance - distanceToPoint) / params.smoothness);
492 float correctionFactor = params.smoothness * h * (1.0f - h);
493 smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
494 correctionFactor /= 1.0f + 3.0f * params.smoothness;
495 float3 cellColor = hash_float3_to_float3(cellPosition + cellOffset);
496 smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
497 smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
498 }
499 }
500 }
501
502 VoronoiOutput octave;
503 octave.distance = smoothDistance;
504 octave.color = smoothColor;
505 octave.position = voronoi_position(cellPosition + smoothPosition);
506 return octave;
507}
508
510{
511 float3 cellPosition = floor(coord);
512 float3 localPosition = coord - cellPosition;
513
514 float distanceF1 = FLT_MAX;
515 float distanceF2 = FLT_MAX;
516 float3 offsetF1 = make_float3(0.0f, 0.0f, 0.0f);
517 float3 positionF1 = make_float3(0.0f, 0.0f, 0.0f);
518 float3 offsetF2 = make_float3(0.0f, 0.0f, 0.0f);
519 float3 positionF2 = make_float3(0.0f, 0.0f, 0.0f);
520 for (int k = -1; k <= 1; k++) {
521 for (int j = -1; j <= 1; j++) {
522 for (int i = -1; i <= 1; i++) {
523 float3 cellOffset = make_float3(i, j, k);
524 float3 pointPosition = cellOffset + hash_float3_to_float3(cellPosition + cellOffset) *
525 params.randomness;
526 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
527 if (distanceToPoint < distanceF1) {
528 distanceF2 = distanceF1;
529 distanceF1 = distanceToPoint;
530 offsetF2 = offsetF1;
531 offsetF1 = cellOffset;
532 positionF2 = positionF1;
533 positionF1 = pointPosition;
534 }
535 else if (distanceToPoint < distanceF2) {
536 distanceF2 = distanceToPoint;
537 offsetF2 = cellOffset;
538 positionF2 = pointPosition;
539 }
540 }
541 }
542 }
543
544 VoronoiOutput octave;
545 octave.distance = distanceF2;
546 octave.color = hash_float3_to_float3(cellPosition + offsetF2);
547 octave.position = voronoi_position(positionF2 + cellPosition);
548 return octave;
549}
550
552 const float3 coord)
553{
554 float3 cellPosition = floor(coord);
555 float3 localPosition = coord - cellPosition;
556
557 float3 vectorToClosest = make_float3(0.0f, 0.0f, 0.0f);
558 float minDistance = FLT_MAX;
559 for (int k = -1; k <= 1; k++) {
560 for (int j = -1; j <= 1; j++) {
561 for (int i = -1; i <= 1; i++) {
562 float3 cellOffset = make_float3(i, j, k);
563 float3 vectorToPoint = cellOffset +
564 hash_float3_to_float3(cellPosition + cellOffset) *
565 params.randomness -
566 localPosition;
567 float distanceToPoint = dot(vectorToPoint, vectorToPoint);
568 if (distanceToPoint < minDistance) {
569 minDistance = distanceToPoint;
570 vectorToClosest = vectorToPoint;
571 }
572 }
573 }
574 }
575
576 minDistance = FLT_MAX;
577 for (int k = -1; k <= 1; k++) {
578 for (int j = -1; j <= 1; j++) {
579 for (int i = -1; i <= 1; i++) {
580 float3 cellOffset = make_float3(i, j, k);
581 float3 vectorToPoint = cellOffset +
582 hash_float3_to_float3(cellPosition + cellOffset) *
583 params.randomness -
584 localPosition;
585 float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
586 if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
587 float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
588 normalize(perpendicularToEdge));
589 minDistance = min(minDistance, distanceToEdge);
590 }
591 }
592 }
593 }
594
595 return minDistance;
596}
597
599 const float3 coord)
600{
601 float3 cellPosition = floor(coord);
602 float3 localPosition = coord - cellPosition;
603
604 float3 closestPoint = make_float3(0.0f, 0.0f, 0.0f);
605 float3 closestPointOffset = make_float3(0.0f, 0.0f, 0.0f);
606 float minDistance = FLT_MAX;
607 for (int k = -1; k <= 1; k++) {
608 for (int j = -1; j <= 1; j++) {
609 for (int i = -1; i <= 1; i++) {
610 float3 cellOffset = make_float3(i, j, k);
611 float3 pointPosition = cellOffset + hash_float3_to_float3(cellPosition + cellOffset) *
612 params.randomness;
613 float distanceToPoint = distance(pointPosition, localPosition);
614 if (distanceToPoint < minDistance) {
615 minDistance = distanceToPoint;
616 closestPoint = pointPosition;
617 closestPointOffset = cellOffset;
618 }
619 }
620 }
621 }
622
623 minDistance = FLT_MAX;
624 float3 closestPointToClosestPoint = make_float3(0.0f, 0.0f, 0.0f);
625 for (int k = -1; k <= 1; k++) {
626 for (int j = -1; j <= 1; j++) {
627 for (int i = -1; i <= 1; i++) {
628 if (i == 0 && j == 0 && k == 0) {
629 continue;
630 }
631 float3 cellOffset = make_float3(i, j, k) + closestPointOffset;
632 float3 pointPosition = cellOffset + hash_float3_to_float3(cellPosition + cellOffset) *
633 params.randomness;
634 float distanceToPoint = distance(closestPoint, pointPosition);
635 if (distanceToPoint < minDistance) {
636 minDistance = distanceToPoint;
637 closestPointToClosestPoint = pointPosition;
638 }
639 }
640 }
641 }
642
643 return distance(closestPointToClosestPoint, closestPoint) / 2.0f;
644}
645
646/* **** 4D Voronoi **** */
647
648ccl_device float4 voronoi_position(const float4 coord)
649{
650 return coord;
651}
652
654{
655 float4 cellPosition = floor(coord);
656 float4 localPosition = coord - cellPosition;
657
658 float minDistance = FLT_MAX;
659 float4 targetOffset = zero_float4();
660 float4 targetPosition = zero_float4();
661 for (int u = -1; u <= 1; u++) {
662 for (int k = -1; k <= 1; k++) {
663 ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
664 {
665 for (int i = -1; i <= 1; i++) {
666 float4 cellOffset = make_float4(i, j, k, u);
667 float4 pointPosition = cellOffset + hash_float4_to_float4(cellPosition + cellOffset) *
668 params.randomness;
669 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
670 if (distanceToPoint < minDistance) {
671 targetOffset = cellOffset;
672 minDistance = distanceToPoint;
673 targetPosition = pointPosition;
674 }
675 }
676 }
677 }
678 }
679
680 VoronoiOutput octave;
681 octave.distance = minDistance;
682 octave.color = hash_float4_to_float3(cellPosition + targetOffset);
683 octave.position = voronoi_position(targetPosition + cellPosition);
684 return octave;
685}
686
688 const float4 coord)
689{
690 float4 cellPosition = floor(coord);
691 float4 localPosition = coord - cellPosition;
692
693 float smoothDistance = 0.0f;
694 float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
695 float4 smoothPosition = zero_float4();
696 float h = -1.0f;
697 for (int u = -2; u <= 2; u++) {
698 for (int k = -2; k <= 2; k++) {
699 ccl_loop_no_unroll for (int j = -2; j <= 2; j++)
700 {
701 for (int i = -2; i <= 2; i++) {
702 float4 cellOffset = make_float4(i, j, k, u);
703 float4 pointPosition = cellOffset + hash_float4_to_float4(cellPosition + cellOffset) *
704 params.randomness;
705 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
706 h = h == -1.0f ?
707 1.0f :
708 smoothstep(0.0f,
709 1.0f,
710 0.5f + 0.5f * (smoothDistance - distanceToPoint) / params.smoothness);
711 float correctionFactor = params.smoothness * h * (1.0f - h);
712 smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
713 correctionFactor /= 1.0f + 3.0f * params.smoothness;
714 float3 cellColor = hash_float4_to_float3(cellPosition + cellOffset);
715 smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
716 smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
717 }
718 }
719 }
720 }
721
722 VoronoiOutput octave;
723 octave.distance = smoothDistance;
724 octave.color = smoothColor;
725 octave.position = voronoi_position(cellPosition + smoothPosition);
726 return octave;
727}
728
730{
731 float4 cellPosition = floor(coord);
732 float4 localPosition = coord - cellPosition;
733
734 float distanceF1 = FLT_MAX;
735 float distanceF2 = FLT_MAX;
736 float4 offsetF1 = zero_float4();
737 float4 positionF1 = zero_float4();
738 float4 offsetF2 = zero_float4();
739 float4 positionF2 = zero_float4();
740 for (int u = -1; u <= 1; u++) {
741 for (int k = -1; k <= 1; k++) {
742 ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
743 {
744 for (int i = -1; i <= 1; i++) {
745 float4 cellOffset = make_float4(i, j, k, u);
746 float4 pointPosition = cellOffset + hash_float4_to_float4(cellPosition + cellOffset) *
747 params.randomness;
748 float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
749 if (distanceToPoint < distanceF1) {
750 distanceF2 = distanceF1;
751 distanceF1 = distanceToPoint;
752 offsetF2 = offsetF1;
753 offsetF1 = cellOffset;
754 positionF2 = positionF1;
755 positionF1 = pointPosition;
756 }
757 else if (distanceToPoint < distanceF2) {
758 distanceF2 = distanceToPoint;
759 offsetF2 = cellOffset;
760 positionF2 = pointPosition;
761 }
762 }
763 }
764 }
765 }
766
767 VoronoiOutput octave;
768 octave.distance = distanceF2;
769 octave.color = hash_float4_to_float3(cellPosition + offsetF2);
770 octave.position = voronoi_position(positionF2 + cellPosition);
771 return octave;
772}
773
775 const float4 coord)
776{
777 float4 cellPosition = floor(coord);
778 float4 localPosition = coord - cellPosition;
779
780 float4 vectorToClosest = zero_float4();
781 float minDistance = FLT_MAX;
782 for (int u = -1; u <= 1; u++) {
783 for (int k = -1; k <= 1; k++) {
784 ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
785 {
786 for (int i = -1; i <= 1; i++) {
787 float4 cellOffset = make_float4(i, j, k, u);
788 float4 vectorToPoint = cellOffset +
789 hash_float4_to_float4(cellPosition + cellOffset) *
790 params.randomness -
791 localPosition;
792 float distanceToPoint = dot(vectorToPoint, vectorToPoint);
793 if (distanceToPoint < minDistance) {
794 minDistance = distanceToPoint;
795 vectorToClosest = vectorToPoint;
796 }
797 }
798 }
799 }
800 }
801
802 minDistance = FLT_MAX;
803 for (int u = -1; u <= 1; u++) {
804 for (int k = -1; k <= 1; k++) {
805 ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
806 {
807 for (int i = -1; i <= 1; i++) {
808 float4 cellOffset = make_float4(i, j, k, u);
809 float4 vectorToPoint = cellOffset +
810 hash_float4_to_float4(cellPosition + cellOffset) *
811 params.randomness -
812 localPosition;
813 float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
814 if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
815 float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
816 normalize(perpendicularToEdge));
817 minDistance = min(minDistance, distanceToEdge);
818 }
819 }
820 }
821 }
822 }
823
824 return minDistance;
825}
826
828 const float4 coord)
829{
830 float4 cellPosition = floor(coord);
831 float4 localPosition = coord - cellPosition;
832
833 float4 closestPoint = zero_float4();
834 float4 closestPointOffset = zero_float4();
835 float minDistance = FLT_MAX;
836 for (int u = -1; u <= 1; u++) {
837 for (int k = -1; k <= 1; k++) {
838 ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
839 {
840 for (int i = -1; i <= 1; i++) {
841 float4 cellOffset = make_float4(i, j, k, u);
842 float4 pointPosition = cellOffset + hash_float4_to_float4(cellPosition + cellOffset) *
843 params.randomness;
844 float distanceToPoint = distance(pointPosition, localPosition);
845 if (distanceToPoint < minDistance) {
846 minDistance = distanceToPoint;
847 closestPoint = pointPosition;
848 closestPointOffset = cellOffset;
849 }
850 }
851 }
852 }
853 }
854
855 minDistance = FLT_MAX;
856 float4 closestPointToClosestPoint = zero_float4();
857 for (int u = -1; u <= 1; u++) {
858 for (int k = -1; k <= 1; k++) {
859 ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
860 {
861 for (int i = -1; i <= 1; i++) {
862 if (i == 0 && j == 0 && k == 0 && u == 0) {
863 continue;
864 }
865 float4 cellOffset = make_float4(i, j, k, u) + closestPointOffset;
866 float4 pointPosition = cellOffset + hash_float4_to_float4(cellPosition + cellOffset) *
867 params.randomness;
868 float distanceToPoint = distance(closestPoint, pointPosition);
869 if (distanceToPoint < minDistance) {
870 minDistance = distanceToPoint;
871 closestPointToClosestPoint = pointPosition;
872 }
873 }
874 }
875 }
876 }
877
878 return distance(closestPointToClosestPoint, closestPoint) / 2.0f;
879}
880
881/* **** Fractal Voronoi **** */
882
883/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
884 * by lerps. */
885template<typename T>
887 const T coord)
888{
889 float amplitude = 1.0f;
890 float max_amplitude = 0.0f;
891 float scale = 1.0f;
892
894 const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
895
896 for (int i = 0; i <= ceilf(params.detail); ++i) {
897 VoronoiOutput octave = (params.feature == NODE_VORONOI_F2) ?
898 voronoi_f2(params, coord * scale) :
899 (params.feature == NODE_VORONOI_SMOOTH_F1 &&
900 params.smoothness != 0.0f) ?
901 voronoi_smooth_f1(params, coord * scale) :
902 voronoi_f1(params, coord * scale);
903
904 if (zero_input) {
905 max_amplitude = 1.0f;
906 output = octave;
907 break;
908 }
909 else if (i <= params.detail) {
910 max_amplitude += amplitude;
911 output.distance += octave.distance * amplitude;
912 output.color += octave.color * amplitude;
913 output.position = mix(output.position, octave.position / scale, amplitude);
914 scale *= params.lacunarity;
915 amplitude *= params.roughness;
916 }
917 else {
918 float remainder = params.detail - floorf(params.detail);
919 if (remainder != 0.0f) {
920 max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
921 output.distance = mix(
922 output.distance, output.distance + octave.distance * amplitude, remainder);
923 output.color = mix(output.color, output.color + octave.color * amplitude, remainder);
924 output.position = mix(
925 output.position, mix(output.position, octave.position / scale, amplitude), remainder);
926 }
927 }
928 }
929
930 if (params.normalize) {
931 output.distance /= max_amplitude * params.max_distance;
932 output.color /= max_amplitude;
933 }
934
935 output.position = safe_divide(output.position, params.scale);
936
937 return output;
938}
939
940/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced
941 * by lerps. */
942template<typename T>
944 const T coord)
945{
946 float amplitude = 1.0f;
947 float max_amplitude = params.max_distance;
948 float scale = 1.0f;
949 float distance = 8.0f;
950
951 const bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
952
953 for (int i = 0; i <= ceilf(params.detail); ++i) {
954 const float octave_distance = voronoi_distance_to_edge(params, coord * scale);
955
956 if (zero_input) {
957 distance = octave_distance;
958 break;
959 }
960 else if (i <= params.detail) {
961 max_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude);
962 distance = mix(distance, min(distance, octave_distance / scale), amplitude);
963 scale *= params.lacunarity;
964 amplitude *= params.roughness;
965 }
966 else {
967 float remainder = params.detail - floorf(params.detail);
968 if (remainder != 0.0f) {
969 float lerp_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude);
970 max_amplitude = mix(max_amplitude, lerp_amplitude, remainder);
971 float lerp_distance = mix(distance, min(distance, octave_distance / scale), amplitude);
972 distance = mix(distance, min(distance, lerp_distance), remainder);
973 }
974 }
975 }
976
977 if (params.normalize) {
978 distance /= max_amplitude;
979 }
980
981 return distance;
982}
983
984ccl_device void svm_voronoi_output(const uint4 stack_offsets,
985 ccl_private float *stack,
986 const float distance,
987 const float3 color,
988 const float3 position,
989 const float w,
990 const float radius)
991{
992 uint distance_stack_offset, color_stack_offset, position_stack_offset;
993 uint w_out_stack_offset, radius_stack_offset, unused;
994
996 stack_offsets.z, &unused, &unused, &distance_stack_offset, &color_stack_offset);
998 stack_offsets.w, &position_stack_offset, &w_out_stack_offset, &radius_stack_offset);
999
1000 if (stack_valid(distance_stack_offset))
1001 stack_store_float(stack, distance_stack_offset, distance);
1002 if (stack_valid(color_stack_offset))
1003 stack_store_float3(stack, color_stack_offset, color);
1004 if (stack_valid(position_stack_offset))
1005 stack_store_float3(stack, position_stack_offset, position);
1006 if (stack_valid(w_out_stack_offset))
1007 stack_store_float(stack, w_out_stack_offset, w);
1008 if (stack_valid(radius_stack_offset))
1009 stack_store_float(stack, radius_stack_offset, radius);
1010}
1011
1012template<uint node_feature_mask>
1015 ccl_private float *stack,
1016 uint dimensions,
1017 uint feature,
1018 uint metric,
1019 int offset)
1020{
1021 /* Read node defaults and stack offsets. */
1022 uint4 stack_offsets = read_node(kg, &offset);
1023 uint4 defaults1 = read_node(kg, &offset);
1024 uint4 defaults2 = read_node(kg, &offset);
1025
1026 uint coord_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset;
1027 uint roughness_stack_offset, lacunarity_stack_offset, smoothness_stack_offset,
1028 exponent_stack_offset;
1029 uint randomness_stack_offset, normalize;
1030
1031 svm_unpack_node_uchar4(stack_offsets.x,
1032 &coord_stack_offset,
1033 &w_stack_offset,
1034 &scale_stack_offset,
1035 &detail_stack_offset);
1036 svm_unpack_node_uchar4(stack_offsets.y,
1037 &roughness_stack_offset,
1038 &lacunarity_stack_offset,
1039 &smoothness_stack_offset,
1040 &exponent_stack_offset);
1041 svm_unpack_node_uchar2(stack_offsets.z, &randomness_stack_offset, &normalize);
1042
1043 /* Read from stack. */
1044 float3 coord = stack_load_float3(stack, coord_stack_offset);
1045 float w = stack_load_float_default(stack, w_stack_offset, defaults1.x);
1046
1048 params.feature = (NodeVoronoiFeature)feature;
1049 params.metric = (NodeVoronoiDistanceMetric)metric;
1050 params.scale = stack_load_float_default(stack, scale_stack_offset, defaults1.y);
1051 params.detail = stack_load_float_default(stack, detail_stack_offset, defaults1.z);
1052 params.roughness = stack_load_float_default(stack, roughness_stack_offset, defaults1.w);
1053 params.lacunarity = stack_load_float_default(stack, lacunarity_stack_offset, defaults2.x);
1054 params.smoothness = stack_load_float_default(stack, smoothness_stack_offset, defaults2.y);
1055 params.exponent = stack_load_float_default(stack, exponent_stack_offset, defaults2.z);
1056 params.randomness = stack_load_float_default(stack, randomness_stack_offset, defaults2.w);
1057 params.max_distance = 0.0f;
1058 params.normalize = normalize;
1059
1060 params.detail = clamp(params.detail, 0.0f, 15.0f);
1061 params.roughness = clamp(params.roughness, 0.0f, 1.0f);
1062 params.randomness = clamp(params.randomness, 0.0f, 1.0f);
1063 params.smoothness = clamp(params.smoothness / 2.0f, 0.0f, 0.5f);
1064
1065 coord *= params.scale;
1066 w *= params.scale;
1067
1068 /* Compute output, specialized for each dimension. */
1069 switch (params.feature) {
1071 float distance = 0.0f;
1072 params.max_distance = 0.5f + 0.5f * params.randomness;
1073 switch (dimensions) {
1074 case 1:
1076 break;
1077 case 2:
1079 break;
1080 case 3:
1081 distance = fractal_voronoi_distance_to_edge(params, coord);
1082 break;
1083 case 4:
1085 break;
1086 }
1087
1088 svm_voronoi_output(stack_offsets, stack, distance, zero_float3(), zero_float3(), 0.0f, 0.0f);
1089 break;
1090 }
1092 float radius = 0.0f;
1093 switch (dimensions) {
1094 case 1:
1095 radius = voronoi_n_sphere_radius(params, w);
1096 break;
1097 case 2:
1099 break;
1100 case 3:
1101 radius = voronoi_n_sphere_radius(params, coord);
1102 break;
1103 case 4:
1105 break;
1106 }
1107
1108 svm_voronoi_output(stack_offsets, stack, 0.0f, zero_float3(), zero_float3(), 0.0f, radius);
1109 break;
1110 }
1111 default: {
1113 switch (dimensions) {
1114 case 1:
1115 params.max_distance = (0.5f + 0.5f * params.randomness) *
1116 ((params.feature == NODE_VORONOI_F2) ? 2.0f : 1.0f);
1117 output = fractal_voronoi_x_fx(params, w);
1118 break;
1119 case 2:
1120 IF_KERNEL_NODES_FEATURE(VORONOI_EXTRA)
1121 {
1122 params.max_distance = voronoi_distance(zero_float2(),
1123 make_float2(0.5f + 0.5f * params.randomness,
1124 0.5f + 0.5f * params.randomness),
1125 params) *
1126 ((params.feature == NODE_VORONOI_F2) ? 2.0f : 1.0f);
1128 }
1129 break;
1130 case 3:
1131 IF_KERNEL_NODES_FEATURE(VORONOI_EXTRA)
1132 {
1133 params.max_distance = voronoi_distance(zero_float3(),
1134 make_float3(0.5f + 0.5f * params.randomness,
1135 0.5f + 0.5f * params.randomness,
1136 0.5f + 0.5f * params.randomness),
1137 params) *
1138 ((params.feature == NODE_VORONOI_F2) ? 2.0f : 1.0f);
1139 output = fractal_voronoi_x_fx(params, coord);
1140 }
1141 break;
1142 case 4:
1143 IF_KERNEL_NODES_FEATURE(VORONOI_EXTRA)
1144 {
1145 params.max_distance = voronoi_distance(zero_float4(),
1146 make_float4(0.5f + 0.5f * params.randomness,
1147 0.5f + 0.5f * params.randomness,
1148 0.5f + 0.5f * params.randomness,
1149 0.5f + 0.5f * params.randomness),
1150 params) *
1151 ((params.feature == NODE_VORONOI_F2) ? 2.0f : 1.0f);
1152 output = fractal_voronoi_x_fx(params, float3_to_float4(coord, w));
1153 }
1154 break;
1155 }
1156
1157 svm_voronoi_output(stack_offsets,
1158 stack,
1159 output.distance,
1160 output.color,
1161 float4_to_float3(output.position),
1162 output.position.w,
1163 0.0f);
1164 break;
1165 }
1166 }
1167
1168 return offset;
1169}
1170
MINLINE float safe_divide(float a, float b)
unsigned int uint
#define output
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
local_group_size(16, 16) .push_constant(Type b
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define ccl_loop_no_unroll
#define ccl_device
#define ccl_private
#define powf(x, y)
#define ccl_device_noinline
#define CCL_NAMESPACE_END
ccl_device_forceinline float4 make_float4(const float x, const float y, const float z, const float w)
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define ceilf(x)
#define floorf(x)
ccl_device_forceinline float2 make_float2(const float x, const float y)
#define fabsf(x)
ccl_device_inline float3 hash_float_to_float3(float k)
Definition hash.h:203
ccl_device_inline float3 hash_float4_to_float3(float4 k)
Definition hash.h:217
ccl_device_inline float3 hash_float2_to_float3(float2 k)
Definition hash.h:210
ccl_device_inline float2 hash_float2_to_float2(float2 k)
Definition hash.h:181
ccl_device_inline float4 hash_float4_to_float4(float4 k)
Definition hash.h:193
ccl_device_inline float3 hash_float3_to_float3(float3 k)
Definition hash.h:186
#define mix(a, b, c)
Definition hash.h:36
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline void stack_store_float3(ccl_private float *stack, uint a, float3 f)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 stack_load_float3(ccl_private float *stack, uint a)
ccl_device_inline uint4 read_node(KernelGlobals kg, ccl_private int *offset)
ccl_device_forceinline void svm_unpack_node_uchar3(uint i, ccl_private uint *x, ccl_private uint *y, ccl_private uint *z)
ccl_device_forceinline void svm_unpack_node_uchar2(uint i, ccl_private uint *x, ccl_private uint *y)
ccl_device_inline float stack_load_float_default(ccl_private float *stack, uint a, uint value)
ccl_device_inline void stack_store_float(ccl_private float *stack, uint a, float f)
ccl_device_forceinline void svm_unpack_node_uchar4(uint i, ccl_private uint *x, ccl_private uint *y, ccl_private uint *z, ccl_private uint *w)
ccl_device_inline bool stack_valid(uint a)
NodeVoronoiFeature
@ NODE_VORONOI_SMOOTH_F1
@ NODE_VORONOI_N_SPHERE_RADIUS
@ NODE_VORONOI_F2
@ NODE_VORONOI_DISTANCE_TO_EDGE
NodeVoronoiDistanceMetric
@ NODE_VORONOI_EUCLIDEAN
@ NODE_VORONOI_MANHATTAN
@ NODE_VORONOI_CHEBYCHEV
@ NODE_VORONOI_MINKOWSKI
#define IF_KERNEL_NODES_FEATURE(feature)
ShaderData
MINLINE float smoothstep(float edge0, float edge1, float x)
CCL_NAMESPACE_BEGIN ccl_device_inline float2 zero_float2()
Definition math_float2.h:14
ccl_device_inline float2 floor(const float2 a)
ccl_device_inline float reduce_max(const float2 a)
ccl_device_inline float reduce_add(const float2 a)
ccl_device_inline float2 power(float2 v, float e)
ccl_device_inline float2 fabs(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:15
CCL_NAMESPACE_BEGIN ccl_device_inline float4 zero_float4()
Definition math_float4.h:15
float hash_float_to_float(float k)
Definition node_hash.h:13
float distance(float a, float b)
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
float3 color
Definition voronoi.h:42
float4 position
Definition voronoi.h:43
float distance
Definition voronoi.h:41
bool normalize
Definition voronoi.h:35
NodeVoronoiDistanceMetric metric
Definition voronoi.h:37
NodeVoronoiFeature feature
Definition voronoi.h:36
float x
float y
uint x
Definition types_uint4.h:15
uint y
Definition types_uint4.h:15
uint z
Definition types_uint4.h:15
uint w
Definition types_uint4.h:15
ccl_device_inline float4 float3_to_float4(const float3 a)
Definition util/math.h:540
ccl_device_inline float3 float4_to_float3(const float4 a)
Definition util/math.h:535
ccl_device_inline float2 float3_to_float2(const float3 a)
Definition util/math.h:530
ccl_device_inline int clamp(int a, int mn, int mx)
Definition util/math.h:379
ccl_device VoronoiOutput voronoi_smooth_f1(ccl_private const VoronoiParams &params, const float coord)
Definition voronoi.h:107
ccl_device VoronoiOutput fractal_voronoi_x_fx(ccl_private const VoronoiParams &params, const T coord)
Definition voronoi.h:886
ccl_device VoronoiOutput voronoi_f2(ccl_private const VoronoiParams &params, const float coord)
Definition voronoi.h:141
ccl_device_noinline int svm_node_tex_voronoi(KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint dimensions, uint feature, uint metric, int offset)
Definition voronoi.h:1013
ccl_device float voronoi_distance(const float a, const float b)
Definition voronoi.h:48
ccl_device VoronoiOutput voronoi_f1(ccl_private const VoronoiParams &params, const float coord)
Definition voronoi.h:80
ccl_device float fractal_voronoi_distance_to_edge(ccl_private const VoronoiParams &params, const T coord)
Definition voronoi.h:943
ccl_device float voronoi_distance_to_edge(ccl_private const VoronoiParams &params, const float coord)
Definition voronoi.h:179
ccl_device float4 voronoi_position(const float coord)
Definition voronoi.h:75
ccl_device void svm_voronoi_output(const uint4 stack_offsets, ccl_private float *stack, const float distance, const float3 color, const float3 position, const float w, const float radius)
Definition voronoi.h:984
ccl_device float voronoi_n_sphere_radius(ccl_private const VoronoiParams &params, const float coord)
Definition voronoi.h:194