WIP: uv-simple-select #1

Closed
Chris Blackbourn wants to merge 182 commits from uv-simple-select into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
9 changed files with 281 additions and 137 deletions
Showing only changes of commit 153e4256d4 - Show all commits

View File

@ -1141,6 +1141,11 @@ def brush_texture_settings(layout, brush, sculpt):
# texture_sample_bias # texture_sample_bias
layout.prop(brush, "texture_sample_bias", slider=True, text="Sample Bias") layout.prop(brush, "texture_sample_bias", slider=True, text="Sample Bias")
if brush.sculpt_tool == 'DRAW':
col = layout.column()
col.active = tex_slot.map_mode == 'AREA_PLANE'
col.prop(brush, "use_color_as_displacement", text="Vector Displacement")
def brush_mask_texture_settings(layout, brush): def brush_mask_texture_settings(layout, brush):
mask_tex_slot = brush.mask_texture_slot mask_tex_slot = brush.mask_texture_slot

View File

@ -37,6 +37,7 @@
#include "WM_api.h" #include "WM_api.h"
#include "wm_cursors.h" #include "wm_cursors.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h" #include "IMB_imbuf_types.h"
#include "ED_image.h" #include "ED_image.h"
@ -200,10 +201,18 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
y = len * sinf(angle); y = len * sinf(angle);
} }
if (col) { float avg;
float rgba[4]; float rgba[4];
paint_get_tex_pixel(mtex, x, y, pool, thread_id, &avg, rgba);
paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace); if (col) {
if (convert_to_linear) {
IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, colorspace);
}
linearrgb_to_srgb_v3_v3(rgba, rgba);
clamp_v4(rgba, 0.0f, 1.0f);
buffer[index * 4] = rgba[0] * 255; buffer[index * 4] = rgba[0] * 255;
buffer[index * 4 + 1] = rgba[1] * 255; buffer[index * 4 + 1] = rgba[1] * 255;
@ -211,8 +220,6 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
buffer[index * 4 + 3] = rgba[3] * 255; buffer[index * 4 + 3] = rgba[3] * 255;
} }
else { else {
float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id);
avg += br->texture_sample_bias; avg += br->texture_sample_bias;
/* Clamp to avoid precision overflow. */ /* Clamp to avoid precision overflow. */

View File

@ -352,16 +352,17 @@ void paint_calc_redraw_planes(float planes[4][4],
float paint_calc_object_space_radius(struct ViewContext *vc, float paint_calc_object_space_radius(struct ViewContext *vc,
const float center[3], const float center[3],
float pixel_radius); 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, * Returns true when a color was sampled and false when a value was sampled.
*/
bool paint_get_tex_pixel(const struct MTex *mtex,
float u, float u,
float v, float v,
float rgba[4],
struct ImagePool *pool, struct ImagePool *pool,
int thread, int thread,
bool convert, float *r_intensity,
struct ColorSpace *colorspace); float r_rgba[4]);
/** /**
* Used for both 3D view and image window. * Used for both 3D view and image window.

View File

@ -146,45 +146,29 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3], flo
return len_v3(delta) / scale; 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 intensity;
float rgba_dummy[4];
const float co[3] = {u, v, 0.0f};
RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba_dummy);
return intensity;
}
void paint_get_tex_pixel_col(const MTex *mtex,
float u, float u,
float v, float v,
float rgba[4],
struct ImagePool *pool, struct ImagePool *pool,
int thread, int thread,
bool convert_to_linear, /* Return arguments. */
struct ColorSpace *colorspace) float *r_intensity,
float r_rgba[4])
{ {
const float co[3] = {u, v, 0.0f}; const float co[3] = {u, v, 0.0f};
float intensity; float intensity;
const bool has_rgb = RE_texture_evaluate(
mtex, co, thread, pool, false, false, &intensity, r_rgba);
*r_intensity = intensity;
const bool hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); if (!has_rgb) {
r_rgba[0] = intensity;
if (!hasrgb) { r_rgba[1] = intensity;
rgba[0] = intensity; r_rgba[2] = intensity;
rgba[1] = intensity; r_rgba[3] = 1.0f;
rgba[2] = intensity;
rgba[3] = 1.0f;
} }
if (convert_to_linear) { return has_rgb;
IMB_colormanagement_colorspace_to_scene_linear_v3(rgba, colorspace);
}
linearrgb_to_srgb_v3_v3(rgba, rgba);
clamp_v4(rgba, 0.0f, 1.0f);
} }
void paint_stroke_operator_properties(wmOperatorType *ot) void paint_stroke_operator_properties(wmOperatorType *ot)

