Blender V4.3
BasicStrokeShaders.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10#include <fstream>
11
12#include "AdvancedFunctions0D.h"
13#include "AdvancedFunctions1D.h"
14#include "BasicStrokeShaders.h"
15#include "StrokeIO.h"
16#include "StrokeIterators.h"
17#include "StrokeRenderer.h"
18
20#include "../system/RandGen.h"
22
25
26#include "BKE_global.hh"
27
28#include "BLI_sys_types.h"
29
30#include "IMB_imbuf.hh"
31#include "IMB_imbuf_types.hh"
32
34
35//
36// Thickness modifiers
37//
39
41{
43 int i = 0;
44 int size = stroke.strokeVerticesSize();
45 for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
46 // XXX What's the use of i here? And is not the thickness always overridden by the last line of
47 // the loop?
48 if ((1 == i) || (size - 2 == i)) {
49 v->attribute().setThickness(_thickness / 4.0, _thickness / 4.0);
50 }
51 if ((0 == i) || (size - 1 == i)) {
52 v->attribute().setThickness(0, 0);
53 }
54
55 v->attribute().setThickness(_thickness / 2.0, _thickness / 2.0);
56 }
57 return 0;
58}
59
61{
63 int i = 0;
64 int size = stroke.strokeVerticesSize();
65 for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
66 // XXX What's the use of i here? And is not the thickness always overridden by the last line of
67 // the loop?
68 if ((1 == i) || (size - 2 == i)) {
69 v->attribute().setThickness(_thickness / 2.0, 0);
70 }
71 if ((0 == i) || (size - 1 == i)) {
72 v->attribute().setThickness(0, 0);
73 }
74
75 v->attribute().setThickness(_thickness, 0);
76 }
77 return 0;
78}
79
81{
82 int n = stroke.strokeVerticesSize() - 1, i;
84 for (i = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend;
85 ++v, ++i)
86 {
87 float t;
88 if (i < float(n) / 2.0f) {
89 t = (1.0 - float(i) / float(n)) * _ThicknessMin + float(i) / float(n) * _ThicknessMax;
90 }
91 else {
92 t = (1.0 - float(i) / float(n)) * _ThicknessMax + float(i) / float(n) * _ThicknessMin;
93 }
94 v->attribute().setThickness(t / 2.0, t / 2.0);
95 }
96 return 0;
97}
98
100{
101 float slength = stroke.getLength2D();
102 float maxT = min(_ratio * slength, _ThicknessMax);
103 int n = stroke.strokeVerticesSize() - 1, i;
105 for (i = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend;
106 ++v, ++i)
107 {
108 // XXX Why not using an if/else here? Else, if last condition is true, everything else is
109 // computed for nothing!
110 float t;
111 if (i < float(n) / 2.0f) {
112 t = (1.0 - float(i) / float(n)) * _ThicknessMin + float(i) / float(n) * maxT;
113 }
114 else {
115 t = (1.0 - float(i) / float(n)) * maxT + float(i) / float(n) * _ThicknessMin;
116 }
117 v->attribute().setThickness(t / 2.0, t / 2.0);
118 if (i == n - 1) {
119 v->attribute().setThickness(_ThicknessMin / 2.0, _ThicknessMin / 2.0);
120 }
121 }
122 return 0;
123}
124
126{
127 float step = (_maxThickness - _minThickness) / 3.0f;
128 float l = stroke.getLength2D();
129 float thickness = 0.0f;
130 if (l > 300.0f) {
131 thickness = _minThickness + 3.0f * step;
132 }
133 else if ((l < 300.0f) && (l > 100.0f)) {
134 thickness = _minThickness + 2.0f * step;
135 }
136 else if ((l < 100.0f) && (l > 50.0f)) {
137 thickness = _minThickness + 1.0f * step;
138 }
139 else { // else if (l < 50.0f), tsst...
140 thickness = _minThickness;
141 }
142
144 int i = 0;
145 int size = stroke.strokeVerticesSize();
146 for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
147 // XXX What's the use of i here? And is not the thickness always overridden by the last line of
148 // the loop?
149 if ((1 == i) || (size - 2 == i)) {
150 v->attribute().setThickness(thickness / 4.0, thickness / 4.0);
151 }
152 if ((0 == i) || (size - 1 == i)) {
153 v->attribute().setThickness(0, 0);
154 }
155
156 v->attribute().setThickness(thickness / 2.0, thickness / 2.0);
157 }
158 return 0;
159}
160
161static const uint NB_VALUE_NOISE = 512;
162
164{
165 _amplitude = 1.0f;
166 _scale = 1.0f / 2.0f / float(NB_VALUE_NOISE);
167}
168
169ThicknessNoiseShader::ThicknessNoiseShader(float iAmplitude, float iPeriod)
170{
171 _amplitude = iAmplitude;
172 _scale = 1.0f / iPeriod / float(NB_VALUE_NOISE);
173}
174
176{
178 real initU1 = v->strokeLength() * real(NB_VALUE_NOISE) +
180 real initU2 = v->strokeLength() * real(NB_VALUE_NOISE) +
182
183 real bruit, bruit2;
184 PseudoNoise mynoise, mynoise2;
185 for (vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
186 bruit = mynoise.turbulenceSmooth(_scale * v->curvilinearAbscissa() + initU1,
187 2); // 2 : nbOctaves
188 bruit2 = mynoise2.turbulenceSmooth(_scale * v->curvilinearAbscissa() + initU2,
189 2); // 2 : nbOctaves
190 const float *originalThickness = v->attribute().getThickness();
191 float r = bruit * _amplitude + originalThickness[0];
192 float l = bruit2 * _amplitude + originalThickness[1];
193 v->attribute().setThickness(r, l);
194 }
195
196 return 0;
197}
198
199//
200// Color shaders
201//
203
205{
207 for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
208 v->attribute().setColor(_color[0], _color[1], _color[2]);
209 v->attribute().setAlpha(_color[3]);
210 }
211 return 0;
212}
213
215{
217 int n = stroke.strokeVerticesSize() - 1, yo;
218 float newcolor[4];
219 for (yo = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend;
220 ++v, ++yo)
221 {
222 for (int i = 0; i < 4; ++i) {
223 newcolor[i] = (1.0 - float(yo) / float(n)) * _colorMin[i] +
224 float(yo) / float(n) * _colorMax[i];
225 }
226 v->attribute().setColor(newcolor[0], newcolor[1], newcolor[2]);
227 v->attribute().setAlpha(newcolor[3]);
228 }
229 return 0;
230}
231
233{
236 StrokeVertex *sv;
237 for (v = stroke.verticesBegin(), vend = stroke.verticesEnd(); v != vend; ++v) {
238 if (fun(v) < 0) {
239 return -1;
240 }
241 const float *diffuse = fun.result.diffuse();
242 sv = dynamic_cast<StrokeVertex *>(&(*v));
243 sv->attribute().setColor(
244 diffuse[0] * _coefficient, diffuse[1] * _coefficient, diffuse[2] * _coefficient);
245 sv->attribute().setAlpha(diffuse[3]);
246 }
247 return 0;
248}
249
251{
252 _amplitude = 1.0f;
253 _scale = 1.0f / 2.0f / float(NB_VALUE_NOISE);
254}
255
256ColorNoiseShader::ColorNoiseShader(float iAmplitude, float iPeriod)
257{
258 _amplitude = iAmplitude;
259 _scale = 1.0f / iPeriod / float(NB_VALUE_NOISE);
260}
261
263{
265 real initU = v->strokeLength() * real(NB_VALUE_NOISE) +
267
268 real bruit;
269 PseudoNoise mynoise;
270 for (vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
271 bruit = mynoise.turbulenceSmooth(_scale * v->curvilinearAbscissa() + initU,
272 2); // 2 : nbOctaves
273 const float *originalColor = v->attribute().getColor();
274 float r = bruit * _amplitude + originalColor[0];
275 float g = bruit * _amplitude + originalColor[1];
276 float b = bruit * _amplitude + originalColor[2];
277 v->attribute().setColor(r, g, b);
278 }
279 return 0;
280}
281
282//
283// Texture Shaders
284//
286
288{
289 if (_mtex) {
290 return stroke.setMTex(_mtex);
291 }
292 if (_nodeTree) {
293 stroke.setNodeTree(_nodeTree);
294 return 0;
295 }
296 return -1;
297}
298
300{
301 stroke.setTextureStep(_step);
302 return 0;
303}
304
305//
306// Geometry Shaders
307//
309
311{
312 float l = stroke.getLength2D();
313 if (l <= 1.0e-6) {
314 return 0;
315 }
316
319 ++v1;
321 --vn;
323 --vn_1;
324
325 Vec2d first((v0)->x(), (v0)->y());
326 Vec2d last((vn)->x(), (vn)->y());
327
328 Vec2d d1(first - Vec2d((v1)->x(), (v1)->y()));
329 d1.normalize();
330 Vec2d dn(last - Vec2d((vn_1)->x(), (vn_1)->y()));
331 dn.normalize();
332
333 Vec2d newFirst(first + _amount * d1);
334 (v0)->setPoint(newFirst[0], newFirst[1]);
335 Vec2d newLast(last + _amount * dn);
336 (vn)->setPoint(newLast[0], newLast[1]);
337
338 stroke.UpdateLength();
339 return 0;
340}
341
343{
344 stroke.Resample(_sampling);
345 stroke.UpdateLength();
346 return 0;
347}
348
350{
351 // float l = stroke.getLength2D();
354 StrokeVertex *sv;
355 for (it = stroke.verticesBegin(); !it.isEnd(); ++it) {
356 if (fun(it) < 0) {
357 return -1;
358 }
359 Vec2f n(fun.result);
360 sv = dynamic_cast<StrokeVertex *>(&(*it));
361 Vec2d newPoint(sv->x() + _amount * n.x(), sv->y() + _amount * n.y());
362 sv->setPoint(newPoint[0], newPoint[1]);
363 }
364 stroke.UpdateLength();
365 return 0;
366}
367
370{
371 if (stroke.strokeVerticesSize() < 4) {
372 return 0;
373 }
374
375 // Build the Bezier curve from this set of data points:
376 vector<Vec2d> data;
378 data.emplace_back(v->x(), v->y()); // first one
380 ++v;
381 for (vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
382 if (!((fabs(v->x() - (previous)->x()) < M_EPSILON) &&
383 (fabs(v->y() - (previous)->y()) < M_EPSILON)))
384 {
385 data.emplace_back(v->x(), v->y());
386 }
387 previous = v;
388 }
389
390 // here we build the bezier curve
391 BezierCurve bcurve(data, _error);
392
393 // bad performances are here !!! // FIXME
394 vector<Vec2d> CurveVertices;
395 vector<BezierCurveSegment *> &bsegments = bcurve.segments();
396 vector<BezierCurveSegment *>::iterator s = bsegments.begin(), send;
397 vector<Vec2d> &segmentsVertices = (*s)->vertices();
398 vector<Vec2d>::iterator p, pend;
399 // first point
400 CurveVertices.push_back(segmentsVertices[0]);
401 for (send = bsegments.end(); s != send; ++s) {
402 segmentsVertices = (*s)->vertices();
403 p = segmentsVertices.begin();
404 ++p;
405 for (pend = segmentsVertices.end(); p != pend; ++p) {
406 CurveVertices.push_back(*p);
407 }
408 }
409
410 // Re-sample the Stroke depending on the number of vertices of the bezier curve:
411 int originalSize = CurveVertices.size();
412#if 0
413 float sampling = stroke.ComputeSampling(originalSize);
414 stroke.Resample(sampling);
415#endif
416 stroke.Resample(originalSize);
417 int newsize = stroke.strokeVerticesSize();
418 int nExtraVertex = 0;
419 if (newsize < originalSize) {
420 cerr << "Warning: insufficient resampling" << endl;
421 }
422 else {
423 nExtraVertex = newsize - originalSize;
424 if (nExtraVertex != 0) {
425 if (G.debug & G_DEBUG_FREESTYLE) {
426 cout << "Bezier Shader : Stroke " << stroke.getId() << " have not been resampled" << endl;
427 }
428 }
429 }
430
431 // assigns the new coordinates:
432 p = CurveVertices.begin();
433 vector<Vec2d>::iterator last = p;
434 int n;
436 for (n = 0,
437 it = stroke.strokeVerticesBegin(),
438 itend = stroke.strokeVerticesEnd(),
439 pend = CurveVertices.end();
440 (it != itend) && (p != pend);
441 ++it, ++p, ++n)
442 {
443 it->setX(p->x());
444 it->setY(p->y());
445 last = p;
446 }
447 stroke.UpdateLength();
448
449 // Deal with extra vertices:
450 if (nExtraVertex == 0) {
451 return 0;
452 }
453
454 // nExtraVertex should stay unassigned
455 vector<StrokeAttribute> attributes;
456 vector<StrokeVertex *> verticesToRemove;
457 for (int i = 0; i < nExtraVertex; ++i, ++it, ++n) {
458 verticesToRemove.push_back(&(*it));
459 if (it.isEnd()) {
460 // XXX Shocking! :P Shouldn't we break in this case???
461 if (G.debug & G_DEBUG_FREESTYLE) {
462 cout << "messed up!" << endl;
463 }
464 }
465 }
466 for (it = stroke.strokeVerticesBegin(); it != itend; ++it) {
467 attributes.push_back(it->attribute());
468 }
469
470 for (vector<StrokeVertex *>::iterator vr = verticesToRemove.begin(),
471 vrend = verticesToRemove.end();
472 vr != vrend;
473 ++vr)
474 {
475 stroke.RemoveVertex(*vr);
476 }
477
478 vector<StrokeAttribute>::iterator a = attributes.begin(), aend = attributes.end();
479 int index = 0;
480 int index1 = int(floor(float(originalSize) / 2.0));
481 int index2 = index1 + nExtraVertex;
482 for (it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd();
483 (it != itend) && (a != aend);
484 ++it)
485 {
486 (it)->setAttribute(*a);
487 if ((index <= index1) || (index > index2)) {
488 ++a;
489 }
490 ++index;
491 }
492 return 0;
493}
494
496 public:
501 int size;
502 float _error;
503
506 int iSize)
507 {
508 _error = 0.0f;
509 _begin = b;
510 _last = l;
511 A = Vec2d((_begin)->x(), (_begin)->y());
512 B = Vec2d((_last)->x(), (_last)->y());
513 size = iSize;
514 }
515
516 float error()
517 {
518 float maxE = 0.0f;
519 for (StrokeInternal::StrokeVertexIterator it = _begin; it != _last; ++it) {
520 Vec2d P(it->x(), it->y());
521 float d = GeomUtils::distPointSegment(P, A, B);
522 if (d > maxE) {
523 maxE = d;
524 }
525 }
526 _error = maxE;
527 return maxE;
528 }
529
531 // The first piece is this same object (modified)
532 // The second piece is returned by the method
534 {
536 int ns = size - 1; // number of segments (ns > 1)
537 int ns1 = ns / 2;
538 int ns2 = ns - ns1;
539 for (int i = 0; i < ns1; ++it, ++i) {
540 /* pass */
541 }
542
543 CurvePiece *second = new CurvePiece(it, _last, ns2 + 1);
544 size = ns1 + 1;
545 _last = it;
546 B = Vec2d((_last)->x(), (_last)->y());
547 return second;
548 }
549};
550
552{
553 vector<CurvePiece *> _pieces;
554 vector<CurvePiece *> _results;
555 vector<CurvePiece *>::iterator cp, cpend;
556
557 // Compute first approx:
560 --b;
561 int size = stroke.strokeVerticesSize();
562
563 CurvePiece *piece = new CurvePiece(a, b, size);
564 _pieces.push_back(piece);
565
566 while (!_pieces.empty()) {
567 piece = _pieces.back();
568 _pieces.pop_back();
569 if (piece->size > 2 && piece->error() > _error) {
570 CurvePiece *second = piece->subdivide();
571 _pieces.push_back(second);
572 _pieces.push_back(piece);
573 }
574 else {
575 _results.push_back(piece);
576 }
577 }
578
579 // actually modify the geometry for each piece:
580 for (cp = _results.begin(), cpend = _results.end(); cp != cpend; ++cp) {
581 a = (*cp)->_begin;
582 b = (*cp)->_last;
583 Vec2d u = (*cp)->B - (*cp)->A;
584 Vec2d n(u[1], -u[0]);
585 n.normalize();
586 // Vec2d n(0, 0);
587 float offset = ((*cp)->_error);
589 for (v = a; v != b; ++v) {
590 v->setPoint((*cp)->A.x() + v->u() * u.x() + n.x() * offset,
591 (*cp)->A.y() + v->u() * u.y() + n.y() * offset);
592 }
593#if 0
594 u.normalize();
595 (*a)->setPoint((*a)->x() - u.x() * 10, (*a)->y() - u.y() * 10);
596#endif
597 }
598 stroke.UpdateLength();
599
600 // delete stuff
601 for (cp = _results.begin(), cpend = _results.end(); cp != cpend; ++cp) {
602 delete (*cp);
603 }
604 _results.clear();
605 return 0;
606}
607
609{
613 --b;
614 int size = stroke.strokeVerticesSize();
615 CurvePiece piece(a, b, size);
616
617 Vec2d u = piece.B - piece.A;
618 Vec2f n(u[1], -u[0]);
619 n.normalize();
620 if (norm_fun(stroke) < 0) {
621 return -1;
622 }
623 Vec2f strokeN(norm_fun.result);
624 if (n * strokeN < 0) {
625 n[0] = -n[0];
626 n[1] = -n[1];
627 }
628 float offset = piece.error() / 2.0f * _offset;
630 for (v = a, vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
631 v->setPoint(piece.A.x() + v->u() * u.x() + n.x() * offset,
632 piece.A.y() + v->u() * u.y() + n.y() * offset);
633 }
634 stroke.UpdateLength();
635 return 0;
636}
637
639//
640// Tip Remover
641//
643
645{
646 _tipLength = tipLength;
647}
648
650{
651 int originalSize = stroke.strokeVerticesSize();
652
653 if (originalSize < 4) {
654 return 0;
655 }
656
658 vector<StrokeVertex *> verticesToRemove;
659 vector<StrokeAttribute> oldAttributes;
660 for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
661 if ((v->curvilinearAbscissa() < _tipLength) ||
662 (v->strokeLength() - v->curvilinearAbscissa() < _tipLength))
663 {
664 verticesToRemove.push_back(&(*v));
665 }
666 oldAttributes.push_back(v->attribute());
667 }
668
669 if (originalSize - verticesToRemove.size() < 2) {
670 return 0;
671 }
672
673 vector<StrokeVertex *>::iterator sv, svend;
674 for (sv = verticesToRemove.begin(), svend = verticesToRemove.end(); sv != svend; ++sv) {
675 stroke.RemoveVertex(*sv);
676 }
677
678 // Resample so that our new stroke have the same number of vertices than before
679 stroke.Resample(originalSize);
680
681 if (int(stroke.strokeVerticesSize()) != originalSize) { // soc
682 cerr << "Warning: resampling problem" << endl;
683 }
684
685 // assign old attributes to new stroke vertices:
686 vector<StrokeAttribute>::iterator a = oldAttributes.begin(), aend = oldAttributes.end();
687 for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd();
688 (v != vend) && (a != aend);
689 ++v, ++a)
690 {
691 v->setAttribute(*a);
692 }
693 // we're done!
694 return 0;
695}
696
697} // namespace Freestyle::StrokeShaders
Functions taking 0D input.
Functions taking 1D input.
@ G_DEBUG_FREESTYLE
unsigned int uint
Class gathering basic stroke shaders.
Functions taking 0D input.
Functions taking 1D input.
Contains defines and structs used throughout the imbuf module.
Class to define a pseudo Perlin noise.
Pseudo-random number generator.
String utilities.
Functions to manage I/O for the stroke.
Iterators used to iterate over the elements of the Stroke.
Classes to render a stroke with OpenGL.
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
std::vector< BezierCurveSegment * > & segments()
Definition Bezier.h:70
const float * diffuse() const
Definition FrsMaterial.h:88
real turbulenceSmooth(real x, uint nbOctave=8)
static real drand48()
Definition RandGen.cpp:94
void setColor(float r, float g, float b)
Definition Stroke.h:202
void setAlpha(float alpha)
Definition Stroke.h:224
virtual int shade(Stroke &stroke) const
! Bezier curve stroke shader
virtual int shade(Stroke &stroke) const
StrokeInternal::StrokeVertexIterator _begin
CurvePiece * subdivide()
Subdivides the curve into two pieces.
StrokeInternal::StrokeVertexIterator _last
CurvePiece(StrokeInternal::StrokeVertexIterator b, StrokeInternal::StrokeVertexIterator l, int iSize)
virtual int shade(Stroke &stroke) const
virtual int shade(Stroke &stroke) const
void setX(real x)
Definition Stroke.h:407
void setPoint(real x, real y)
Definition Stroke.h:419
const StrokeAttribute & attribute() const
Definition Stroke.h:376
virtual Id getId() const
Definition Stroke.h:500
void setTextureStep(float step)
Definition Stroke.h:755
virtual Interface0DIterator verticesBegin()
Definition Stroke.cpp:771
void RemoveVertex(StrokeVertex *iVertex)
Definition Stroke.cpp:703
virtual Interface0DIterator verticesEnd()
Definition Stroke.cpp:778
void UpdateLength()
Definition Stroke.cpp:723
int setMTex(MTex *mtex)
Definition Stroke.h:761
uint strokeVerticesSize() const
Definition Stroke.h:839
float ComputeSampling(int iNVertices)
Definition Stroke.cpp:491
StrokeInternal::StrokeVertexIterator strokeVerticesEnd()
Definition Stroke.cpp:765
StrokeInternal::StrokeVertexIterator strokeVerticesBegin(float t=0.0f)
Definition Stroke.cpp:756
void setNodeTree(bNodeTree *iNodeTree)
Definition Stroke.h:773
real getLength2D() const
Definition Stroke.h:623
int Resample(int iNPoints)
Definition Stroke.cpp:525
value_type x() const
Definition VecMat.h:296
value_type y() const
Definition VecMat.h:306
Vec< T, N > & normalize()
Definition VecMat.h:104
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
ccl_device_inline float2 floor(const float2 a)
ccl_device_inline float2 fabs(const float2 a)
#define G(x, y, z)
real distPointSegment(const T &P, const T &A, const T &B)
Definition GeomUtils.h:32
VecMat::Vec2< double > Vec2d
Definition Geom.h:23
static const real M_EPSILON
Definition Precision.h:17
static uint a[3]
Definition RandGen.cpp:82
static uint x[3]
Definition RandGen.cpp:77
double real
Definition Precision.h:14
#define min(a, b)
Definition sort.c:32