Blender V4.3
sculpt_detail.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8#include "sculpt_dyntopo.hh"
9
10#include "MEM_guardedalloc.h"
11
12#include "BLI_blenlib.h"
13#include "BLI_math_matrix.h"
14#include "BLI_math_rotation.h"
15#include "BLI_math_vector.hh"
16#include "BLI_time.h"
17
18#include "BLT_translation.hh"
19
20#include "DNA_brush_types.h"
21#include "DNA_mesh_types.h"
22
23#include "BKE_brush.hh"
24#include "BKE_context.hh"
25#include "BKE_layer.hh"
26#include "BKE_object.hh"
27#include "BKE_paint.hh"
28#include "BKE_pbvh_api.hh"
29#include "BKE_screen.hh"
30
31#include "GPU_immediate.hh"
32#include "GPU_immediate_util.hh"
33#include "GPU_matrix.hh"
34#include "GPU_state.hh"
35
36#include "WM_api.hh"
37#include "WM_types.hh"
38
39#include "ED_screen.hh"
40#include "ED_space_api.hh"
41#include "ED_view3d.hh"
42
43#include "DEG_depsgraph.hh"
44
45#include "sculpt_intern.hh"
46#include "sculpt_undo.hh"
47
48#include "RNA_access.hh"
49#include "RNA_define.hh"
50#include "RNA_prototypes.hh"
51
52#include "UI_interface.hh"
53
54#include "CLG_log.h"
55
56#include <cmath>
57#include <cstdlib>
58
60
61static CLG_LogRef LOG = {"sculpt.detail"};
62
63/* -------------------------------------------------------------------- */
75
84
86{
88
89 return SCULPT_mode_poll(C) && ob->sculpt->bm;
90}
91
94/* -------------------------------------------------------------------- */
99{
100 const Scene &scene = *CTX_data_scene(C);
101 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
104 SculptSession &ss = *ob.sculpt;
105
106 const View3D *v3d = CTX_wm_view3d(C);
107 const Base *base = CTX_data_active_base(C);
108 if (!BKE_base_is_visible(v3d, base)) {
109 return OPERATOR_CANCELLED;
110 }
111
114
115 IndexMaskMemory memory;
116 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
117
118 if (nodes.is_empty()) {
119 return OPERATOR_CANCELLED;
120 }
121
122 node_mask.foreach_index([&](const int i) { BKE_pbvh_node_mark_topology_update(nodes[i]); });
123
124 /* Get the bounding box, its center and size. */
125 const Bounds<float3> bounds = bke::pbvh::bounds_get(pbvh);
126 const float3 center = math::midpoint(bounds.min, bounds.max);
127 const float3 dim = bounds.max - bounds.min;
128 const float size = math::reduce_max(dim);
129
130 /* Update topology size. */
131 const float max_edge_len = 1.0f /
132 (sd->constant_detail * mat4_to_scale(ob.object_to_world().ptr()));
133 const float min_edge_len = max_edge_len * detail_size::EDGE_LENGTH_MIN_FACTOR;
134
135 undo::push_begin(scene, ob, op);
137
138 const double start_time = BLI_time_now_seconds();
139
141 pbvh,
142 *ss.bm_log,
144 min_edge_len,
145 max_edge_len,
146 center,
147 nullptr,
148 size,
149 false,
150 false))
151 {
152 node_mask.foreach_index([&](const int i) { BKE_pbvh_node_mark_topology_update(nodes[i]); });
153 }
154
155 CLOG_INFO(&LOG, 2, "Detail flood fill took %f seconds.", BLI_time_now_seconds() - start_time);
156
157 undo::push_end(ob);
158
159 /* Force rebuild of bke::pbvh::Tree for better BB placement. */
162
163 /* Redraw. */
165
166 return OPERATOR_FINISHED;
167}
168
170{
171 /* Identifiers. */
172 ot->name = "Detail Flood Fill";
173 ot->idname = "SCULPT_OT_detail_flood_fill";
174 ot->description = "Flood fill the mesh with the selected detail setting";
175
176 /* API callbacks. */
179
181}
182
185/* -------------------------------------------------------------------- */
190 Dyntopo = 0,
191 Voxel = 1,
192};
193
195 {int(SampleDetailModeType::Dyntopo), "DYNTOPO", 0, "Dyntopo", "Sample dyntopo detail"},
196 {int(SampleDetailModeType::Voxel), "VOXEL", 0, "Voxel", "Sample mesh voxel size"},
197 {0, nullptr, 0, nullptr, nullptr},
198};
199
200static bool sample_detail_voxel(bContext *C, ViewContext *vc, const int mval[2])
201{
203 Object &ob = *vc->obact;
204 SculptSession &ss = *ob.sculpt;
205 Mesh &mesh = *static_cast<Mesh *>(ob.data);
207 const OffsetIndices faces = mesh.faces();
208 const Span<int> corner_verts = mesh.corner_verts();
209 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
210 const bke::AttributeAccessor attributes = mesh.attributes();
211 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
212
214
215 /* Update the active vertex. */
216 const float mval_fl[2] = {float(mval[0]), float(mval[1])};
217 if (!SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) {
218 return false;
219 }
221
222 /* Average the edge length of the connected edges to the active vertex. */
223 const int active_vert = std::get<int>(ss.active_vert());
224 const float3 active_vert_position = positions[active_vert];
225 float edge_length = 0.0f;
226 Vector<int> neighbors;
227 for (const int neighbor : vert_neighbors_get_mesh(
228 faces, corner_verts, vert_to_face_map, hide_poly, active_vert, neighbors))
229 {
230 edge_length += math::distance(active_vert_position, positions[neighbor]);
231 }
232 mesh.remesh_voxel_size = edge_length / float(neighbors.size());
233 return true;
234}
235
238 float *tmin)
239{
240 if (BKE_pbvh_node_get_tmin(&node) < *tmin) {
242 node, srd.ray_start, &srd.isect_precalc, &srd.depth, &srd.edge_length))
243 {
244 srd.hit = true;
245 *tmin = srd.depth;
246 }
247 }
248}
249
250static void sample_detail_dyntopo(bContext *C, ViewContext *vc, const int mval[2])
251{
253 Object &ob = *vc->obact;
254 const Brush &brush = *BKE_paint_brush_for_read(&sd.paint);
255
256 SCULPT_stroke_modifiers_check(C, ob, brush);
257
258 const float mval_fl[2] = {float(mval[0]), float(mval[1])};
259 float ray_start[3], ray_end[3], ray_normal[3];
260 float depth = SCULPT_raycast_init(vc, mval_fl, ray_start, ray_end, ray_normal, false);
261
263 srd.hit = false;
264 srd.ray_start = ray_start;
265 srd.depth = depth;
266 srd.edge_length = 0.0f;
268
270
272 pbvh,
273 [&](bke::pbvh::Node &node, float *tmin) {
274 sculpt_raycast_detail_cb(static_cast<bke::pbvh::BMeshNode &>(node), srd, tmin);
275 },
276 ray_start,
277 ray_normal,
278 false);
279
280 if (srd.hit && srd.edge_length > 0.0f) {
281 /* Convert edge length to world space detail resolution. */
282 sd.constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob.object_to_world().ptr()));
283 }
284}
285
286static int sample_detail(bContext *C, const int event_xy[2], const SampleDetailModeType mode)
287{
288 /* Find 3D view to pick from. */
289 bScreen *screen = CTX_wm_screen(C);
290 ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, event_xy);
291 ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, event_xy) : nullptr;
292 if (region == nullptr) {
293 return OPERATOR_CANCELLED;
294 }
295
296 /* Set context to 3D view. */
297 ScrArea *prev_area = CTX_wm_area(C);
298 ARegion *prev_region = CTX_wm_region(C);
299 CTX_wm_area_set(C, area);
300 CTX_wm_region_set(C, region);
301
304
305 Object *ob = vc.obact;
306 if (ob == nullptr) {
307 return OPERATOR_CANCELLED;
308 }
309
311 if (!pbvh) {
312 return OPERATOR_CANCELLED;
313 }
314
315 const View3D *v3d = CTX_wm_view3d(C);
316 const Base *base = CTX_data_active_base(C);
317 if (!BKE_base_is_visible(v3d, base)) {
318 return OPERATOR_CANCELLED;
319 }
320
321 const int mval[2] = {
322 event_xy[0] - region->winrct.xmin,
323 event_xy[1] - region->winrct.ymin,
324 };
325
326 /* Pick sample detail. */
327 switch (mode) {
329 if (pbvh->type() != bke::pbvh::Type::BMesh) {
330 CTX_wm_area_set(C, prev_area);
331 CTX_wm_region_set(C, prev_region);
332 return OPERATOR_CANCELLED;
333 }
334 sample_detail_dyntopo(C, &vc, mval);
335 break;
337 if (pbvh->type() != bke::pbvh::Type::Mesh) {
338 CTX_wm_area_set(C, prev_area);
339 CTX_wm_region_set(C, prev_region);
340 return OPERATOR_CANCELLED;
341 }
342 if (!sample_detail_voxel(C, &vc, mval)) {
343 return OPERATOR_CANCELLED;
344 }
345 break;
346 }
347
348 /* Restore context. */
349 CTX_wm_area_set(C, prev_area);
350 CTX_wm_region_set(C, prev_region);
351
352 return OPERATOR_FINISHED;
353}
354
356{
357 int ss_co[2];
358 RNA_int_get_array(op->ptr, "location", ss_co);
360 return sample_detail(C, ss_co, mode);
361}
362
363static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
364{
365 ED_workspace_status_text(C, IFACE_("Click on the mesh to set the detail"));
369}
370
372{
373 switch (event->type) {
374 case LEFTMOUSE:
375 if (event->val == KM_PRESS) {
377 sample_detail(C, event->xy, mode);
378
379 RNA_int_set_array(op->ptr, "location", event->xy);
381 ED_workspace_status_text(C, nullptr);
383
384 return OPERATOR_FINISHED;
385 }
386 break;
387 case EVT_ESCKEY:
388 case RIGHTMOUSE: {
390 ED_workspace_status_text(C, nullptr);
391
392 return OPERATOR_CANCELLED;
393 }
394 }
395
397}
398
400{
401 /* Identifiers. */
402 ot->name = "Sample Detail Size";
403 ot->idname = "SCULPT_OT_sample_detail_size";
404 ot->description = "Sample the mesh detail on clicked point";
405
406 /* API callbacks. */
411
413
414 PropertyRNA *prop;
415 prop = RNA_def_int_array(ot->srna,
416 "location",
417 2,
418 nullptr,
419 0,
420 SHRT_MAX,
421 "Location",
422 "Screen coordinates of sampling",
423 0,
424 SHRT_MAX);
426 prop = RNA_def_enum(ot->srna,
427 "mode",
430 "Detail Mode",
431 "Target sculpting workflow that is going to use the sampled size");
433}
434
437/* -------------------------------------------------------------------- */
441/* Defines how much the mouse movement will modify the detail size value. */
442#define DETAIL_SIZE_DELTA_SPEED 0.08f
443#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f
444
450
454
456
457 float init_mval[2];
459
460 float outline_col[4];
461
464
465 /* The values stored here vary based on the detailing mode. */
469
470 float radius;
471
474
477
478 float preview_tri[3][3];
479 float gizmo_mat[4][4];
480};
481
484 const float start_co[3],
485 const float end_co[3],
486 bool flip,
487 const float angle)
488{
489 float object_space_constant_detail;
490 if (cd->mode == DETAILING_MODE_RESOLUTION) {
491 object_space_constant_detail = detail_size::constant_to_detail_size(cd->current_value,
492 *cd->active_object);
493 }
494 else if (cd->mode == DETAILING_MODE_BRUSH_PERCENT) {
495 object_space_constant_detail = detail_size::brush_to_detail_size(cd->current_value,
496 cd->brush_radius);
497 }
498 else {
499 object_space_constant_detail = detail_size::relative_to_detail_size(
500 cd->current_value, cd->brush_radius, cd->pixel_radius, U.pixelsize);
501 }
502
503 /* The constant detail represents the maximum edge length allowed before subdividing it. If the
504 * triangle grid preview is created with this value it will represent an ideal mesh density where
505 * all edges have the exact maximum length, which never happens in practice. As the minimum edge
506 * length for dyntopo is 0.4 * max_edge_length, this adjust the detail size to the average
507 * between max and min edge length so the preview is more accurate. */
508 object_space_constant_detail *= 0.7f;
509
510 const float total_len = len_v3v3(cd->preview_tri[0], cd->preview_tri[1]);
511 const int tot_lines = int(total_len / object_space_constant_detail) + 1;
512 const float tot_lines_fl = total_len / object_space_constant_detail;
513 float spacing_disp[3];
514 sub_v3_v3v3(spacing_disp, end_co, start_co);
515 normalize_v3(spacing_disp);
516
517 float line_disp[3];
518 rotate_v2_v2fl(line_disp, spacing_disp, DEG2RAD(angle));
519 mul_v3_fl(spacing_disp, total_len / tot_lines_fl);
520
521 immBegin(GPU_PRIM_LINES, uint(tot_lines) * 2);
522 for (int i = 0; i < tot_lines; i++) {
523 float line_length;
524 if (flip) {
525 line_length = total_len * (float(i) / float(tot_lines_fl));
526 }
527 else {
528 line_length = total_len * (1.0f - (float(i) / float(tot_lines_fl)));
529 }
530 float line_start[3];
531 copy_v3_v3(line_start, start_co);
532 madd_v3_v3v3fl(line_start, line_start, spacing_disp, i);
533 float line_end[3];
534 madd_v3_v3v3fl(line_end, line_start, line_disp, line_length);
535 immVertex3fv(pos3d, line_start);
536 immVertex3fv(pos3d, line_end);
537 }
538 immEnd();
539}
540
541static void dyntopo_detail_size_edit_draw(const bContext * /*C*/, ARegion * /*region*/, void *arg)
542{
545 GPU_line_smooth(true);
546
551
552 /* Draw Cursor */
554 GPU_line_width(3.0f);
555
556 imm_draw_circle_wire_3d(pos3d, 0, 0, cd->radius, 80);
557
558 /* Draw Triangle. */
559 immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
561 immVertex3fv(pos3d, cd->preview_tri[0]);
562 immVertex3fv(pos3d, cd->preview_tri[1]);
563
564 immVertex3fv(pos3d, cd->preview_tri[1]);
565 immVertex3fv(pos3d, cd->preview_tri[2]);
566
567 immVertex3fv(pos3d, cd->preview_tri[2]);
568 immVertex3fv(pos3d, cd->preview_tri[0]);
569 immEnd();
570
571 /* Draw Grid */
572 GPU_line_width(1.0f);
574 pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], false, 60.0f);
576 pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], true, 120.0f);
578 pos3d, cd, cd->preview_tri[0], cd->preview_tri[2], false, -60.0f);
579
583 GPU_line_smooth(false);
584}
585
587{
588 Object *active_object = CTX_data_active_object(C);
589 SculptSession &ss = *active_object->sculpt;
590 ARegion *region = CTX_wm_region(C);
592 op->customdata);
593 ED_region_draw_cb_exit(region->type, cd->draw_handle);
594 ss.draw_faded_cursor = false;
596 ED_workspace_status_text(C, nullptr);
597
598 ScrArea *area = CTX_wm_area(C);
599 ED_area_status_text(area, nullptr);
600}
601
603{
604 /* TODO: Get range from RNA for these values? */
605 if (cd->mode == DETAILING_MODE_RESOLUTION) {
606 cd->min_value = 1.0f;
607 cd->max_value = 500.0f;
608 }
609 else if (cd->mode == DETAILING_MODE_BRUSH_PERCENT) {
610 cd->min_value = 0.5f;
611 cd->max_value = 100.0f;
612 }
613 else {
614 cd->min_value = 0.5f;
615 cd->max_value = 40.0f;
616 }
617}
618
621{
622 SculptSession &ss = *ob.sculpt;
623 BMVert *active_vertex = std::get<BMVert *>(ss.active_vert());
624
625 float len_accum = 0;
626 Vector<BMVert *, 64> neighbors;
627 for (BMVert *neighbor : vert_neighbors_get_bmesh(*active_vertex, neighbors)) {
628 len_accum += len_v3v3(active_vertex->co, neighbor->co);
629 }
630 const int num_neighbors = neighbors.size();
631
632 if (num_neighbors > 0) {
633 const float avg_edge_len = len_accum / num_neighbors;
634 /* Use 0.7 as the average of min and max dyntopo edge length. */
635 const float detail_size = 0.7f / (avg_edge_len *
636 mat4_to_scale(cd->active_object->object_to_world().ptr()));
637 float sampled_value;
638 if (cd->mode == DETAILING_MODE_RESOLUTION) {
639 sampled_value = detail_size;
640 }
641 else if (cd->mode == DETAILING_MODE_BRUSH_PERCENT) {
643 detail_size, cd->brush_radius, *cd->active_object);
644 }
645 else {
647 detail_size, cd->brush_radius, cd->pixel_radius, U.pixelsize, *cd->active_object);
648 }
649 cd->current_value = clamp_f(sampled_value, cd->min_value, cd->max_value);
650 }
651}
652
654 const wmEvent *event)
655{
656 const float mval[2] = {float(event->mval[0]), float(event->mval[1])};
657
658 float detail_size_delta;
659 float invert = cd->mode == DETAILING_MODE_RESOLUTION ? 1.0f : -1.0f;
660 if (cd->accurate_mode) {
661 detail_size_delta = mval[0] - cd->accurate_mval[0];
662 cd->current_value = cd->accurate_value +
663 detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED * invert;
664 }
665 else {
666 detail_size_delta = mval[0] - cd->init_mval[0];
667 cd->current_value = cd->init_value + detail_size_delta * DETAIL_SIZE_DELTA_SPEED * invert;
668 }
669
670 if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
671 cd->accurate_mode = true;
672 copy_v2_v2(cd->accurate_mval, mval);
674 }
675 if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
676 cd->accurate_mode = false;
677 cd->accurate_value = 0.0f;
678 }
679
681}
682
685{
686 Scene *scene = CTX_data_scene(C);
687
688 Sculpt *sd = scene->toolsettings->sculpt;
689 PointerRNA sculpt_ptr = RNA_pointer_create(&scene->id, &RNA_Sculpt, sd);
690
691 char msg[UI_MAX_DRAW_STR];
692 const char *format_string;
693 const char *property_name;
694 if (cd->mode == DETAILING_MODE_RESOLUTION) {
695 property_name = "constant_detail_resolution";
696 format_string = "%s: %0.4f";
697 }
698 else if (cd->mode == DETAILING_MODE_BRUSH_PERCENT) {
699 property_name = "detail_percent";
700 format_string = "%s: %3.1f%%";
701 }
702 else {
703 property_name = "detail_size";
704 format_string = "%s: %0.4f";
705 }
706 const PropertyRNA *prop = RNA_struct_find_property(&sculpt_ptr, property_name);
707 const char *ui_name = RNA_property_ui_name(prop);
708 SNPRINTF(msg, format_string, ui_name, cd->current_value);
709 ScrArea *area = CTX_wm_area(C);
710 ED_area_status_text(area, msg);
711
712 WorkspaceStatus status(C);
713 status.item(IFACE_("Confirm"), ICON_EVENT_RETURN, ICON_MOUSE_LMB);
714 status.item(IFACE_("Cancel"), ICON_EVENT_ESC, ICON_MOUSE_RMB);
715 status.item(IFACE_("Change Size"), ICON_MOUSE_MOVE);
716 status.item_bool(IFACE_("Sample Mode"), cd->sample_mode, ICON_EVENT_CTRL);
717 status.item_bool(IFACE_("Precision Mode"), cd->accurate_mode, ICON_EVENT_SHIFT);
718}
719
721{
722 Object &active_object = *CTX_data_active_object(C);
723 SculptSession &ss = *active_object.sculpt;
724 ARegion *region = CTX_wm_region(C);
726 op->customdata);
728
729 /* Cancel modal operator */
730 if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
731 (event->type == RIGHTMOUSE && event->val == KM_PRESS))
732 {
734 ED_region_tag_redraw(region);
735 return OPERATOR_FINISHED;
736 }
737
738 /* Finish modal operator */
739 if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
740 (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
741 (event->type == EVT_PADENTER && event->val == KM_PRESS))
742 {
743 ED_region_draw_cb_exit(region->type, cd->draw_handle);
744 if (cd->mode == DETAILING_MODE_RESOLUTION) {
746 }
747 else if (cd->mode == DETAILING_MODE_BRUSH_PERCENT) {
749 }
750 else {
751 sd->detail_size = cd->current_value;
752 }
753
754 ss.draw_faded_cursor = false;
756 ED_region_tag_redraw(region);
757 ED_workspace_status_text(C, nullptr);
758
759 ScrArea *area = CTX_wm_area(C);
760 ED_area_status_text(area, nullptr);
761 return OPERATOR_FINISHED;
762 }
763
764 ED_region_tag_redraw(region);
765
767 if (event->val == KM_PRESS) {
768 cd->sample_mode = true;
769 }
770 else if (event->val == KM_RELEASE) {
771 cd->sample_mode = false;
772 }
773 }
774
775 /* Sample mode sets the detail size sampling the average edge length under the surface. */
776 if (cd->sample_mode) {
780 }
781 /* Regular mode, changes the detail size by moving the cursor. */
784
786}
787
789{
790 if (mode == DETAILING_MODE_RESOLUTION) {
791 return sd->constant_detail;
792 }
793 else if (mode == DETAILING_MODE_BRUSH_PERCENT) {
794 return sd->detail_percent;
795 }
796 else {
797 return sd->detail_size;
798 }
799}
800
802{
803 const ToolSettings *tool_settings = CTX_data_tool_settings(C);
804 Sculpt *sd = tool_settings->sculpt;
805
806 ARegion *region = CTX_wm_region(C);
807 Object &active_object = *CTX_data_active_object(C);
808 Brush *brush = BKE_paint_brush(&sd->paint);
809
810 DyntopoDetailSizeEditCustomData *cd = MEM_cnew<DyntopoDetailSizeEditCustomData>(__func__);
811
812 /* Initial operator Custom Data setup. */
815 cd->active_object = &active_object;
816 cd->init_mval[0] = event->mval[0];
817 cd->init_mval[1] = event->mval[1];
820 }
821 else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
823 }
824 else {
826 }
827
828 const float initial_detail_size = dyntopo_detail_size_initial_value(sd, cd->mode);
829 cd->current_value = initial_detail_size;
830 cd->init_value = initial_detail_size;
831 copy_v4_v4(cd->outline_col, brush->add_col);
832 op->customdata = cd;
833
834 SculptSession &ss = *active_object.sculpt;
836 cd->radius = ss.cursor_radius;
837
840
841 const Scene *scene = CTX_data_scene(C);
842 cd->brush_radius = sculpt_calc_radius(vc, *brush, *scene, ss.cursor_location);
843 cd->pixel_radius = BKE_brush_size_get(scene, brush);
844
845 /* Generates the matrix to position the gizmo in the surface of the mesh using the same
846 * location and orientation as the brush cursor. */
847 float cursor_trans[4][4], cursor_rot[4][4];
848 const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
849 float quat[4];
850 copy_m4_m4(cursor_trans, active_object.object_to_world().ptr());
851 translate_m4(cursor_trans, ss.cursor_location[0], ss.cursor_location[1], ss.cursor_location[2]);
852
853 float cursor_normal[3];
855 copy_v3_v3(cursor_normal, ss.cursor_sampled_normal);
856 }
857 else {
858 copy_v3_v3(cursor_normal, ss.cursor_normal);
859 }
860
861 rotation_between_vecs_to_quat(quat, z_axis, cursor_normal);
862 quat_to_mat4(cursor_rot, quat);
863 copy_m4_m4(cd->gizmo_mat, cursor_trans);
864 mul_m4_m4_post(cd->gizmo_mat, cursor_rot);
865
866 /* Initialize the position of the triangle vertices. */
867 const float y_axis[3] = {0.0f, cd->radius, 0.0f};
868 for (int i = 0; i < 3; i++) {
869 zero_v3(cd->preview_tri[i]);
870 rotate_v2_v2fl(cd->preview_tri[i], y_axis, DEG2RAD(120.0f * i));
871 }
872
874
876 ED_region_tag_redraw(region);
877
878 ss.draw_faded_cursor = true;
879
880 const char *status_str = IFACE_(
881 "Move the mouse to change the dyntopo detail size. LMB: confirm size, ESC/RMB: cancel, "
882 "SHIFT: precision mode, CTRL: sample detail size");
883
884 ED_workspace_status_text(C, status_str);
886
888}
889
891{
892 /* identifiers */
893 ot->name = "Edit Dyntopo Detail Size";
894 ot->description = "Modify the detail size of dyntopo interactively";
895 ot->idname = "SCULPT_OT_dyntopo_detail_size_edit";
896
897 /* api callbacks */
902
904}
905
906} // namespace blender::ed::sculpt_paint::dyntopo
907
909
910float constant_to_detail_size(const float constant_detail, const Object &ob)
911{
912 return 1.0f / (constant_detail * mat4_to_scale(ob.object_to_world().ptr()));
913}
914
915float brush_to_detail_size(const float brush_percent, const float brush_radius)
916{
917 return brush_radius * brush_percent / 100.0f;
918}
919
920float relative_to_detail_size(const float relative_detail,
921 const float brush_radius,
922 const float pixel_radius,
923 const float pixel_size)
924{
925 return (brush_radius / pixel_radius) * (relative_detail * pixel_size) / RELATIVE_SCALE_FACTOR;
926}
927
928float constant_to_brush_detail(const float constant_detail,
929 const float brush_radius,
930 const Object &ob)
931{
932 const float object_scale = mat4_to_scale(ob.object_to_world().ptr());
933
934 return 100.0f / (constant_detail * brush_radius * object_scale);
935}
936
937float constant_to_relative_detail(const float constant_detail,
938 const float brush_radius,
939 const float pixel_radius,
940 const float pixel_size,
941 const Object &ob)
942{
943 const float object_scale = mat4_to_scale(ob.object_to_world().ptr());
944
945 return (pixel_radius / brush_radius) * (RELATIVE_SCALE_FACTOR / pixel_size) *
946 (1.0f / (constant_detail * object_scale));
947}
948
949} // namespace blender::ed::sculpt_paint::dyntopo::detail_size
950
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1075
bScreen * CTX_wm_screen(const bContext *C)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Base * CTX_data_active_base(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
bool BKE_base_is_visible(const View3D *v3d, const Base *base)
General operations, lookup, etc. for blender objects.
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2601
void BKE_sculptsession_free_pbvh(Object &object)
Definition paint.cc:2099
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
A BVH for high poly meshes.
void BKE_pbvh_node_mark_topology_update(blender::bke::pbvh::Node &node)
float BKE_pbvh_node_get_tmin(const blender::bke::pbvh::Node *node)
Definition pbvh.cc:766
@ PBVH_Collapse
@ PBVH_Subdivide
ARegion * BKE_area_find_region_xy(const ScrArea *area, int regiontype, const int xy[2]) ATTR_NONNULL(3)
Definition screen.cc:844
ScrArea ScrArea * BKE_screen_find_area_xy(const bScreen *screen, int spacetype, const int xy[2]) ATTR_NONNULL(1
MINLINE float clamp_f(float value, float min, float max)
void isect_ray_tri_watertight_v3_precalc(struct IsectRayPrecalc *isect_precalc, const float ray_direction[3])
float mat4_to_scale(const float mat[4][4])
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
void mul_m4_m4_post(float R[4][4], const float B[4][4])
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3])
#define DEG2RAD(_deg)
void quat_to_mat4(float m[4][4], const float q[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
void rotate_v2_v2fl(float r[2], const float p[2], float angle)
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE float normalize_v3(float n[3])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#define ELEM(...)
#define IFACE_(msgid)
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ SCULPT_DYNTOPO_DETAIL_MANUAL
@ SCULPT_DYNTOPO_DETAIL_CONSTANT
@ SCULPT_DYNTOPO_DETAIL_BRUSH
@ RGN_TYPE_WINDOW
@ SPACE_VIEW3D
@ OPERATOR_RUNNING_MODAL
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:803
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:966
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
#define REGION_DRAW_POST_VIEW
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
void immEnd()
void immUnbindProgram()
void immUniformColor4f(float r, float g, float b, float a)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void imm_draw_circle_wire_3d(uint pos, float x, float y, float radius, int nsegments)
void GPU_matrix_push()
#define GPU_matrix_mul(x)
void GPU_matrix_pop()
@ GPU_PRIM_LINES
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_line_width(float width)
Definition gpu_state.cc:161
void GPU_line_smooth(bool enable)
Definition gpu_state.cc:78
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
#define UI_MAX_DRAW_STR
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DRAW
Definition WM_types.hh:428
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#define NC_SCENE
Definition WM_types.hh:345
#define ND_TOOLSETTINGS
Definition WM_types.hh:416
#define NC_OBJECT
Definition WM_types.hh:346
unsigned int U
Definition btGjkEpa3.h:78
void item_bool(std::string text, bool inverted, int icon1, int icon2=0)
Definition area.cc:924
void item(std::string text, int icon1, int icon2=0)
Definition area.cc:908
int64_t size() const
Span< NodeT > nodes() const
void foreach_index(Fn &&fn) const
const Depsgraph * depsgraph
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_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition invert.h:9
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
bool raycast_node_detail_bmesh(BMeshNode &node, const float3 &ray_start, IsectRayPrecalc *isect_precalc, float *depth, float *r_edge_length)
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2612
Bounds< float3 > bounds_get(const Tree &pbvh)
Definition pbvh.cc:1480
bool bmesh_update_topology(BMesh &bm, Tree &pbvh, BMLog &bm_log, PBVHTopologyUpdateMode mode, float min_edge_len, float max_edge_len, const float center[3], const float view_normal[3], float radius, bool use_frontface, bool use_projected)
Span< float3 > vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2482
void raycast(Tree &pbvh, FunctionRef< void(Node &node, float *tmin)> cb, const float3 &ray_start, const float3 &ray_normal, bool original)
float relative_to_detail_size(const float relative_detail, const float brush_radius, const float pixel_radius, const float pixel_size)
float constant_to_detail_size(const float constant_detail, const Object &ob)
float constant_to_relative_detail(const float constant_detail, const float brush_radius, const float pixel_radius, const float pixel_size, const Object &ob)
float constant_to_brush_detail(const float constant_detail, const float brush_radius, const Object &ob)
float brush_to_detail_size(const float brush_percent, const float brush_radius)
void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
static EnumPropertyItem prop_sculpt_sample_detail_mode_types[]
static int sample_detail(bContext *C, const int event_xy[2], const SampleDetailModeType mode)
static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op)
static float dyntopo_detail_size_initial_value(const Sculpt *sd, const eDyntopoDetailingMode mode)
static void dyntopo_detail_size_update_header(bContext *C, const DyntopoDetailSizeEditCustomData *cd)
static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wmEvent *event)
static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *)
void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void sample_detail_dyntopo(bContext *C, ViewContext *vc, const int mval[2])
static void dyntopo_detail_size_parallel_lines_draw(uint pos3d, DyntopoDetailSizeEditCustomData *cd, const float start_co[3], const float end_co[3], bool flip, const float angle)
static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCustomData *cd, const wmEvent *event)
static void dyntopo_detail_size_sample_from_surface(Object &ob, DyntopoDetailSizeEditCustomData *cd)
static void dyntopo_detail_size_edit_draw(const bContext *, ARegion *, void *arg)
static bool sample_detail_voxel(bContext *C, ViewContext *vc, const int mval[2])
void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
static void dyntopo_detail_size_bounds(DyntopoDetailSizeEditCustomData *cd)
static void sculpt_raycast_detail_cb(bke::pbvh::BMeshNode &node, SculptDetailRaycastData &srd, float *tmin)
static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *op)
static bool sculpt_and_dynamic_topology_poll(bContext *C)
static bool sculpt_and_constant_or_manual_detail_poll(bContext *C)
void push_node(const Depsgraph &depsgraph, const Object &object, const bke::pbvh::Node *node, Type type)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
Span< BMVert * > vert_neighbors_get_bmesh(BMVert &vert, Vector< BMVert *, 64 > &r_neighbors)
Definition sculpt.cc:389
float sculpt_calc_radius(const ViewContext &vc, const Brush &brush, const Scene &scene, const float3 location)
Definition sculpt.cc:115
Span< int > vert_neighbors_get_mesh(const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face, const Span< bool > hide_poly, const int vert, Vector< int > &r_neighbors)
Definition sculpt.cc:431
T reduce_max(const VecBase< T, Size > &a)
T distance(const T &a, const T &b)
T midpoint(const T &a, const T &b)
void RNA_int_set_array(PointerRNA *ptr, const char *name, const int *values)
void RNA_int_get_array(PointerRNA *ptr, const char *name, int *values)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
const char * RNA_property_ui_name(const PropertyRNA *prop)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_int_array(StructOrFunctionRNA *cont_, const char *identifier, const int len, const int *default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
bool SCULPT_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, const float mval[2], bool use_sampled_normal)
Definition sculpt.cc:4580
void SCULPT_vertex_random_access_ensure(Object &object)
Definition sculpt.cc:144
void SCULPT_stroke_modifiers_check(const bContext *C, Object &ob, const Brush &brush)
Definition sculpt.cc:4358
float SCULPT_raycast_init(ViewContext *vc, const float mval[2], float ray_start[3], float ray_end[3], float ray_normal[3], bool original)
Definition sculpt.cc:4536
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3560
#define DETAIL_SIZE_DELTA_ACCURATE_SPEED
#define DETAIL_SIZE_DELTA_SPEED
float co[3]
float add_col[4]
struct SculptSession * sculpt
BMLog * bm_log
Definition BKE_paint.hh:402
blender::float3 cursor_normal
Definition BKE_paint.hh:441
bool draw_faded_cursor
Definition BKE_paint.hh:438
float cursor_radius
Definition BKE_paint.hh:439
ActiveVert active_vert() const
Definition paint.cc:2180
blender::float3 cursor_location
Definition BKE_paint.hh:440
blender::float3 cursor_sampled_normal
Definition BKE_paint.hh:442
float detail_percent
float detail_size
float constant_detail
Object * obact
Definition ED_view3d.hh:71
short val
Definition WM_types.hh:724
int xy[2]
Definition WM_types.hh:726
int mval[2]
Definition WM_types.hh:728
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct PointerRNA * ptr
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
@ WM_CURSOR_EYEDROPPER
Definition wm_cursors.hh:35
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ EVT_RIGHTCTRLKEY
@ EVT_LEFTCTRLKEY
@ EVT_PADENTER
@ LEFTMOUSE
@ EVT_ESCKEY
@ EVT_LEFTSHIFTKEY
@ EVT_RETKEY
wmOperatorType * ot
Definition wm_files.cc:4125