Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py5
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h3
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c44
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c147
-rw-r--r--source/blender/makesdna/DNA_scene_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c10
7 files changed, 200 insertions, 14 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 4dc44342fbe..b67c8effa3f 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -1240,9 +1240,7 @@ class VIEW3D_PT_sculpt_topology(Panel, View3DPaintPanel):
sub = col.column(align=True)
sub.active = brush and brush.sculpt_tool not in ('MASK')
if (sculpt.detail_type_method == 'CONSTANT'):
- row = sub.row(align=True)
- row.prop(sculpt, "detail_size")
- row.prop(sculpt, "constant_detail_scale")
+ sub.prop(sculpt, "constant_detail")
else:
sub.prop(sculpt, "detail_size")
sub.prop(sculpt, "detail_refine_method", text="")
@@ -1251,6 +1249,7 @@ class VIEW3D_PT_sculpt_topology(Panel, View3DPaintPanel):
col.prop(sculpt, "use_smooth_shading")
col.operator("sculpt.optimize")
if (sculpt.detail_type_method == 'CONSTANT'):
+ col.operator("sculpt.sample_detail_size")
col.operator("sculpt.detail_flood_fill")
col.separator()
col.prop(sculpt, "symmetrize_direction")
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 0828ea54280..3601ff1ce04 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -98,6 +98,9 @@ int BKE_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], int use
const float ray_start[3], const float ray_normal[3],
float *dist);
+int BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node, const float ray_start[3],
+ const float ray_normal[3], float *detail, float *dist);
+
/* for orthographic cameras, project the far away ray segment points to the root node so
* we can have better precision. */
void BKE_pbvh_raycast_project_ray_root(PBVH *bvh, bool original, float ray_start[3],
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 3fae446f1f4..808b3faad9b 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1035,6 +1035,50 @@ int pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3],
return hit;
}
+int BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node, const float ray_start[3],
+ const float ray_normal[3], float *detail, float *dist)
+{
+ GHashIterator gh_iter;
+ int hit = 0;
+ BMFace *f_hit = NULL;
+
+ if (node->flag & PBVH_FullyHidden)
+ return 0;
+
+ GHASH_ITER (gh_iter, node->bm_faces) {
+ BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+
+ BLI_assert(f->len == 3);
+ if (f->len == 3 && !paint_is_bmesh_face_hidden(f)) {
+ BMVert *v_tri[3];
+ int hit_local;
+ BM_face_as_array_vert_tri(f, v_tri);
+ hit_local = ray_face_intersection(ray_start, ray_normal,
+ v_tri[0]->co,
+ v_tri[1]->co,
+ v_tri[2]->co,
+ NULL, dist);
+ if (hit_local) {
+ f_hit = f;
+ }
+ hit |= hit_local;
+ }
+ }
+
+ if (hit) {
+ float len1, len2, len3;
+ BMVert *v_tri[3];
+ BM_face_as_array_vert_tri(f_hit, v_tri);
+ len1 = len_v3v3(v_tri[0]->co, v_tri[1]->co);
+ len2 = len_v3v3(v_tri[1]->co, v_tri[2]->co);
+ len3 = len_v3v3(v_tri[2]->co, v_tri[0]->co);
+
+ *detail = (len1 + len2 + len3)/3.0f;
+ }
+
+ return hit;
+}
+
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
{
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index d4cd6bcf9d8..75d2a8333a1 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -185,6 +185,9 @@ int pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3],
const float ray_normal[3], float *dist,
int use_original);
+int pbvh_bmesh_node_raycast_detail(PBVHNode *node, const float ray_start[3],
+ const float ray_normal[3], float *detail, float *dist);
+
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c6f8007d57e..9ef5852555f 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -4261,6 +4261,13 @@ typedef struct {
int original;
} SculptRaycastData;
+typedef struct {
+ float *ray_start, *ray_normal;
+ int hit;
+ float dist;
+ float detail;
+} SculptDetailRaycastData;
+
static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
{
if (BKE_pbvh_node_get_tmin(node) < *tmin) {
@@ -4289,6 +4296,18 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
}
}
+static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
+{
+ if (BKE_pbvh_node_get_tmin(node) < *tmin) {
+ SculptDetailRaycastData *srd = data_v;
+ if (BKE_pbvh_bmesh_node_raycast_detail(node, srd->ray_start, srd->ray_normal,
+ &srd->detail, &srd->dist)) {
+ srd->hit = 1;
+ *tmin = srd->dist;
+ }
+ }
+}
+
/* Do a raycast in the tree to find the 3d brush location
* (This allows us to ignore the GL depth buffer)
* Returns 0 if the ray doesn't hit the mesh, non-zero otherwise
@@ -4511,7 +4530,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
- sd->constant_detail_scale * (float)sd->detail_size / 100.0f);
+ sd->constant_detail / 100.0f);
}
else {
BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
@@ -5169,8 +5188,8 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
ts->sculpt->detail_size = 30;
}
- if (ts->sculpt->constant_detail_scale == 0.0)
- ts->sculpt->constant_detail_scale = 1.0f;
+ if (ts->sculpt->constant_detail == 0.0f)
+ ts->sculpt->constant_detail = 30.0f;
/* Create sculpt mode session data */
if (ob->sculpt)
@@ -5244,7 +5263,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
/* update topology size */
BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
- sd->constant_detail_scale * (float)sd->detail_size / 100.0f);
+ sd->constant_detail/ 100.0f);
sculpt_undo_push_begin("Dynamic topology flood fill");
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
@@ -5268,7 +5287,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
static void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Flood Fill";
+ ot->name = "Detail Flood Fill";
ot->idname = "SCULPT_OT_detail_flood_fill";
ot->description = "Flood fill the mesh with the selected detail setting";
@@ -5279,6 +5298,123 @@ static void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static void sample_detail(bContext *C, int ss_co[2])
+{
+ ViewContext vc;
+ Object *ob;
+ Sculpt *sd;
+ float ray_start[3], ray_end[3], ray_normal[3], dist;
+ float obimat[4][4];
+ SculptDetailRaycastData srd;
+ RegionView3D *rv3d;
+ float mouse[2] = {ss_co[0], ss_co[1]};
+ view3d_set_viewcontext(C, &vc);
+
+ rv3d = vc.ar->regiondata;
+ ob = vc.obact;
+
+ sd = CTX_data_tool_settings(C)->sculpt;
+
+ sculpt_stroke_modifiers_check(C, ob);
+
+ /* TODO: what if the segment is totally clipped? (return == 0) */
+ ED_view3d_win_to_segment(vc.ar, vc.v3d, mouse, ray_start, ray_end, true);
+
+ invert_m4_m4(obimat, ob->obmat);
+ mul_m4_v3(obimat, ray_start);
+ mul_m4_v3(obimat, ray_end);
+
+ sub_v3_v3v3(ray_normal, ray_end, ray_start);
+ dist = normalize_v3(ray_normal);
+
+ if (!rv3d->is_persp) {
+ BKE_pbvh_raycast_project_ray_root(ob->sculpt->pbvh, false, ray_start, ray_end, ray_normal);
+
+ /* recalculate the normal */
+ sub_v3_v3v3(ray_normal, ray_end, ray_start);
+ dist = normalize_v3(ray_normal);
+ }
+
+ srd.hit = 0;
+ srd.ray_start = ray_start;
+ srd.ray_normal = ray_normal;
+ srd.dist = dist;
+ srd.detail = sd->constant_detail;
+
+ BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd,
+ ray_start, ray_normal, false);
+
+ if (srd.hit)
+ {
+ sd->constant_detail = srd.detail * 100.0f;
+ }
+}
+
+static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
+{
+ int ss_co[2];
+ RNA_int_get_array(op->ptr, "location", ss_co);
+ sample_detail(C, ss_co);
+ return OPERATOR_FINISHED;
+}
+
+
+static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e)) {
+ ScrArea *sa = CTX_wm_area(C);
+ ED_area_headerprint(sa, "Click on the mesh to set the detail");
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wmEvent *e) {
+
+ switch (e->type) {
+ case LEFTMOUSE:
+ if (e->val == KM_PRESS) {
+ ScrArea *sa = CTX_wm_area(C);
+ int ss_co[2] = {e->mval[0], e->mval[1]};
+
+ sample_detail(C, ss_co);
+
+ RNA_int_set_array(op->ptr, "location", ss_co);
+ ED_area_headerprint(sa, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ return OPERATOR_FINISHED;
+ }
+ break;
+
+ case RIGHTMOUSE:
+ {
+ ScrArea *sa = CTX_wm_area(C);
+ ED_area_headerprint(sa, NULL);
+ return OPERATOR_CANCELLED;
+ break;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+
+static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sample Detail Size";
+ ot->idname = "SCULPT_OT_sample_detail_size";
+ ot->description = "Sample the mesh detail on clicked point";
+
+ /* api callbacks */
+ ot->invoke = sculpt_sample_detail_size_invoke;
+ ot->exec = sculpt_sample_detail_size_exec;
+ ot->modal = sculpt_sample_detail_size_modal;
+ ot->poll = sculpt_and_dynamic_topology_constant_detail_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX, "Location", "Screen Coordinates of sampling", 0, SHRT_MAX);
+}
+
void ED_operatortypes_sculpt(void)
{
WM_operatortype_append(SCULPT_OT_brush_stroke);
@@ -5288,4 +5424,5 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_optimize);
WM_operatortype_append(SCULPT_OT_symmetrize);
WM_operatortype_append(SCULPT_OT_detail_flood_fill);
+ WM_operatortype_append(SCULPT_OT_sample_detail_size);
}
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 02b213a1b68..b9621b4753c 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -857,7 +857,7 @@ typedef struct Sculpt {
float gravity_factor;
/* scale for constant detail size */
- float constant_detail_scale;
+ float constant_detail;
struct Object *gravity_object;
void *pad2;
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 77cad9affb7..55301198031 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -414,15 +414,15 @@ static void rna_def_sculpt(BlenderRNA *brna)
"Show diffuse color of object and overlay sculpt mask on top of it");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_ShowDiffuseColor_update");
- prop = RNA_def_property(srna, "detail_size", PROP_INT, PROP_NONE);
+ prop = RNA_def_property(srna, "detail_size", PROP_INT, PROP_PIXEL);
RNA_def_property_ui_range(prop, 2, 100, 0, -1);
- RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting");
+ RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (in pixels)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
- prop = RNA_def_property(srna, "constant_detail_scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.001, 100.0);
+ prop = RNA_def_property(srna, "constant_detail", PROP_FLOAT, PROP_PERCENTAGE);
+ RNA_def_property_range(prop, 0.001, 10000.0);
RNA_def_property_ui_range(prop, 0.1, 100.0, 10, 2);
- RNA_def_property_ui_text(prop, "Scale", "Multiplier for constant detail size");
+ RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (as percentage of blender unit)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "use_smooth_shading", PROP_BOOLEAN, PROP_NONE);