Blender V4.3
kelvinlet.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BKE_kelvinlet.h"
10#include "BLI_math_base.h"
11#include "BLI_math_vector.h"
12
13/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
14 * Pixar Technical Memo #17-03 */
15
17 KelvinletParams *params, float radius, float force, float shear_modulus, float poisson_ratio)
18{
19 params->a = 1.0f / (4.0f * float(M_PI) * shear_modulus);
20 params->b = params->a / (4.0f * (1.0f - poisson_ratio));
21 params->c = 2 * (3.0f * params->a - 2.0f * params->b);
22
23 /* Used in scale and twist. */
24 params->f = force;
25
26 /* This can be exposed if needed */
27 const float radius_e[KELVINLET_MAX_ITERATIONS] = {1.0f, 2.0f, 2.0f};
28 params->radius_scaled[0] = radius * radius_e[0];
29 params->radius_scaled[1] = params->radius_scaled[0] * radius_e[1];
30 params->radius_scaled[2] = params->radius_scaled[1] * radius_e[2];
31}
32
33static void init_kelvinlet_grab(float radius_e[3],
34 float kelvinlet[3],
35 const float radius,
37 const int num_iterations)
38{
39 const float a = params->a;
40 const float b = params->b;
41 const float *radius_scaled = params->radius_scaled;
42
43 for (int i = 0; i < num_iterations; i++) {
44 radius_e[i] = sqrtf(pow2f(radius) + pow2f(params->radius_scaled[i]));
45 }
46
47 /* Regularized Kelvinlets: Formula (6) */
48 for (int i = 0; i < num_iterations; i++) {
49 kelvinlet[i] = ((a - b) / radius_e[i]) + ((b * pow2f(radius)) / pow3f(radius_e[i])) +
50 ((a * pow2f(radius_scaled[i])) / (2.0f * pow3f(radius_e[i])));
51 }
52}
53
54void BKE_kelvinlet_grab(float radius_elem_disp[3],
56 const float elem_orig_co[3],
57 const float brush_location[3],
58 const float brush_delta[3])
59{
60 float radius_e[3], kelvinlet[3];
61 const float c = params->c;
62 const float radius = len_v3v3(brush_location, elem_orig_co);
63
64 init_kelvinlet_grab(radius_e, kelvinlet, radius, params, 1);
65
66 const float fade = kelvinlet[0] * c;
67
68 mul_v3_v3fl(radius_elem_disp, brush_delta, fade);
69}
70
71void BKE_kelvinlet_grab_biscale(float radius_elem_disp[3],
73 const float elem_orig_co[3],
74 const float brush_location[3],
75 const float brush_delta[3])
76{
77 float radius_e[3], kelvinlet[3];
78 const float c = params->c;
79 const float *radius_scaled = params->radius_scaled;
80 float radius = len_v3v3(brush_location, elem_orig_co);
81
82 init_kelvinlet_grab(radius_e, kelvinlet, radius, params, 2);
83
84 const float u = kelvinlet[0] - kelvinlet[1];
85 const float fade = u * c / ((1.0f / radius_scaled[0]) - (1.0f / radius_scaled[1]));
86
87 mul_v3_v3fl(radius_elem_disp, brush_delta, fade);
88}
89
90void BKE_kelvinlet_grab_triscale(float radius_elem_disp[3],
92 const float elem_orig_co[3],
93 const float brush_location[3],
94 const float brush_delta[3])
95{
96 float radius_e[3], kelvinlet[3], weights[3];
97 const float c = params->c;
98 const float *radius_scaled = params->radius_scaled;
99 const float radius = len_v3v3(brush_location, elem_orig_co);
100
101 init_kelvinlet_grab(radius_e, kelvinlet, radius, params, 3);
102
103 weights[0] = 1.0f;
104 weights[1] = -((pow2f(radius_scaled[2]) - pow2f(radius_scaled[0])) /
105 (pow2f(radius_scaled[2]) - pow2f(radius_scaled[1])));
106 weights[2] = ((pow2f(radius_scaled[1]) - pow2f(radius_scaled[0])) /
107 (pow2f(radius_scaled[2]) - pow2f(radius_scaled[1])));
108
109 const float u = weights[0] * kelvinlet[0] + weights[1] * kelvinlet[1] +
110 weights[2] * kelvinlet[2];
111 const float fade = u * c /
112 (weights[0] / radius_scaled[0] + weights[1] / radius_scaled[1] +
113 weights[2] / radius_scaled[2]);
114
115 mul_v3_v3fl(radius_elem_disp, brush_delta, fade);
116}
117
119 void (*)(float[3], const float *, const float *, const float *, const KelvinletParams *);
120
122 float r_disp[3],
123 const float vertex_co[3],
124 const float location[3],
125 const float normal[3],
126 const KelvinletParams *p)
127{
128 float k[4][3], k_it[4][3];
129 kelvinlet(k[0], vertex_co, location, normal, p);
130 copy_v3_v3(k_it[0], k[0]);
131 mul_v3_fl(k_it[0], 0.5f);
132 add_v3_v3v3(k_it[0], vertex_co, k_it[0]);
133 kelvinlet(k[1], k_it[0], location, normal, p);
134 copy_v3_v3(k_it[1], k[1]);
135 mul_v3_fl(k_it[1], 0.5f);
136 add_v3_v3v3(k_it[1], vertex_co, k_it[1]);
137 kelvinlet(k[2], k_it[1], location, normal, p);
138 copy_v3_v3(k_it[2], k[2]);
139 add_v3_v3v3(k_it[2], vertex_co, k_it[2]);
140 sub_v3_v3v3(k_it[2], k_it[2], location);
141 kelvinlet(k[3], k_it[2], location, normal, p);
142 copy_v3_v3(r_disp, k[0]);
143 madd_v3_v3fl(r_disp, k[1], 2.0f);
144 madd_v3_v3fl(r_disp, k[2], 2.0f);
145 add_v3_v3(r_disp, k[3]);
146 mul_v3_fl(r_disp, 1.0f / 6.0f);
147}
148
149/* Regularized Kelvinlets: Formula (16) */
150static void kelvinlet_scale(float disp[3],
151 const float vertex_co[3],
152 const float location[3],
153 const float[3] /*normal*/,
154 const KelvinletParams *p)
155{
156 float radius_vertex[3];
157 sub_v3_v3v3(radius_vertex, vertex_co, location);
158 const float radius = len_v3(radius_vertex);
159 const float radius_e = sqrtf(pow2f(radius) + pow2f(p->radius_scaled[0]));
160 const float u = (2.0f * p->b - p->a) * (1.0f / pow3f(radius_e)) +
161 ((3.0f * pow2f(p->radius_scaled[0])) / (2.0f * pow5f(radius_e)));
162 const float fade = u * p->c;
163 mul_v3_v3fl(disp, radius_vertex, fade * p->f);
164}
165
166void BKE_kelvinlet_scale(float radius_elem_disp[3],
167 const KelvinletParams *params,
168 const float elem_orig_co[3],
169 const float brush_location[3],
170 const float surface_normal[3])
171{
173 kelvinlet_scale, radius_elem_disp, elem_orig_co, brush_location, surface_normal, params);
174}
175
176/* Regularized Kelvinlets: Formula (15) */
177static void kelvinlet_twist(float disp[3],
178 const float vertex_co[3],
179 const float location[3],
180 const float normal[3],
181 const KelvinletParams *p)
182{
183 float radius_vertex[3], q_r[3];
184 sub_v3_v3v3(radius_vertex, vertex_co, location);
185 const float radius = len_v3(radius_vertex);
186 const float radius_e = sqrtf(pow2f(radius) + pow2f(p->radius_scaled[0]));
187 const float u = -p->a * (1.0f / pow3f(radius_e)) +
188 ((3.0f * pow2f(p->radius_scaled[0])) / (2.0f * pow5f(radius_e)));
189 const float fade = u * p->c;
190 cross_v3_v3v3(q_r, normal, radius_vertex);
191 mul_v3_v3fl(disp, q_r, fade * p->f);
192}
193
194void BKE_kelvinlet_twist(float radius_elem_disp[3],
195 const KelvinletParams *params,
196 const float elem_orig_co[3],
197 const float brush_location[3],
198 const float surface_normal[3])
199{
201 kelvinlet_twist, radius_elem_disp, elem_orig_co, brush_location, surface_normal, params);
202}
#define KELVINLET_MAX_ITERATIONS
MINLINE float pow2f(float x)
MINLINE float pow3f(float x)
#define M_PI
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
local_group_size(16, 16) .push_constant(Type b
#define sqrtf(x)
draw_view in_light_buf[] float
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(*)(float[3], const float *, const float *, const float *, const KelvinletParams *) kelvinlet_fn
Definition kelvinlet.cc:118
void BKE_kelvinlet_grab(float radius_elem_disp[3], const KelvinletParams *params, const float elem_orig_co[3], const float brush_location[3], const float brush_delta[3])
Definition kelvinlet.cc:54
void BKE_kelvinlet_grab_triscale(float radius_elem_disp[3], const KelvinletParams *params, const float elem_orig_co[3], const float brush_location[3], const float brush_delta[3])
Definition kelvinlet.cc:90
static void init_kelvinlet_grab(float radius_e[3], float kelvinlet[3], const float radius, const KelvinletParams *params, const int num_iterations)
Definition kelvinlet.cc:33
void BKE_kelvinlet_init_params(KelvinletParams *params, float radius, float force, float shear_modulus, float poisson_ratio)
Definition kelvinlet.cc:16
void BKE_kelvinlet_grab_biscale(float radius_elem_disp[3], const KelvinletParams *params, const float elem_orig_co[3], const float brush_location[3], const float brush_delta[3])
Definition kelvinlet.cc:71
static void sculpt_kelvinet_integrate(kelvinlet_fn kelvinlet, float r_disp[3], const float vertex_co[3], const float location[3], const float normal[3], const KelvinletParams *p)
Definition kelvinlet.cc:121
static void kelvinlet_scale(float disp[3], const float vertex_co[3], const float location[3], const float[3], const KelvinletParams *p)
Definition kelvinlet.cc:150
void BKE_kelvinlet_scale(float radius_elem_disp[3], const KelvinletParams *params, const float elem_orig_co[3], const float brush_location[3], const float surface_normal[3])
Definition kelvinlet.cc:166
static void kelvinlet_twist(float disp[3], const float vertex_co[3], const float location[3], const float normal[3], const KelvinletParams *p)
Definition kelvinlet.cc:177
void BKE_kelvinlet_twist(float radius_elem_disp[3], const KelvinletParams *params, const float elem_orig_co[3], const float brush_location[3], const float surface_normal[3])
Definition kelvinlet.cc:194
MINLINE float pow5f(float x)
CCL_NAMESPACE_BEGIN ccl_device float fade(float t)
Definition noise.h:14
float radius_scaled[KELVINLET_MAX_ITERATIONS]