Sort-of-fix for bug #5382, sculpt - image/texture brush heavily distorted when not sculpting flat relative to screen

Fix for bug #5248, sculpt - mirrored tiled texture odd results

Changed the algorithm used for projecting the brush texture onto the model. The old algorithm was never implemented properly, causing increasingly
wonky distortions of the brush as it got farther away from parallel to the screen. The new system uses the screen coords of vertices, the obvious
advantage being that 2D screen coords can be mapped quite easily to 2D texture coords. The main disadvantage of this method is that there are still
distortions in the brush as the surface beneath it becomes less parallel the screen. These distortions, however, are not as bad as the old ones
because they are predictable from the user's perspective. (It's analogous to a movie being projected onto a sphere; if the viewer is in front of the
sphere there is no apparent distortion, but from the side the movie appears stretched and distorted.)

This may still be worth revisiting after the release.
This commit is contained in:
Nicholas Bishop 2006-12-29 08:40:19 +00:00
parent efce404ddd
commit d9e0e883f2
5 changed files with 82 additions and 109 deletions

View File

@ -403,10 +403,6 @@ typedef struct SculptData
BrushData drawbrush, smoothbrush, pinchbrush, inflatebrush, grabbrush, layerbrush;
short brush_type;
/* Symmetry is separate from the other BrushData because the same
settings are always used for all brush types */
short symm_x, symm_y, symm_z;
/* For the Brush Shape */
short texscale;
short texact, texnr;
@ -419,7 +415,11 @@ typedef struct SculptData
char draw_mode;
/* Control tablet input */
char tablet_size, tablet_strength, pad[2];
char tablet_size, tablet_strength;
/* Symmetry is separate from the other BrushData because the same
settings are always used for all brush types */
char symm, pad[7];
} SculptData;
#define SCULPTREPT_DRAG 1
@ -633,6 +633,10 @@ typedef struct Scene {
#define GRAB_BRUSH 5
#define LAYER_BRUSH 6
#define SYMM_X 1
#define SYMM_Y 2
#define SYMM_Z 4
/* toolsettings->imagepaint_flag */
#define IMAGEPAINT_DRAWING 1
#define IMAGEPAINT_DRAW_TOOL 2

View File

@ -4261,9 +4261,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,"");
cy-= 20;
uiBlockBeginAlign(block);
uiDefButS(block,TOG,B_NOP,"X",cx,cy,67,19,&sd->symm_x,0,0,0,0,"Mirror brush across X axis");
uiDefButS(block,TOG,B_NOP,"Y",cx+67,cy,67,19,&sd->symm_y,0,0,0,0,"Mirror brush across Y axis");
uiDefButS(block,TOG,B_NOP,"Z",cx+134,cy,66,19,&sd->symm_z,0,0,0,0,"Mirror brush across Z axis");
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_Y, 0, "Y", cx+67,cy,67,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");
uiBlockEndAlign(block);

View File