View File

@ -54,6 +54,7 @@
#include "BKE_scene.h" #include "BKE_scene.h"
#include "BKE_subdiv_ccg.h" #include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h" #include "BKE_subsurf.h"
#include "BLI_math_vector.hh"
#include "NOD_texture.h" #include "NOD_texture.h"
@ -2555,80 +2556,12 @@ static float brush_strength(const Sculpt *sd,
} }
} }
float SCULPT_brush_strength_factor(SculptSession *ss, static float sculpt_apply_hardness(const SculptSession *ss, const float input_len)
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)
{ {
StrokeCache *cache = ss->cache; const StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene; float final_len = input_len;
const MTex *mtex = BKE_brush_mask_texture_get(br, OB_MODE_SCULPT);
float avg = 1.0f;
float rgba[4];
float point[3];
sub_v3_v3v3(point, brush_point, cache->plane_offset);
if (!mtex->tex) {
avg = 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);
}
else {
float symm_point[3], point_2d[2];
/* Quite warnings. */
float x = 0.0f, y = 0.0f;
/* If the active area is being applied for symmetry, flip it
* across the symmetry axis and rotate it back to the original
* position in order to project it. This insures that the
* brush texture will be oriented correctly. */
if (cache->radial_symmetry_pass) {
mul_m4_v3(cache->symm_rot_mat_inv, point);
}
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) {
/* Similar to fixed mode, but projects from brush angle
* rather than view direction. */
mul_m4_v3(cache->brush_local_mat, symm_point);
x = symm_point[0];
y = symm_point[1];
x *= mtex->size[0];
y *= mtex->size[1];
x += mtex->ofs[0];
y += mtex->ofs[1];
avg = paint_get_tex_pixel(mtex, x, y, ss->tex_pool, thread_id);
avg += br->texture_sample_bias;
}
else {
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);
}
}
/* Hardness. */
float final_len = len;
const float hardness = cache->paint_brush.hardness; const float hardness = cache->paint_brush.hardness;
float p = len / cache->radius; float p = input_len / cache->radius;
if (p < hardness) { if (p < hardness) {
final_len = 0.0f; final_len = 0.0f;
} }
@ -2640,9 +2573,100 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
final_len = p * cache->radius; final_len = p * cache->radius;
} }
return final_len;
}
static void sculpt_apply_texture(const SculptSession *ss,
const Brush *brush,
const float brush_point[3],
const int thread_id,
float *r_value,
float r_rgba[4])
{
StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene;
const MTex *mtex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
if (!mtex->tex) {
*r_value = 1.0f;
copy_v4_fl(r_rgba, 1.0f);
return;
}
float point[3];
sub_v3_v3v3(point, brush_point, cache->plane_offset);
if (mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
/* Get strength by feeding the vertex location directly into a texture. */
*r_value = BKE_brush_sample_tex_3d(scene, brush, mtex, point, r_rgba, 0, ss->tex_pool);
}
else {
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
* position in order to project it. This insures that the
* brush texture will be oriented correctly. */
if (cache->radial_symmetry_pass) {
mul_m4_v3(cache->symm_rot_mat_inv, point);
}
flip_v3_v3(symm_point, point, cache->mirror_symmetry_pass);
/* Still no symmetry supported for other paint modes.
* Sculpt does it DIY. */
if (mtex->brush_map_mode == MTEX_MAP_MODE_AREA) {
/* Similar to fixed mode, but projects from brush angle
* rather than view direction. */
mul_m4_v3(cache->brush_local_mat, symm_point);
float x = symm_point[0];
float y = symm_point[1];
x *= mtex->size[0];
y *= mtex->size[1];
x += mtex->ofs[0];
y += mtex->ofs[1];
paint_get_tex_pixel(mtex, x, y, ss->tex_pool, thread_id, r_value, r_rgba);
add_v3_fl(r_rgba, brush->texture_sample_bias); // v3 -> Ignore alpha
*r_value -= 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};
*r_value = BKE_brush_sample_tex_3d(scene, brush, mtex, point_3d, r_rgba, 0, ss->tex_pool);
}
}
}
float SCULPT_brush_strength_factor(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)
{
StrokeCache *cache = ss->cache;
float avg = 1.0f;
float rgba[4];
sculpt_apply_texture(ss, brush, brush_point, thread_id, &avg, rgba);
/* Hardness. */
const float final_len = sculpt_apply_hardness(ss, len);
/* Falloff curve. */ /* Falloff curve. */
avg *= BKE_brush_curve_strength(br, final_len, cache->radius); avg *= BKE_brush_curve_strength(brush, final_len, cache->radius);
avg *= frontface(br, cache->view_normal, vno, fno); avg *= frontface(brush, cache->view_normal, vno, fno);
/* Paint mask. */ /* Paint mask. */
avg *= 1.0f - mask; avg *= 1.0f - mask;
@ -2653,6 +2677,69 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
return avg; return avg;
} }
void SCULPT_brush_strength_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_rgba[4])
{
StrokeCache *cache = ss->cache;
float avg = 1.0f;
sculpt_apply_texture(ss, brush, brush_point, thread_id, &avg, r_rgba);
/* Hardness. */
const float final_len = sculpt_apply_hardness(ss, len);
/* Falloff curve. */
const float falloff = BKE_brush_curve_strength(brush, final_len, cache->radius) *
frontface(brush, cache->view_normal, vno, fno);
/* Paint mask. */
const float paint_mask = 1.0f - mask;
/* Auto-masking. */
const float automasking_factor = SCULPT_automasking_factor_get(
cache->automasking, ss, vertex, automask_data);
const float masks_combined = falloff * paint_mask * automasking_factor;
mul_v4_fl(r_rgba, masks_combined);
}
void SCULPT_calc_vertex_displacement(SculptSession *ss,
const Brush *brush,
float rgba[4],
float out_offset[3])
{
mul_v3_fl(rgba, ss->cache->bstrength);
/* Handle brush inversion */
if (ss->cache->bstrength < 0) {
rgba[0] *= -1;
rgba[1] *= -1;
}
/* Apply texture size */
for (int i = 0; i < 3; ++i) {
rgba[i] *= blender::math::safe_divide(1.0f, pow2f(brush->mtex.size[i]));
}
/* Transform vector to object space */
mul_mat3_m4_v3(ss->cache->brush_local_mat_inv, rgba);
/* Handle symmetry */
if (ss->cache->radial_symmetry_pass) {
mul_m4_v3(ss->cache->symm_rot_mat, rgba);
}
flip_v3_v3(out_offset, rgba, ss->cache->mirror_symmetry_pass);
}
bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v) bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v)
{ {
SculptSearchSphereData *data = static_cast<SculptSearchSphereData *>(data_v); SculptSearchSphereData *data = static_cast<SculptSearchSphereData *>(data_v);
@ -2920,7 +3007,10 @@ static void calc_local_y(ViewContext *vc, const float center[3], float y[3])
mul_m4_v3(ob->world_to_object, y); mul_m4_v3(ob->world_to_object, y);
} }
static void calc_brush_local_mat(const MTex *mtex, Object *ob, float local_mat[4][4]) static void calc_brush_local_mat(const MTex *mtex,
Object *ob,
float local_mat[4][4],
float local_mat_inv[4][4])
{ {
const StrokeCache *cache = ob->sculpt->cache; const StrokeCache *cache = ob->sculpt->cache;
float tmat[4][4]; float tmat[4][4];
@ -2966,6 +3056,8 @@ static void calc_brush_local_mat(const MTex *mtex, Object *ob, float local_mat[4
scale_m4_fl(scale, radius); scale_m4_fl(scale, radius);
mul_m4_m4m4(tmat, mat, scale); mul_m4_m4m4(tmat, mat, scale);
/* Return tmat as is (for converting from local area coords to model-space coords). */
copy_m4_m4(local_mat_inv, tmat);
/* Return inverse (for converting from model-space coords to local area coords). */ /* Return inverse (for converting from model-space coords to local area coords). */
invert_m4_m4(local_mat, tmat); invert_m4_m4(local_mat, tmat);
} }
@ -3000,7 +3092,7 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0) { if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0) {
const Brush *brush = BKE_paint_brush(&sd->paint); const Brush *brush = BKE_paint_brush(&sd->paint);
const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT); const MTex *mask_tex = BKE_brush_mask_texture_get(brush, OB_MODE_SCULPT);
calc_brush_local_mat(mask_tex, ob, cache->brush_local_mat); calc_brush_local_mat(mask_tex, ob, cache->brush_local_mat, cache->brush_local_mat_inv);
} }
} }

