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.
This commit is contained in:
Antony Riakiotakis 2014-03-22 23:35:07 +02:00
parent c45c472e1b
commit e732c5809c
7 changed files with 200 additions and 14 deletions

View File

@ -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")

View File

@ -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],

View File

@ -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)
{

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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);