Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorAntony Riakiotakis <kalast@gmail.com>2013-01-21 01:32:14 +0400
committerAntony Riakiotakis <kalast@gmail.com>2013-01-21 01:32:14 +0400
commite6f82619899af71b823e58812b231599d4dd46e2 (patch)
tree02410f8a066eed56cb5806f351b0e661358884ec /source
parent952c83cb621b97789ca5436390f28309c38ab0ff (diff)
3D mapping for projective texture painting (only for draw brush). Useful
to draw with procedural textures on surface of object. 2D painting will still paint as if tiled. When we unify the paint systems, the texture sampling functions will need to be changed. Sculpt uses a slightly different system that passes both screen and 3d coordinates to the sampling function. This commit however is not too disrupting for that however so it can go in now.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_brush.h3
-rw-r--r--source/blender/blenkernel/intern/brush.c55
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c45
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c9
-rw-r--r--source/blender/makesrna/intern/rna_brush.c1
5 files changed, 85 insertions, 28 deletions
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 248fe9c8968..b19a9c4d4eb 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -67,7 +67,8 @@ float BKE_brush_curve_strength_clamp(struct Brush *br, float p, const float len)
float BKE_brush_curve_strength(struct Brush *br, float p, const float len); /* used for sculpt */
/* sampling */
-void BKE_brush_sample_tex(const struct Scene *scene, struct Brush *brush, const float xy[2], float rgba[4], const int thread);
+void BKE_brush_sample_tex(const struct Scene *scene, struct Brush *brush, const float sampleco[3], float rgba[4], const int thread);
+void BKE_brush_sample_tex_2D(const struct Scene *scene, struct Brush *brush, const float xy[2], float rgba[4], const int thread);
void BKE_brush_imbuf_new(const struct Scene *scene, struct Brush *brush, short flt, short texfalloff, int size,
struct ImBuf **imbuf, int use_color_correction);
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index e8275471b09..bb4f073a3d7 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -471,8 +471,46 @@ int BKE_brush_clone_image_delete(Brush *brush)
return 0;
}
-/* Brush Sampling */
-void BKE_brush_sample_tex(const Scene *scene, Brush *brush, const float xy[2], float rgba[4], const int thread)
+/* Brush Sampling for 3d brushes. Currently used for texture painting only, but should be generalized */
+void BKE_brush_sample_tex(const Scene *scene, Brush *brush, const float sampleco[3], float rgba[4], const int thread)
+{
+ MTex *mtex = &brush->mtex;
+
+ if (mtex && mtex->tex) {
+ float co[3], tin, tr, tg, tb, ta;
+ int hasrgb;
+ const int radius = BKE_brush_size_get(scene, brush);
+
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) {
+ copy_v3_v3(co, sampleco);
+ } else {
+ co[0] = sampleco[0] / radius;
+ co[1] = sampleco[1] / radius;
+ co[2] = 0.0f;
+ }
+
+ hasrgb = externtex(mtex, co, &tin, &tr, &tg, &tb, &ta, thread);
+
+ if (hasrgb) {
+ rgba[0] = tr;
+ rgba[1] = tg;
+ rgba[2] = tb;
+ rgba[3] = ta;
+ }
+ else {
+ rgba[0] = tin;
+ rgba[1] = tin;
+ rgba[2] = tin;
+ rgba[3] = 1.0f;
+ }
+ }
+ else {
+ rgba[0] = rgba[1] = rgba[2] = rgba[3] = 1.0f;
+ }
+}
+
+/* Brush Sampling for 2D brushes. when we unify the brush systems this will be necessarily a separate function */
+void BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2], float rgba[4], const int thread)
{
MTex *mtex = &brush->mtex;
@@ -505,7 +543,8 @@ void BKE_brush_sample_tex(const Scene *scene, Brush *brush, const float xy[2], f
}
}
-/* TODO, use define for 'texfall' arg */
+/* TODO, use define for 'texfall' arg
+ * NOTE: only used for 2d brushes currently! */
void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf, int use_color_correction)
{
ImBuf *ibuf;
@@ -544,10 +583,10 @@ void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texf
dstf[3] = alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
}
else if (texfall == 1) {
- BKE_brush_sample_tex(scene, brush, xy, dstf, 0);
+ BKE_brush_sample_tex_2D(scene, brush, xy, dstf, 0);
}
else {
- BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
+ BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0);
mul_v3_v3v3(dstf, rgba, brush_rgb);
dstf[3] = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
}
@@ -574,11 +613,11 @@ void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texf
dst[3] = FTOCHAR(alpha_f);
}
else if (texfall == 1) {
- BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
+ BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0);
rgba_float_to_uchar(dst, rgba);
}
else if (texfall == 2) {
- BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
+ BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0);
mul_v3_v3(rgba, brush->rgb);
alpha_f = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
@@ -587,7 +626,7 @@ void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texf
dst[3] = FTOCHAR(alpha_f);
}
else {
- BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
+ BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0);
alpha_f = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
dst[0] = crgb[0];
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index b9e5a082ff8..40311658ed4 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -355,7 +355,7 @@ typedef union pixelStore {
typedef struct ProjPixel {
float projCoSS[2]; /* the floating point screen projection of this pixel */
-
+ float worldCoSS[3];
/* Only used when the airbrush is disabled.
* Store the max mask value to avoid painting over an area with a lower opacity
* with an advantage that we can avoid touching the pixel at all, if the
@@ -1526,6 +1526,11 @@ static int project_paint_pixel_sizeof(const short tool)
}
}
+static bool project_paint_supports_3d_mapping(Brush *brush)
+{
+ return (brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D) && (brush->imagepaint_tool == PAINT_TOOL_DRAW);
+}
+
/* run this function when we know a bucket's, face's pixel can be initialized,
* return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */
static ProjPixel *project_paint_uvpixel_init(
@@ -1537,6 +1542,7 @@ static ProjPixel *project_paint_uvpixel_init(
const int face_index,
const int image_index,
const float pixelScreenCo[4],
+ const float world_spaceCo[3],
const int side,
const float w[3])
{
@@ -1565,6 +1571,9 @@ static ProjPixel *project_paint_uvpixel_init(
}
/* screenspace unclamped, we could keep its z and w values but don't need them at the moment */
+ if(project_paint_supports_3d_mapping(ps->brush))
+ copy_v3_v3(projPixel->worldCoSS, world_spaceCo);
+
copy_v2_v2(projPixel->projCoSS, pixelScreenCo);
projPixel->x_px = x_px;
@@ -2374,6 +2383,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
float *uv1co, *uv2co, *uv3co; /* for convenience only, these will be assigned to tf->uv[0],1,2 or tf->uv[0],2,3 */
float pixelScreenCo[4];
+ bool do_3d_mapping = project_paint_supports_3d_mapping(ps->brush);
rcti bounds_px; /* ispace bounds */
/* vars for getting uvspace bounds */
@@ -2449,7 +2459,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
v1coSS = ps->screenCoords[(*(&mf->v1 + i1))];
v2coSS = ps->screenCoords[(*(&mf->v1 + i2))];
v3coSS = ps->screenCoords[(*(&mf->v1 + i3))];
-
+
/* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/
project_bucket_clip_face(
is_ortho, bucket_bounds,
@@ -2501,9 +2511,9 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
else screen_px_from_persp(uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w);
/* a pity we need to get the worldspace pixel location here */
- if (do_clip) {
+ if (do_clip || do_3d_mapping) {
interp_v3_v3v3v3(wco, ps->dm_mvert[(*(&mf->v1 + i1))].co, ps->dm_mvert[(*(&mf->v1 + i2))].co, ps->dm_mvert[(*(&mf->v1 + i3))].co, w);
- if (ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
+ if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
continue; /* Watch out that no code below this needs to run */
}
}
@@ -2520,9 +2530,10 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if (mask > 0.0f) {
BLI_linklist_prepend_arena(
bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, side, w),
- arena
- );
+ project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index,
+ image_index, pixelScreenCo, wco, side, w),
+ arena
+ );
}
}
@@ -2725,11 +2736,11 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
}
/* a pity we need to get the worldspace pixel location here */
- if (do_clip) {
+ if (do_clip || do_3d_mapping) {
if (side) interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v3].co, ps->dm_mvert[mf->v4].co, w);
else interp_v3_v3v3v3(wco, ps->dm_mvert[mf->v1].co, ps->dm_mvert[mf->v2].co, ps->dm_mvert[mf->v3].co, w);
- if (ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
+ if (do_clip && ED_view3d_clipping_test(ps->rv3d, wco, TRUE)) {
continue; /* Watch out that no code below this needs to run */
}
}
@@ -2739,7 +2750,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if (mask > 0.0f) {
BLI_linklist_prepend_arena(
bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, side, w),
+ project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, wco, side, w),
arena
);
}
@@ -4105,7 +4116,7 @@ static void *do_projectpaint_thread(void *ph_v)
/*if (dist < radius) {*/ /* correct but uses a sqrtf */
if (dist_nosqrt <= radius_squared) {
- float samplecos[2];
+ float samplecos[3];
dist = sqrtf(dist_nosqrt);
falloff = BKE_brush_curve_strength_clamp(ps->brush, dist, radius);
@@ -4114,9 +4125,11 @@ static void *do_projectpaint_thread(void *ph_v)
if (ps->brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
sub_v2_v2v2(samplecos, projPixel->projCoSS, pos);
}
- else {
- copy_v2_v2(samplecos, projPixel->projCoSS);
- }
+ /* taking 3d copy to account for 3D mapping too. It gets concatenated during sampling */
+ else if (project_paint_supports_3d_mapping(ps->brush))
+ copy_v3_v3(samplecos, projPixel->worldCoSS);
+ else
+ copy_v3_v3(samplecos, projPixel->projCoSS);
}
if (falloff > 0.0f) {
@@ -5008,7 +5021,9 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps)
ps->pixel_sizeof = project_paint_pixel_sizeof(ps->tool);
BLI_assert(ps->pixel_sizeof >= sizeof(ProjPixel));
- ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) ? false : true;
+ /* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
+ ps->do_masking = (brush->flag & BRUSH_AIRBRUSH || brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW ||
+ project_paint_supports_3d_mapping(brush)) ? false : true;
ps->is_texbrush = (brush->mtex.tex) ? 1 : 0;
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 9965727ed79..c8cd38045bd 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -205,7 +205,7 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
xy[0] = x + xoff;
xy[1] = y + yoff;
- BKE_brush_sample_tex(scene, brush, xy, tf, 0);
+ BKE_brush_sample_tex_2D(scene, brush, xy, tf, 0);
}
bf[0] = tf[0] * mf[0];
@@ -236,7 +236,7 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
xy[0] = x + xoff;
xy[1] = y + yoff;
- BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
+ BKE_brush_sample_tex_2D(scene, brush, xy, rgba, 0);
rgba_float_to_uchar(t, rgba);
}
@@ -314,6 +314,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2
short flt;
const int diameter = 2 * BKE_brush_size_get(scene, brush);
const float alpha = BKE_brush_alpha_get(scene, brush);
+ const bool do_tiled = ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_3D);
if (diameter != cache->lastsize ||
alpha != cache->lastalpha ||
@@ -331,7 +332,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2
flt = cache->flt;
size = (cache->size) ? cache->size : diameter;
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) {
+ if (do_tiled) {
BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction);
brush_painter_fixed_tex_partial_update(painter, pos);
}
@@ -342,7 +343,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2
cache->lastalpha = alpha;
cache->lastjitter = brush->jitter;
}
- else if ((brush->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) && mtex && mtex->tex) {
+ else if (do_tiled && mtex && mtex->tex) {
int dx = (int)painter->lastpaintpos[0] - (int)pos[0];
int dy = (int)painter->lastpaintpos[1] - (int)pos[1];
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index f17ee48a87c..4fb26f2b007 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -432,6 +432,7 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna)
static EnumPropertyItem prop_tex_paint_map_mode_items[] = {
{MTEX_MAP_MODE_VIEW, "VIEW_PLANE", 0, "View Plane", ""},
{MTEX_MAP_MODE_TILED, "TILED", 0, "Tiled", ""},
+ {MTEX_MAP_MODE_3D, "3D", 0, "3D", ""},
{0, NULL, 0, NULL, NULL}
};