Sculpt: smothing ops now slide UVs
* Wrote a new function, SCULPT_reproject_cdata, to reproject loop customdata after smoothing. * SCULPT_reproject_cdata is only called if UV layers exist. * All of the smoothing tools (hopefully all) use it. * This change is necassary to properly support vector displacement maps in the future; otherwise DynTopo will introduce lots of noise into the uv tangent space.
This commit is contained in:
parent
7d25a5ab3f
commit
673e1fbac5
|
@ -1285,6 +1285,12 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
|
|||
"show_origco",
|
||||
toolsettings_only=True, ui_editing=False)
|
||||
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"save_temp_layers",
|
||||
toolsettings_only=True, ui_editing=False)
|
||||
|
||||
col.separator()
|
||||
|
||||
col.operator("sculpt.set_limit_surface")
|
||||
|
|
|
@ -191,7 +191,7 @@ void BKE_brush_channel_free(BrushChannel *ch);
|
|||
void BKE_brush_channel_copy_data(BrushChannel *dst, BrushChannel *src, bool keep_mappings);
|
||||
void BKE_brush_channel_init(BrushChannel *ch, BrushChannelType *def);
|
||||
|
||||
BrushChannelSet *BKE_brush_channelset_create();
|
||||
BrushChannelSet *BKE_brush_channelset_create(const char *info);
|
||||
#ifdef DEBUG_CURVE_MAPPING_ALLOC
|
||||
BrushChannelSet *_BKE_brush_channelset_copy(BrushChannelSet *src);
|
||||
# define BKE_brush_channelset_copy(src) \
|
||||
|
|
|
@ -818,6 +818,8 @@ typedef struct SculptSession {
|
|||
*/
|
||||
struct SculptCustomLayer **layers_to_free;
|
||||
int tot_layers_to_free;
|
||||
|
||||
bool save_temp_layers;
|
||||
} SculptSession;
|
||||
|
||||
void BKE_sculptsession_free(struct Object *ob);
|
||||
|
|
|
@ -64,7 +64,7 @@ static void brush_init_data(ID *id)
|
|||
|
||||
MEMCPY_STRUCT_AFTER(brush, DNA_struct_default_get(Brush), id);
|
||||
|
||||
brush->channels = BKE_brush_channelset_create();
|
||||
brush->channels = BKE_brush_channelset_create(NULL);
|
||||
|
||||
/* enable fake user by default */
|
||||
id_fake_user_set(&brush->id);
|
||||
|
|
|
@ -278,6 +278,7 @@ places in rna_engine_codebase are relevent:
|
|||
MAKE_FLOAT(tip_roundness, "Tip Roundness", "", 1.0f, 0.0f, 1.0f)
|
||||
MAKE_BOOL(accumulate, "Accumulate", "", false)
|
||||
MAKE_BOOL_EX(show_origco, "Show OrigCo", "", false, BRUSH_CHANNEL_INHERIT)
|
||||
MAKE_BOOL_EX(save_temp_layers, "Save Temp Layers", "Developer option; save temporary vertex attributes", false, BRUSH_CHANNEL_INHERIT)
|
||||
MAKE_ENUM(direction, "Direction", "", 0, {\
|
||||
{0, "ADD", "ADD", "Add", "Add effect of brush"},
|
||||
{1, "SUBTRACT", "REMOVE", "Subtract", "Subtract effect of brush"},
|
||||
|
|
|
@ -478,12 +478,30 @@ float BKE_brush_channel_curve_evaluate(BrushChannel *ch, float val, const float
|
|||
return BKE_brush_curve_strength_ex(ch->curve.preset, ch->curve.curve, val, maxval);
|
||||
}
|
||||
|
||||
BrushChannelSet *BKE_brush_channelset_create()
|
||||
BrushChannelSet *BKE_brush_channelset_create(const char *info)
|
||||
{
|
||||
BrushChannelSet *chset = (BrushChannelSet *)MEM_callocN(sizeof(BrushChannelSet),
|
||||
"BrushChannelSet");
|
||||
static char *tags[512] = {0};
|
||||
|
||||
chset->namemap = BLI_ghash_str_new("BrushChannelSet");
|
||||
char buf[512] = "BrushChannelSet", *tag;
|
||||
|
||||
if (info) {
|
||||
strcat(buf, " ");
|
||||
strcat(buf, info);
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(tags); i++) {
|
||||
if (tags[i] && STREQ(tags[i], buf)) {
|
||||
tag = tags[i];
|
||||
}
|
||||
else if (!tags[i]) {
|
||||
tags[i] = tag = strdup(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BrushChannelSet *chset = (BrushChannelSet *)MEM_callocN(sizeof(BrushChannelSet),
|
||||
info ? tag : "BrushChannelSet");
|
||||
|
||||
chset->namemap = BLI_ghash_str_new("BrushChannelSet ghash");
|
||||
|
||||
return chset;
|
||||
}
|
||||
|
@ -807,7 +825,7 @@ BrushChannelSet *_BKE_brush_channelset_copy(BrushChannelSet *src)
|
|||
BrushChannelSet *BKE_brush_channelset_copy(BrushChannelSet *src)
|
||||
#endif
|
||||
{
|
||||
BrushChannelSet *chset = BKE_brush_channelset_create();
|
||||
BrushChannelSet *chset = BKE_brush_channelset_create(NULL);
|
||||
|
||||
if (!src->totchannel) {
|
||||
return chset;
|
||||
|
@ -871,7 +889,7 @@ void BKE_brush_commandlist_start(BrushCommandList *list,
|
|||
if (cmd->params_final) {
|
||||
BKE_brush_channelset_free(cmd->params_final);
|
||||
}
|
||||
cmd->params_final = BKE_brush_channelset_create();
|
||||
cmd->params_final = BKE_brush_channelset_create("params_final");
|
||||
|
||||
BKE_brush_channelset_merge(cmd->params_final, cmd->params, chset_final);
|
||||
|
||||
|
@ -889,7 +907,7 @@ void BKE_brush_resolve_channels(Brush *brush, Sculpt *sd)
|
|||
BKE_brush_channelset_free(brush->channels_final);
|
||||
}
|
||||
|
||||
brush->channels_final = BKE_brush_channelset_create();
|
||||
brush->channels_final = BKE_brush_channelset_create("channels_final");
|
||||
|
||||
BKE_brush_channelset_merge(brush->channels_final, brush->channels, sd->channels);
|
||||
}
|
||||
|
@ -1346,7 +1364,7 @@ BrushCommand *BKE_brush_commandlist_add(BrushCommandList *cl,
|
|||
}
|
||||
}
|
||||
else {
|
||||
cmd->params = BKE_brush_channelset_create();
|
||||
cmd->params = BKE_brush_channelset_create("params");
|
||||
}
|
||||
|
||||
cmd->params_final = NULL;
|
||||
|
@ -1886,7 +1904,7 @@ BrushTex *BKE_brush_tex_create()
|
|||
{
|
||||
BrushTex *bt = MEM_callocN(sizeof(BrushTex), "BrushTex");
|
||||
|
||||
bt->channels = BKE_brush_channelset_create();
|
||||
bt->channels = BKE_brush_channelset_create("brush tex");
|
||||
|
||||
return bt;
|
||||
}
|
||||
|
|
|
@ -993,7 +993,7 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
|
|||
bool setup_ui = !brush->channels || !brush->channels->totchannel;
|
||||
|
||||
if (!brush->channels) {
|
||||
brush->channels = BKE_brush_channelset_create();
|
||||
brush->channels = BKE_brush_channelset_create("brush");
|
||||
}
|
||||
|
||||
BrushChannelSet *chset = brush->channels;
|
||||
|
@ -1009,6 +1009,7 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
|
|||
|
||||
ADDCH(sharp_mode);
|
||||
ADDCH(show_origco);
|
||||
ADDCH(save_temp_layers);
|
||||
|
||||
ADDCH(use_surface_falloff);
|
||||
|
||||
|
@ -1522,13 +1523,13 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
|
|||
namestack_push(__func__);
|
||||
|
||||
if (!brush->channels) {
|
||||
brush->channels = BKE_brush_channelset_create();
|
||||
brush->channels = BKE_brush_channelset_create("brush 2");
|
||||
}
|
||||
|
||||
if (brush->channels) {
|
||||
// forcibly reset all non-user-defined channels for this brush
|
||||
|
||||
BrushChannelSet *chset = BKE_brush_channelset_create();
|
||||
BrushChannelSet *chset = BKE_brush_channelset_create("brush 3");
|
||||
Brush tmp = *brush;
|
||||
tmp.channels = chset;
|
||||
|
||||
|
@ -1542,6 +1543,8 @@ void BKE_brush_builtin_create(Brush *brush, int tool)
|
|||
BKE_brush_channel_copy_data(ch, ch2, false);
|
||||
}
|
||||
}
|
||||
|
||||
BKE_brush_channelset_free(chset);
|
||||
}
|
||||
|
||||
BrushChannelSet *chset = brush->channels;
|
||||
|
@ -1851,6 +1854,7 @@ void BKE_brush_check_toolsettings(Sculpt *sd)
|
|||
ADDCH(unprojected_radius);
|
||||
|
||||
ADDCH(show_origco);
|
||||
ADDCH(save_temp_layers);
|
||||
|
||||
ADDCH(smooth_strength_factor);
|
||||
ADDCH(smooth_strength_projection);
|
||||
|
|
|
@ -4678,10 +4678,15 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
|
|||
int custom_max_steps,
|
||||
bool disable_surface_relax)
|
||||
{
|
||||
/* disable surface smooth if uv layers are present, to avoid expensive reprojection operation */
|
||||
if (CustomData_has_layer(&pbvh->bm->ldata, CD_MLOOPUV)) {
|
||||
disable_surface_relax = true;
|
||||
}
|
||||
|
||||
/* 2 is enough for edge faces - manifold edge */
|
||||
BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
|
||||
BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32);
|
||||
|
||||
const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK);
|
||||
const int cd_vert_node_offset = pbvh->cd_vert_node_offset;
|
||||
const int cd_face_node_offset = pbvh->cd_face_node_offset;
|
||||
|
|
|
@ -1700,6 +1700,9 @@ static void sculpt_update_object(Depsgraph *depsgraph,
|
|||
ss->building_vp_handle = false;
|
||||
|
||||
ss->scene = scene;
|
||||
if (sd->channels) {
|
||||
ss->save_temp_layers = BRUSHSET_GET_INT(sd->channels, save_temp_layers, NULL);
|
||||
}
|
||||
|
||||
if (need_mask) {
|
||||
if (mmd == NULL) {
|
||||
|
|
|
@ -1073,7 +1073,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
BKE_brush_channelset_read(reader, sce->toolsettings->sculpt->channels);
|
||||
}
|
||||
else if (sce->toolsettings->sculpt) {
|
||||
sce->toolsettings->sculpt->channels = BKE_brush_channelset_create();
|
||||
sce->toolsettings->sculpt->channels = BKE_brush_channelset_create("sculpt toolsettings");
|
||||
}
|
||||
|
||||
if (sce->toolsettings->sculpt) {
|
||||
|
@ -1640,7 +1640,7 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
|
|||
ts->sculpt->channels = BKE_brush_channelset_copy(ts->sculpt->channels);
|
||||
}
|
||||
else {
|
||||
ts->sculpt->channels = BKE_brush_channelset_create();
|
||||
ts->sculpt->channels = BKE_brush_channelset_create("sculpt toolsettings");
|
||||
}
|
||||
|
||||
BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag);
|
||||
|
|
|
@ -514,6 +514,10 @@ static bool sculpt_temp_customlayer_get(SculptSession *ss,
|
|||
bool autocreate,
|
||||
SculptLayerParams *params)
|
||||
{
|
||||
if (ss->save_temp_layers && !params->simple_array) {
|
||||
params->permanent = true;
|
||||
}
|
||||
|
||||
bool simple_array = params->simple_array;
|
||||
bool permanent = params->permanent;
|
||||
bool nocopy = params->nocopy;
|
||||
|
@ -4657,6 +4661,8 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
|
|||
const Brush *brush = data->brush;
|
||||
PBVHNode *node = data->nodes[n];
|
||||
|
||||
bool do_reproject = SCULPT_need_reproject(ss);
|
||||
|
||||
float direction[3];
|
||||
copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
|
||||
|
||||
|
@ -4750,7 +4756,10 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
|
|||
float *co = vd.co;
|
||||
|
||||
float oldco[3];
|
||||
float oldno[3];
|
||||
|
||||
copy_v3_v3(oldco, co);
|
||||
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
|
||||
|
||||
SCULPT_bmesh_four_neighbor_average(ss,
|
||||
avg,
|
||||
|
@ -4774,6 +4783,10 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
|
|||
madd_v3_v3v3fl(val, co, val, fade);
|
||||
SCULPT_clip(sd, ss, co, val);
|
||||
|
||||
if (do_reproject) {
|
||||
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
|
||||
}
|
||||
|
||||
if (vd.mvert) {
|
||||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
}
|
||||
|
@ -6064,6 +6077,8 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
|
|||
ss, &test, data->brush->falloff_shape);
|
||||
const int thread_id = BLI_task_parallel_thread_id(tls);
|
||||
|
||||
const bool do_reproject = SCULPT_need_reproject;
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
|
||||
|
||||
|
@ -6080,8 +6095,17 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
|
|||
vd.vertex,
|
||||
thread_id);
|
||||
|
||||
float oldco[3], oldno[3];
|
||||
|
||||
copy_v3_v3(oldco, vd.co);
|
||||
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
|
||||
|
||||
SCULPT_relax_vertex(ss, &vd, fade * bstrength, SCULPT_BOUNDARY_DEFAULT, vd.co);
|
||||
|
||||
if (do_reproject) {
|
||||
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
|
||||
}
|
||||
|
||||
if (vd.mvert) {
|
||||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
}
|
||||
|
@ -12171,13 +12195,13 @@ void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerR
|
|||
// should not happen!
|
||||
printf("had to create brush->channels for brush '%s'!", brush->id.name + 2);
|
||||
|
||||
brush->channels = BKE_brush_channelset_create();
|
||||
brush->channels = BKE_brush_channelset_create("brush 0");
|
||||
BKE_brush_builtin_patch(brush, brush->sculpt_tool);
|
||||
BKE_brush_channelset_compat_load(brush->channels, brush, true);
|
||||
}
|
||||
|
||||
if (brush->channels && sd->channels) {
|
||||
ss->cache->channels_final = BKE_brush_channelset_create();
|
||||
ss->cache->channels_final = BKE_brush_channelset_create("channels_final");
|
||||
BKE_brush_channelset_merge(ss->cache->channels_final, brush->channels, sd->channels);
|
||||
}
|
||||
else if (brush->channels) {
|
||||
|
|
|
@ -559,6 +559,10 @@ void SCULPT_dyntopo_ensure_templayer(SculptSession *ss,
|
|||
const char *name,
|
||||
bool not_temporary)
|
||||
{
|
||||
if (ss->save_temp_layers) {
|
||||
not_temporary = true;
|
||||
}
|
||||
|
||||
int li = CustomData_get_named_layer_index(&ss->bm->vdata, type, name);
|
||||
|
||||
if (li < 0) {
|
||||
|
|
|
@ -559,6 +559,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
|||
|
||||
const int thread_id = BLI_task_parallel_thread_id(tls);
|
||||
|
||||
bool do_reproject = SCULPT_need_reproject(ss);
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
||||
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
||||
continue;
|
||||
|
@ -579,11 +581,19 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
|||
|
||||
CLAMP(fade, 0.0f, 1.0f);
|
||||
|
||||
float oldco[3], oldno[3];
|
||||
|
||||
copy_v3_v3(oldco, vd.co);
|
||||
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
|
||||
|
||||
SCULPT_relax_vertex(
|
||||
ss, &vd, fade * bstrength, SCULPT_BOUNDARY_DEFAULT | SCULPT_BOUNDARY_FACE_SET, vd.co);
|
||||
if (vd.mvert) {
|
||||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
}
|
||||
if (do_reproject) {
|
||||
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
|
||||
}
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
|
|
@ -346,10 +346,14 @@ static void mesh_filter_task_cb(void *__restrict userdata,
|
|||
BKE_pbvh_check_tri_areas(ss->pbvh, node);
|
||||
}
|
||||
|
||||
bool do_reproject = SCULPT_need_reproject(ss);
|
||||
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
|
||||
float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
|
||||
float orig_co[3], oldco[3], oldno[3], val[3], avg[3], normal[3], disp[3];
|
||||
float disp2[3], transform[3][3], final_pos[3];
|
||||
|
||||
float fade = vd.mask ? *vd.mask : 0.0f;
|
||||
fade = 1.0f - fade;
|
||||
fade *= data->filter_strength;
|
||||
|
@ -363,6 +367,9 @@ static void mesh_filter_task_cb(void *__restrict userdata,
|
|||
continue;
|
||||
}
|
||||
|
||||
copy_v3_v3(oldco, vd.co);
|
||||
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
|
||||
|
||||
if (ELEM(filter_type, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
|
||||
copy_v3_v3(orig_co, vd.co);
|
||||
}
|
||||
|
@ -549,6 +556,16 @@ static void mesh_filter_task_cb(void *__restrict userdata,
|
|||
if (vd.mvert) {
|
||||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
}
|
||||
|
||||
if (do_reproject && ELEM(filter_type,
|
||||
MESH_FILTER_SMOOTH,
|
||||
MESH_FILTER_SURFACE_SMOOTH,
|
||||
MESH_FILTER_RELAX,
|
||||
MESH_FILTER_RELAX_FACE_SETS,
|
||||
MESH_FILTER_ENHANCE_DETAILS,
|
||||
MESH_FILTER_SHARPEN)) {
|
||||
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
|
||||
}
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
|
||||
|
|
|
@ -779,22 +779,21 @@ void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], SculptVer
|
|||
|
||||
/* Mask the mesh boundaries smoothing only the mesh surface without using automasking. */
|
||||
|
||||
#if 0
|
||||
void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
|
||||
float result[3],
|
||||
SculptVertRef vertex,
|
||||
float projection,
|
||||
float slide_fset,
|
||||
float bound_smooth,
|
||||
SculptCustomLayer *bound_scl,
|
||||
bool do_origco);
|
||||
#endif
|
||||
|
||||
void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
|
||||
float result[3],
|
||||
SculptVertRef vertex,
|
||||
SculptSmoothArgs *args);
|
||||
|
||||
BLI_INLINE bool SCULPT_need_reproject(SculptSession *ss)
|
||||
{
|
||||
return ss->bm && CustomData_has_layer(&ss->bm->ldata, CD_MLOOPUV);
|
||||
}
|
||||
|
||||
void SCULPT_reproject_cdata(SculptSession *ss,
|
||||
SculptVertRef vertex,
|
||||
float origco[3],
|
||||
float origno[3]);
|
||||
|
||||
void SCULPT_smooth_vcol_boundary(
|
||||
Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength);
|
||||
|
||||
|
|
|
@ -25,13 +25,16 @@
|
|||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_array.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
|
@ -77,6 +80,243 @@
|
|||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
void SCULPT_reproject_cdata(SculptSession *ss,
|
||||
SculptVertRef vertex,
|
||||
float origco[3],
|
||||
float origno[3])
|
||||
{
|
||||
BMVert *v = (BMVert *)vertex.i;
|
||||
|
||||
if (!ss->bm || !v->e) {
|
||||
return;
|
||||
}
|
||||
|
||||
// int totuv = CustomData_number_of_layers(&ss->bm->ldata, CD_MLOOPUV);
|
||||
CustomData *ldata = &ss->bm->ldata;
|
||||
|
||||
int totuv = 0;
|
||||
CustomDataLayer *uvlayer = NULL;
|
||||
|
||||
if (ldata->typemap[CD_MLOOPUV] != -1) {
|
||||
for (int i = ldata->typemap[CD_MLOOPUV];
|
||||
i < ldata->totlayer && ldata->layers[i].type == CD_MLOOPUV;
|
||||
i++) {
|
||||
totuv++;
|
||||
}
|
||||
|
||||
uvlayer = ldata->layers + ldata->typemap[CD_MLOOPUV];
|
||||
}
|
||||
|
||||
BMEdge *e;
|
||||
int tag = BM_ELEM_TAG_ALT;
|
||||
|
||||
float origin[3];
|
||||
float ray[3];
|
||||
|
||||
copy_v3_v3(origin, v->co);
|
||||
copy_v3_v3(ray, v->no);
|
||||
negate_v3(ray);
|
||||
|
||||
struct IsectRayPrecalc precalc;
|
||||
isect_ray_tri_watertight_v3_precalc(&precalc, ray);
|
||||
|
||||
float *lastuvs = BLI_array_alloca(lastuvs, totuv * 2);
|
||||
|
||||
e = v->e;
|
||||
|
||||
/* first clear some flags */
|
||||
do {
|
||||
e->head.api_flag &= ~tag;
|
||||
|
||||
BMLoop *l = e->l;
|
||||
do {
|
||||
l->head.hflag &= ~tag;
|
||||
l->next->head.hflag &= ~tag;
|
||||
l->prev->head.hflag &= ~tag;
|
||||
} while ((l = l->radial_next) != e->l);
|
||||
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
|
||||
|
||||
BMLoop **ls = NULL;
|
||||
BLI_array_staticdeclare(ls, 32);
|
||||
|
||||
bool first = true;
|
||||
bool bad = false;
|
||||
|
||||
do {
|
||||
BMLoop *l = e->l;
|
||||
|
||||
if (!l) {
|
||||
continue;
|
||||
}
|
||||
#if 0
|
||||
bool bound = l == l->radial_next;
|
||||
|
||||
// check for faceset boundaries
|
||||
bound = bound || (BM_ELEM_CD_GET_INT(l->f, ss->cd_faceset_offset) !=
|
||||
BM_ELEM_CD_GET_INT(l->radial_next->f, ss->cd_faceset_offset));
|
||||
|
||||
// check for seam and sharp edges
|
||||
bound = bound || (e->head.hflag & BM_ELEM_SEAM) || !(e->head.hflag & BM_ELEM_SMOOTH);
|
||||
|
||||
if (bound) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
do {
|
||||
BMLoop *l2 = l->v != v ? l->next : l;
|
||||
|
||||
if (l2->head.hflag & tag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
l2->head.hflag |= tag;
|
||||
BLI_array_append(ls, l2);
|
||||
|
||||
for (int i = 0; i < totuv; i++) {
|
||||
const int cd_uv = uvlayer[i].offset;
|
||||
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l2, cd_uv);
|
||||
|
||||
// check that we are not part of a uv seam
|
||||
if (!first) {
|
||||
const float dx = lastuvs[i * 2] - luv->uv[0];
|
||||
const float dy = lastuvs[i * 2 + 1] - luv->uv[1];
|
||||
const float eps = 0.00001f;
|
||||
|
||||
if (fabsf(dx * dx + dy * dy) > eps) {
|
||||
bad = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lastuvs[i * 2] = luv->uv[0];
|
||||
lastuvs[i * 2 + 1] = luv->uv[1];
|
||||
}
|
||||
|
||||
if (bad) {
|
||||
break;
|
||||
}
|
||||
} while ((l = l->radial_next) != e->l);
|
||||
|
||||
if (bad) {
|
||||
break;
|
||||
}
|
||||
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
|
||||
|
||||
if (bad || !BLI_array_len(ls)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int totloop = BLI_array_len(ls);
|
||||
|
||||
const float *v_proj_axis = v->no;
|
||||
float v_proj[3][3];
|
||||
MSculptVert *mv = BKE_PBVH_SCULPTVERT(ss->cd_sculpt_vert, v);
|
||||
|
||||
project_plane_normalized_v3_v3v3(v_proj[1], mv->origco, v_proj_axis);
|
||||
|
||||
/* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */
|
||||
|
||||
char *_blocks = alloca(ldata->totsize * totloop);
|
||||
void **blocks = BLI_array_alloca(blocks, totloop);
|
||||
|
||||
for (int i = 0; i < totloop; i++, _blocks += ldata->totsize) {
|
||||
blocks[i] = (void *)_blocks;
|
||||
}
|
||||
|
||||
float vco[3], vno[3];
|
||||
|
||||
copy_v3_v3(vco, v->co);
|
||||
copy_v3_v3(vno, v->no);
|
||||
|
||||
BMFace _fakef, *fakef = &_fakef;
|
||||
|
||||
#if 0
|
||||
BMFace *projf = NULL;
|
||||
// find face vertex projects into
|
||||
for (int i = 0; i < totloop; i++) {
|
||||
BMLoop *l = ls[i];
|
||||
|
||||
copy_v3_v3(ray, l->f->no);
|
||||
negate_v3(ray);
|
||||
|
||||
float t, uv[2];
|
||||
|
||||
//*
|
||||
bool hit = isect_ray_tri_v3(origin, ray, l->prev->v->co, origco, l->next->v->co, &t, uv);
|
||||
if (hit) {
|
||||
projf = l->f;
|
||||
break;
|
||||
} //*/
|
||||
}
|
||||
|
||||
if (!projf) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// build fake f with original coordinates
|
||||
for (int i = 0; i < totloop; i++) {
|
||||
// create fake face
|
||||
BMLoop *l = ls[i];
|
||||
float no[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
BMLoop *fakels = BLI_array_alloca(fakels, l->f->len);
|
||||
BMVert *fakevs = BLI_array_alloca(fakevs, l->f->len);
|
||||
BMLoop *l2 = l->f->l_first;
|
||||
BMLoop *fakel = fakels;
|
||||
BMVert *fakev = fakevs;
|
||||
int j = 0;
|
||||
|
||||
do {
|
||||
*fakel = *l2;
|
||||
fakel->next = fakels + ((j + 1) % l->f->len);
|
||||
fakel->prev = fakels + ((j + l->f->len - 1) % l->f->len);
|
||||
|
||||
*fakev = *l2->v;
|
||||
fakel->v = fakev;
|
||||
|
||||
SCULPT_vertex_check_origdata(ss, (SculptVertRef){.i = (intptr_t)l2->v});
|
||||
|
||||
if (l2->v == v) {
|
||||
copy_v3_v3(fakev->co, origco);
|
||||
copy_v3_v3(fakev->no, origno);
|
||||
add_v3_v3(no, origno);
|
||||
}
|
||||
else {
|
||||
add_v3_v3(no, l2->v->no);
|
||||
}
|
||||
|
||||
fakel++;
|
||||
fakev++;
|
||||
j++;
|
||||
} while ((l2 = l2->next) != l->f->l_first);
|
||||
|
||||
*fakef = *l->f;
|
||||
fakef->l_first = fakels;
|
||||
|
||||
// set original face normal
|
||||
// normalize_v3(no);
|
||||
// copy_v3_v3(fakef->no, no);
|
||||
|
||||
// interpolate
|
||||
BMLoop _interpl, *interpl = &_interpl;
|
||||
|
||||
MSculptVert saved = *mv;
|
||||
|
||||
*interpl = *l;
|
||||
interpl->head.data = blocks[i];
|
||||
// memcpy(interpl->head.data, l2->head.data, ldata->totsize);
|
||||
|
||||
BM_loop_interp_from_face(ss->bm, interpl, fakef, false, false);
|
||||
|
||||
*mv = saved;
|
||||
|
||||
CustomData_bmesh_copy_data(&ss->bm->ldata, &ss->bm->ldata, interpl->head.data, &l->head.data);
|
||||
}
|
||||
|
||||
BLI_array_free(ls);
|
||||
}
|
||||
|
||||
MINLINE float safe_shell_angle_to_dist(const float angle)
|
||||
{
|
||||
float th = cosf(angle);
|
||||
|
@ -93,6 +333,11 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
|
|||
SculptVertRef vertex,
|
||||
SculptSmoothArgs *args)
|
||||
{
|
||||
if (args->do_origco) {
|
||||
// copy_v3_v3(result, SCULPT_vertex_co_get(ss, vertex));
|
||||
// return;
|
||||
}
|
||||
|
||||
float avg[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
float projection = args->projection;
|
||||
|
@ -133,6 +378,10 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
|
|||
}
|
||||
}
|
||||
|
||||
float startco[3], startno[3];
|
||||
copy_v3_v3(startco, co);
|
||||
copy_v3_v3(startno, no);
|
||||
|
||||
const bool weighted = args->do_weighted_smooth && !is_boundary;
|
||||
float *areas = NULL;
|
||||
|
||||
|
@ -1131,7 +1380,13 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
|
|||
// continue;
|
||||
//}
|
||||
|
||||
float startco[3], startno[3];
|
||||
|
||||
copy_v3_v3(startco, vd.co);
|
||||
SCULPT_vertex_normal_get(ss, vd.vertex, startno);
|
||||
|
||||
int steps = data->do_origco ? 2 : 1;
|
||||
|
||||
for (int step = 0; step < steps; step++) {
|
||||
float *co = step ? (float *)SCULPT_vertex_origco_get(ss, vd.vertex) : vd.co;
|
||||
|
||||
|
@ -1166,6 +1421,9 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata,
|
|||
madd_v3_v3v3fl(val, co, val, fade);
|
||||
SCULPT_clip(sd, ss, co, val);
|
||||
|
||||
if (step == 0) {
|
||||
SCULPT_reproject_cdata(ss, vd.vertex, startco, startno);
|
||||
}
|
||||
// interp_v3_v3v3(vel, vel, val, 0.5);
|
||||
}
|
||||
}
|
||||
|
@ -1437,6 +1695,8 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
|
|||
bool check_fsets = ss->cache->brush->flag2 & BRUSH_SMOOTH_PRESERVE_FACE_SETS;
|
||||
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
|
||||
|
||||
bool do_reproject = SCULPT_need_reproject(ss);
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
||||
SCULPT_orig_vert_data_update(&orig_data, vd.vertex);
|
||||
|
||||
|
@ -1454,6 +1714,11 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
|
|||
thread_id);
|
||||
|
||||
float disp[3];
|
||||
float oldco[3], oldno[3];
|
||||
|
||||
copy_v3_v3(oldco, vd.co);
|
||||
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
|
||||
|
||||
SCULPT_surface_smooth_laplacian_step(ss,
|
||||
disp,
|
||||
vd.co,
|
||||
|
@ -1469,6 +1734,10 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
|
|||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
}
|
||||
|
||||
if (do_reproject) {
|
||||
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
|
||||
}
|
||||
|
||||
modified = true;
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
|
@ -1592,6 +1861,13 @@ static void SCULPT_do_directional_smooth_task_cb_ex(void *__restrict userdata,
|
|||
float avg[3] = {0.0f, 0.0f, 0.0f};
|
||||
int neighbor_count = 0;
|
||||
|
||||
float oldco[3], oldno[3];
|
||||
|
||||
copy_v3_v3(oldco, vd.co);
|
||||
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
|
||||
|
||||
bool do_reproject = SCULPT_need_reproject(ss);
|
||||
|
||||
SculptVertexNeighborIter ni;
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
|
||||
float vertex_neighbor_disp[3];
|
||||
|
@ -1618,6 +1894,10 @@ static void SCULPT_do_directional_smooth_task_cb_ex(void *__restrict userdata,
|
|||
madd_v3_v3v3fl(final_disp, vd.co, final_disp, fade);
|
||||
SCULPT_clip(data->sd, ss, vd.co, final_disp);
|
||||
|
||||
if (do_reproject) {
|
||||
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
|
||||
}
|
||||
|
||||
if (vd.mvert) {
|
||||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
}
|
||||
|
@ -1660,6 +1940,8 @@ static void SCULPT_do_uniform_weigths_smooth_task_cb_ex(void *__restrict userdat
|
|||
ss, &test, data->brush->falloff_shape);
|
||||
const int thread_id = BLI_task_parallel_thread_id(tls);
|
||||
|
||||
bool do_reproject = SCULPT_need_reproject(ss);
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
||||
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
|
||||
continue;
|
||||
|
@ -1677,6 +1959,11 @@ static void SCULPT_do_uniform_weigths_smooth_task_cb_ex(void *__restrict userdat
|
|||
float len_accum = 0;
|
||||
int tot_neighbors = 0;
|
||||
|
||||
float oldco[3], oldno[3];
|
||||
|
||||
copy_v3_v3(oldco, vd.co);
|
||||
SCULPT_vertex_normal_get(ss, vd.vertex, oldno);
|
||||
|
||||
SculptVertexNeighborIter ni;
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.vertex, ni) {
|
||||
len_accum += len_v3v3(SCULPT_vertex_co_get(ss, vd.vertex),
|
||||
|
@ -1718,6 +2005,11 @@ static void SCULPT_do_uniform_weigths_smooth_task_cb_ex(void *__restrict userdat
|
|||
if (vd.mvert) {
|
||||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
}
|
||||
|
||||
if (do_reproject) {
|
||||
SCULPT_reproject_cdata(ss, vd.vertex, oldco, oldno);
|
||||
}
|
||||
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue