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')
-rw-r--r--source/blender/blenkernel/BKE_mesh_remesh_voxel.h3
-rw-r--r--source/blender/blenkernel/BKE_softbody.h4
-rw-r--r--source/blender/blenkernel/CMakeLists.txt12
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.c115
-rw-r--r--source/blender/blenkernel/intern/object.c1
-rw-r--r--source/blender/blenkernel/intern/softbody.c288
-rw-r--r--source/blender/blenloader/intern/readfile.c6
-rw-r--r--source/blender/blenloader/intern/writefile.c5
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_remesh.c52
-rw-r--r--source/blender/gpu/intern/gpu_backend.hh3
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h1
-rw-r--r--source/blender/makesdna/DNA_object_force_types.h33
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c1
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c179
16 files changed, 665 insertions, 40 deletions
diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
index 2265fa6e105..277747e3e27 100644
--- a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
+++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h
@@ -56,6 +56,9 @@ struct Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(struct Mesh *mesh,
bool adaptive_scale,
void *update_cb,
void *update_cb_data);
+struct Mesh *BKE_mesh_remesh_tetgen_to_mesh_nomain(struct Mesh *mesh,
+ unsigned int **tets,
+ int *numtets);
/* Data reprojection functions */
void BKE_mesh_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source);
diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h
index 28d299679ed..fb377302c7a 100644
--- a/source/blender/blenkernel/BKE_softbody.h
+++ b/source/blender/blenkernel/BKE_softbody.h
@@ -30,6 +30,7 @@ struct Depsgraph;
struct Object;
struct Scene;
struct SoftBody;
+struct ReportList;
typedef struct BodyPoint {
float origS[3], origE[3], origT[3], pos[3], vec[3], force[3];
@@ -49,6 +50,9 @@ typedef struct BodyPoint {
/* allocates and initializes general main data */
extern struct SoftBody *sbNew(struct Scene *scene);
+/* reads custom structs for file i/o */
+extern void sbCustomRead(struct Object *ob);
+
/* frees internal data and softbody itself */
extern void sbFree(struct Object *ob);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 6f32eb8a90f..6cf72eb09d9 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -45,6 +45,7 @@ set(INC
../../../intern/iksolver/extern
../../../intern/atomic
../../../intern/clog
+ ../../../intern/softbody
../../../intern/libmv
../../../intern/mantaflow/extern
../../../intern/memutil
@@ -433,6 +434,7 @@ set(LIB
bf_ikplugin
bf_imbuf
bf_intern_clog
+ bf_intern_admmpd
bf_intern_ghost
bf_intern_guardedalloc
bf_intern_libmv # Uses stub when disabled.
@@ -685,6 +687,16 @@ if(WITH_QUADRIFLOW)
add_definitions(-DWITH_QUADRIFLOW)
endif()
+if(WITH_TETGEN)
+ list(APPEND INC
+ ../../../intern/tetgen
+ )
+ list(APPEND LIB
+ bf_intern_tetgen
+ )
+ add_definitions(-DWITH_TETGEN)
+endif()
+
if(WITH_XR_OPENXR)
add_definitions(-DWITH_XR_OPENXR)
endif()
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.c b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
index 010b306ec76..05cc9769bf7 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.c
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.c
@@ -56,6 +56,10 @@
# include "quadriflow_capi.hpp"
#endif
+#ifdef WITH_TETGEN
+# include "tetgen_api.h"
+#endif
+
#ifdef WITH_OPENVDB
struct OpenVDBLevelSet *BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(
Mesh *mesh, struct OpenVDBTransform *transform)
@@ -260,6 +264,117 @@ static Mesh *BKE_mesh_remesh_quadriflow(Mesh *input_mesh,
}
#endif
+#ifdef WITH_TETGEN
+static Mesh *BKE_mesh_remesh_tetgen(Mesh *input_mesh, unsigned int **tets, int *numtets)
+{
+ // Ensure that the triangulated mesh data is up to data
+ BKE_mesh_runtime_looptri_recalc(input_mesh);
+ const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh);
+
+ // Gather the required data
+ MVertTri *verttri = MEM_callocN(sizeof(*verttri) * BKE_mesh_runtime_looptri_len(input_mesh),
+ "remesh_looptri");
+ BKE_mesh_runtime_verttri_from_looptri(
+ verttri, input_mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(input_mesh));
+
+ unsigned int totfaces = BKE_mesh_runtime_looptri_len(input_mesh);
+ unsigned int totverts = input_mesh->totvert;
+ float *verts = (float *)MEM_malloc_arrayN(totverts * 3, sizeof(float), "remesh_input_verts");
+ unsigned int *faces = (unsigned int *)MEM_malloc_arrayN(
+ totfaces * 3, sizeof(unsigned int), "remesh_intput_faces");
+
+ for (unsigned int i = 0; i < totverts; i++) {
+ MVert *mvert = &input_mesh->mvert[i];
+ verts[i * 3] = mvert->co[0];
+ verts[i * 3 + 1] = mvert->co[1];
+ verts[i * 3 + 2] = mvert->co[2];
+ }
+
+ for (unsigned int i = 0; i < totfaces; i++) {
+ MVertTri *vt = &verttri[i];
+ faces[i * 3] = vt->tri[0];
+ faces[i * 3 + 1] = vt->tri[1];
+ faces[i * 3 + 2] = vt->tri[2];
+ }
+
+ // Call the tetgen remesher
+ TetGenRemeshData tg;
+ init_tetgenremeshdata(&tg);
+ tg.in_totfaces = totfaces;
+ tg.in_totverts = totverts;
+ tg.in_verts = verts;
+ tg.in_faces = faces;
+ bool success = tetgen_resmesh(&tg);
+
+ MEM_freeN(verts);
+ verts = NULL;
+ tg.in_verts = NULL;
+ MEM_freeN(faces);
+ faces = NULL;
+ tg.in_faces = NULL;
+ MEM_freeN(verttri);
+ verttri = NULL;
+
+ Mesh *mesh = NULL;
+ if (success) {
+ // Construct the new output mesh
+ mesh = BKE_mesh_new_nomain(tg.out_totverts, 0, 0, (tg.out_totfacets * 3), tg.out_totfacets);
+
+ for (int i = 0; i < tg.out_totverts; i++) {
+ copy_v3_v3(mesh->mvert[i].co, &tg.out_verts[i * 3]);
+ }
+
+ MPoly *mp = mesh->mpoly;
+ MLoop *ml = mesh->mloop;
+ for (int i = 0; i < tg.out_totfacets; i++, mp++, ml += 3) {
+ mp->loopstart = (int)(ml - mesh->mloop);
+ mp->totloop = 3;
+ ml[0].v = tg.out_facets[i * 3];
+ ml[1].v = tg.out_facets[i * 3 + 1];
+ ml[2].v = tg.out_facets[i * 3 + 2];
+ }
+ BKE_mesh_calc_edges(mesh, false, false);
+ BKE_mesh_calc_normals(mesh);
+
+ *numtets = tg.out_tottets;
+ *tets = (unsigned int *)MEM_malloc_arrayN(
+ tg.out_tottets * 4, sizeof(unsigned int), "remesh_output_tets");
+ //*tets = (unsigned int *)malloc(tg.out_tottets*4*sizeof(unsigned int));
+ memcpy(*tets, tg.out_tets, tg.out_tottets * 4 * sizeof(unsigned int));
+
+ } // end success
+
+ if (tg.out_verts != NULL) {
+ MEM_freeN(tg.out_verts);
+ tg.out_verts = NULL;
+ }
+
+ if (tg.out_facets != NULL) {
+ MEM_freeN(tg.out_facets);
+ tg.out_facets = NULL;
+ }
+
+ if (tg.out_tets != NULL) {
+ MEM_freeN(tg.out_tets);
+ tg.out_tets = NULL;
+ }
+
+ return mesh;
+}
+#endif
+
+struct Mesh *BKE_mesh_remesh_tetgen_to_mesh_nomain(struct Mesh *mesh,
+ unsigned int **tets,
+ int *numtets)
+{
+#ifdef WITH_TETGEN
+ return BKE_mesh_remesh_tetgen(mesh, tets, numtets);
+#else
+ UNUSED_VARS(mesh, tets, numtets);
+#endif
+ return NULL;
+}
+
Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(Mesh *mesh,
int target_faces,
int seed,
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 31420b3adc6..15ad653e6f8 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1395,6 +1395,7 @@ Object *BKE_object_add_for_data(
void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag)
{
+
SoftBody *sb = ob_src->soft;
SoftBody *sbn;
bool tagged_no_main = ob_dst->id.tag & LIB_TAG_NO_MAIN;
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 6a6f74d9fb4..bca2af1fb18 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -44,6 +44,8 @@
#include "CLG_log.h"
+#include "admmpd_api.h"
+
#include "MEM_guardedalloc.h"
/* types */
@@ -77,6 +79,8 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+#include "../windowmanager/WM_api.h"
+
#include "PIL_time.h"
static CLG_LogRef LOG = {"bke.softbody"};
@@ -934,8 +938,8 @@ static void free_softbody_intern(SoftBody *sb)
}
}
MEM_freeN(sb->bpoint);
+ sb->bpoint = NULL;
}
-
if (sb->bspring) {
MEM_freeN(sb->bspring);
}
@@ -3081,6 +3085,8 @@ static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts,
{
SoftBody *sb = ob->soft;
if (sb) {
+ // int sb_totpt = sb->totpoint;
+
BodyPoint *bp = sb->bpoint;
int a;
if (sb->solverflags & SBSO_ESTIMATEIPO) {
@@ -3120,9 +3126,30 @@ static void sb_new_scratch(SoftBody *sb)
SoftBody *sbNew(Scene *scene)
{
SoftBody *sb;
-
sb = MEM_callocN(sizeof(SoftBody), "softbody");
+ sb->solver_mode = SOLVER_MODE_LEGACY; // SOLVER_MODE_ADMMPD;
+ sb->admmpd_mesh_mode = 0; // embedded
+ sb->admmpd_substeps = 1;
+ sb->admmpd_max_admm_iters = 20;
+ sb->admmpd_self_collision = 0;
+ sb->admmpd_material = 0; // ARAP
+ sb->admmpd_embed_res = 3;
+ sb->admmpd_converge_eps = 1e-4;
+ sb->admmpd_youngs_exp = 6;
+ sb->admmpd_poisson = 0.399;
+ sb->admmpd_density_kgm3 = 1522;
+ sb->admmpd_ck_exp = 7;
+ sb->admmpd_pk_exp = 4;
+ sb->admmpd_floor_z = -999;
+ sb->admmpd_gravity = -9.8;
+ sb->admmpd_strainlimit_min = 0; // no compression
+ sb->admmpd_strainlimit_max = 100; // 100x stretch
+ sb->admmpd_maxthreads = -1;
+ sb->admmpd_loglevel = 1; // low
+ sb->admmpd_linsolver = 1; // PCG
+ sb->admmpd = MEM_callocN(sizeof(ADMMPDInterfaceData), "SoftBody_admmpd");
+
sb->mediafrict = 0.5f;
sb->nodemass = 1.0f;
sb->grav = 9.8f;
@@ -3183,6 +3210,13 @@ void sbFree(Object *ob)
free_softbody_intern(sb);
if ((ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
+
+ if (sb->admmpd) {
+ admmpd_dealloc(sb->admmpd);
+ MEM_freeN(sb->admmpd);
+ sb->admmpd = NULL;
+ }
+
/* Only free shared data on non-CoW copies */
BKE_ptcache_free_list(&sb->shared->ptcaches);
sb->shared->pointcache = NULL;
@@ -3205,7 +3239,6 @@ void sbFreeSimulation(SoftBody *sb)
void sbObjectToSoftbody(Object *ob)
{
// ob->softflag |= OB_SB_REDO;
-
free_softbody_intern(ob->soft);
}
@@ -3531,6 +3564,98 @@ static void sbStoreLastFrame(struct Depsgraph *depsgraph, Object *object, float
object_orig->soft->last_frame = framenr;
}
+static void update_collider_admmpd(Depsgraph *depsgraph,
+ Collection *collection,
+ Object *vertexowner)
+{
+ SoftBody *sb = vertexowner->soft;
+ if (!sb) {
+ return;
+ }
+ if (!sb->admmpd) {
+ return;
+ }
+
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(
+ depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision);
+
+ // How many faces and vertices do we need to allocate?
+ int tot_verts = 0;
+ int tot_faces = 0;
+ for (int i = 0; i < numobjects; ++i) {
+ Object *ob = objects[i];
+ if (ob->type == OB_MESH) {
+ if (ob->pd && ob->pd->deflect) {
+ CollisionModifierData *cmd = (CollisionModifierData *)BKE_modifiers_findby_type(
+ ob, eModifierType_Collision);
+ if (!cmd)
+ continue;
+ tot_verts += cmd->mvert_num;
+ tot_faces += cmd->tri_num;
+ }
+ }
+ }
+
+ float *obs_v0 = MEM_callocN(sizeof(float) * 3 * tot_verts, __func__);
+ float *obs_v1 = MEM_callocN(sizeof(float) * 3 * tot_verts, __func__);
+ unsigned int *obs_faces = MEM_callocN(sizeof(unsigned int) * 3 * tot_faces, __func__);
+
+ // Copy over vertices and faces
+ int curr_verts = 0;
+ int curr_faces = 0;
+ for (int i = 0; i < numobjects; ++i) {
+ Object *ob = objects[i];
+ if (ob->type == OB_MESH) {
+ if (ob->pd && ob->pd->deflect) {
+ CollisionModifierData *cmd = (CollisionModifierData *)BKE_modifiers_findby_type(
+ ob, eModifierType_Collision);
+ if (!cmd)
+ continue;
+
+ for (int j = 0; j < cmd->mvert_num; ++j) {
+ int v_idx = j * 3 + curr_verts * 3;
+ for (int k = 0; k < 3; ++k) {
+ obs_v0[v_idx + k] = cmd->x[j].co[k];
+ obs_v1[v_idx + k] = cmd->xnew[j].co[k];
+ }
+ }
+
+ for (int j = 0; j < cmd->tri_num; ++j) {
+ int f_idx = j * 3 + curr_faces * 3;
+ for (int k = 0; k < 3; ++k) {
+ obs_faces[f_idx + k] = cmd->tri[j].tri[k] + curr_verts;
+ }
+ }
+
+ curr_verts += cmd->mvert_num;
+ curr_faces += cmd->tri_num;
+ }
+ }
+ }
+
+ // Update via API
+ admmpd_update_obstacles(sb->admmpd, obs_v0, obs_v1, tot_verts, obs_faces, tot_faces);
+
+ // Cleanup
+ MEM_freeN(obs_v0);
+ MEM_freeN(obs_v1);
+ MEM_freeN(obs_faces);
+ BKE_collision_objects_free(objects);
+}
+
+void sbCustomRead(struct Object *ob)
+{
+ SoftBody *sb = ob->soft;
+ if (!sb) {
+ return;
+ }
+
+ // ADMM-PD data is not currently written to file.
+ // Instead, we'll create new data when a .blend file is loaded.
+ sb->admmpd = MEM_callocN(sizeof(ADMMPDInterfaceData), "SoftBody_admmpd");
+}
+
/* simulates one step. framenr is in frames */
void sbObjectStep(struct Depsgraph *depsgraph,
Scene *scene,
@@ -3539,7 +3664,18 @@ void sbObjectStep(struct Depsgraph *depsgraph,
float (*vertexCos)[3],
int numVerts)
{
+
SoftBody *sb = ob->soft;
+ if (!sb) {
+ return;
+ }
+
+ if (sb->admmpd == NULL) {
+ CLOG_ERROR(&LOG, "No ADMM-PD data");
+ WM_reportf(RPT_ERROR, "No ADMM-PD data");
+ return;
+ }
+
PointCache *cache;
PTCacheID pid;
float dtime, timescale;
@@ -3555,9 +3691,11 @@ void sbObjectStep(struct Depsgraph *depsgraph,
/* check for changes in mesh, should only happen in case the mesh
* structure changes during an animation */
- if (sb->bpoint && numVerts != sb->totpoint) {
- BKE_ptcache_invalidate(cache);
- return;
+ if (sb->solver_mode == SOLVER_MODE_LEGACY) {
+ if (sb->bpoint && numVerts != sb->totpoint) {
+ BKE_ptcache_invalidate(cache);
+ return;
+ }
}
/* clamp frame ranges */
@@ -3570,38 +3708,93 @@ void sbObjectStep(struct Depsgraph *depsgraph,
}
/* verify if we need to create the softbody data */
- if (sb->bpoint == NULL ||
- ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) {
+ if (sb->solver_mode == SOLVER_MODE_ADMMPD) {
+ /* If it's the first frame, we probably want to intialize. */
+ bool is_first_frame = framenr == startframe;
+
+ /* Do we need to initialize the ADMM-PD mesh?
+ * a) Has never been initialized.
+ * b) The mesh topology has changed.
+ * TODO: ob->obmat or vertexCos change. */
+ int init_mesh = 0;
+ if (is_first_frame || admmpd_mesh_needs_update(sb->admmpd, ob)) {
+ init_mesh = admmpd_update_mesh(sb->admmpd, ob, vertexCos);
+ if (init_mesh == 0) {
+ CLOG_ERROR(&LOG, "%s", sb->admmpd->last_error);
+ WM_reportf(RPT_ERROR, sb->admmpd->last_error);
+ return;
+ }
+ else if (init_mesh == -1) {
+ WM_reportf(RPT_WARNING, sb->admmpd->last_error);
+ }
+ }
- switch (ob->type) {
- case OB_MESH:
- mesh_to_softbody(scene, ob);
- break;
- case OB_LATTICE:
- lattice_to_softbody(scene, ob);
- break;
- case OB_CURVE:
- case OB_SURF:
- curve_surf_to_softbody(scene, ob);
- break;
- default:
- renew_softbody(scene, ob, numVerts, 0);
- break;
+ /* Do we need to initialize the ADMM-PD solver?
+ * a) Has never been initialized
+ * b) Some settings require re-initialization
+ * c) The mesh has changed */
+ int init_solver = 0;
+ if (is_first_frame || init_mesh || admmpd_solver_needs_update(sb->admmpd, scene, ob)) {
+ init_solver = admmpd_update_solver(sb->admmpd, scene, ob, vertexCos);
+ if (init_solver == 0) {
+ CLOG_ERROR(&LOG, "%s", sb->admmpd->last_error);
+ WM_reportf(RPT_ERROR, sb->admmpd->last_error);
+ return;
+ }
+ else if (init_solver == -1) {
+ WM_reportf(RPT_WARNING, sb->admmpd->last_error);
+ }
}
- softbody_update_positions(ob, sb, vertexCos, numVerts);
- softbody_reset(ob, sb, vertexCos, numVerts);
+ /* In case of paramter change, ob->soft->bpoint has not
+ * been set yet. So we need to resize which can be done
+ * in the copy_to_object function while leaving vertexCos to null. */
+ admmpd_copy_to_object(sb->admmpd, ob, NULL);
+
+ if (init_mesh || init_solver) {
+ BKE_ptcache_invalidate(cache);
+ }
+ }
+ else if (sb->solver_mode == SOLVER_MODE_LEGACY) {
+ if (sb->bpoint == NULL ||
+ ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) {
+
+ switch (ob->type) {
+ case OB_MESH:
+ mesh_to_softbody(scene, ob);
+ break;
+ case OB_LATTICE:
+ lattice_to_softbody(scene, ob);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ curve_surf_to_softbody(scene, ob);
+ break;
+ default:
+ renew_softbody(scene, ob, numVerts, 0);
+ break;
+ }
+
+ softbody_update_positions(ob, sb, vertexCos, numVerts);
+ softbody_reset(ob, sb, vertexCos, numVerts);
+ }
}
/* still no points? go away */
if (sb->totpoint == 0) {
return;
}
+
if (framenr == startframe) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
/* first frame, no simulation to do, just set the positions */
- softbody_update_positions(ob, sb, vertexCos, numVerts);
+ if (sb->solver_mode == SOLVER_MODE_ADMMPD) {
+ admmpd_copy_from_object(sb->admmpd, ob);
+ }
+ else if (sb->solver_mode == SOLVER_MODE_LEGACY) {
+ softbody_update_positions(ob, sb, vertexCos, numVerts);
+ }
BKE_ptcache_validate(cache, framenr);
cache->flag &= ~PTCACHE_REDO_NEEDED;
@@ -3620,17 +3813,25 @@ void sbObjectStep(struct Depsgraph *depsgraph,
if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED ||
(!can_simulate && cache_result == PTCACHE_READ_OLD)) {
- softbody_to_object(ob, vertexCos, numVerts, sb->local);
- BKE_ptcache_validate(cache, framenr);
+ if (sb->solver_mode == SOLVER_MODE_ADMMPD) {
+ /* We have read the cache into softbody, so we need to pass it to ADMM-PD */
+ admmpd_copy_from_object(sb->admmpd, ob);
+ /* Now that we have the updated ADMM-PD vertices, we have
+ * to map them to surface vertices (vertexCos) */
+ admmpd_copy_to_object(sb->admmpd, ob, vertexCos);
+ }
+ else if (sb->solver_mode == SOLVER_MODE_LEGACY) {
+ softbody_to_object(ob, vertexCos, numVerts, sb->local);
+ }
+ BKE_ptcache_validate(cache, framenr);
if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED &&
can_write_cache) {
BKE_ptcache_write(&pid, framenr);
}
sbStoreLastFrame(depsgraph, ob, framenr);
-
return;
}
if (cache_result == PTCACHE_READ_OLD) {
@@ -3656,18 +3857,29 @@ void sbObjectStep(struct Depsgraph *depsgraph,
BKE_ptcache_write(&pid, startframe);
}
- softbody_update_positions(ob, sb, vertexCos, numVerts);
-
- /* checking time: */
- dtime = framedelta * timescale;
-
- /* do simulation */
- softbody_step(depsgraph, scene, ob, sb, dtime);
-
- softbody_to_object(ob, vertexCos, numVerts, 0);
+ if (sb->solver_mode == SOLVER_MODE_ADMMPD) {
+ admmpd_copy_from_object(sb->admmpd, ob);
+ update_collider_admmpd(depsgraph, sb->collision_group, ob);
+ int solve_retval = admmpd_solve(sb->admmpd, ob, vertexCos);
+ if (solve_retval == 0) {
+ CLOG_ERROR(&LOG, "%s", sb->admmpd->last_error);
+ WM_reportf(RPT_ERROR, sb->admmpd->last_error);
+ }
+ else if (solve_retval == -1) {
+ WM_reportf(RPT_WARNING, sb->admmpd->last_error);
+ }
+ admmpd_copy_to_object(sb->admmpd, ob, vertexCos);
+ }
+ else if (sb->solver_mode == SOLVER_MODE_LEGACY) {
+ softbody_update_positions(ob, sb, vertexCos, numVerts);
+ /* checking time: */
+ dtime = framedelta * timescale;
+ /* do simulation */
+ softbody_step(depsgraph, scene, ob, sb, dtime);
+ softbody_to_object(ob, vertexCos, numVerts, 0);
+ }
BKE_ptcache_validate(cache, framenr);
BKE_ptcache_write(&pid, framenr);
-
sbStoreLastFrame(depsgraph, ob, framenr);
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 42b97550db1..9003bc4f794 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -152,6 +152,7 @@
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
#include "BKE_simulation.h"
+#include "BKE_softbody.h"
#include "BKE_sound.h"
#include "BKE_volume.h"
#include "BKE_workspace.h"
@@ -5686,6 +5687,11 @@ static void direct_link_object(BlendDataReader *reader, Object *ob)
sb->bpoint = NULL; // init pointers so it gets rebuilt nicely
sb->bspring = NULL;
sb->scratch = NULL;
+ sb->admmpd = NULL;
+
+ /* Re-alloc or read custom data structs */
+ sbCustomRead(ob);
+
/* although not used anymore */
/* still have to be loaded to be compatible with old files */
BLO_read_pointer_array(reader, (void **)&sb->keys);
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index ed4f997a856..b6f0d5bd70b 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1875,6 +1875,9 @@ static void write_object(BlendWriter *writer, Object *ob, const void *id_address
BLO_write_struct(writer, PartDeflect, ob->pd);
if (ob->soft) {
+ /* Don't write ADMM-PD data. */
+ ADMMPDInterfaceData *admmpd = ob->soft->admmpd;
+ ob->soft->admmpd = NULL;
/* Set deprecated pointers to prevent crashes of older Blenders */
ob->soft->pointcache = ob->soft->shared->pointcache;
ob->soft->ptcaches = ob->soft->shared->ptcaches;
@@ -1882,6 +1885,8 @@ static void write_object(BlendWriter *writer, Object *ob, const void *id_address
BLO_write_struct(writer, SoftBody_Shared, ob->soft->shared);
write_pointcaches(writer, &(ob->soft->shared->ptcaches));
BLO_write_struct(writer, EffectorWeights, ob->soft->effector_weights);
+ /* Reset the ADMM-PD data pointer */
+ ob->soft->admmpd = admmpd;
}
if (ob->rigidbody_object) {
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 50825ae1ae4..6bc615c9b9e 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -302,6 +302,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
void OBJECT_OT_voxel_size_edit(struct wmOperatorType *ot);
void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot);
+void OBJECT_OT_tetgen_remesh(struct wmOperatorType *ot);
/* object_transfer_data.c */
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 92880e5a114..c699882ef4a 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -273,6 +273,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_voxel_size_edit);
WM_operatortype_append(OBJECT_OT_quadriflow_remesh);
+ WM_operatortype_append(OBJECT_OT_tetgen_remesh);
}
void ED_operatormacros_object(void)
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index f14c734da4e..9be84dc4b8c 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -1200,4 +1200,56 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
255);
}
+static int tetgen_remesh_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ Mesh *mesh = ob->data;
+ Mesh *new_mesh = NULL;
+
+ unsigned int *tets = NULL;
+ int numtets;
+ new_mesh = BKE_mesh_remesh_tetgen_to_mesh_nomain(mesh, &tets, &numtets);
+ if (tets) {
+ MEM_freeN(tets);
+ }
+
+ if (!new_mesh) {
+ BKE_report(op->reports, RPT_ERROR, "TetGen remesher failed to create mesh");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+
+ if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) {
+ BKE_mesh_smooth_flag_set(ob->data, true);
+ }
+
+ if (ob->mode == OB_MODE_SCULPT) {
+ ED_sculpt_undo_geometry_end(ob);
+ }
+
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_tetgen_remesh(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "TetGen Remesh";
+ ot->description =
+ "Create a new tet mesh using the surface data of the current mesh. All data "
+ "layers will be lost";
+ ot->idname = "OBJECT_OT_tetgen_remesh";
+
+ /* api callbacks */
+ ot->poll = object_remesh_poll;
+ ot->exec = tetgen_remesh_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/** \} */
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh
index 6ab0e32a754..ab6e9cd7351 100644
--- a/source/blender/gpu/intern/gpu_backend.hh
+++ b/source/blender/gpu/intern/gpu_backend.hh
@@ -28,7 +28,10 @@
#include "gpu_batch_private.hh"
#include "gpu_context_private.hh"
#include "gpu_drawlist_private.hh"
+<<<<<<< HEAD
+=======
#include "gpu_shader_private.hh"
+>>>>>>> master
namespace blender {
namespace gpu {
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index a6aef5b08ad..37cda5f0e12 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -309,6 +309,7 @@ enum {
enum {
REMESH_VOXEL = 0,
REMESH_QUAD = 1,
+ REMESH_TET = 2,
};
/* Subsurf Type */
diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h
index 3b0640544ae..33b16350354 100644
--- a/source/blender/makesdna/DNA_object_force_types.h
+++ b/source/blender/makesdna/DNA_object_force_types.h
@@ -193,6 +193,8 @@ typedef struct SBVertex {
float vec[4];
} SBVertex;
+typedef struct ADMMPDInterfaceData ADMMPDInterfaceData;
+
/* Container for data that is shared among CoW copies.
*
* This is placed in a separate struct so that values can be changed
@@ -209,6 +211,33 @@ typedef struct SoftBody {
struct BodyPoint *bpoint;
/** Not saved in file. */
struct BodySpring *bspring;
+
+ struct ADMMPDInterfaceData *admmpd;
+
+ /* ADMM-PD settings */
+ int solver_mode; // 0=legacy, 1=admmpd
+ int admmpd_mesh_mode; // 0=embedded, 1=tetgen, 2=cloth
+ int admmpd_substeps; // break time step into smaller bits
+ int admmpd_max_admm_iters; // max solver iterations
+ int admmpd_self_collision; // 0 or 1
+ int admmpd_material; // see enum
+ int admmpd_embed_res; // embedded resolution depth
+ float admmpd_converge_eps; // convergence epsilon
+ float admmpd_youngs_exp; // Youngs mod exponent
+ float admmpd_poisson; // Poisson ratio
+ float admmpd_density_kgm3; // unit-density of object
+ float admmpd_ck_exp; // collision stiffness exponent (10^n)
+ float admmpd_pk_exp; // goal stiffness exponent (10^n)
+ float admmpd_floor_z; // floor position
+ float admmpd_gravity; // in m/s^2
+ float admmpd_strainlimit_min; // [0,1]
+ float admmpd_strainlimit_max; // [1,100]
+ int admmpd_maxthreads; // -1 = auto
+ int admmpd_loglevel; // 0=none, 1=low, 2=high
+ int admmpd_linsolver; // global step
+ char admmpd_namedVG_selfcollision[64];
+ // int admmpd_pad; // padding
+
char _pad;
char msg_lock;
short msg_value;
@@ -405,6 +434,10 @@ typedef struct SoftBody {
#define SBC_MODE_MAX 3
#define SBC_MODE_AVGMINMAX 4
+/* sb->solver_mode */
+#define SOLVER_MODE_ADMMPD 0
+#define SOLVER_MODE_LEGACY 1
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index bb5ec0d6835..53de811eaa8 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -58,6 +58,7 @@ const EnumPropertyItem rna_enum_mesh_delimit_mode_items[] = {
static const EnumPropertyItem rna_enum_mesh_remesh_mode_items[] = {
{REMESH_VOXEL, "VOXEL", 0, "Voxel", "Use the voxel remesher"},
{REMESH_QUAD, "QUAD", 0, "Quad", "Use the quad remesher"},
+ {REMESH_TET, "TET", 0, "Tet", "Use the tetrahedralize remesher"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index bb3756d9cfc..562d1565961 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -602,6 +602,13 @@ static void rna_SoftBodySettings_spring_vgroup_set(PointerRNA *ptr, const char *
rna_object_vgroup_name_set(ptr, value, sb->namedVG_Spring_K, sizeof(sb->namedVG_Spring_K));
}
+static void rna_SoftBodySettings_selfcollide_vgroup_set(PointerRNA *ptr, const char *value)
+{
+ SoftBody *sb = (SoftBody *)ptr->data;
+ rna_object_vgroup_name_set(
+ ptr, value, sb->admmpd_namedVG_selfcollision, sizeof(sb->admmpd_namedVG_selfcollision));
+}
+
static char *rna_SoftBodySettings_path(PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
@@ -862,7 +869,6 @@ static void rna_CollisionSettings_update(Main *UNUSED(bmain),
PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
-
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
}
@@ -870,7 +876,6 @@ static void rna_CollisionSettings_update(Main *UNUSED(bmain),
static void rna_softbody_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Object *ob = (Object *)ptr->owner_id;
-
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
}
@@ -1787,6 +1792,45 @@ static void rna_def_softbody(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem solvermode_items[] = {
+ {SOLVER_MODE_LEGACY, "LEGACY", 0, "Legacy", "Legacy solver"},
+ {SOLVER_MODE_ADMMPD, "ADMMPD", 0, "ADMM-PD", "Experimental ADMM-PD"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem admmpd_initmode_items[] = {
+ {0, "EMBEDDED", 0, "Embedded", "Embed surface in low-res lattice"},
+ {1, "TETGEN", 0, "TetGen", "Tetrahedralize the surface mesh"},
+ {2, "CLOTH", 0, "Cloth", "Simulate surface mesh as a cloth"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem admmpd_material_items[] = {
+ {0, "ARAP", 0, "ARAP", "As-rigid-as-possible"},
+ {1, "NH", 0, "Neo-Hookean", "Classic neo-Hookean"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem admmpd_loglevel_items[] = {
+ {0, "NONE", 0, "None", "No terminal output"},
+ {1, "LOW", 0, "Low", "Minimal terminal output"},
+ {2, "HIGH", 0, "High", "Output per-solve timings"},
+ {3, "DEBUG", 0, "Debug", "A lot of terminal output"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem admmpd_linsolver_items[] = {
+ {0, "LTLD", 0, "LDL^T", "Factors the matrix on any collision or change in pin stiffness"},
+ {1,
+ "PCG",
+ 0,
+ "Conjugate Gradients",
+ "Iterative solver but factors preconditioner on change in pin stiffness"},
+ //{2, "MCGS", 0, "Multi-Color Gauss-Seidel", "Fast if many threads are available, no support
+ //for self collision"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static const EnumPropertyItem aerodynamics_type[] = {
{0, "SIMPLE", 0, "Simple", "Edges receive a drag force from surrounding media"},
{1,
@@ -1803,6 +1847,137 @@ static void rna_def_softbody(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Soft Body Settings", "Soft body simulation settings for an object");
+ /* Solver mode */
+
+ prop = RNA_def_property(srna, "solver_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "solver_mode");
+ RNA_def_property_enum_items(prop, solvermode_items);
+ RNA_def_property_ui_text(prop, "Solver", "Choose Solver Type");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ /* ADMM-PD settings */
+
+ prop = RNA_def_property(srna, "admmpd_mesh_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "admmpd_mesh_mode");
+ RNA_def_property_enum_items(prop, admmpd_initmode_items);
+ RNA_def_property_ui_text(prop, "Mesh Mode", "ADMM-PD initialization mode");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_gravity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "admmpd_gravity");
+ RNA_def_property_ui_text(prop, "Gravity", "Gravity in m/s^2");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_substeps", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "admmpd_substeps");
+ RNA_def_property_range(prop, 1.f, 100.f);
+ RNA_def_property_ui_text(prop, "Substeps", "Number of solver substeps");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_maxthreads", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "admmpd_maxthreads");
+ RNA_def_property_range(prop, -1.f, 64.f);
+ RNA_def_property_ui_text(prop, "Max Threads", "-1 auto computes number of threads to use");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_max_admm_iters", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "admmpd_max_admm_iters");
+ RNA_def_property_range(prop, 1.f, 1000.f);
+ RNA_def_property_ui_text(prop, "Max Iterations", "Max number of solver iterations");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_converge_eps", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "admmpd_converge_eps");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Tolerance", "Decrease tolerance for a more accurate solution");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_youngs_exp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "admmpd_youngs_exp");
+ RNA_def_property_range(prop, 1.f, 10.f);
+ RNA_def_property_ui_text(prop, "Young's Mod", "Young's modulus exponent: 10^n");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_poisson", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "admmpd_poisson");
+ RNA_def_property_range(prop, 0.0f, 0.499f);
+ RNA_def_property_ui_text(prop, "Poisson's Ratio", "Material stiffness");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_material", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "admmpd_material");
+ RNA_def_property_enum_items(prop, admmpd_material_items);
+ RNA_def_property_ui_text(prop, "Material", "Elastic material model");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_strainlimit_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "admmpd_strainlimit_max");
+ RNA_def_property_range(prop, 1.0f, 100.f);
+ RNA_def_property_ui_text(prop, "Strain Limit", "Limits stetch: lower reduces stretching");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_loglevel", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "admmpd_loglevel");
+ RNA_def_property_enum_items(prop, admmpd_loglevel_items);
+ RNA_def_property_ui_text(prop, "Verbosity", "Controls the amount of terminal ouput");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_linsolver", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "admmpd_linsolver");
+ RNA_def_property_enum_items(prop, admmpd_linsolver_items);
+ RNA_def_property_ui_text(prop, "Linear Solver", "Solver used for global step");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_embed_res", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "admmpd_embed_res");
+ RNA_def_property_range(prop, 1.f, 10.f);
+ RNA_def_property_ui_text(prop, "Lattice Resolution", "Max depth of lattice subdivisions");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_density_kgm3", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "admmpd_density_kgm3");
+ RNA_def_property_range(prop, 1.0f, 10000.f);
+ RNA_def_property_ui_text(prop, "Unit Density", "Unit density in kg/m^3");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_floor_z", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "admmpd_floor_z");
+ RNA_def_property_range(prop, -999.f, 999.f);
+ RNA_def_property_ui_text(prop, "Floor", "Position of the floor along z-axis");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_self_collision", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "admmpd_self_collision", OB_SB_SELF);
+ RNA_def_property_ui_text(prop, "Self Collision", "Enable self collisions (slow)");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "vertex_group_selfcollide", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "admmpd_namedVG_selfcollision");
+ RNA_def_property_ui_text(
+ prop, "Self Collide VG", "Optional vertex group for self collision vertices");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SoftBodySettings_selfcollide_vgroup_set");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_ck_exp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "admmpd_ck_exp");
+ RNA_def_property_range(prop, -1000.0f, 1000.0f);
+ RNA_def_property_ui_text(prop, "Stiffness", "Exponent of collision spring stiffness: 10^n");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
+ prop = RNA_def_property(srna, "admmpd_pk_exp", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "admmpd_pk_exp");
+ RNA_def_property_range(prop, -1000.0f, 1000.0f);
+ RNA_def_property_ui_text(prop, "Stiffness", "Exponent of goal position stiffness: 10^n");
+ RNA_def_property_update(prop, 0, "rna_softbody_update");
+
/* General Settings */
prop = RNA_def_property(srna, "friction", PROP_FLOAT, PROP_NONE);