== Sculpt Mode ==

* Added new brush, "Flatten". This brush pushes vertices along the normal defined by the average normal of each vertex within the brush area. The vertices are pushed towards the plane defined by vertices towards the edge of the brush. Essentially, this means that the direction of flattening is dependent on the surface beneath the brush.

* In order to make space for the flatten brush, the controls inside the Sculpt palette were widened to 268. (Note that the panel width didn't change, so it still fits properly in the vertical layout.)

* Todo: it would probably make sense to make the "View" slider available under the Brush tab available for the Flatten brush (currently it's only used for the Draw brush.)
This commit is contained in:
2007-03-14 20:00:01 +00:00
parent 26aa15969f
commit a567e43628
4 changed files with 140 additions and 60 deletions

View File

@@ -373,7 +373,7 @@ typedef struct SculptData
struct MTex *mtex[10]; struct MTex *mtex[10];
/* Settings for each brush */ /* Settings for each brush */
BrushData drawbrush, smoothbrush, pinchbrush, inflatebrush, grabbrush, layerbrush; BrushData drawbrush, smoothbrush, pinchbrush, inflatebrush, grabbrush, layerbrush, flattenbrush;
short brush_type; short brush_type;
/* For the Brush Shape */ /* For the Brush Shape */
@@ -605,6 +605,7 @@ typedef struct Scene {
#define INFLATE_BRUSH 4 #define INFLATE_BRUSH 4
#define GRAB_BRUSH 5 #define GRAB_BRUSH 5
#define LAYER_BRUSH 6 #define LAYER_BRUSH 6
#define FLATTEN_BRUSH 7
/* SculptData.texrept */ /* SculptData.texrept */
#define SCULPTREPT_DRAG 1 #define SCULPTREPT_DRAG 1
#define SCULPTREPT_TILE 2 #define SCULPTREPT_TILE 2

View File

@@ -4451,11 +4451,12 @@ void sculptmode_draw_interface_tools(uiBlock *block, unsigned short cx, unsigned
uiBlockBeginAlign(block); uiBlockBeginAlign(block);
uiDefButS(block,ROW,REDRAWBUTSEDIT,"Draw",cx,cy,67,19,&sd->brush_type,14.0,DRAW_BRUSH,0,0,"Draw lines on the model"); uiDefButS(block,ROW,REDRAWBUTSEDIT,"Draw",cx,cy,67,19,&sd->brush_type,14.0,DRAW_BRUSH,0,0,"Draw lines on the model");
uiDefButS(block,ROW,REDRAWBUTSEDIT,"Smooth",cx+67,cy,67,19,&sd->brush_type,14.0,SMOOTH_BRUSH,0,0,"Interactively smooth areas of the model"); uiDefButS(block,ROW,REDRAWBUTSEDIT,"Smooth",cx+67,cy,67,19,&sd->brush_type,14.0,SMOOTH_BRUSH,0,0,"Interactively smooth areas of the model");
uiDefButS(block,ROW,REDRAWBUTSEDIT,"Pinch",cx+134,cy,66,19,&sd->brush_type,14.0,PINCH_BRUSH,0,0,"Interactively pinch areas of the model"); uiDefButS(block,ROW,REDRAWBUTSEDIT,"Pinch",cx+134,cy,67,19,&sd->brush_type,14.0,PINCH_BRUSH,0,0,"Interactively pinch areas of the model");
uiDefButS(block,ROW,REDRAWBUTSEDIT,"Inflate",cx+201,cy,67,19,&sd->brush_type,14,INFLATE_BRUSH,0,0,"Push vertices along the direction of their normals");
cy-= 20; cy-= 20;
uiDefButS(block,ROW,REDRAWBUTSEDIT,"Inflate",cx,cy,67,19,&sd->brush_type,14,INFLATE_BRUSH,0,0,"Push vertices along the direction of their normals"); uiDefButS(block,ROW,REDRAWBUTSEDIT,"Grab", cx,cy,89,19,&sd->brush_type,14,GRAB_BRUSH,0,0,"Grabs a group of vertices and moves them with the mouse");
uiDefButS(block,ROW,REDRAWBUTSEDIT,"Grab", cx+67,cy,67,19,&sd->brush_type,14,GRAB_BRUSH,0,0,"Grabs a group of vertices and moves them with the mouse"); uiDefButS(block,ROW,REDRAWBUTSEDIT,"Layer", cx+89,cy,89,19,&sd->brush_type,14, LAYER_BRUSH,0,0,"Adds a layer of depth");
uiDefButS(block,ROW,REDRAWBUTSEDIT,"Layer", cx+134,cy,66,19,&sd->brush_type,14, LAYER_BRUSH,0,0,"Adds a layer of depth"); uiDefButS(block,ROW,REDRAWBUTSEDIT,"Flatten", cx+178,cy,90,19,&sd->brush_type,14, FLATTEN_BRUSH,0,0,"Interactively flatten areas of the model");
cy-= 25; cy-= 25;
uiBlockEndAlign(block); uiBlockEndAlign(block);
@@ -4463,17 +4464,17 @@ void sculptmode_draw_interface_tools(uiBlock *block, unsigned short cx, unsigned
uiDefBut(block,LABEL,B_NOP,"Shape",cx,cy,90,19,NULL,0,0,0,0,""); uiDefBut(block,LABEL,B_NOP,"Shape",cx,cy,90,19,NULL,0,0,0,0,"");
cy-= 20; cy-= 20;
uiBlockBeginAlign(block); uiBlockBeginAlign(block);
if(sd->brush_type!=SMOOTH_BRUSH && sd->brush_type!=GRAB_BRUSH) { if(sd->brush_type != SMOOTH_BRUSH && sd->brush_type != GRAB_BRUSH && sd->brush_type != FLATTEN_BRUSH) {
uiDefButC(block,ROW,B_NOP,"Add",cx,cy,67,19,&sculptmode_brush()->dir,15.0,1.0,0, 0,"Add depth to model [Shift]"); uiDefButC(block,ROW,B_NOP,"Add",cx,cy,89,19,&sculptmode_brush()->dir,15.0,1.0,0, 0,"Add depth to model [Shift]");
uiDefButC(block,ROW,B_NOP,"Sub",cx+67,cy,67,19,&sculptmode_brush()->dir,15.0,2.0,0, 0,"Subtract depth from model [Shift]"); uiDefButC(block,ROW,B_NOP,"Sub",cx+89,cy,89,19,&sculptmode_brush()->dir,15.0,2.0,0, 0,"Subtract depth from model [Shift]");
} }
if(sd->brush_type!=GRAB_BRUSH) if(sd->brush_type!=GRAB_BRUSH)
uiDefButC(block,TOG,B_NOP,"Airbrush",cx+134,cy,66,19,&sculptmode_brush()->airbrush,0,0,0,0,"Brush makes changes without waiting for the mouse to move"); uiDefButC(block,TOG,B_NOP,"Airbrush",cx+178,cy,89,19,&sculptmode_brush()->airbrush,0,0,0,0,"Brush makes changes without waiting for the mouse to move");
cy-= 20; cy-= 20;
but= uiDefButS(block,NUMSLI,B_NOP,"Size: ",cx,cy,200,19,&sculptmode_brush()->size,1.0,200.0,0,0,"Set brush radius in pixels"); but= uiDefButS(block,NUMSLI,B_NOP,"Size: ",cx,cy,268,19,&sculptmode_brush()->size,1.0,200.0,0,0,"Set brush radius in pixels");
cy-= 20; cy-= 20;
if(sd->brush_type!=GRAB_BRUSH) if(sd->brush_type!=GRAB_BRUSH)
uiDefButC(block,NUMSLI,B_NOP,"Strength: ",cx,cy,200,19,&sculptmode_brush()->strength,1.0,100.0,0,0,"Set brush strength"); uiDefButC(block,NUMSLI,B_NOP,"Strength: ",cx,cy,268,19,&sculptmode_brush()->strength,1.0,100.0,0,0,"Set brush strength");
cy-= 25; cy-= 25;
uiBlockEndAlign(block); uiBlockEndAlign(block);
@@ -4481,9 +4482,9 @@ void sculptmode_draw_interface_tools(uiBlock *block, unsigned short cx, unsigned
uiDefBut( block,LABEL,B_NOP,"Symmetry",cx,cy,90,19,NULL,0,0,0,0,""); uiDefBut( block,LABEL,B_NOP,"Symmetry",cx,cy,90,19,NULL,0,0,0,0,"");
cy-= 20; cy-= 20;
uiBlockBeginAlign(block); uiBlockBeginAlign(block);
uiDefButBitC(block, TOG, SYMM_X, 0, "X", cx,cy,67,19, &sd->symm, 0,0,0,0, "Mirror brush across X axis"); uiDefButBitC(block, TOG, SYMM_X, 0, "X", cx,cy,89,19, &sd->symm, 0,0,0,0, "Mirror brush across X axis");
uiDefButBitC(block, TOG, SYMM_Y, 0, "Y", cx+67,cy,67,19, &sd->symm, 0,0,0,0, "Mirror brush across Y axis"); uiDefButBitC(block, TOG, SYMM_Y, 0, "Y", cx+89,cy,89,19, &sd->symm, 0,0,0,0, "Mirror brush across Y axis");
uiDefButBitC(block, TOG, SYMM_Z, 0, "Z", cx+134,cy,67,19, &sd->symm, 0,0,0,0, "Mirror brush across Z axis"); uiDefButBitC(block, TOG, SYMM_Z, 0, "Z", cx+178,cy,90,19, &sd->symm, 0,0,0,0, "Mirror brush across Z axis");
uiBlockEndAlign(block); uiBlockEndAlign(block);
cx+= 210; cx+= 210;

View File

@@ -4117,10 +4117,9 @@ void do_view3d_sculptmenu(void *arg, int event)
case 3: case 3:
case 4: case 4:
case 5: case 5:
case 6:
sd->brush_type= event+1; sd->brush_type= event+1;
break; break;
case 6:
br->dir= br->dir==1 ? 2 : 1; break;
case 7: case 7:
br->airbrush= !br->airbrush; break; br->airbrush= !br->airbrush; break;
case 8: case 8:
@@ -4151,6 +4150,8 @@ void do_view3d_sculptmenu(void *arg, int event)
case 17: case 17:
sculptmode_propset_init(PropsetSize); sculptmode_propset_init(PropsetSize);
break; break;
case 18:
br->dir= br->dir==1 ? 2 : 1; break;
} }
allqueue(REDRAWBUTSEDIT, 0); allqueue(REDRAWBUTSEDIT, 0);
@@ -4208,11 +4209,12 @@ uiBlock *view3d_sculptmenu(void *arg_unused)
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, (br->airbrush ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Airbrush|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, ""); uiDefIconTextBut(block, BUTM, 1, (br->airbrush ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Airbrush|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
if(sd->brush_type!=SMOOTH_BRUSH) { if(sd->brush_type!=SMOOTH_BRUSH && sd->brush_type!=FLATTEN_BRUSH) {
uiDefIconTextBut(block, BUTM, 1, (br->dir==1 ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Add|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, ""); uiDefIconTextBut(block, BUTM, 1, (br->dir==1 ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Add|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
} }
} }
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==FLATTEN_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Flatten", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==LAYER_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Layer|L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, ""); uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==LAYER_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Layer|L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==GRAB_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Grab|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, ""); uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==GRAB_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Grab|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==INFLATE_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Inflate|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, ""); uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==INFLATE_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Inflate|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");

View File

@@ -115,6 +115,7 @@ typedef struct ActiveData {
struct ActiveData *next, *prev; struct ActiveData *next, *prev;
unsigned int Index; unsigned int Index;
float Fade; float Fade;
float dist;
} ActiveData; } ActiveData;
typedef struct GrabData { typedef struct GrabData {
@@ -195,10 +196,17 @@ void sculptmode_init(Scene *sce)
memset(sd, 0, sizeof(SculptData)); memset(sd, 0, sizeof(SculptData));
sd->drawbrush.size=sd->smoothbrush.size=sd->pinchbrush.size=sd->inflatebrush.size=sd->grabbrush.size=sd->layerbrush.size= 50; sd->drawbrush.size = sd->smoothbrush.size = sd->pinchbrush.size =
sd->drawbrush.strength=sd->smoothbrush.strength=sd->pinchbrush.strength=sd->inflatebrush.strength=sd->grabbrush.strength=sd->layerbrush.strength= 25; sd->inflatebrush.size = sd->grabbrush.size =
sd->drawbrush.dir=sd->pinchbrush.dir=sd->inflatebrush.dir=sd->layerbrush.dir= 1; sd->layerbrush.size = sd->flattenbrush.size = 50;
sd->drawbrush.airbrush=sd->smoothbrush.airbrush=sd->pinchbrush.airbrush=sd->inflatebrush.airbrush=sd->layerbrush.airbrush= 0; sd->drawbrush.strength = sd->smoothbrush.strength =
sd->pinchbrush.strength = sd->inflatebrush.strength =
sd->grabbrush.strength = sd->layerbrush.strength =
sd->flattenbrush.strength = 25;
sd->drawbrush.dir = sd->pinchbrush.dir = sd->inflatebrush.dir = sd->layerbrush.dir= 1;
sd->drawbrush.airbrush = sd->smoothbrush.airbrush =
sd->pinchbrush.airbrush = sd->inflatebrush.airbrush =
sd->layerbrush.airbrush = sd->flattenbrush.airbrush = 0;
sd->drawbrush.view= 0; sd->drawbrush.view= 0;
sd->brush_type= DRAW_BRUSH; sd->brush_type= DRAW_BRUSH;
sd->texact= -1; sd->texact= -1;
@@ -430,6 +438,8 @@ float brush_strength(EditData *e)
return 1; return 1;
case INFLATE_BRUSH: case INFLATE_BRUSH:
return b->strength / 5000.0f * dir * pressure * flip; return b->strength / 5000.0f * dir * pressure * flip;
case FLATTEN_BRUSH:
return b->strength / 500.0f * pressure;
default: default:
return 0; return 0;
} }
@@ -647,6 +657,62 @@ void do_inflate_brush(const EditData *e, const ListBase *active_verts)
} }
} }
void calc_flatten_center(Mesh *me, ActiveData *node, const EditData *e, float co[3])
{
const int FTOT = 10;
ActiveData *outer[FTOT];
int i;
for(i = 0; i < FTOT; ++i)
outer[i] = node;
for(; node; node = node->next) {
for(i = 0; i < FTOT; ++i) {
if(node->dist > outer[i]->dist) {
outer[i] = node;
break;
}
}
}
co[0] = co[1] = co[2] = 0.0f;
for(i = 0; i < FTOT; ++i)
VecAddf(co, co, me->mvert[outer[i]->Index].co);
VecMulf(co, 1.0f / FTOT);
}
void do_flatten_brush(const EditData *e, const ListBase *active_verts)
{
Mesh *me= get_mesh(OBACT);
ActiveData *node= active_verts->first;
/* area_normal and cntr define the plane towards which vertices are squashed */
vec3f area_normal= calc_area_normal(&e->out, active_verts);
float cntr[3];
calc_flatten_center(me, node, e, cntr);
while(node){
float *co= me->mvert[node->Index].co;
float p1[3], sub1[3], sub2[3], intr[3], val[3];
/* Find the intersection between squash-plane and vertex (along the area normal) */
VecSubf(p1, co, &area_normal.x);
VecSubf(sub1, cntr, p1);
VecSubf(sub2, co, p1);
VecSubf(intr, co, p1);
VecMulf(intr, Inpf(&area_normal.x, sub1) / Inpf(&area_normal.x, sub2));
VecAddf(intr, intr, p1);
VecSubf(val, intr, co);
VecMulf(val, node->Fade);
VecAddf(val, val, co);
sculpt_clip(e, co, val);
node= node->next;
}
}
/* Creates a smooth curve for the brush shape. This is the cos(x) curve from /* Creates a smooth curve for the brush shape. This is the cos(x) curve from
[0,PI] scaled to [0,len]. The range is scaled to [0,1]. */ [0,PI] scaled to [0,len]. The range is scaled to [0,1]. */
float simple_strength(float p, const float len) float simple_strength(float p, const float len)
@@ -857,6 +923,7 @@ void do_brush_action(float *vertexcosnos, EditData e,
/* Fade is used to store the final strength at which the brush /* Fade is used to store the final strength at which the brush
should modify a particular vertex. */ should modify a particular vertex. */
adata->Fade= tex_strength(&e,vert,av_dist,i) * bstrength; adata->Fade= tex_strength(&e,vert,av_dist,i) * bstrength;
adata->dist = av_dist;
if(e.grabdata && e.grabdata->firsttime) if(e.grabdata && e.grabdata->firsttime)
BLI_addtail(&e.grabdata->active_verts[e.grabdata->index], adata); BLI_addtail(&e.grabdata->active_verts[e.grabdata->index], adata);
else else
@@ -866,44 +933,50 @@ void do_brush_action(float *vertexcosnos, EditData e,
} }
} }
/* Apply one type of brush action */ /* Only act if some verts are inside the brush area */
switch(G.scene->sculptdata.brush_type){ if(active_verts.first || (e.grabdata && e.grabdata->active_verts[e.grabdata->index].first)) {
case DRAW_BRUSH: /* Apply one type of brush action */
do_draw_brush(&e, &active_verts); switch(G.scene->sculptdata.brush_type){
break; case DRAW_BRUSH:
case SMOOTH_BRUSH: do_draw_brush(&e, &active_verts);
do_smooth_brush(&e, &active_verts); break;
break; case SMOOTH_BRUSH:
case PINCH_BRUSH: do_smooth_brush(&e, &active_verts);
do_pinch_brush(&e, &active_verts); break;
break; case PINCH_BRUSH:
case INFLATE_BRUSH: do_pinch_brush(&e, &active_verts);
do_inflate_brush(&e, &active_verts); break;
break; case INFLATE_BRUSH:
case GRAB_BRUSH: do_inflate_brush(&e, &active_verts);
do_grab_brush(&e); break;
break; case GRAB_BRUSH:
case LAYER_BRUSH: do_grab_brush(&e);
do_layer_brush(&e, &active_verts); break;
break; case LAYER_BRUSH:
} do_layer_brush(&e, &active_verts);
break;
/* Copy the modified vertices from mesh to the active key */ case FLATTEN_BRUSH:
if(keyblock) { do_flatten_brush(&e, &active_verts);
float *co= keyblock->data; break;
if(co) { }
adata = e.grabdata ? e.grabdata->active_verts[e.grabdata->index].first : active_verts.first;
for(; adata; adata= adata->next) /* Copy the modified vertices from mesh to the active key */
if(adata->Index < keyblock->totelem) if(keyblock) {
VecCopyf(&co[adata->Index*3], me->mvert[adata->Index].co); float *co= keyblock->data;
if(co) {
adata = e.grabdata ? e.grabdata->active_verts[e.grabdata->index].first : active_verts.first;
for(; adata; adata= adata->next)
if(adata->Index < keyblock->totelem)
VecCopyf(&co[adata->Index*3], me->mvert[adata->Index].co);
}
} }
}
if(vertexcosnos) if(vertexcosnos)
BLI_freelistN(&active_verts); BLI_freelistN(&active_verts);
else { else {
if(!e.grabdata) if(!e.grabdata)
addlisttolist(damaged_verts, &active_verts); addlisttolist(damaged_verts, &active_verts);
}
} }
} }
@@ -1014,7 +1087,8 @@ BrushData *sculptmode_brush(void)
sd->brush_type==PINCH_BRUSH ? &sd->pinchbrush : sd->brush_type==PINCH_BRUSH ? &sd->pinchbrush :
sd->brush_type==INFLATE_BRUSH ? &sd->inflatebrush : sd->brush_type==INFLATE_BRUSH ? &sd->inflatebrush :
sd->brush_type==GRAB_BRUSH ? &sd->grabbrush : sd->brush_type==GRAB_BRUSH ? &sd->grabbrush :
sd->brush_type==LAYER_BRUSH ? &sd->layerbrush : NULL); sd->brush_type==LAYER_BRUSH ? &sd->layerbrush :
sd->brush_type==FLATTEN_BRUSH ? &sd->flattenbrush : NULL);
} }
void sculptmode_update_tex() void sculptmode_update_tex()
@@ -1399,7 +1473,7 @@ void sculptmode_selectbrush_menu(void)
pupmenu_set_active(sd->brush_type); pupmenu_set_active(sd->brush_type);
val= pupmenu("Select Brush%t|Draw|Smooth|Pinch|Inflate|Grab|Layer"); val= pupmenu("Select Brush%t|Draw|Smooth|Pinch|Inflate|Grab|Layer|Flatten");
if(val>0) { if(val>0) {
sd->brush_type= val; sd->brush_type= val;
@@ -1730,6 +1804,8 @@ void sculpt(void)
BIF_undo_push("Grab Brush"); break; BIF_undo_push("Grab Brush"); break;
case LAYER_BRUSH: case LAYER_BRUSH:
BIF_undo_push("Layer Brush"); break; BIF_undo_push("Layer Brush"); break;
case FLATTEN_BRUSH:
BIF_undo_push("Flatten Brush"); break;
default: default:
BIF_undo_push("Sculpting"); break; BIF_undo_push("Sculpting"); break;
} }