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;
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
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
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:
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);
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);
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);
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
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
#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 normalize(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
#define T
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
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
VecBase< float, 4 > float4
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