1 /* This file is part of Dilay
2 * Copyright © 2015-2018 Alexander Bau
3 * Use and redistribute under the terms of the GNU General Public License
4 */
5 #include <memory>
6 #include "dynamic/faces.hpp"
7 #include "dynamic/mesh.hpp"
8 #include "primitive/plane.hpp"
9 #include "primitive/sphere.hpp"
10 #include "primitive/triangle.hpp"
11 #include "tool/sculpt/util/brush.hpp"
12 #include "util.hpp"
13
SBFlattenParameters()14 SBFlattenParameters::SBFlattenParameters ()
15 : _lockPlane (false)
16 {
17 }
18
hasLockedPlane() const19 bool SBFlattenParameters::hasLockedPlane () const { return bool(this->_lockedPlane); }
20
lockedPlane() const21 const PrimPlane& SBFlattenParameters::lockedPlane () const { return *this->_lockedPlane; }
22
lockedPlane(const PrimPlane & p)23 void SBFlattenParameters::lockedPlane (const PrimPlane& p) { this->_lockedPlane = p; }
24
resetLockedPlane()25 void SBFlattenParameters::resetLockedPlane () { this->_lockedPlane.reset (); }
26
mirror(const PrimPlane & m)27 void SBFlattenParameters::mirror (const PrimPlane& m)
28 {
29 if (this->hasLockedPlane ())
30 {
31 this->_lockedPlane->point (m.mirror (this->_lockedPlane->point ()));
32 this->_lockedPlane->normal (m.mirrorDirection (this->_lockedPlane->normal ()));
33 }
34 }
35
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const36 void SBDrawParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
37 {
38 if (faces.isEmpty () == false)
39 {
40 if (this->flat ())
41 {
42 const float intensity = 0.3f * this->intensity ();
43 const glm::vec3 planeNormal = this->invert (brush.normal ());
44 const glm::vec3 planePos = brush.position () + (planeNormal * intensity * brush.radius ());
45 const PrimPlane plane (planePos, planeNormal);
46
47 brush.mesh ().forEachVertex (faces, [&brush, &plane, intensity](unsigned int i) {
48 const glm::vec3& oldPos = brush.mesh ().vertex (i);
49 const float factor = intensity * Util::linearStep (oldPos, brush.position (),
50 0.5f * brush.radius (), brush.radius ());
51 const float distance = glm::min (0.0f, plane.distance (oldPos));
52 const glm::vec3 newPos = oldPos - (plane.normal () * factor * distance);
53
54 brush.mesh ().vertex (i, newPos);
55 });
56 }
57 else
58 {
59 const float intensity = 0.1f * this->intensity () * brush.radius ();
60 const glm::vec3 avgDir = this->invert (brush.mesh ().averageNormal (faces));
61
62 brush.mesh ().forEachVertex (faces, [&brush, &avgDir, intensity](unsigned int i) {
63 const glm::vec3& oldPos = brush.mesh ().vertex (i);
64 const float factor =
65 intensity * Util::smoothStep (oldPos, brush.position (), 0.0f, brush.radius ());
66 const glm::vec3 newPos = oldPos + (factor * avgDir);
67
68 brush.mesh ().vertex (i, newPos);
69 });
70 }
71 }
72 }
73
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const74 void SBGrablikeParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
75 {
76 brush.mesh ().forEachVertex (faces, [&brush](unsigned int i) {
77 const glm::vec3& oldPos = brush.mesh ().vertex (i);
78 const float factor = Util::linearStep (oldPos, brush.lastPosition (), 0.0f, brush.radius ());
79 const glm::vec3 newPos = oldPos + (factor * brush.delta ());
80
81 brush.mesh ().vertex (i, newPos);
82 });
83 }
84
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const85 void SBSmoothParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
86 {
87 brush.mesh ().forEachVertex (faces, [this, &brush](unsigned int i) {
88 const glm::vec3 avgPos = brush.mesh ().averagePosition (i);
89 const glm::vec3& oldPos = brush.mesh ().vertex (i);
90 const glm::vec3 newPos = oldPos + (this->intensity () * (avgPos - oldPos));
91
92 brush.mesh ().vertex (i, newPos);
93 });
94 }
95
sculpt(const SculptBrush &,const DynamicFaces &) const96 void SBReduceParameters::sculpt (const SculptBrush&, const DynamicFaces&) const {}
97
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const98 void SBFlattenParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
99 {
100 if (faces.isEmpty () == false)
101 {
102 PrimPlane plane (glm::vec3 (0.0f), glm::vec3 (1.0f));
103
104 if (this->hasLockedPlane ())
105 {
106 plane = this->lockedPlane ();
107 }
108 else
109 {
110 glm::vec3 avgPos, avgNormal;
111 brush.mesh ().average (faces, avgPos, avgNormal);
112 plane = PrimPlane (avgPos, avgNormal);
113 }
114
115 brush.mesh ().forEachVertex (faces, [this, &brush, &plane](unsigned int i) {
116 const glm::vec3& oldPos = brush.mesh ().vertex (i);
117 const float distance = plane.distance (oldPos);
118
119 float factor =
120 this->intensity () * Util::linearStep (oldPos, brush.position (), 0.0f, brush.radius ());
121 factor *= this->hasLockedPlane () ? distance : glm::max (0.0f, distance);
122
123 const glm::vec3 newPos = oldPos - (plane.normal () * factor);
124 brush.mesh ().vertex (i, newPos);
125 });
126 }
127 }
128
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const129 void SBCreaseParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
130 {
131 if (faces.isEmpty () == false && brush.position () != brush.lastPosition ())
132 {
133 const glm::vec3 normal = this->invert (brush.normal ());
134
135 brush.mesh ().forEachVertex (faces, [this, &brush, &normal](unsigned int i) {
136 const glm::vec3& oldPos = brush.mesh ().vertex (i);
137 const glm::vec3 delta = brush.position () - oldPos;
138 const float distance = glm::length (delta) / brush.radius ();
139
140 if (distance <= 1.0f)
141 {
142 const float invDistance2 = (distance - 1.0f) * (distance - 1.0f);
143 const float hFactor = invDistance2 * this->intensity ();
144 float vFactor = invDistance2 * invDistance2 * brush.radius () * this->intensity () * 0.5f;
145 const glm::vec3 newPos = (oldPos + (hFactor * delta)) + (normal * vFactor);
146
147 brush.mesh ().vertex (i, newPos);
148 }
149 });
150 }
151 }
152
sculpt(const SculptBrush & brush,const DynamicFaces & faces) const153 void SBPinchParameters::sculpt (const SculptBrush& brush, const DynamicFaces& faces) const
154 {
155 brush.mesh ().forEachVertex (faces, [&brush](unsigned int i) {
156 const glm::vec3& oldPos = brush.mesh ().vertex (i);
157 const glm::vec3 delta = brush.position () - oldPos;
158 const float distance = glm::length (delta) / brush.radius ();
159
160 if (distance <= 1.0f)
161 {
162 const float invDistance2 = (distance - 1.0f) * (distance - 1.0f);
163 const float hFactor = invDistance2 * 0.5f;
164 const glm::vec3 newPos = oldPos + (hFactor * delta);
165
166 brush.mesh ().vertex (i, newPos);
167 }
168 });
169 }
170
171 struct SculptBrush::Impl
172 {
173 SculptBrush* self;
174 float radius;
175 float detailFactor;
176 float stepWidthFactor;
177 bool subdivide;
178 DynamicMesh* _mesh;
179 bool hasPointOfAction;
180 glm::vec3 _prevPosition;
181 glm::vec3 _position;
182 glm::vec3 _normal;
183
184 std::unique_ptr<SBParameters> _parameters;
185
ImplSculptBrush::Impl186 Impl (SculptBrush* s)
187 : self (s)
188 , radius (0.0f)
189 , detailFactor (0.0f)
190 , stepWidthFactor (0.0f)
191 , subdivide (true)
192 , _mesh (nullptr)
193 , hasPointOfAction (false)
194 {
195 }
196
meshSculptBrush::Impl197 DynamicMesh& mesh () const
198 {
199 assert (this->hasPointOfAction);
200 assert (this->_mesh);
201 return *this->_mesh;
202 }
203
meshSculptBrush::Impl204 void mesh (DynamicMesh& m) { this->_mesh = &m; }
205
subdivThresholdSculptBrush::Impl206 float subdivThreshold () const
207 {
208 assert (this->detailFactor > 0.0f);
209 assert (this->detailFactor < 1.0f);
210
211 return (1.0f - this->detailFactor) * this->radius;
212 }
213
lastPositionSculptBrush::Impl214 const glm::vec3& lastPosition () const
215 {
216 assert (this->hasPointOfAction);
217 return this->_prevPosition;
218 }
219
positionSculptBrush::Impl220 const glm::vec3& position () const
221 {
222 assert (this->hasPointOfAction);
223 return this->_position;
224 }
225
normalSculptBrush::Impl226 const glm::vec3& normal () const
227 {
228 assert (this->hasPointOfAction);
229 return this->_normal;
230 }
231
deltaSculptBrush::Impl232 glm::vec3 delta () const
233 {
234 assert (this->hasPointOfAction);
235 return this->_position - this->_prevPosition;
236 }
237
sphereSculptBrush::Impl238 PrimSphere sphere () const
239 {
240 assert (this->_parameters);
241
242 const glm::vec3& pos =
243 this->_parameters->useLastPos () ? this->lastPosition () : this->position ();
244 return PrimSphere (pos, this->radius);
245 }
246
stepWidthSculptBrush::Impl247 float stepWidth () const { return this->stepWidthFactor * glm::log (this->self->radius () + 1); }
248
setPointOfActionSculptBrush::Impl249 void setPointOfAction (DynamicMesh& mesh, const glm::vec3& p, const glm::vec3& n)
250 {
251 this->_mesh = &mesh;
252 this->_prevPosition = this->hasPointOfAction ? this->_position : p;
253 this->_position = p;
254 this->_normal = n;
255 this->hasPointOfAction = true;
256 }
257
resetPointOfActionSculptBrush::Impl258 void resetPointOfAction ()
259 {
260 this->hasPointOfAction = false;
261 this->_mesh = nullptr;
262 }
263
mirrorSculptBrush::Impl264 void mirror (const PrimPlane& plane)
265 {
266 if (this->_parameters)
267 {
268 this->_parameters->mirror (plane);
269 }
270
271 if (this->hasPointOfAction)
272 {
273 this->_prevPosition = plane.mirror (this->_prevPosition);
274 this->_position = plane.mirror (this->_position);
275 this->_normal = plane.mirrorDirection (this->_normal);
276 }
277 }
278
getAffectedFacesSculptBrush::Impl279 DynamicFaces getAffectedFaces () const
280 {
281 assert (this->hasPointOfAction);
282 assert (this->_parameters);
283
284 DynamicFaces faces;
285 this->_mesh->intersects (this->sphere (), faces);
286
287 if (this->_parameters->discardBack ())
288 {
289 faces.filter ([this](unsigned int i) {
290 return glm::dot (this->normal (), this->_mesh->face (i).cross ()) > 0.0f;
291 });
292 }
293 return faces;
294 }
295
sculptSculptBrush::Impl296 void sculpt (const DynamicFaces& faces) const
297 {
298 assert (this->_parameters);
299 this->_parameters->sculpt (*this->self, faces);
300 }
301
parametersPointerSculptBrush::Impl302 SBParameters* parametersPointer () const { return this->_parameters.get (); }
303
parametersPointerSculptBrush::Impl304 void parametersPointer (SBParameters* p) { this->_parameters.reset (p); }
305 };
306
307 DELEGATE_BIG3_SELF (SculptBrush)
308
309 GETTER_CONST (float, SculptBrush, radius)
310 GETTER_CONST (float, SculptBrush, detailFactor)
311 GETTER_CONST (float, SculptBrush, stepWidthFactor)
312 GETTER_CONST (bool, SculptBrush, subdivide)
313 DELEGATE_CONST (DynamicMesh&, SculptBrush, mesh)
314 SETTER (float, SculptBrush, radius)
315 SETTER (float, SculptBrush, detailFactor)
316 SETTER (float, SculptBrush, stepWidthFactor)
317 SETTER (bool, SculptBrush, subdivide)
318 DELEGATE_CONST (float, SculptBrush, subdivThreshold)
319 DELEGATE_CONST (const glm::vec3&, SculptBrush, lastPosition)
320 DELEGATE_CONST (const glm::vec3&, SculptBrush, position)
321 DELEGATE_CONST (const glm::vec3&, SculptBrush, normal)
322 DELEGATE_CONST (glm::vec3, SculptBrush, delta)
323 DELEGATE_CONST (PrimSphere, SculptBrush, sphere)
324 DELEGATE_CONST (float, SculptBrush, stepWidth)
325 GETTER_CONST (bool, SculptBrush, hasPointOfAction)
326 DELEGATE3 (void, SculptBrush, setPointOfAction, DynamicMesh&, const glm::vec3&, const glm::vec3&)
327 DELEGATE (void, SculptBrush, resetPointOfAction)
328 DELEGATE1 (void, SculptBrush, mirror, const PrimPlane&)
329 DELEGATE_CONST (DynamicFaces, SculptBrush, getAffectedFaces)
330 DELEGATE1_CONST (void, SculptBrush, sculpt, const DynamicFaces&)
331 DELEGATE_CONST (SBParameters*, SculptBrush, parametersPointer)
332 DELEGATE1 (void, SculptBrush, parametersPointer, SBParameters*)
333