Vector displacement for the sculpting draw brush #104481

Merged
Jeroen Bakker merged 18 commits from robin.hohni/blender:sculpt-vector-displacement into main 2023-02-14 15:29:40 +01:00
15 changed files with 297 additions and 150 deletions
Showing only changes of commit ce08bff6f0 - Show all commits

View File

@ -1141,6 +1141,13 @@ def brush_texture_settings(layout, brush, sculpt):
# texture_sample_bias
layout.prop(brush, "texture_sample_bias", slider=True, text="Sample Bias")
# use_rgb_as_vector_displacement (Only working for draw brush for now)
if brush.sculpt_tool == 'DRAW':
col = layout.column()
col.active = tex_slot.map_mode == 'AREA_PLANE'
col.prop(brush, "use_rgb_as_vector_displacement", text="RGB as Vector Displacement")
Jeroen-Bakker marked this conversation as resolved
Review

Python has some rules about the number of lines between statements. Here it is max 1.

Python has some rules about the number of lines between statements. Here it is max 1.
def brush_mask_texture_settings(layout, brush):
mask_tex_slot = brush.mask_texture_slot

View File

@ -203,7 +203,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
if (col) {
float rgba[4];
paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace);
paint_get_tex_pixel_srgb_with_clamp(mtex, x, y, rgba, thread_id, pool, convert_to_linear, colorspace);
buffer[index * 4] = rgba[0] * 255;
buffer[index * 4 + 1] = rgba[1] * 255;
@ -211,7 +211,9 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
buffer[index * 4 + 3] = rgba[3] * 255;
}
else {
float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id);
float avg;
float rgba_dummy[4];
paint_get_tex_pixel(mtex, x, y, thread_id, pool, &avg, rgba_dummy);
avg += br->texture_sample_bias;

View File

