Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/kelvinlet.c')
-rw-r--r--source/blender/blenkernel/intern/kelvinlet.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/kelvinlet.c b/source/blender/blenkernel/intern/kelvinlet.c
new file mode 100644
index 00000000000..a7b48107873
--- /dev/null
+++ b/source/blender/blenkernel/intern/kelvinlet.c
@@ -0,0 +1,215 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_kelvinlet.h"
+
+/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
+ * Pixar Technical Memo #17-03 */
+
+void BKE_kelvinlet_init_params(
+ KelvinletParams *params, float radius, float force, float shear_modulus, float poisson_ratio)
+{
+ params->a = 1.0f / (4.0f * (float)M_PI * shear_modulus);
+ params->b = params->a / (4.0f * (1.0f - poisson_ratio));
+ params->c = 2 * (3.0f * params->a - 2.0f * params->b);
+
+ /* Used in scale and twist. */
+ params->f = force;
+
+ /* This can be exposed if needed */
+ const float radius_e[KELVINLET_MAX_ITERATIONS] = {1.0f, 2.0f, 2.0f};
+ params->radius_scaled[0] = radius * radius_e[0];
+ params->radius_scaled[1] = params->radius_scaled[0] * radius_e[1];
+ params->radius_scaled[2] = params->radius_scaled[1] * radius_e[2];
+}
+
+static void init_kelvinlet_grab(float radius_e[3],
+ float kelvinlet[3],
+ const float radius,
+ const KelvinletParams *params,
+ const int num_iterations)
+{
+ const float a = params->a;
+ const float b = params->b;
+ const float *radius_scaled = params->radius_scaled;
+
+ for (int i = 0; i < num_iterations; i++) {
+ radius_e[i] = sqrtf(pow2f(radius) + pow2f(params->radius_scaled[i]));
+ }
+
+ /* Regularized Kelvinlets: Formula (6) */
+ for (int i = 0; i < num_iterations; i++) {
+ kelvinlet[i] = ((a - b) / radius_e[i]) + ((b * pow2f(radius)) / pow3f(radius_e[i])) +
+ ((a * pow2f(radius_scaled[i])) / (2.0f * pow3f(radius_e[i])));
+ }
+}
+
+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])
+{
+ float radius_e[3], kelvinlet[3];
+ const float c = params->c;
+ const float radius = len_v3v3(brush_location, elem_orig_co);
+
+ init_kelvinlet_grab(radius_e, kelvinlet, radius, params, 1);
+
+ const float fade = kelvinlet[0] * c;
+
+ mul_v3_v3fl(radius_elem_disp, brush_delta, fade);
+}
+
+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])
+{
+ float radius_e[3], kelvinlet[3];
+ const float c = params->c;
+ const float *radius_scaled = params->radius_scaled;
+ float radius = len_v3v3(brush_location, elem_orig_co);
+
+ init_kelvinlet_grab(radius_e, kelvinlet, radius, params, 2);
+
+ const float u = kelvinlet[0] - kelvinlet[1];
+ const float fade = u * c / ((1.0f / radius_scaled[0]) - (1.0f / radius_scaled[1]));
+
+ mul_v3_v3fl(radius_elem_disp, brush_delta, fade);
+}
+
+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])
+{
+ float radius_e[3], kelvinlet[3], weights[3];
+ const float c = params->c;
+ const float *radius_scaled = params->radius_scaled;
+ const float radius = len_v3v3(brush_location, elem_orig_co);
+
+ init_kelvinlet_grab(radius_e, kelvinlet, radius, params, 3);
+
+ weights[0] = 1.0f;
+ weights[1] = -((pow2f(radius_scaled[2]) - pow2f(radius_scaled[0])) /
+ (pow2f(radius_scaled[2]) - pow2f(radius_scaled[1])));
+ weights[2] = ((pow2f(radius_scaled[1]) - pow2f(radius_scaled[0])) /
+ (pow2f(radius_scaled[2]) - pow2f(radius_scaled[1])));
+
+ const float u = weights[0] * kelvinlet[0] + weights[1] * kelvinlet[1] +
+ weights[2] * kelvinlet[2];
+ const float fade = u * c /
+ (weights[0] / radius_scaled[0] + weights[1] / radius_scaled[1] +
+ weights[2] / radius_scaled[2]);
+
+ mul_v3_v3fl(radius_elem_disp, brush_delta, fade);
+}
+
+typedef void (*kelvinlet_fn)(
+ float[3], const float *, const float *, const float *, const KelvinletParams *);
+
+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)
+{
+ float k[4][3], k_it[4][3];
+ kelvinlet(k[0], vertex_co, location, normal, p);
+ copy_v3_v3(k_it[0], k[0]);
+ mul_v3_fl(k_it[0], 0.5f);
+ add_v3_v3v3(k_it[0], vertex_co, k_it[0]);
+ kelvinlet(k[1], k_it[0], location, normal, p);
+ copy_v3_v3(k_it[1], k[1]);
+ mul_v3_fl(k_it[1], 0.5f);
+ add_v3_v3v3(k_it[1], vertex_co, k_it[1]);
+ kelvinlet(k[2], k_it[1], location, normal, p);
+ copy_v3_v3(k_it[2], k[2]);
+ add_v3_v3v3(k_it[2], vertex_co, k_it[2]);
+ sub_v3_v3v3(k_it[2], k_it[2], location);
+ kelvinlet(k[3], k_it[2], location, normal, p);
+ copy_v3_v3(r_disp, k[0]);
+ madd_v3_v3fl(r_disp, k[1], 2.0f);
+ madd_v3_v3fl(r_disp, k[2], 2.0f);
+ add_v3_v3(r_disp, k[3]);
+ mul_v3_fl(r_disp, 1.0f / 6.0f);
+}
+
+/* Regularized Kelvinlets: Formula (16) */
+static void kelvinlet_scale(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ const float UNUSED(normal[3]),
+ const KelvinletParams *p)
+{
+ float radius_vertex[3];
+ sub_v3_v3v3(radius_vertex, vertex_co, location);
+ const float radius = len_v3(radius_vertex);
+ const float radius_e = sqrtf(pow2f(radius) + pow2f(p->radius_scaled[0]));
+ const float u = (2.0f * p->b - p->a) * ((1.0f / pow3f(radius_e))) +
+ ((3.0f * pow2f(p->radius_scaled[0])) / (2.0f * pow5f(radius_e)));
+ const float fade = u * p->c;
+ mul_v3_v3fl(disp, radius_vertex, fade * p->f);
+}
+
+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])
+{
+ sculpt_kelvinet_integrate(
+ kelvinlet_scale, radius_elem_disp, elem_orig_co, brush_location, surface_normal, params);
+}
+
+/* Regularized Kelvinlets: Formula (15) */
+static void kelvinlet_twist(float disp[3],
+ const float vertex_co[3],
+ const float location[3],
+ const float normal[3],
+ const KelvinletParams *p)
+{
+ float radius_vertex[3], q_r[3];
+ sub_v3_v3v3(radius_vertex, vertex_co, location);
+ const float radius = len_v3(radius_vertex);
+ const float radius_e = sqrtf(pow2f(radius) + pow2f(p->radius_scaled[0]));
+ const float u = -p->a * ((1.0f / pow3f(radius_e))) +
+ ((3.0f * pow2f(p->radius_scaled[0])) / (2.0f * pow5f(radius_e)));
+ const float fade = u * p->c;
+ cross_v3_v3v3(q_r, normal, radius_vertex);
+ mul_v3_v3fl(disp, q_r, fade * p->f);
+}
+
+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])
+{
+ sculpt_kelvinet_integrate(
+ kelvinlet_twist, radius_elem_disp, elem_orig_co, brush_location, surface_normal, params);
+}