View File

@ -265,7 +265,24 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
SCULPT_automasking_node_update(ss, &automask_data, &vd); SCULPT_automasking_node_update(ss, &automask_data, &vd);
/* Offset vertex. */ /* Offset vertex. */
const float fade = SCULPT_brush_strength_factor(ss, if (ss->cache->brush->flag2 & BRUSH_USE_COLOR_AS_DISPLACEMENT &&
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)) {
float r_rgba[4];
SCULPT_brush_strength_color(ss,
brush,
vd.co,
sqrtf(test.dist),
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.vertex,
thread_id,
&automask_data,
r_rgba);
SCULPT_calc_vertex_displacement(ss, brush, r_rgba, proxy[vd.i]);
}
else {
float fade = SCULPT_brush_strength_factor(ss,
brush, brush,
vd.co, vd.co,
sqrtf(test.dist), sqrtf(test.dist),
@ -275,8 +292,8 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
vd.vertex, vd.vertex,
thread_id, thread_id,
&automask_data); &automask_data);
mul_v3_v3fl(proxy[vd.i], offset, fade); mul_v3_v3fl(proxy[vd.i], offset, fade);
}
if (vd.is_mesh) { if (vd.is_mesh) {
BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex); BKE_pbvh_vert_tag_update_normal(ss->pbvh, vd.vertex);

View File

@ -586,8 +586,13 @@ struct StrokeCache {
float sculpt_normal_symm[3]; float sculpt_normal_symm[3];
/* Used for area texture mode, local_mat gets calculated by /* Used for area texture mode, local_mat gets calculated by
* calc_brush_local_mat() and used in tex_strength(). */ * calc_brush_local_mat() and used in sculpt_apply_texture().
* Transforms from model-space coords to local area coords.
*/
float brush_local_mat[4][4]; float brush_local_mat[4][4];
/* The matrix from local area coords to model-space coords is used to calculate the vector
* displacement in area plane mode. */
float brush_local_mat_inv[4][4];
float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */ float plane_offset[3]; /* used to shift the plane around when doing tiled strokes */
int tile_pass; int tile_pass;
@ -1241,6 +1246,30 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
int thread_id, int thread_id,
AutomaskingNodeData *automask_data); AutomaskingNodeData *automask_data);
/**
* Return a color of a brush texture on a particular vertex multiplied by active masks.
*/
void SCULPT_brush_strength_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_rgba[4]);
/**
* Calculates the vertex offset for a single vertex depending on the brush setting rgb as vector
* displacement.
*/
void SCULPT_calc_vertex_displacement(SculptSession *ss,
const Brush *brush,
float rgba[3],
float out_offset[3]);
/** /**
* Tilts a normal by the x and y tilt values using the view axis. * Tilts a normal by the x and y tilt values using the view axis.
*/ */

View File

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

View File

@ -2899,6 +2899,14 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Texture Sample Bias", "Value added to texture samples"); RNA_def_property_ui_text(prop, "Texture Sample Bias", "Value added to texture samples");
RNA_def_property_update(prop, 0, "rna_Brush_update"); RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_color_as_displacement", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_USE_COLOR_AS_DISPLACEMENT);
RNA_def_property_ui_text(prop,
"Vector Displacement",
"Handles each pixel color as individual vector for displacement. Works "
"only with area plane mapping");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "normal_weight", PROP_FLOAT, PROP_FACTOR); prop = RNA_def_property(srna, "normal_weight", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "normal_weight"); RNA_def_property_float_sdna(prop, NULL, "normal_weight");
RNA_def_property_float_default(prop, 0); RNA_def_property_float_default(prop, 0);