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:
authorAntony Riakiotakis <kalast@gmail.com>2014-03-23 01:35:07 +0400
committerAntony Riakiotakis <kalast@gmail.com>2014-03-23 01:35:41 +0400
commite732c5809c2be01a0c622987bf9fbe7b37d3ed4c (patch)
tree0f6717db6a0da358500ade55715034a584f20f9c
parentc45c472e1b373c5125955056bcf3dd9b5edb8d18 (diff)
Detail sampling operator
Located on topology panel. To use just click on button and click on mesh. Operator will just use the dimensions of the triangles below to set the constant detail setting. Also changed pair of scale/detail size with nice separate float percentage value.
-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);