@ -352,14 +352,14 @@ void paint_calc_redraw_planes(float planes[4][4],
float paint_calc_object_space_radius(struct ViewContext *vc,
const float center[3],
float pixel_radius);
float paint_get_tex_pixel(
const struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread);
void paint_get_tex_pixel_col(const struct MTex *mtex,
bool paint_get_tex_pixel(
const struct MTex *mtex, float u, float v, int thread, struct ImagePool *pool, float *r_intensity, float r_rgba[4]);
void paint_get_tex_pixel_srgb_with_clamp(const struct MTex *mtex,
float u,
float v,
float rgba[4],
struct ImagePool *pool,
int thread,
struct ImagePool *pool,
bool convert,
struct ColorSpace *colorspace);

View File

@ -146,32 +146,45 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3], flo
return len_v3(delta) / scale;
}
float paint_get_tex_pixel(const MTex *mtex, float u, float v, struct ImagePool *pool, int thread)
bool paint_get_tex_pixel(const MTex *mtex,
float u,
float v,
int thread,
struct ImagePool *pool,
/* Return arguments. */
float *r_intensity,
float r_rgba[4])
{
float intensity;
float rgba_dummy[4];
const float co[3] = {u, v, 0.0f};
float intensity;
const bool hasRGB = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, r_rgba);
*r_intensity = intensity;
RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba_dummy);
if (!hasRGB) {
r_rgba[0] = intensity;
r_rgba[1] = intensity;
r_rgba[2] = intensity;
r_rgba[3] = 1.0f;
}
return intensity;
return hasRGB;
}
void paint_get_tex_pixel_col(const MTex *mtex,
void paint_get_tex_pixel_srgb_with_clamp(const MTex *mtex,
float u,
float v,
float rgba[4],
struct ImagePool *pool,
int thread,
struct ImagePool *pool,
bool convert_to_linear,
struct ColorSpace *colorspace)
{
const float co[3] = {u, v, 0.0f};
float intensity;
const bool hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
const bool hasRGB = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
if (!hasrgb) {
if (!hasRGB) {
rgba[0] = intensity;
rgba[1] = intensity;
rgba[2] = intensity;

View File

@ -74,6 +74,8 @@
#include "RNA_define.h"
#include "bmesh.h"
#include "IMB_imbuf_types.h"
#include "RE_texture.h"
using blender::float3;
using blender::MutableSpan;
@ -2555,20 +2557,21 @@ static float brush_strength(const Sculpt *sd,
}
}
float SCULPT_brush_strength_factor(SculptSession *ss,
const Brush *br,
const float brush_point[3],
float len,
const float vno[3],
const float fno[3],
float mask,
const PBVHVertRef vertex,
const int thread_id,
AutomaskingNodeData *automask_data)
float SCULPT_brush_factor_with_color(SculptSession *ss,
const Brush *brush,
const float brush_point[3],
float len,
const float vno[3],
const float fno[3],
float mask,
const PBVHVertRef vertex,
int thread_id,
AutomaskingNodeData *automask_data,
float r_rgb[3])
{
StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene;
const MTex *mtex = BKE_brush_mask_texture_get(br, OB_MODE_SCULPT);
const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
float avg = 1.0f;
float rgba[4];
float point[3];
@ -2576,16 +2579,16 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
sub_v3_v3v3(point, brush_point, cache->plane_offset);
if (!mtex->tex) {
avg = 1.0f;
rgba[0] = 1.0f;
rgba[1] = 1.0f;
rgba[2] = 1.0f;
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
/* Get strength by feeding the vertex location directly into a texture. */
avg = BKE_brush_sample_tex_3d(scene, br, mtex, point, rgba, 0, ss->tex_pool);
avg = BKE_brush_sample_tex_3d(scene, brush, mtex, point, rgba, thread_id, ss->tex_pool);
}
else {
float symm_point[3], point_2d[2];
/* Quite warnings. */
float x = 0.0f, y = 0.0f;
float symm_point[3];
/* If the active area is being applied for symmetry, flip it
* across the symmetry axis and rotate it back to the original
@ -2596,8 +2599,6 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
}
flip_v3_v3(symm_point, point, cache->mirror_symmetry_pass);
ED_view3d_project_float_v2_m4(cache->vc->region, symm_point, point_2d, cache->projection_mat);
/* Still no symmetry supported for other paint modes.
* Sculpt does it DIY. */
if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
@ -2606,22 +2607,25 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
mul_m4_v3(cache->brush_local_mat, symm_point);
x = symm_point[0];
y = symm_point[1];
float x = symm_point[0];
float y = symm_point[1];
x *= mtex->size[0];
y *= mtex->size[1];
x *= brush->mtex.size[0];
y *= brush->mtex.size[1];
x += mtex->ofs[0];
y += mtex->ofs[1];
x += brush->mtex.ofs[0];
y += brush->mtex.ofs[1];
avg = paint_get_tex_pixel(mtex, x, y, ss->tex_pool, thread_id);
paint_get_tex_pixel(&brush->mtex, x, y, thread_id, ss->tex_pool, &avg, rgba);
avg += br->texture_sample_bias;
add_v3_fl(rgba, brush->texture_sample_bias); // v3 -> Ignore alpha
avg -= brush->texture_sample_bias;
}
else {
float point_2d[2];
ED_view3d_project_float_v2_m4(cache->vc->region, symm_point, point_2d, cache->projection_mat);
const float point_3d[3] = {point_2d[0], point_2d[1], 0.0f};
avg = BKE_brush_sample_tex_3d(scene, br, mtex, point_3d, rgba, 0, ss->tex_pool);
avg = BKE_brush_sample_tex_3d(scene, brush, mtex, point_3d, rgba, thread_id, ss->tex_pool);
}
}
@ -2641,18 +2645,39 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
}
/* Falloff curve. */
avg *= BKE_brush_curve_strength(br, final_len, cache->radius);
avg *= frontface(br, cache->view_normal, vno, fno);
const float falloff = BKE_brush_curve_strength(brush, final_len, cache->radius)
* frontface(brush, cache->view_normal, vno, fno);
/* Paint mask. */
avg *= 1.0f - mask;
const float paint_mask = 1.0f - mask;
/* Auto-masking. */
avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex, automask_data);
const float automasking_factor = SCULPT_automasking_factor_get(cache->automasking, ss, vertex, automask_data);
/* Apply masks */
const float masks_combined = falloff * paint_mask * automasking_factor;
mul_v3_fl(rgba, masks_combined);
avg *= masks_combined;
/* Copy rgba for vector displacement */
copy_v3_v3(r_rgb, rgba);
return avg;
}
void SCULPT_calc_vertex_displacement(SculptSession *ss, float rgb[3], float out_offset[3])
{
rgb[2] *= ss->cache->bstrength;
float mat[4][4];
invert_m4_m4(mat, ss->cache->brush_local_mat);
mul_mat3_m4_v3(mat, rgb);
if (ss->cache->radial_symmetry_pass) {
mul_m4_v3(ss->cache->symm_rot_mat, rgb); // TODO: Not working yet
}
flip_v3_v3(out_offset, rgb, ss->cache->mirror_symmetry_pass);
}
bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
{
SculptSearchSphereData *data = static_cast<SculptSearchSphereData *>(data_v);
@ -3236,7 +3261,9 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
const float fade = SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -3245,7 +3272,8 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
nullptr);
nullptr,
rgb);
mul_v3_v3fl(proxy[vd.i], offset, fade);