@ -4087,11 +4087,11 @@ void do_view3d_sculptmenu(void *arg, int event)
case 8:
br->airbrush= !br->airbrush; break;
case 9:
sd->symm_x= !sd->symm_x; break;
sd->symm ^= SYMM_X; break;
case 10:
sd->symm_y= !sd->symm_y; break;
sd->symm ^= SYMM_Y; break;
case 11:
sd->symm_z= !sd->symm_z; break;
sd->symm ^= SYMM_Z; break;
case 12:
if(G.vd)
G.vd->pivot_last= !G.vd->pivot_last;
@ -4166,9 +4166,9 @@ uiBlock *view3d_sculptmenu(void *arg_unused)
if(G.vd)
uiDefIconTextBut(block, BUTM, 1, (G.vd->pivot_last ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Pivot last", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, (sd->symm_z ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Symmetry Z|Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
uiDefIconTextBut(block, BUTM, 1, (sd->symm_y ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Symmetry Y|Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
uiDefIconTextBut(block, BUTM, 1, (sd->symm_x ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Symmetry X|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
uiDefIconTextBut(block, BUTM, 1, (sd->symm & SYMM_Z ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Symmetry Z|Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
uiDefIconTextBut(block, BUTM, 1, (sd->symm & SYMM_Y ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Symmetry Y|Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
uiDefIconTextBut(block, BUTM, 1, (sd->symm & SYMM_X ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Symmetry X|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
if(sd->brush_type!=GRAB_BRUSH)
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, 8, "");

View File

@ -145,6 +145,8 @@ typedef struct EditData {
char clip[3];
float cliptol[3];
char symm;
} EditData;
typedef struct RectNode {
@ -996,6 +998,16 @@ float simple_strength(float p, const float len)
return 0.5f * (cos(M_PI*p/len) + 1);
}
void flip_coord(float co[3], const char symm)
{
if(symm & SYMM_X)
co[0]= -co[0];
if(symm & SYMM_Y)
co[1]= -co[1];
if(symm & SYMM_Z)
co[2]= -co[2];
}
float tex_strength(EditData *e, float *point, const float len,const unsigned vindex)
{
SculptData *sd= sculpt_data();
@ -1019,63 +1031,35 @@ float tex_strength(EditData *e, float *point, const float len,const unsigned vin
externtex(&mtex,point,&avg,&jnk,&jnk,&jnk,&jnk);
} else {
vec3f t2;
float theta, magn;
float cx;
const short bsize= sculptmode_brush()->size * 2;
const short half= sculptmode_brush()->size;
int px, py;
unsigned i;
unsigned int *p;
unsigned i, *p;
RenderInfo *ri= ss->texrndr;
/* If no texture or Default, use smooth curve */
if(sd->texact == -1 || !sd->mtex[sd->texact] ||
!sd->mtex[sd->texact]->tex->type)
return simple_strength(len,e->size);
/* Find direction from center to point */
VecSubf(&t2.x,point,&e->center.x);
Normalise(&t2.x);
theta= e->right.x*t2.x+e->right.y*t2.y+e->right.z*t2.z;
/* Avoid NaN errors */
if( theta < -1 )
theta = -1;
else if( theta > 1 )
theta = 1;
theta = acos( theta );
/* Checks whether theta should be in the III/IV quadrants using the
dot product with the Up vector */
if(e->up.x*t2.x+e->up.y*t2.y+e->up.z*t2.z > 0)
theta = 2 * M_PI - theta;
magn= len/e->size;
/* XXX: This code assumes that the texture can be treated as a square */
/* Find alpha's center, we assume a square */
cx= ri->pr_rectx/2.0f;
/* Scale the magnitude to match the size of the tex */
magn*= cx;
/* XXX: not sure if this +c business is correct....
Find the pixel in the tex */
px= magn * cos(theta) + cx;
py= magn * sin(theta) + cx;
ProjVert pv;
if(!e->symm)
pv= projverts[vindex];
else {
float co[3];
VecCopyf(co, point);
flip_coord(co, e->symm);
project(co, pv.co);
}
if(sd->texrept==SCULPTREPT_TILE) {
const float scale= sd->texscale;
px+= e->mouse[0];
py+= e->mouse[1];
px= (pv.co[0] + half) * (ri->pr_rectx*1.0f/bsize);
py= (pv.co[1] + half) * (ri->pr_recty*1.0f/bsize);
px%= (int)scale;
py%= (int)scale;
p= ri->rect + (int)(ri->pr_recty*py/scale) * ri->pr_rectx + (int)(ri->pr_rectx*px/scale);
} else {
px= (pv.co[0] - e->mouse[0] + half) * (ri->pr_rectx*1.0f/bsize);
py= (pv.co[1] - e->mouse[1] + half) * (ri->pr_recty*1.0f/bsize);
p= ri->rect + py * ri->pr_rectx + px;
}
else p= ri->rect + py * ri->pr_rectx + px;
for(i=0; i<3; ++i)
avg+= ((unsigned char*)(p))[i] / 255.0f;
@ -1180,39 +1164,24 @@ void do_brush_action(float *vertexcosnos, EditData e,
}
}
EditData flip_editdata(EditData *e, short x, short y, short z)
EditData flip_editdata(EditData *e, const char symm)
{
EditData fe= *e;
GrabData *gd= fe.grabdata;
if(x) {
fe.center.x= -fe.center.x;
fe.up.x= -fe.up.x;
fe.right.x= -fe.right.x;
fe.out.x= -fe.out.x;
}
flip_coord(&fe.center.x, symm);
flip_coord(&fe.up.x, symm);
flip_coord(&fe.right.x, symm);
flip_coord(&fe.out.x, symm);
fe.symm= symm;
if(y) {
fe.center.y= -fe.center.y;
fe.up.y= -fe.up.y;
fe.right.y= -fe.right.y;
fe.out.y= -fe.out.y;
}
if(z) {
fe.center.z= -fe.center.z;
fe.up.z= -fe.up.z;
fe.right.z= -fe.right.z;
fe.out.z= -fe.out.z;
}
project(&fe.center.x,fe.mouse);
project(&e->center.x,fe.mouse);
if(gd) {
gd->index= x + y*2 + z*4;
gd->index= symm;
gd->delta_symm= gd->delta;
if(x) gd->delta_symm.x= -gd->delta_symm.x;
if(y) gd->delta_symm.y= -gd->delta_symm.y;
if(z) gd->delta_symm.z= -gd->delta_symm.z;
flip_coord(&gd->delta_symm.x, symm);
}
return fe;
@ -1221,24 +1190,24 @@ EditData flip_editdata(EditData *e, short x, short y, short z)
void do_symmetrical_brush_actions(float *vertexcosnos, EditData *e,
ListBase *damaged_verts, ListBase *damaged_rects)
{
const SculptData *sd= &G.scene->sculptdata;
do_brush_action(vertexcosnos,flip_editdata(e,0,0,0),damaged_verts,damaged_rects);
if(sd->symm_x)
do_brush_action(vertexcosnos,flip_editdata(e,1,0,0),damaged_verts,damaged_rects);
if(sd->symm_y)
do_brush_action(vertexcosnos,flip_editdata(e,0,1,0),damaged_verts,damaged_rects);
if(sd->symm_z)
do_brush_action(vertexcosnos,flip_editdata(e,0,0,1),damaged_verts,damaged_rects);
if(sd->symm_x && sd->symm_y)
do_brush_action(vertexcosnos,flip_editdata(e,1,1,0),damaged_verts,damaged_rects);
if(sd->symm_x && sd->symm_z)
do_brush_action(vertexcosnos,flip_editdata(e,1,0,1),damaged_verts,damaged_rects);
if(sd->symm_y && sd->symm_z)
do_brush_action(vertexcosnos,flip_editdata(e,0,1,1),damaged_verts,damaged_rects);
if(sd->symm_x && sd->symm_y && sd->symm_z)
do_brush_action(vertexcosnos,flip_editdata(e,1,1,1),damaged_verts,damaged_rects);
const char symm= sculpt_data()->symm;
do_brush_action(vertexcosnos, flip_editdata(e, 0), damaged_verts, damaged_rects);
if(symm & SYMM_X)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_X), damaged_verts, damaged_rects);
if(symm & SYMM_Y)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_Y), damaged_verts, damaged_rects);
if(symm & SYMM_Z)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_Z), damaged_verts, damaged_rects);
if(symm & SYMM_X && symm & SYMM_Y)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_X | SYMM_Y), damaged_verts, damaged_rects);
if(symm & SYMM_X && symm & SYMM_Z)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_X | SYMM_Z), damaged_verts, damaged_rects);
if(symm & SYMM_Y && symm & SYMM_Z)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_Y | SYMM_Z), damaged_verts, damaged_rects);
if(symm & SYMM_X && symm & SYMM_Y && symm & SYMM_Z)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_X | SYMM_Y | SYMM_Z), damaged_verts, damaged_rects);
}
void add_face_normal(vec3f *norm, const MFace* face)

View File

@ -1287,13 +1287,13 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
update_prop= 1; break;
/* Symmetry */
case XKEY:
sd->symm_x= !sd->symm_x;
sd->symm^= SYMM_X;
update_prop= 1; break;
case YKEY:
sd->symm_y= !sd->symm_y;
sd->symm^= SYMM_Y;
update_prop= 1; break;
case ZKEY:
sd->symm_z= !sd->symm_z;
sd->symm^= SYMM_Z;
update_prop= 1; break;
/* Interface */
case NKEY: