Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/sculpt.c
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
| Show First 20 Lines • Show All 3,337 Lines • ▼ Show 20 Lines | |||||
| /* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity | /* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity | ||||
| * Pixar Technical Memo #17-03 */ | * Pixar Technical Memo #17-03 */ | ||||
| typedef struct KelvinletParams { | typedef struct KelvinletParams { | ||||
| float f; | float f; | ||||
| float a; | float a; | ||||
| float b; | float b; | ||||
| float c; | float c; | ||||
| float radius_scaled; | float *radius_scaled; | ||||
| float grab_delta[3]; | |||||
| } KelvinletParams; | } KelvinletParams; | ||||
| static int sculpt_kelvinlet_get_scale_iteration_count(eBrushElasticDeformType type) | |||||
| { | |||||
| if (type == BRUSH_ELASTIC_DEFORM_GRAB) { | |||||
| return 1; | |||||
| } | |||||
| if (type == BRUSH_ELASTIC_DEFORM_GRAB_BISCALE) { | |||||
| return 2; | |||||
| } | |||||
| if (type == BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE) { | |||||
| return 3; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static void sculpt_kelvinet_integrate(void (*kelvinlet)(float disp[3], | static void sculpt_kelvinet_integrate(void (*kelvinlet)(float disp[3], | ||||
| const float vertex_co[3], | const float vertex_co[3], | ||||
| const float location[3], | const float location[3], | ||||
| float normal[3], | float normal[3], | ||||
| KelvinletParams *p), | KelvinletParams *p), | ||||
| float r_disp[3], | float r_disp[3], | ||||
| const float vertex_co[3], | const float vertex_co[3], | ||||
| const float location[3], | const float location[3], | ||||
| Show All 16 Lines | static void sculpt_kelvinet_integrate(void (*kelvinlet)(float disp[3], | ||||
| kelvinlet(k[3], k_it[2], location, normal, p); | kelvinlet(k[3], k_it[2], location, normal, p); | ||||
| copy_v3_v3(r_disp, k[0]); | copy_v3_v3(r_disp, k[0]); | ||||
| madd_v3_v3fl(r_disp, k[1], 2); | madd_v3_v3fl(r_disp, k[1], 2); | ||||
| madd_v3_v3fl(r_disp, k[2], 2); | madd_v3_v3fl(r_disp, k[2], 2); | ||||
| add_v3_v3(r_disp, k[3]); | add_v3_v3(r_disp, k[3]); | ||||
| mul_v3_fl(r_disp, 1.0f / 6.0f); | mul_v3_fl(r_disp, 1.0f / 6.0f); | ||||
| } | } | ||||
| static void sculpt_init_kelvinlet_grab( | |||||
| float *r_e, float *kvl, KelvinletParams *p, float r, int it_n) | |||||
| { | |||||
| for (int it = 0; it < it_n; it++) { | |||||
| r_e[it] = sqrtf(r * r + p->radius_scaled[it] * p->radius_scaled[it]); | |||||
| } | |||||
| /* Regularized Kelvinlets: Formula (6) */ | |||||
jbakker: we should add a the link to the original paper and add its name as numbers may get outdated… | |||||
| for (int s_it = 0; s_it < it_n; s_it++) { | |||||
| kvl[s_it] = ((p->a - p->b) / r_e[s_it]) + | |||||
| ((p->b * r * r) / (r_e[s_it] * r_e[s_it] * r_e[s_it])) + | |||||
| ((p->a * p->radius_scaled[s_it] * p->radius_scaled[s_it]) / | |||||
| (2.0f * r_e[s_it] * r_e[s_it] * r_e[s_it])); | |||||
| } | |||||
| } | |||||
| static void sculpt_kelvinlet_grab(float disp[3], | |||||
| const float vertex_co[3], | |||||
| const float location[3], | |||||
| float UNUSED(normal[3]), | |||||
| KelvinletParams *p) | |||||
| { | |||||
| float r_v[3]; | |||||
| float r_e[3]; | |||||
| float kvl[3]; | |||||
| sub_v3_v3v3(r_v, vertex_co, location); | |||||
| float r = len_v3(r_v); | |||||
| sculpt_init_kelvinlet_grab(r_e, kvl, p, r, 1); | |||||
| float fade = kvl[0] * p->c; | |||||
| mul_v3_v3fl(disp, p->grab_delta, fade * p->f); | |||||
| } | |||||
| static void sculpt_kelvinlet_grab_biscale(float disp[3], | |||||
| const float vertex_co[3], | |||||
| const float location[3], | |||||
| float UNUSED(normal[3]), | |||||
| KelvinletParams *p) | |||||
| { | |||||
| float r_v[3]; | |||||
| float r_e[3]; | |||||
| float kvl[3]; | |||||
| sub_v3_v3v3(r_v, vertex_co, location); | |||||
| float r = len_v3(r_v); | |||||
| sculpt_init_kelvinlet_grab(r_e, kvl, p, r, 2); | |||||
| /* Regularized Kelvinlets: Multi-scale extrapolation. Formula (11) */ | |||||
| const float u = kvl[0] - kvl[1]; | |||||
| float fade = u * p->c / ((1.0f / p->radius_scaled[0]) - (1.0f / p->radius_scaled[1])); | |||||
| mul_v3_v3fl(disp, p->grab_delta, fade * p->f); | |||||
| } | |||||
| static void sculpt_kelvinlet_grab_triscale(float disp[3], | |||||
| const float vertex_co[3], | |||||
| const float location[3], | |||||
| float UNUSED(normal[3]), | |||||
| KelvinletParams *p) | |||||
| { | |||||
| float r_v[3]; | |||||
| float r_e[3]; | |||||
| float kvl[3]; | |||||
| sub_v3_v3v3(r_v, vertex_co, location); | |||||
| float r = len_v3(r_v); | |||||
| sculpt_init_kelvinlet_grab(r_e, kvl, p, r, 3); | |||||
| /* Regularized Kelvinlets: Multi-scale extrapolation. Formula (11) */ | |||||
| float weights[3]; | |||||
| weights[0] = 1.0f; | |||||
| weights[1] = -( | |||||
| (p->radius_scaled[2] * p->radius_scaled[2] - p->radius_scaled[0] * p->radius_scaled[0]) / | |||||
| (p->radius_scaled[2] * p->radius_scaled[2] - p->radius_scaled[1] * p->radius_scaled[1])); | |||||
| weights[2] = | |||||
| ((p->radius_scaled[1] * p->radius_scaled[1] - p->radius_scaled[0] * p->radius_scaled[0]) / | |||||
| (p->radius_scaled[2] * p->radius_scaled[2] - p->radius_scaled[1] * p->radius_scaled[1])); | |||||
| const float u = weights[0] * kvl[0] + weights[1] * kvl[1] + weights[2] * kvl[2]; | |||||
| float fade = u * p->c / | |||||
| (weights[0] / p->radius_scaled[0] + weights[1] / p->radius_scaled[1] + | |||||
| weights[2] / p->radius_scaled[2]); | |||||
| mul_v3_v3fl(disp, p->grab_delta, fade * p->f); | |||||
| } | |||||
| /* Regularized Kelvinlets: Formula (16) */ | /* Regularized Kelvinlets: Formula (16) */ | ||||
| static void sculpt_kelvinlet_scale(float disp[3], | static void sculpt_kelvinlet_scale(float disp[3], | ||||
| const float vertex_co[3], | const float vertex_co[3], | ||||
| const float location[3], | const float location[3], | ||||
| float UNUSED(normal[3]), | float UNUSED(normal[3]), | ||||
| KelvinletParams *p) | KelvinletParams *p) | ||||
| { | { | ||||
| float r_v[3]; | float r_v[3]; | ||||
| sub_v3_v3v3(r_v, vertex_co, location); | sub_v3_v3v3(r_v, vertex_co, location); | ||||
| float r = len_v3(r_v); | float r = len_v3(r_v); | ||||
| float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled); | float r_e = sqrtf(r * r + p->radius_scaled[0] * p->radius_scaled[0]); | ||||
| float u = (2.0f * p->b - p->a) * ((1.0f / (r_e * r_e * r_e))) + | float u = (2.0f * p->b - p->a) * ((1.0f / (r_e * r_e * r_e))) + | ||||
| ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e)); | ((3.0f * p->radius_scaled[0] * p->radius_scaled[0]) / | ||||
| (2.0f * r_e * r_e * r_e * r_e * r_e)); | |||||
| float fade = u * p->c; | float fade = u * p->c; | ||||
| mul_v3_v3fl(disp, r_v, fade * p->f); | mul_v3_v3fl(disp, r_v, fade * p->f); | ||||
| } | } | ||||
| /* Regularized Kelvinlets: Formula (15) */ | /* Regularized Kelvinlets: Formula (15) */ | ||||
| static void sculpt_kelvinlet_twist(float disp[3], | static void sculpt_kelvinlet_twist(float disp[3], | ||||
| const float vertex_co[3], | const float vertex_co[3], | ||||
| const float location[3], | const float location[3], | ||||
| float normal[3], | float normal[3], | ||||
| KelvinletParams *p) | KelvinletParams *p) | ||||
| { | { | ||||
| float r_v[3], q_r[3]; | float r_v[3], q_r[3]; | ||||
| sub_v3_v3v3(r_v, vertex_co, location); | sub_v3_v3v3(r_v, vertex_co, location); | ||||
| float r = len_v3(r_v); | float r = len_v3(r_v); | ||||
| float r_e = sqrtf(r * r + p->radius_scaled * p->radius_scaled); | float r_e = sqrtf(r * r + p->radius_scaled[0] * p->radius_scaled[0]); | ||||
| float u = -p->a * ((1.0f / (r_e * r_e * r_e))) + | float u = -p->a * ((1.0f / (r_e * r_e * r_e))) + | ||||
| ((3.0f * p->radius_scaled * p->radius_scaled) / (2.0f * r_e * r_e * r_e * r_e * r_e)); | ((3.0f * p->radius_scaled[0] * p->radius_scaled[0]) / | ||||
| (2.0f * r_e * r_e * r_e * r_e * r_e)); | |||||
| float fade = u * p->c; | float fade = u * p->c; | ||||
| cross_v3_v3v3(q_r, normal, r_v); | cross_v3_v3v3(q_r, normal, r_v); | ||||
| mul_v3_v3fl(disp, q_r, fade * p->f); | mul_v3_v3fl(disp, q_r, fade * p->f); | ||||
| } | } | ||||
| static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, | static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, | ||||
| const int n, | const int n, | ||||
| const TaskParallelTLS *__restrict UNUSED(tls)) | const TaskParallelTLS *__restrict UNUSED(tls)) | ||||
| Show All 11 Lines | static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, | ||||
| const float bstrength = ss->cache->bstrength; | const float bstrength = ss->cache->bstrength; | ||||
| sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); | sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); | ||||
| proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; | proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; | ||||
| /* Maybe this can be exposed to the user */ | /* Maybe this can be exposed to the user */ | ||||
| float radius_e[3] = {1.0f, 2.0f, 2.0f}; | float radius_e[3] = {1.0f, 2.0f, 2.0f}; | ||||
| float r_e[3]; | |||||
| float kvl[3]; | |||||
| float radius_scaled[3]; | float radius_scaled[3]; | ||||
| radius_scaled[0] = ss->cache->radius * radius_e[0]; | radius_scaled[0] = ss->cache->radius * radius_e[0]; | ||||
| radius_scaled[1] = radius_scaled[0] * radius_e[1]; | radius_scaled[1] = radius_scaled[0] * radius_e[1]; | ||||
| radius_scaled[2] = radius_scaled[1] * radius_e[2]; | radius_scaled[2] = radius_scaled[1] * radius_e[2]; | ||||
| float shear_modulus = 1.0f; | float shear_modulus = 1.0f; | ||||
| float poisson_ratio = brush->elastic_deform_volume_preservation; | float poisson_ratio = brush->elastic_deform_volume_preservation; | ||||
| Show All 14 Lines | if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) { | ||||
| int symm = ss->cache->mirror_symmetry_pass; | int symm = ss->cache->mirror_symmetry_pass; | ||||
| if (symm == 1 || symm == 2 || symm == 4 || symm == 7) { | if (symm == 1 || symm == 2 || symm == 4 || symm == 7) { | ||||
| dir = -dir; | dir = -dir; | ||||
| } | } | ||||
| } | } | ||||
| BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) | ||||
| { | { | ||||
| sculpt_orig_vert_data_update(&orig_data, &vd); | sculpt_orig_vert_data_update(&orig_data, &vd); | ||||
| float fade, final_disp[3], weights[3]; | float final_disp[3]; | ||||
| float r = len_v3v3(location, orig_data.co); | |||||
| KelvinletParams params; | KelvinletParams params; | ||||
| params.a = a; | params.a = a; | ||||
| params.b = b; | params.b = b; | ||||
| params.c = c; | params.c = c; | ||||
| params.radius_scaled = radius_scaled[0]; | params.radius_scaled = radius_scaled; | ||||
| copy_v3_v3(params.grab_delta, grab_delta); | |||||
| int multi_scale_it = sculpt_kelvinlet_get_scale_iteration_count(brush->elastic_deform_type); | normalize_v3(params.grab_delta); | ||||
jbakkerUnsubmitted Done Inline Actionsso grab_delta is not a delta, but a direction. or this is something to investigate or use the correct namings. jbakker: so `grab_delta` is not a delta, but a direction. or this is something to investigate or use the… | |||||
| for (int it = 0; it < max_ii(1, multi_scale_it); it++) { | |||||
| r_e[it] = sqrtf(r * r + radius_scaled[it] * radius_scaled[it]); | |||||
| } | |||||
| /* Regularized Kelvinlets: Formula (6) */ | |||||
| for (int s_it = 0; s_it < multi_scale_it; s_it++) { | |||||
| kvl[s_it] = ((a - b) / r_e[s_it]) + ((b * r * r) / (r_e[s_it] * r_e[s_it] * r_e[s_it])) + | |||||
| ((a * radius_scaled[s_it] * radius_scaled[s_it]) / | |||||
| (2.0f * r_e[s_it] * r_e[s_it] * r_e[s_it])); | |||||
| } | |||||
| switch (brush->elastic_deform_type) { | switch (brush->elastic_deform_type) { | ||||
| /* Regularized Kelvinlets: Multi-scale extrapolation. Formula (11) */ | |||||
| case BRUSH_ELASTIC_DEFORM_GRAB: | case BRUSH_ELASTIC_DEFORM_GRAB: | ||||
| fade = kvl[0] * c; | params.f = len_v3(grab_delta) * bstrength * 10.0f; | ||||
| mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.f); | sculpt_kelvinet_integrate(sculpt_kelvinlet_grab, | ||||
| final_disp, | |||||
| orig_data.co, | |||||
| location, | |||||
| ss->cache->sculpt_normal_symm, | |||||
| ¶ms); | |||||
| break; | break; | ||||
| case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: { | case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: { | ||||
| const float u = kvl[0] - kvl[1]; | params.f = len_v3(grab_delta) * bstrength * 10.0f; | ||||
| fade = u * c / ((1.0f / radius_scaled[0]) - (1.0f / radius_scaled[1])); | sculpt_kelvinet_integrate(sculpt_kelvinlet_grab_biscale, | ||||
| mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.0f); | final_disp, | ||||
| orig_data.co, | |||||
| location, | |||||
| ss->cache->sculpt_normal_symm, | |||||
| ¶ms); | |||||
| break; | break; | ||||
| } | } | ||||
| case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: { | case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: { | ||||
| weights[0] = 1.0f; | params.f = len_v3(grab_delta) * bstrength * 10.0f; | ||||
| weights[1] = -( | sculpt_kelvinet_integrate(sculpt_kelvinlet_grab_triscale, | ||||
| (radius_scaled[2] * radius_scaled[2] - radius_scaled[0] * radius_scaled[0]) / | final_disp, | ||||
| (radius_scaled[2] * radius_scaled[2] - radius_scaled[1] * radius_scaled[1])); | orig_data.co, | ||||
| weights[2] = ((radius_scaled[1] * radius_scaled[1] - radius_scaled[0] * radius_scaled[0]) / | location, | ||||
| (radius_scaled[2] * radius_scaled[2] - radius_scaled[1] * radius_scaled[1])); | ss->cache->sculpt_normal_symm, | ||||
| ¶ms); | |||||
| const float u = weights[0] * kvl[0] + weights[1] * kvl[1] + weights[2] * kvl[2]; | |||||
| fade = u * c / | |||||
| (weights[0] / radius_scaled[0] + weights[1] / radius_scaled[1] + | |||||
| weights[2] / radius_scaled[2]); | |||||
| mul_v3_v3fl(final_disp, grab_delta, fade * bstrength * 20.0f); | |||||
| break; | break; | ||||
| } | } | ||||
| case BRUSH_ELASTIC_DEFORM_SCALE: | case BRUSH_ELASTIC_DEFORM_SCALE: | ||||
| params.f = len_v3(grab_delta) * dir * bstrength; | params.f = len_v3(grab_delta) * dir * bstrength; | ||||
| sculpt_kelvinet_integrate(sculpt_kelvinlet_scale, | sculpt_kelvinet_integrate(sculpt_kelvinlet_scale, | ||||
| final_disp, | final_disp, | ||||
| orig_data.co, | orig_data.co, | ||||
| location, | location, | ||||
| ▲ Show 20 Lines • Show All 6,226 Lines • Show Last 20 Lines | |||||
we should add a the link to the original paper and add its name as numbers may get outdated more quickly and does not tell us a thing https://graphics.pixar.com/library/Kelvinlets/gradDerivation.pdf