View File

@ -266,18 +266,26 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
/* Offset vertex. */
const float fade = SCULPT_brush_strength_factor(ss,
brush,
vd.co,
sqrtf(test.dist),
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
float rgb[3];
float fade = SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], offset, fade);
if(ss->cache->brush->flag2 & BRUSH_RGB_AS_VECTOR_DISPLACEMENT
&& (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) {
SCULPT_calc_vertex_displacement(ss, rgb, proxy[vd.i]);
}
else {
mul_v3_v3fl(proxy[vd.i], offset, fade);
}
if (vd.is_mesh) {
BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);
@ -304,6 +312,7 @@ void SCULPT_do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
* initialize before threads so they can do curve mapping. */
BKE_curvemapping_init(brush->curve);
/* Threaded loop over nodes. */
SculptThreadedTaskData data = {
.sd = sd,
@ -371,7 +380,8 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -380,7 +390,8 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], val, fade);
@ -476,7 +487,8 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -485,7 +497,8 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], val, fade);
@ -601,7 +614,8 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -610,7 +624,8 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], val, fade);
@ -763,7 +778,8 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
if (SCULPT_plane_trim(ss->cache, brush, val)) {
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -772,7 +788,8 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], val, fade);
@ -927,7 +944,8 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -936,7 +954,8 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], val, fade);
@ -1061,7 +1080,8 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
/* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
ss->cache->radius * test.dist,
@ -1070,7 +1090,8 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], val, fade);
@ -1221,7 +1242,8 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
else {
SCULPT_automasking_node_update(ss, &automask_data, &vd);
fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -1230,7 +1252,8 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
}
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@ -1363,7 +1386,8 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
orig_data.co,
sqrtf(test.dist),
@ -1372,7 +1396,8 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@ -1445,7 +1470,8 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
float vec[3], rot[3][3];
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
orig_data.co,
sqrtf(test.dist),
@ -1454,7 +1480,8 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
@ -1524,7 +1551,8 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -1533,7 +1561,8 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
const int vi = vd.index;
float *disp_factor;
@ -1644,7 +1673,8 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -1653,7 +1683,8 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float val[3];
if (vd.fno) {
@ -1719,7 +1750,8 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -1728,7 +1760,8 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@ -1805,7 +1838,8 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
/* Offset vertex. */
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -1814,7 +1848,8 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float val1[3];
float val2[3];
@ -1928,7 +1963,8 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -1937,7 +1973,8 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float disp_center[3];
float x_disp[3];
float z_disp[3];
@ -2051,16 +2088,18 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
float fade = bstrength * SCULPT_brush_strength_factor(ss,
brush,
orig_data.co,
sqrtf(test.dist),
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
float rgb[3];
float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
orig_data.co,
sqrtf(test.dist),
orig_data.no,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data,
rgb);
if (grab_silhouette) {
float silhouette_test_dir[3];
@ -2262,7 +2301,8 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
/* Offset vertex. */
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = SCULPT_brush_factor_with_color(ss,
brush,
orig_data.co,
sqrtf(test.dist),
@ -2271,7 +2311,8 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@ -2352,7 +2393,8 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = SCULPT_brush_factor_with_color(ss,
brush,
orig_data.co,
sqrtf(test.dist),
@ -2361,7 +2403,8 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float current_disp[3];
float current_disp_norm[3];
float final_disp[3] = {0.0f, 0.0f, 0.0f};
@ -2516,7 +2559,8 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = SCULPT_brush_factor_with_color(ss,
brush,
orig_data.co,
sqrtf(test.dist),
@ -2525,7 +2569,8 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
if (vd.is_mesh) {
@ -2599,7 +2644,8 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -2608,7 +2654,8 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float limit_co[3];
float disp[3];
@ -2672,7 +2719,8 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -2681,7 +2729,8 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float current_disp[3];
float current_disp_norm[3];
@ -2840,8 +2889,9 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
float rgb[3];
const float fade = bstrength *
SCULPT_brush_strength_factor(ss,
SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -2850,7 +2900,8 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
*vd.mask,
vd.vertex,
thread_id,
&automask_data) *
&automask_data,
rgb) *
ss->cache->pressure;
float avg[3], val[3];
@ -2931,7 +2982,8 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
}
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -2940,7 +2992,8 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
if (bstrength > 0.0f) {
(*vd.mask) += fade * bstrength * (1.0f - *vd.mask);

View File

@ -507,8 +507,9 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
dist = dist_to_plane_v3(current_vertex_location, deform_plane);
}
float rgb[3];
const float fade = sim_factor * bstrength *
SCULPT_brush_strength_factor(ss,
SCULPT_brush_factor_with_color(ss,
brush,
current_vertex_location,
dist,
@ -517,7 +518,8 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float brush_disp[3];

View File

@ -144,7 +144,9 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
if (face_hidden) {
continue;
}
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -153,7 +155,8 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
if (fade > 0.05f) {
ss->face_sets[vert_map->indices[j]] = ss->cache->paint_face_set;
@ -165,7 +168,9 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
}
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -174,7 +179,8 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
if (fade > 0.05f) {
SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set);
@ -225,7 +231,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
continue;
}
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -234,7 +241,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
if (vd.is_mesh) {

View File

@ -1237,18 +1237,25 @@ const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
char falloff_shape);
/**
* Return a multiplier for brush strength on a particular vertex.
* Return a color and grayscale of a brush texture at a particular vertex multiplied by active masks.
* The grayscale value is usually multiplied by the offset vector and the color is used for non-linear vertex displacement.
*/
float SCULPT_brush_strength_factor(struct SculptSession *ss,
const struct Brush *br,
const float point[3],
float len,
const float vno[3],
const float fno[3],
float mask,
const PBVHVertRef vertex,
int thread_id,
struct AutomaskingNodeData *automask_data);
float SCULPT_brush_factor_with_color(struct SculptSession *ss,
const struct Brush *brush,
const float point[3],
float len,
const float vno[3],
const float fno[3],
float mask,
const PBVHVertRef vertex,
int thread_id,
struct AutomaskingNodeData *automask_data,
float rgb[3]);
/**
* Calculates the vertex offset for a single vertex depending on the brush setting rgb as vector displacement.
*/
void SCULPT_calc_vertex_displacement(SculptSession *ss, float rgb[3], float out_offset[3]);
/**
* Tilts a normal by the x and y tilt values using the view axis.

View File

@ -72,7 +72,8 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
/* Use the brush falloff to weight the sampled normals. */
const float fade = SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -81,7 +82,8 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
/* Sample the normal and area of the +X and -X axis individually. */
if (local_co[0] > 0.0f) {
@ -187,8 +189,9 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
/* Deform the local space along the Y axis to avoid artifacts on curved strokes. */
/* This produces a not round brush tip. */
float rgb[3];
local_co[1] *= 2.0f;
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
len_v3(local_co),
@ -197,7 +200,8 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
mul_v3_v3fl(proxy[vd.i], val, fade);

View File

@ -59,7 +59,8 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -68,7 +69,8 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float smooth_color[4];
SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex);
@ -153,7 +155,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
distance_to_stroke_location,
@ -162,7 +165,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
/* Density. */
float noise = 1.0f;
@ -409,7 +413,8 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -418,7 +423,8 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float current_disp[3];
float current_disp_norm[3];

View File

@ -174,7 +174,8 @@ template<typename ImageBuffer> class PaintingKernel {
const float3 face_normal(0.0f, 0.0f, 0.0f);
const float mask = 0.0f;
const float falloff_strength = SCULPT_brush_strength_factor(
float rgb[3];
const float falloff_strength = SCULPT_brush_factor_with_color(
ss,
brush,
pixel_pos,
@ -184,7 +185,8 @@ template<typename ImageBuffer> class PaintingKernel {
mask,
BKE_pbvh_make_vref(PBVH_REF_NONE),
thread_id,
automask_data);
automask_data,
rgb);
float4 paint_color = brush_color * falloff_strength * brush_strength;
float4 buffer_color;
blend_color_mix_float(buffer_color, color, paint_color);

View File

@ -206,7 +206,8 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -215,7 +216,8 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float disp[3];
madd_v3_v3v3fl(disp, vd.co, ss->cache->detail_directions[vd.index], fade);
@ -296,7 +298,8 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(
ss,
brush,
vd.co,
@ -306,7 +309,8 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
if (smooth_mask) {
float val = SCULPT_neighbor_mask_average(ss, vd.vertex) - *vd.mask;
val *= fade * bstrength;
@ -474,7 +478,8 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -483,7 +488,8 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
float disp[3];
SCULPT_surface_smooth_laplacian_step(
@ -522,7 +528,8 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
SCULPT_automasking_node_update(ss, &automask_data, &vd);
const float fade = bstrength * SCULPT_brush_strength_factor(ss,
float rgb[3];
const float fade = bstrength * SCULPT_brush_factor_with_color(ss,
brush,
vd.co,
sqrtf(test.dist),
@ -531,7 +538,8 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data);
&automask_data,
rgb);
SCULPT_surface_smooth_displace_step(
ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, beta, fade);
}

View File

@ -412,6 +412,7 @@ typedef enum eBrushFlags2 {
BRUSH_CLOTH_USE_COLLISION = (1 << 6),
BRUSH_AREA_RADIUS_PRESSURE = (1 << 7),
BRUSH_GRAB_SILHOUETTE = (1 << 8),
BRUSH_RGB_AS_VECTOR_DISPLACEMENT = (1 << 9),
} eBrushFlags2;
typedef enum {

View File

@ -2893,6 +2893,12 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Texture Sample Bias", "Value added to texture samples");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_rgb_as_vector_displacement", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_RGB_AS_VECTOR_DISPLACEMENT);
RNA_def_property_ui_text(prop, "RGB as vector displacement",
"Handles each pixel as individual vector for displacement instead of an offset in normal direction");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "normal_weight", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "normal_weight");
RNA_def_property_float_default(prop, 0);