Files
test2/source/blender/blenkernel/intern/kelvinlet.c
Sergey Sharybin a12a8a71bb Remove "All Rights Reserved" from Blender Foundation copyright code
The goal is to solve confusion of the "All rights reserved" for licensing
code under an open-source license.

The phrase "All rights reserved" comes from a historical convention that
required this phrase for the copyright protection to apply. This convention
is no longer relevant.

However, even though the phrase has no meaning in establishing the copyright
it has not lost meaning in terms of licensing.

This change makes it so code under the Blender Foundation copyright does
not use "all rights reserved". This is also how the GPL license itself
states how to apply it to the source code:

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software ...

This change does not change copyright notice in cases when the copyright
is dual (BF and an author), or just an author of the code. It also does
mot change copyright which is inherited from NaN Holding BV as it needs
some further investigation about what is the proper way to handle it.
2023-03-30 10:51:59 +02:00

200 lines
7.5 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright Blender Foundation */
/** \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);
}