Sculpt Tiling Feature
authorAntony Riakiotakis <kalast@gmail.com>
Thu, 23 Jul 2015 20:52:03 +0000 (22:52 +0200)
committerAntony Riakiotakis <kalast@gmail.com>
Thu, 23 Jul 2015 20:52:27 +0000 (22:52 +0200)
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

release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/editors/sculpt_paint/sculpt.c
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_sculpt_paint.c

index e381800ae0224471455a47ee1773e81567b6ab96..2294e109f0c407dd5dc82a0846e8a983dbe8d2b4 100644 (file)
@@ -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"
index 37b37ed4cccb4c1369077781a28b49327db9890c..44de9e66d0c03c380ad8dba60358316987e97ee3 100644 (file)
@@ -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);
index a0b0cbea4c3fa57730b3100fe05ec121121d1b2c..fd6d39c9ce6333f13ed1a2d1efd532733effe494 100644 (file)
@@ -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)
index 7b30aa84cfba4ad50f05093901bce837fb44e7bb..3ec9944900ae489dc75e4e7f75ce125b4ad01493 100644 (file)
@@ -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)