forked from bartvdbraak/blender
Sculpt Tiling Feature
Adds 3D-Tiling options to the sculpt tool. This is very similar to the symmetry options in the sense that it replicates the strokes. For tiling this replication happens with a linear offset to fill the whole object along one or more axis. This allows to create geometry that can be tiled seamless. One use case is the creation of tileable textures by sculpting high resolution geometry and then rendering it with an orthographic camera to create maps for diffuse, normal, etc Notes: Patch by Tilman Blumhagen with minor changes (move tile flags to paint symmetry flags). After some feedback from artists, leaving tiling value to constant offset, though I suspect that some method that uses the object bounding box dynamically might be good to have too. It can be added later though :) Thanks a lot for the patch! Patch: D1426
This commit is contained in:
parent
36630b7e85
commit
0c0db92d7a
@ -1553,6 +1553,15 @@ class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
|
||||
row.prop(sculpt, "lock_z", text="Z", toggle=True)
|
||||
|
||||
|
||||
layout.label(text="Tiling:")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(sculpt, "tile_x", text="X", toggle=True)
|
||||
row.prop(sculpt, "tile_y", text="Y", toggle=True)
|
||||
row.prop(sculpt, "tile_z", text="Z", toggle=True)
|
||||
|
||||
layout.column().prop(sculpt, "tile_offset", text="Tile Offset")
|
||||
|
||||
class VIEW3D_PT_tools_brush_appearance(Panel, View3DPaintPanel):
|
||||
bl_category = "Options"
|
||||
bl_label = "Appearance"
|
||||
|
@ -3454,6 +3454,46 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
|
||||
|
||||
typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups);
|
||||
|
||||
static void do_tiled(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups, BrushActionFunc action)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
StrokeCache *cache = ss->cache;
|
||||
const float * bbMin = ob->bb->vec[0];
|
||||
const float * bbMax = ob->bb->vec[6];
|
||||
|
||||
float start[3];
|
||||
float end[3];
|
||||
const float * step = sd->paint.tile_offset;
|
||||
int dim;
|
||||
|
||||
for (dim = 0; dim < 3; ++dim) {
|
||||
if ((sd->paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
|
||||
int n = (cache->location[dim] - bbMin[dim]) / step[dim];
|
||||
start[dim] = cache->location[dim] - n * step[dim];
|
||||
end[dim] = bbMax[dim];
|
||||
}
|
||||
else
|
||||
start[dim] = end[dim] = cache->location[dim];
|
||||
}
|
||||
|
||||
copy_v3_v3(cache->location, start);
|
||||
do {
|
||||
do {
|
||||
do {
|
||||
action(sd, ob, brush, ups);
|
||||
cache->location[2] += step[2];
|
||||
} while (cache->location[2] < end[2]);
|
||||
cache->location[2] = start[2];
|
||||
|
||||
cache->location[1] += step[1];
|
||||
} while (cache->location[1] < end[1]);
|
||||
cache->location[1] = start[1];
|
||||
|
||||
cache->location[0] += step[0];
|
||||
} while (cache->location[0] < end[0]);
|
||||
}
|
||||
|
||||
|
||||
static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups,
|
||||
BrushActionFunc action,
|
||||
const char symm, const int axis,
|
||||
@ -3466,7 +3506,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush, UnifiedPain
|
||||
const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
|
||||
ss->cache->radial_symmetry_pass = i;
|
||||
calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather);
|
||||
action(sd, ob, brush, ups);
|
||||
do_tiled(sd, ob, brush, ups, action);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3504,7 +3544,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
|
||||
cache->radial_symmetry_pass = 0;
|
||||
|
||||
calc_brushdata_symm(sd, cache, i, 0, 0, feather);
|
||||
action(sd, ob, brush, ups);
|
||||
do_tiled(sd, ob, brush, ups, action);
|
||||
|
||||
do_radial_symmetry(sd, ob, brush, ups, action, i, 'X', feather);
|
||||
do_radial_symmetry(sd, ob, brush, ups, action, i, 'Y', feather);
|
||||
@ -5053,6 +5093,12 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
|
||||
if (ts->sculpt->constant_detail == 0.0f)
|
||||
ts->sculpt->constant_detail = 30.0f;
|
||||
|
||||
/* Set sane default tiling offsets */
|
||||
if (!ts->sculpt->paint.tile_offset[0]) ts->sculpt->paint.tile_offset[0] = 1.0f;
|
||||
if (!ts->sculpt->paint.tile_offset[1]) ts->sculpt->paint.tile_offset[1] = 1.0f;
|
||||
if (!ts->sculpt->paint.tile_offset[2]) ts->sculpt->paint.tile_offset[2] = 1.0f;
|
||||
|
||||
|
||||
/* Create sculpt mode session data */
|
||||
if (ob->sculpt)
|
||||
BKE_sculptsession_free(ob);
|
||||
|
@ -941,6 +941,9 @@ typedef struct Paint {
|
||||
|
||||
/* flags used for symmetry */
|
||||
int symmetry_flags;
|
||||
|
||||
float tile_offset[3];
|
||||
int pad2;
|
||||
} Paint;
|
||||
|
||||
/* ------------------------------------------- */
|
||||
@ -1029,7 +1032,6 @@ typedef struct Sculpt {
|
||||
float pad;
|
||||
|
||||
struct Object *gravity_object;
|
||||
void *pad2;
|
||||
} Sculpt;
|
||||
|
||||
typedef struct UvSculpt {
|
||||
@ -1817,7 +1819,10 @@ typedef enum SymmetryFlags {
|
||||
PAINT_SYMM_X = (1 << 0),
|
||||
PAINT_SYMM_Y = (1 << 1),
|
||||
PAINT_SYMM_Z = (1 << 2),
|
||||
PAINT_SYMMETRY_FEATHER = (1 << 3)
|
||||
PAINT_SYMMETRY_FEATHER = (1 << 3),
|
||||
PAINT_TILE_X = (1 << 4),
|
||||
PAINT_TILE_Y = (1 << 5),
|
||||
PAINT_TILE_Z = (1 << 6),
|
||||
} SymmetryFlags;
|
||||
|
||||
#define PAINT_SYMM_AXIS_ALL (PAINT_SYMM_X | PAINT_SYMM_Y | PAINT_SYMM_Z)
|
||||
|
@ -443,6 +443,28 @@ static void rna_def_paint(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Cavity Mask", "Mask painting according to mesh geometry cavity");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "tile_offset", PROP_FLOAT, PROP_XYZ);
|
||||
RNA_def_property_float_sdna(prop, NULL, "tile_offset");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_range(prop, 0.01, FLT_MAX);
|
||||
RNA_def_property_ui_range(prop, 0.01, 100, 1 * 100, 2);
|
||||
RNA_def_property_ui_text(prop, "Tiling offset for the X Axis",
|
||||
"Stride at which tiled strokes are copied");
|
||||
|
||||
prop = RNA_def_property(srna, "tile_x", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "symmetry_flags", PAINT_TILE_X);
|
||||
RNA_def_property_ui_text(prop, "Tile X", "Tile along X axis");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "tile_y", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "symmetry_flags", PAINT_TILE_Y);
|
||||
RNA_def_property_ui_text(prop, "Tile Y", "Tile along Y axis");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "tile_z", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "symmetry_flags", PAINT_TILE_Z);
|
||||
RNA_def_property_ui_text(prop, "Tile Z", "Tile along Z axis");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_sculpt(BlenderRNA *brna)
|
||||
|
Loading…
Reference in New Issue
Block a user