Added unit tests for testing different phases of collision
This commit is contained in:
86
source/blender/blenkernel/BKE_softbody copy.h
Normal file
86
source/blender/blenkernel/BKE_softbody copy.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright Blender Foundation. All rights reserved. */
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Depsgraph;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
struct SoftBody;
|
||||
|
||||
typedef struct BodyPoint {
|
||||
float origS[3], origE[3], origT[3], pos[3], vec[3], force[3];
|
||||
float goal;
|
||||
float prevpos[3], prevvec[3], prevdx[3], prevdv[3]; /* used for Heun integration */
|
||||
float impdv[3], impdx[3];
|
||||
int nofsprings;
|
||||
int *springs;
|
||||
float choke, choke2, frozen;
|
||||
float colball;
|
||||
short loc_flag; /* reserved by locale module specific states */
|
||||
// char octantflag;
|
||||
float mass;
|
||||
float springweight;
|
||||
} BodyPoint;
|
||||
|
||||
/**
|
||||
* Allocates and initializes general main data.
|
||||
*/
|
||||
extern struct SoftBody *sbNew(void);
|
||||
|
||||
/**
|
||||
* Frees internal data and soft-body itself.
|
||||
*/
|
||||
extern void sbFree(struct Object *ob);
|
||||
|
||||
/**
|
||||
* Frees simulation data to reset simulation.
|
||||
*/
|
||||
extern void sbFreeSimulation(struct SoftBody *sb);
|
||||
|
||||
/**
|
||||
* Do one simulation step, reading and writing vertex locs from given array.
|
||||
* */
|
||||
extern void sbObjectStep(struct Depsgraph *depsgraph,
|
||||
struct Scene *scene,
|
||||
struct Object *ob,
|
||||
float cfra,
|
||||
float (*vertexCos)[3],
|
||||
int numVerts);
|
||||
|
||||
/**
|
||||
* Makes totally fresh start situation, resets time.
|
||||
*/
|
||||
extern void sbObjectToSoftbody(struct Object *ob);
|
||||
|
||||
/**
|
||||
* Soft-body global visible functions.
|
||||
* Links the soft-body module to a 'test for Interrupt' function, pass NULL to clear the callback.
|
||||
*/
|
||||
extern void sbSetInterruptCallBack(int (*f)(void));
|
||||
|
||||
/**
|
||||
* A precise position vector denoting the motion of the center of mass give a rotation/scale matrix
|
||||
* using averaging method, that's why estimate and not calculate see: this is kind of reverse
|
||||
* engineering: having to states of a point cloud and recover what happened our advantage here we
|
||||
* know the identity of the vertex there are others methods giving other results.
|
||||
*
|
||||
* \param ob: Any object that can do soft-body e.g. mesh, lattice, curve.
|
||||
* \param lloc: Output of the calculated location (or NULL).
|
||||
* \param lrot: Output of the calculated rotation (or NULL).
|
||||
* \param lscale: Output for the calculated scale (or NULL).
|
||||
*
|
||||
* For velocity & 2nd order stuff see: #vcloud_estimate_transform_v3.
|
||||
*/
|
||||
extern void SB_estimate_transform(Object *ob, float lloc[3], float lrot[3][3], float lscale[3][3]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
3630
source/blender/blenkernel/intern/softbody copy.c
Normal file
3630
source/blender/blenkernel/intern/softbody copy.c
Normal file
File diff suppressed because it is too large
Load Diff
395
source/blender/makesdna/DNA_object_force_types copy.h
Normal file
395
source/blender/makesdna/DNA_object_force_types copy.h
Normal file
@@ -0,0 +1,395 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2004-2005 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup DNA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DNA_defs.h"
|
||||
#include "DNA_listBase.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct BodySpring;
|
||||
|
||||
/** #PartDeflect.forcefield: Effector Fields types. */
|
||||
typedef enum ePFieldType {
|
||||
/** (this is used for general effector weight). */
|
||||
PFIELD_NULL = 0,
|
||||
/** Force away/towards a point depending on force strength. */
|
||||
PFIELD_FORCE = 1,
|
||||
/** Force around the effector normal. */
|
||||
PFIELD_VORTEX = 2,
|
||||
/** Force from the cross product of effector normal and point velocity. */
|
||||
PFIELD_MAGNET = 3,
|
||||
/** Force away and towards a point depending which side of the effector normal the point is. */
|
||||
PFIELD_WIND = 4,
|
||||
/** Force along curve for dynamics, a shaping curve for hair paths. */
|
||||
PFIELD_GUIDE = 5,
|
||||
/** Force based on texture values calculated at point coordinates. */
|
||||
PFIELD_TEXTURE = 6,
|
||||
/** Force of a harmonic (damped) oscillator. */
|
||||
PFIELD_HARMONIC = 7,
|
||||
/** Force away/towards a point depending on point charge. */
|
||||
PFIELD_CHARGE = 8,
|
||||
/** Force due to a Lennard-Jones potential. */
|
||||
PFIELD_LENNARDJ = 9,
|
||||
/** Defines predator / goal for boids. */
|
||||
PFIELD_BOID = 10,
|
||||
/** Force defined by BLI_noise_generic_turbulence. */
|
||||
PFIELD_TURBULENCE = 11,
|
||||
/** Linear & quadratic drag. */
|
||||
PFIELD_DRAG = 12,
|
||||
/** Force based on fluid simulation velocities. */
|
||||
PFIELD_FLUIDFLOW = 13,
|
||||
|
||||
/* Keep last. */
|
||||
NUM_PFIELD_TYPES,
|
||||
} ePFieldType;
|
||||
|
||||
typedef struct PartDeflect {
|
||||
/** General settings flag. */
|
||||
int flag;
|
||||
/** Deflection flag - does mesh deflect particles. */
|
||||
short deflect;
|
||||
/** Force field type, do the vertices attract / repel particles? */
|
||||
short forcefield;
|
||||
/** Fall-off type. */
|
||||
short falloff;
|
||||
/** Point, plane or surface. */
|
||||
short shape;
|
||||
/** Texture effector. */
|
||||
short tex_mode;
|
||||
/** For curve guide. */
|
||||
short kink, kink_axis;
|
||||
short zdir;
|
||||
|
||||
/* Main effector values */
|
||||
/** The strength of the force (+ or - ). */
|
||||
float f_strength;
|
||||
/** Damping ratio of the harmonic effector. */
|
||||
float f_damp;
|
||||
/**
|
||||
* How much force is converted into "air flow", i.e.
|
||||
* force used as the velocity of surrounding medium. */
|
||||
float f_flow;
|
||||
/** How much force is reduced when acting parallel to a surface, e.g. cloth. */
|
||||
float f_wind_factor;
|
||||
|
||||
char _pad0[4];
|
||||
|
||||
/** Noise size for noise effector, restlength for harmonic effector. */
|
||||
float f_size;
|
||||
|
||||
/* fall-off */
|
||||
/** The power law - real gravitation is 2 (square). */
|
||||
float f_power;
|
||||
/** If indicated, use this maximum. */
|
||||
float maxdist;
|
||||
/** If indicated, use this minimum. */
|
||||
float mindist;
|
||||
/** Radial fall-off power. */
|
||||
float f_power_r;
|
||||
/** Radial versions of above. */
|
||||
float maxrad;
|
||||
float minrad;
|
||||
|
||||
/* particle collisions */
|
||||
/** Damping factor for particle deflection. */
|
||||
float pdef_damp;
|
||||
/** Random element of damping for deflection. */
|
||||
float pdef_rdamp;
|
||||
/** Chance of particle passing through mesh. */
|
||||
float pdef_perm;
|
||||
/** Friction factor for particle deflection. */
|
||||
float pdef_frict;
|
||||
/** Random element of friction for deflection. */
|
||||
float pdef_rfrict;
|
||||
/** Surface particle stickiness. */
|
||||
float pdef_stickness;
|
||||
|
||||
/** Used for forces. */
|
||||
float absorption;
|
||||
|
||||
/* softbody collisions */
|
||||
/** Damping factor for softbody deflection. */
|
||||
float pdef_sbdamp;
|
||||
/** Inner face thickness for softbody deflection. */
|
||||
float pdef_sbift;
|
||||
/** Outer face thickness for softbody deflection. */
|
||||
float pdef_sboft;
|
||||
|
||||
/* guide curve, same as for particle child effects */
|
||||
float clump_fac, clump_pow;
|
||||
float kink_freq, kink_shape, kink_amp, free_end;
|
||||
|
||||
/* texture effector */
|
||||
/** Used for calculating partial derivatives. */
|
||||
float tex_nabla;
|
||||
/** Texture of the texture effector. */
|
||||
struct Tex *tex;
|
||||
|
||||
/* effector noise */
|
||||
/** Random noise generator for e.g. wind. */
|
||||
struct RNG *rng;
|
||||
/** Noise of force. */
|
||||
float f_noise;
|
||||
/** Noise random seed. */
|
||||
int seed;
|
||||
|
||||
/* Display Size */
|
||||
/** Runtime only : start of the curve or draw scale. */
|
||||
float drawvec1[4];
|
||||
/** Runtime only : end of the curve. */
|
||||
float drawvec2[4];
|
||||
/** Runtime only. */
|
||||
float drawvec_falloff_min[3];
|
||||
char _pad1[4];
|
||||
/** Runtime only. */
|
||||
float drawvec_falloff_max[3];
|
||||
char _pad2[4];
|
||||
|
||||
/** Force source object. */
|
||||
struct Object *f_source;
|
||||
|
||||
/** Friction of cloth collisions. */
|
||||
float pdef_cfrict;
|
||||
char _pad[4];
|
||||
} PartDeflect;
|
||||
|
||||
typedef struct EffectorWeights {
|
||||
/** Only use effectors from this group of objects. */
|
||||
struct Collection *group;
|
||||
|
||||
/** Effector type specific weights. */
|
||||
float weight[14];
|
||||
float global_gravity;
|
||||
short flag;
|
||||
char _pad[2];
|
||||
} EffectorWeights;
|
||||
|
||||
/* EffectorWeights->flag */
|
||||
#define EFF_WEIGHT_DO_HAIR 1
|
||||
|
||||
typedef struct SBVertex {
|
||||
float vec[4];
|
||||
} SBVertex;
|
||||
|
||||
/* Container for data that is shared among CoW copies.
|
||||
*
|
||||
* This is placed in a separate struct so that values can be changed
|
||||
* without having to update all CoW copies. */
|
||||
typedef struct SoftBody_Shared {
|
||||
struct PointCache *pointcache;
|
||||
struct ListBase ptcaches;
|
||||
} SoftBody_Shared;
|
||||
|
||||
typedef struct SoftBody {
|
||||
/* dynamic data */
|
||||
int totpoint, totspring;
|
||||
/** Not saved in file. */
|
||||
struct BodyPoint *bpoint;
|
||||
/** Not saved in file. */
|
||||
struct BodySpring *bspring;
|
||||
char _pad;
|
||||
char msg_lock;
|
||||
short msg_value;
|
||||
|
||||
/* part of UI: */
|
||||
|
||||
/* general options */
|
||||
/** Softbody mass of *vertex*. */
|
||||
float nodemass;
|
||||
/**
|
||||
* Along with it introduce mass painting
|
||||
* starting to fix old bug .. nastiness that VG are indexes
|
||||
* rather find them by name tag to find it -> jow20090613.
|
||||
* MAX_VGROUP_NAME */
|
||||
char namedVG_Mass[64];
|
||||
/** Softbody amount of gravitation to apply. */
|
||||
float grav;
|
||||
/** Friction to env. */
|
||||
float mediafrict;
|
||||
/** Error limit for ODE solver. */
|
||||
float rklimit;
|
||||
/** User control over simulation speed. */
|
||||
float physics_speed;
|
||||
|
||||
/* goal */
|
||||
/** Softbody goal springs. */
|
||||
float goalspring;
|
||||
/** Softbody goal springs friction. */
|
||||
float goalfrict;
|
||||
/** Quick limits for goal. */
|
||||
float mingoal;
|
||||
float maxgoal;
|
||||
/** Default goal for vertices without vgroup. */
|
||||
float defgoal;
|
||||
/** Index starting at 1. */
|
||||
short vertgroup;
|
||||
/**
|
||||
* Starting to fix old bug .. nastiness that VG are indexes
|
||||
* rather find them by name tag to find it -> jow20090613.
|
||||
* MAX_VGROUP_NAME */
|
||||
char namedVG_Softgoal[64];
|
||||
|
||||
short fuzzyness;
|
||||
|
||||
/* springs */
|
||||
/** Softbody inner springs. */
|
||||
float inspring;
|
||||
/** Softbody inner springs friction. */
|
||||
float infrict;
|
||||
/**
|
||||
* Along with it introduce Spring_K painting
|
||||
* starting to fix old bug .. nastiness that VG are indexes
|
||||
* rather find them by name tag to find it -> jow20090613.
|
||||
* MAX_VGROUP_NAME
|
||||
*/
|
||||
char namedVG_Spring_K[64];
|
||||
|
||||
/* baking */
|
||||
char _pad1[6];
|
||||
/** Local==1: use local coords for baking. */
|
||||
char local, solverflags;
|
||||
|
||||
/* -- these must be kept for backwards compatibility -- */
|
||||
/** Array of size totpointkey. */
|
||||
SBVertex **keys;
|
||||
/** If totpointkey != totpoint or totkey!- (efra-sfra)/interval -> free keys. */
|
||||
int totpointkey, totkey;
|
||||
/* ---------------------------------------------------- */
|
||||
float secondspring;
|
||||
|
||||
/* Self collision. */
|
||||
/** Fixed collision ball size if > 0. */
|
||||
float colball;
|
||||
/** Cooling down collision response. */
|
||||
float balldamp;
|
||||
/** Pressure the ball is loaded with. */
|
||||
float ballstiff;
|
||||
short sbc_mode;
|
||||
short aeroedge;
|
||||
short minloops;
|
||||
short maxloops;
|
||||
short choke;
|
||||
short solver_ID;
|
||||
short plastic;
|
||||
short springpreload;
|
||||
|
||||
/** Scratchpad/cache on live time not saved in file. */
|
||||
struct SBScratch *scratch;
|
||||
float shearstiff;
|
||||
float inpush;
|
||||
|
||||
struct SoftBody_Shared *shared;
|
||||
/** Moved to SoftBody_Shared. */
|
||||
struct PointCache *pointcache DNA_DEPRECATED;
|
||||
/** Moved to SoftBody_Shared. */
|
||||
struct ListBase ptcaches DNA_DEPRECATED;
|
||||
|
||||
struct Collection *collision_group;
|
||||
|
||||
struct EffectorWeights *effector_weights;
|
||||
/* Reverse estimated object-matrix (run-time data, no need to store in the file). */
|
||||
float lcom[3];
|
||||
float lrot[3][3];
|
||||
float lscale[3][3];
|
||||
|
||||
int last_frame;
|
||||
} SoftBody;
|
||||
|
||||
/* pd->flag: various settings */
|
||||
#define PFIELD_USEMAX (1 << 0)
|
||||
// #define PDEFLE_DEFORM (1 << 1) /* UNUSED */
|
||||
/** TODO: do_versions for below */
|
||||
#define PFIELD_GUIDE_PATH_ADD (1 << 2)
|
||||
/** used for do_versions */
|
||||
#define PFIELD_PLANAR (1 << 3)
|
||||
#define PDEFLE_KILL_PART (1 << 4)
|
||||
/** used for do_versions */
|
||||
#define PFIELD_POSZ (1 << 5)
|
||||
#define PFIELD_TEX_OBJECT (1 << 6)
|
||||
/** used for turbulence */
|
||||
#define PFIELD_GLOBAL_CO (1 << 6)
|
||||
#define PFIELD_TEX_2D (1 << 7)
|
||||
/** used for harmonic force */
|
||||
#define PFIELD_MULTIPLE_SPRINGS (1 << 7)
|
||||
#define PFIELD_USEMIN (1 << 8)
|
||||
#define PFIELD_USEMAXR (1 << 9)
|
||||
#define PFIELD_USEMINR (1 << 10)
|
||||
#define PFIELD_TEX_ROOTCO (1 << 11)
|
||||
/** used for do_versions */
|
||||
#define PFIELD_SURFACE (1 << 12)
|
||||
#define PFIELD_VISIBILITY (1 << 13)
|
||||
#define PFIELD_DO_LOCATION (1 << 14)
|
||||
#define PFIELD_DO_ROTATION (1 << 15)
|
||||
/** apply curve weights */
|
||||
#define PFIELD_GUIDE_PATH_WEIGHT (1 << 16)
|
||||
/** multiply smoke force by density */
|
||||
#define PFIELD_SMOKE_DENSITY (1 << 17)
|
||||
/** used for (simple) force */
|
||||
#define PFIELD_GRAVITATION (1 << 18)
|
||||
/** Enable cloth collision side detection based on normal. */
|
||||
#define PFIELD_CLOTH_USE_CULLING (1 << 19)
|
||||
/** Replace collision direction with collider normal. */
|
||||
#define PFIELD_CLOTH_USE_NORMAL (1 << 20)
|
||||
|
||||
/* pd->falloff */
|
||||
#define PFIELD_FALL_SPHERE 0
|
||||
#define PFIELD_FALL_TUBE 1
|
||||
#define PFIELD_FALL_CONE 2
|
||||
|
||||
/* pd->shape */
|
||||
#define PFIELD_SHAPE_POINT 0
|
||||
#define PFIELD_SHAPE_PLANE 1
|
||||
#define PFIELD_SHAPE_SURFACE 2
|
||||
#define PFIELD_SHAPE_POINTS 3
|
||||
#define PFIELD_SHAPE_LINE 4
|
||||
|
||||
/* pd->tex_mode */
|
||||
#define PFIELD_TEX_RGB 0
|
||||
#define PFIELD_TEX_GRAD 1
|
||||
#define PFIELD_TEX_CURL 2
|
||||
|
||||
/* pd->zdir */
|
||||
#define PFIELD_Z_BOTH 0
|
||||
#define PFIELD_Z_POS 1
|
||||
#define PFIELD_Z_NEG 2
|
||||
|
||||
/* ob->softflag */
|
||||
#define OB_SB_ENABLE 1 /* deprecated, use modifier */
|
||||
#define OB_SB_GOAL 2
|
||||
#define OB_SB_EDGES 4
|
||||
#define OB_SB_QUADS 8
|
||||
#define OB_SB_POSTDEF 16
|
||||
// #define OB_SB_REDO 32
|
||||
// #define OB_SB_BAKESET 64
|
||||
// #define OB_SB_BAKEDO 128
|
||||
// #define OB_SB_RESET 256
|
||||
#define OB_SB_SELF 512
|
||||
#define OB_SB_FACECOLL 1024
|
||||
#define OB_SB_EDGECOLL 2048
|
||||
/* #define OB_SB_COLLFINAL 4096 */ /* deprecated */
|
||||
/* #define OB_SB_BIG_UI 8192 */ /* deprecated */
|
||||
#define OB_SB_AERO_ANGLE 16384
|
||||
|
||||
/* sb->solverflags */
|
||||
#define SBSO_MONITOR 1
|
||||
#define SBSO_OLDERR 2
|
||||
#define SBSO_ESTIMATEIPO 4
|
||||
|
||||
/* sb->sbc_mode */
|
||||
#define SBC_MODE_MANUAL 0
|
||||
#define SBC_MODE_AVG 1
|
||||
#define SBC_MODE_MIN 2
|
||||
#define SBC_MODE_MAX 3
|
||||
#define SBC_MODE_AVGMINMAX 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
811
source/blender/modifiers/intern/MOD_weld copy.cc
Normal file
811
source/blender/modifiers/intern/MOD_weld copy.cc
Normal file
@@ -0,0 +1,811 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2005 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup modifiers
|
||||
*
|
||||
* Weld modifier: Remove doubles.
|
||||
*/
|
||||
|
||||
/* TODOs:
|
||||
* - Review weight and vertex color interpolation.;
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLI_vector.hh"
|
||||
#include "BLI_math_vec_types.hh"
|
||||
#include "BLI_math_vector.hh"
|
||||
|
||||
// #include "bmesh_construct.h"
|
||||
#include "bmesh.h"
|
||||
#include "bmesh_tools.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "DNA_defaults.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
|
||||
#include "BKE_bvhutils.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_screen.h"
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "MOD_modifiertypes.h"
|
||||
#include "MOD_ui_common.h"
|
||||
|
||||
#include "GEO_mesh_merge_by_distance.hh"
|
||||
|
||||
using blender::Array;
|
||||
using blender::IndexMask;
|
||||
using blender::Span;
|
||||
using blender::Vector;
|
||||
using namespace blender;
|
||||
using namespace blender::math;
|
||||
// using namespace std;
|
||||
|
||||
|
||||
Vector<Vector<int>> tetFaces({{2,1,0}, {0,1,3}, {1,2,3}, {2,0,3}});
|
||||
float directions[6][3] = {{1,0,0}, {-1,0,0}, {0,1,0}, {0,-1,0}, {0,0,1}, {0,0,-1}};
|
||||
|
||||
float inf = FLT_MAX;
|
||||
float eps = 0.0f;
|
||||
|
||||
static float randomEps(){
|
||||
float eps = 0.0001 ;
|
||||
return -eps + 2.0 * (static_cast <float> (rand()) / static_cast <float> (RAND_MAX)) * eps;
|
||||
// return 0.0f;
|
||||
}
|
||||
|
||||
static bool isInside(float3 vert, BVHTreeFromMesh *treedata){
|
||||
// float eps = 0.0001;
|
||||
|
||||
int count = 0;
|
||||
float min_dist = 0.0f;
|
||||
for(auto dir : directions){
|
||||
float radius = 0.0f;
|
||||
|
||||
float max_length = FLT_MAX;
|
||||
|
||||
BVHTreeRayHit rayhit = {0};
|
||||
rayhit.index = -1;
|
||||
rayhit.dist = max_length;
|
||||
BLI_bvhtree_ray_cast(treedata->tree, vert, dir, radius, &rayhit, treedata->raycast_callback, treedata);
|
||||
|
||||
if (rayhit.index != -1 && rayhit.dist <= max_length) {
|
||||
if(dot_v3v3(rayhit.no, dir) > 0.0f){
|
||||
count++;
|
||||
}
|
||||
|
||||
if((min_dist > 0.0) && (min_dist - rayhit.dist) > 0.0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return count > 3;
|
||||
}
|
||||
|
||||
// Used to populate a tets face normals and planesD
|
||||
static void setTetProperties(Vector<float3> &verts,
|
||||
Vector<int> &tetVertId,
|
||||
Vector<float3> &faceNormals,
|
||||
Vector<float> &planesD,
|
||||
int tetNr){
|
||||
for(int i = 0; i<4; i++){
|
||||
float3 p0 = verts[tetVertId[4*tetNr + tetFaces[i][0]]];
|
||||
float3 p1 = verts[tetVertId[4*tetNr + tetFaces[i][1]]];
|
||||
float3 p2 = verts[tetVertId[4*tetNr + tetFaces[i][2]]];
|
||||
|
||||
float3 normal = cross(p1 - p0, p2 - p0);
|
||||
normal = normalize(normal);
|
||||
|
||||
faceNormals[4*tetNr + i] = normal;
|
||||
planesD[4*tetNr + i] = dot(p0, normal);
|
||||
}
|
||||
}
|
||||
|
||||
static float3 getCircumCenter(float3 p0, float3 p1, float3 p2, float3 p3){
|
||||
float3 b = p1 - p0;
|
||||
float3 c = p2 - p0;
|
||||
float3 d = p3 - p0;
|
||||
|
||||
float det = 2.0 * (b.x*(c.y*d.z - c.z*d.y) - b.y*(c.x*d.z - c.z*d.x) + b.z*(c.x*d.y - c.y*d.x));
|
||||
if (det == 0.0f){
|
||||
return p0;
|
||||
}
|
||||
else{
|
||||
float3 v = cross(c, d)*dot(b, b) + cross(d, b)*dot(c, c) + cross(b, c)*dot(d, d);
|
||||
v /= det;
|
||||
return p0 + v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// bool isSameSide(float3 p0, float3 p1, float3 p2, float3 p4, float3 vert){
|
||||
|
||||
// }
|
||||
|
||||
// bool isInsideTet(float3 p0, float3 p1, float3 p2, float3 p3, float3 vert){
|
||||
|
||||
// }
|
||||
|
||||
static int findContainingTet(Vector<float3> &verts,
|
||||
Vector<int> &tetVertId,
|
||||
Vector<int> &tetFaceNeighbors,
|
||||
Vector<float3> &faceNormals,
|
||||
Vector<float> &planesD,
|
||||
int tetMarkId,
|
||||
Vector<int> &tetMarks,
|
||||
float3 currVert){
|
||||
|
||||
/* --------------------
|
||||
Matthias Method
|
||||
----------------------*/
|
||||
|
||||
// bool found = false;
|
||||
// int tetNr = 0;
|
||||
|
||||
// while(tetNr < tetVertId.size()/4 && tetVertId[4*tetNr]<0)
|
||||
// tetNr++;
|
||||
|
||||
// float3 center(0.0, 0.0, 0.0);
|
||||
// while(!found){
|
||||
// if(tetNr < 0 || tetMarks[tetNr] == tetMarkId){
|
||||
// break;
|
||||
// }
|
||||
|
||||
// tetMarks[tetNr] = tetMarkId;
|
||||
|
||||
// center = {0.0,0.0,0.0};
|
||||
// for(int i = 0; i<4; i++){
|
||||
// center += verts[tetVertId[4*tetNr + i]];
|
||||
// }
|
||||
// center*=0.25;
|
||||
|
||||
// float minT = inf; //
|
||||
// int minFaceNr = -1;
|
||||
|
||||
// for(int i = 0; i<4; i++){
|
||||
// float3 normal = faceNormals[4*tetNr + i];
|
||||
// float d = planesD[4*tetNr + i];
|
||||
|
||||
// float hp = dot(normal, currVert) - d;
|
||||
// float hc = dot(normal, center) - d;
|
||||
|
||||
// float t = hp - hc;
|
||||
// if(t <= eps)
|
||||
// continue;
|
||||
|
||||
// t = -hc/t;
|
||||
|
||||
// if((t >= eps) && ((t - minT) > eps)){
|
||||
// minT = t;
|
||||
// minFaceNr = i;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if(minT >= 1.0){
|
||||
// found = true;
|
||||
// }
|
||||
// else{
|
||||
// tetNr = tetFaceNeighbors[4*tetNr + minFaceNr];
|
||||
// }
|
||||
// }
|
||||
|
||||
// if(found)
|
||||
// return tetNr;
|
||||
// else
|
||||
// return -1;
|
||||
|
||||
/* --------------------
|
||||
Brute force finding first violating tet
|
||||
----------------------*/
|
||||
|
||||
for(int currTet = 0; currTet<tetVertId.size()/4; currTet++){
|
||||
if(tetVertId[4*currTet] == -1)
|
||||
continue;
|
||||
|
||||
float3 p0 = verts[tetVertId[4*currTet + 0]];
|
||||
float3 p1 = verts[tetVertId[4*currTet + 1]];
|
||||
float3 p2 = verts[tetVertId[4*currTet + 2]];
|
||||
float3 p3 = verts[tetVertId[4*currTet + 3]];
|
||||
|
||||
float3 circumCenter = getCircumCenter(p0, p1, p2, p3);
|
||||
float circumRadius = length(p0 - circumCenter);
|
||||
|
||||
// if((circumRadius - length(currVert - circumCenter)) >= eps){
|
||||
if(length(currVert - circumCenter) < circumRadius){
|
||||
return currTet;
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------
|
||||
My method, checks if point is inside tet, if not finds the face that is connecting to the point and center
|
||||
------------------------*/
|
||||
|
||||
// bool found = false;
|
||||
// int tetNr = 0;
|
||||
// while(tetNr < tetVertId.size()/4 && tetVertId[4*tetNr] < 0)
|
||||
// tetNr++;
|
||||
|
||||
// while(!found){
|
||||
// float3 p0 = verts[tetVertId[4*currTet + 0]];
|
||||
// float3 p1 = verts[tetVertId[4*currTet + 1]];
|
||||
// float3 p2 = verts[tetVertId[4*currTet + 2]];
|
||||
// float3 p3 = verts[tetVertId[4*currTet + 3]];
|
||||
|
||||
// if(isInsideTet(p0, p1, p2, p3, currVert))
|
||||
// return tetNr;
|
||||
|
||||
// for(int i = 0; i<4; i++)
|
||||
// }
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
The basic assumption employed is that 2 violating tets cannot not be neighbors.
|
||||
Simple BFS approach that checks neighbors of all violating tets and adds them to stack
|
||||
|
||||
If a violating tet shares a face with a non-violating tet, that's a boundary face and for each violating tet, list of its boundary faces is returned
|
||||
|
||||
Note - BFS can be written better
|
||||
*/
|
||||
static Vector<std::pair<int, Vector<int>>> getViolatingTets(Vector<float3> &verts,
|
||||
Vector<int> &tetVertId,
|
||||
Vector<int> &tetFaceNeighbors,
|
||||
int tetMarkId,
|
||||
Vector<int> &tetMarks,
|
||||
float3 currVert,
|
||||
int containingTetNr
|
||||
){
|
||||
|
||||
Vector< std::pair<int,Vector<int>> > violatingTets;
|
||||
Vector<int> stack;
|
||||
|
||||
stack.append(containingTetNr);
|
||||
|
||||
while(stack.size()){
|
||||
int currTet = stack.last();
|
||||
stack.remove_last();
|
||||
|
||||
if(tetMarks[currTet] == tetMarkId){
|
||||
continue;
|
||||
}
|
||||
tetMarks[currTet] = tetMarkId;
|
||||
Vector<int> currTetBorderFaces;
|
||||
|
||||
for(int i = 0; i<4; i++){
|
||||
int neighborTet = tetFaceNeighbors[4*currTet + i];
|
||||
|
||||
if(neighborTet<0){
|
||||
currTetBorderFaces.append(i);
|
||||
continue;
|
||||
}
|
||||
if(tetMarks[neighborTet]==tetMarkId){
|
||||
continue;
|
||||
}
|
||||
|
||||
float3 p0 = verts[tetVertId[4*neighborTet + 0]];
|
||||
float3 p1 = verts[tetVertId[4*neighborTet + 1]];
|
||||
float3 p2 = verts[tetVertId[4*neighborTet + 2]];
|
||||
float3 p3 = verts[tetVertId[4*neighborTet + 3]];
|
||||
|
||||
float3 circumCenter = getCircumCenter(p0, p1, p2, p3);
|
||||
float circumRadius = length(p0 - circumCenter);
|
||||
|
||||
// if((circumRadius - length(currVert - circumCenter)) >= eps){
|
||||
if(length(currVert - circumCenter) < circumRadius){
|
||||
stack.append(neighborTet);
|
||||
// tetMarks[neighborTet] = tetMarkId;
|
||||
}
|
||||
else{
|
||||
currTetBorderFaces.append(i);
|
||||
}
|
||||
}
|
||||
violatingTets.append({currTet, currTetBorderFaces});
|
||||
}
|
||||
|
||||
return violatingTets;
|
||||
}
|
||||
|
||||
static Vector<int> createTets(Vector<float3> verts, BVHTreeFromMesh *treedata, float minTetQuality){
|
||||
Vector<int> tetVertId; // Stores indices of vertex that form a tet. Every tet is stored as 4 indices
|
||||
Vector<int> tetFaceNeighbors; // Stores index of tet that shares the face as per tetFaces order. 4 neighbors per tet, 1 for each face
|
||||
|
||||
int firstFreeTet = -1;
|
||||
|
||||
Vector<float3> faceNormals; // Stores the normal of each of face of the tet
|
||||
Vector<float> planesD;
|
||||
|
||||
int tetMarkId = 0;
|
||||
Vector<int> tetMarks;
|
||||
/*Used to keep track of visited tets for various processess. In each step where visited tets need to avoided,
|
||||
on visiting them, a unique number is stored representing that particular step
|
||||
*/
|
||||
|
||||
int bigTet = verts.size() - 4;
|
||||
|
||||
for(int i = 0; i<4; i++){
|
||||
tetVertId.append(bigTet + i);
|
||||
tetFaceNeighbors.append(-1);
|
||||
faceNormals.append({0.0, 0.0, 0.0});
|
||||
planesD.append(0.0);
|
||||
}
|
||||
tetMarks.append(0);
|
||||
setTetProperties(verts, tetVertId, faceNormals, planesD, 0);
|
||||
|
||||
for(int vertNr = 0; vertNr<bigTet; vertNr++){
|
||||
float3 currVert = verts[vertNr];
|
||||
|
||||
// std::cout << "Adding vert " << vertNr << std::endl;
|
||||
|
||||
// Find containing tet (need to understand) center can lie outside the tet?
|
||||
tetMarkId += 1;
|
||||
int containingTetNr = -1;
|
||||
containingTetNr = findContainingTet(verts, tetVertId, tetFaceNeighbors, faceNormals, planesD, tetMarkId, tetMarks, currVert);
|
||||
|
||||
if(containingTetNr == -1){
|
||||
std::cout << "Couldn't add vert " << vertNr << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find Violating Tets - Returns all tets that are violating the Delaunay condition along with a list of face indices that are boundary faces
|
||||
// Boundary faces may be outermost face of the structure or the face shared by a violating tet and a non violating tet
|
||||
tetMarkId += 1;
|
||||
Vector<std::pair<int, Vector<int>>> violatingTets = getViolatingTets(verts, tetVertId, tetFaceNeighbors, tetMarkId, tetMarks, currVert, containingTetNr);
|
||||
|
||||
//Create new tets centered at the new point and including the boundary faces
|
||||
Vector<int> newTets; // Stores tet indices of the new tets formed. Used for making neighbors of the new tets formed
|
||||
for(int violatingTetNr = 0; violatingTetNr<violatingTets.size(); violatingTetNr++){
|
||||
int violatingTet = violatingTets[violatingTetNr].first;
|
||||
Vector<int> boundaryFaces = violatingTets[violatingTetNr].second;
|
||||
|
||||
// Copying old tet information
|
||||
Vector<int> currTetVerts;
|
||||
Vector<int> currTetNeighbors;
|
||||
for(int i = 0; i<4; i++){
|
||||
currTetVerts.append(tetVertId[4*violatingTet + i]);
|
||||
currTetNeighbors.append(tetFaceNeighbors[4*violatingTet + i]);
|
||||
}
|
||||
|
||||
// Deleting old tet. For each deleted tet, index 1 stores the index of next free tet
|
||||
tetVertId[4*violatingTet] = -1;
|
||||
tetVertId[4*violatingTet + 1] = firstFreeTet;
|
||||
firstFreeTet = violatingTet;
|
||||
|
||||
for(int i = 0; i<boundaryFaces.size(); i++){
|
||||
Vector<int> faceVerts;
|
||||
for(int j = 2; j>=0; j--){
|
||||
faceVerts.append(currTetVerts[tetFaces[boundaryFaces[i]][j]]);
|
||||
}
|
||||
|
||||
// Make new tet
|
||||
int newTetNr = -1;
|
||||
if(firstFreeTet == -1){
|
||||
newTetNr = tetVertId.size()/4;
|
||||
for(int j = 0; j<4; j++){
|
||||
tetVertId.append(j<3 ? faceVerts[j] : vertNr);
|
||||
tetFaceNeighbors.append(-1);
|
||||
faceNormals.append({0.0,0.0,0.0});
|
||||
planesD.append(0.0);
|
||||
}
|
||||
|
||||
tetMarks.append(0);
|
||||
}
|
||||
else{
|
||||
newTetNr = firstFreeTet;
|
||||
firstFreeTet = tetVertId[4*firstFreeTet + 1];
|
||||
for(int j = 0; j<3; j++){
|
||||
tetVertId[4*newTetNr + j] = faceVerts[j];
|
||||
tetFaceNeighbors[4*newTetNr + j] = -1;
|
||||
}
|
||||
tetVertId[4*newTetNr + 3] = vertNr;
|
||||
tetFaceNeighbors[4*newTetNr + 3] = -1;
|
||||
tetMarks[newTetNr] = 0;
|
||||
}
|
||||
newTets.append(newTetNr);
|
||||
|
||||
tetFaceNeighbors[4*newTetNr] = currTetNeighbors[boundaryFaces[i]];
|
||||
// If the boundary face has no neighboring tet
|
||||
if(currTetNeighbors[boundaryFaces[i]] != -1){
|
||||
// Else correcting the neighbors for the shared face
|
||||
// tetFaceNeighbors[4*newTetNr] = currTetNeighbors[boundaryFaces[i]];
|
||||
for(int j = 0; j<4; j++){
|
||||
if(tetFaceNeighbors[4*currTetNeighbors[boundaryFaces[i]] + j] == violatingTet){
|
||||
tetFaceNeighbors[4*currTetNeighbors[boundaryFaces[i]] + j] = newTetNr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setTetProperties(verts, tetVertId, faceNormals, planesD, newTetNr);
|
||||
}
|
||||
}
|
||||
|
||||
// Setting the neighbors of internal faces of new tets
|
||||
for(int i = 0; i<newTets.size(); i++){
|
||||
for(int j = 0; j<newTets.size(); j++){
|
||||
|
||||
if(j == i){
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int facei = 0; facei<4; facei++){
|
||||
int vertsI[3];
|
||||
for(int k = 0; k<3; k++){
|
||||
vertsI[k] = tetVertId[4*newTets[i] + tetFaces[facei][k]];
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for(int k = 0; k<3; k++){
|
||||
for(int l = 0; l<4; l++){
|
||||
if(vertsI[k] == tetVertId[4*newTets[j] + l]){
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(count == 3){
|
||||
tetFaceNeighbors[4*newTets[i] + facei] = newTets[j];
|
||||
// tetFaceNeighbors[4*newTets[i] + facei] = newTets[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove empty tets and tets that lie outside the structure
|
||||
int emptyTet = 0;
|
||||
int tetLen = tetVertId.size()/4;
|
||||
for(int tetNr = 0; tetNr<tetLen; tetNr++){
|
||||
|
||||
int flag = 1;
|
||||
float3 center(0.0f, 0.0f, 0.0f);
|
||||
for(int i = 0; i<4; i++){
|
||||
center += verts[tetVertId[4*tetNr + i]];
|
||||
if(tetVertId[4*tetNr + i]<0 || tetVertId[4*tetNr + i]>=bigTet){
|
||||
flag = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
center*=0.25;
|
||||
|
||||
if(!flag || !isInside(center, treedata)){
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int i = 0; i<4; i++){
|
||||
tetVertId[4*emptyTet + i] = tetVertId[4*tetNr + i];
|
||||
}
|
||||
emptyTet++;
|
||||
}
|
||||
|
||||
tetVertId.remove(4*emptyTet, 4*(tetLen - emptyTet));
|
||||
|
||||
return tetVertId;
|
||||
}
|
||||
|
||||
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
|
||||
{
|
||||
// Parameters of tetrahedralization, need to be taken as user input, being defined here as placeholders
|
||||
float interiorResolution = 0;
|
||||
float minTetQuality = 0.001; // Exp goes from -4 to 0
|
||||
bool oneFacePerTet = false;
|
||||
float tetScale = 0.8;
|
||||
|
||||
BVHTreeFromMesh treedata = {NULL};
|
||||
BKE_bvhtree_from_mesh_get(&treedata, mesh, BVHTREE_FROM_LOOPTRI, 2);
|
||||
|
||||
Mesh *result;
|
||||
BMesh *bm;
|
||||
bool use_operators = true;
|
||||
|
||||
BMeshCreateParams bmcParam;
|
||||
bmcParam.use_toolflags = true;
|
||||
bm = BM_mesh_create(&bm_mesh_allocsize_default,
|
||||
&bmcParam);
|
||||
|
||||
Vector<float3> tetVerts;
|
||||
|
||||
float3 center(0,0,0);
|
||||
float3 bmin(inf, inf, inf);
|
||||
float3 bmax(-inf, -inf, -inf);
|
||||
|
||||
// Copying surface nodes to tetVerts
|
||||
for(int i = 0; i<mesh->totvert; i++){
|
||||
tetVerts.append({0.0, 0.0, 0.0});
|
||||
tetVerts[i][0] = mesh->mvert[i].co[0] + randomEps();
|
||||
tetVerts[i][1] = mesh->mvert[i].co[1] + randomEps();
|
||||
tetVerts[i][2] = mesh->mvert[i].co[2] + randomEps();
|
||||
|
||||
center += tetVerts[i]; // Can cause overflow?
|
||||
for(int axis = 0; axis<3; axis++){
|
||||
bmin[axis] = min(bmin[axis], tetVerts[i][axis]);
|
||||
bmax[axis] = max(bmax[axis], tetVerts[i][axis]);
|
||||
}
|
||||
|
||||
}
|
||||
center /= (float)tetVerts.size();
|
||||
|
||||
// Computing radius of bounding sphere (max dist of node from center)
|
||||
float radius = 0.0;
|
||||
for(int i = 0; i<tetVerts.size(); i++){
|
||||
float dist = length(tetVerts[i] - center);
|
||||
radius = max(dist, radius);
|
||||
}
|
||||
|
||||
// Interior sampling
|
||||
if(interiorResolution > 0.0){
|
||||
float boundLen[3];
|
||||
sub_v3_v3v3(boundLen, bmax, bmin);
|
||||
float maxBoundLen = max_axis_v3(boundLen);
|
||||
float sampleLen = maxBoundLen/interiorResolution;
|
||||
|
||||
for(int xi = 0; xi<(int)(boundLen[0]/sampleLen); xi++){
|
||||
float x = bmin[0] + xi*sampleLen + randomEps();
|
||||
for(int yi = 0; yi<(int)(boundLen[1]/sampleLen); yi++){
|
||||
float y = bmin[1] + yi*sampleLen + randomEps();
|
||||
for(int zi = 0; zi<(int)(boundLen[2]/sampleLen); zi++){
|
||||
float z = bmin[2] + zi*sampleLen + randomEps();
|
||||
|
||||
if(isInside({x,y,z}, &treedata)){
|
||||
tetVerts.append({x,y,z});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float bigTetSize = radius*5.0;
|
||||
|
||||
tetVerts.append({-bigTetSize, 0.0, -bigTetSize});
|
||||
tetVerts.append({bigTetSize, 0.0, -bigTetSize});
|
||||
tetVerts.append({0.0, bigTetSize, bigTetSize});
|
||||
tetVerts.append({0.0, -bigTetSize, bigTetSize});
|
||||
|
||||
Vector<int> tetVertId = createTets(tetVerts, &treedata, minTetQuality);
|
||||
|
||||
Vector<BMVert *> bmverts;
|
||||
if(oneFacePerTet){
|
||||
for(int i = 0; i<mesh->totvert; i++){
|
||||
bmverts.append(BM_vert_create(bm, mesh->mvert[i].co, NULL, BM_CREATE_NOP));
|
||||
}
|
||||
for(int i = mesh->totvert; i<tetVerts.size(); i++){
|
||||
bmverts.append(BM_vert_create(bm, tetVerts[i], NULL, BM_CREATE_NOP));
|
||||
}
|
||||
}
|
||||
else{
|
||||
// Add vertices multiple times to make the tets distinctly visible
|
||||
for(int tetNr = 0; tetNr<tetVertId.size()/4; tetNr++){
|
||||
float3 center(0,0,0);
|
||||
for(int j = 0; j<4; j++){
|
||||
center += tetVerts[tetVertId[4*tetNr + j]];
|
||||
}
|
||||
center *= 0.25;
|
||||
|
||||
for(int faceNr = 0; faceNr < 4; faceNr++){
|
||||
for(int faceVertNr = 0; faceVertNr < 3; faceVertNr++){
|
||||
float3 vert = tetVerts[tetVertId[4*tetNr + tetFaces[faceNr][faceVertNr]]];
|
||||
vert = center + (vert - center)*tetScale;
|
||||
bmverts.append(BM_vert_create(bm, vert, NULL, BM_CREATE_NOP));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int numTets = tetVertId.size()/4;
|
||||
int nr = 0;
|
||||
for(int i = 0; i<numTets; i++){
|
||||
if(oneFacePerTet){
|
||||
if(tetVertId[4*i] < 0)
|
||||
continue;
|
||||
BM_face_create_quad_tri(bm, bmverts[tetVertId[4*i + 0]], bmverts[tetVertId[4*i + 1]], bmverts[tetVertId[4*i + 2]], bmverts[tetVertId[4*i + 3]], NULL, BM_CREATE_NO_DOUBLE);
|
||||
}
|
||||
else{
|
||||
for(int faceNr = 0; faceNr<4; faceNr++){
|
||||
BM_face_create_quad_tri(bm, bmverts[nr], bmverts[nr+1], bmverts[nr+2], NULL, NULL, BM_CREATE_NO_DOUBLE);
|
||||
nr+=3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomData_MeshMasks cd_mask_extra = {
|
||||
.vmask = CD_MASK_ORIGINDEX, .emask = CD_MASK_ORIGINDEX, .pmask = CD_MASK_ORIGINDEX};
|
||||
|
||||
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cd_mask_extra, mesh);
|
||||
BM_mesh_free(bm);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------
|
||||
// --------------------------------------
|
||||
|
||||
// static Span<MDeformVert> get_vertex_group(const Mesh &mesh, const int defgrp_index)
|
||||
// {
|
||||
// if (defgrp_index == -1) {
|
||||
// return {};
|
||||
// }
|
||||
// const MDeformVert *vertex_group = static_cast<const MDeformVert *>(
|
||||
// CustomData_get_layer(&mesh.vdata, CD_MDEFORMVERT));
|
||||
// if (!vertex_group) {
|
||||
// return {};
|
||||
// }
|
||||
// return {vertex_group, mesh.totvert};
|
||||
// }
|
||||
|
||||
// static Vector<int64_t> selected_indices_from_vertex_group(Span<MDeformVert> vertex_group,
|
||||
// const int index,
|
||||
// const bool invert)
|
||||
// {
|
||||
// Vector<int64_t> selected_indices;
|
||||
// for (const int i : vertex_group.index_range()) {
|
||||
// const bool found = BKE_defvert_find_weight(&vertex_group[i], index) > 0.0f;
|
||||
// if (found != invert) {
|
||||
// selected_indices.append(i);
|
||||
// }
|
||||
// }
|
||||
// return selected_indices;
|
||||
// }
|
||||
|
||||
// static Array<bool> selection_array_from_vertex_group(Span<MDeformVert> vertex_group,
|
||||
// const int index,
|
||||
// const bool invert)
|
||||
// {
|
||||
// Array<bool> selection(vertex_group.size());
|
||||
// for (const int i : vertex_group.index_range()) {
|
||||
// const bool found = BKE_defvert_find_weight(&vertex_group[i], index) > 0.0f;
|
||||
// selection[i] = (found != invert);
|
||||
// }
|
||||
// return selection;
|
||||
// }
|
||||
|
||||
// static std::optional<Mesh *> calculate_weld(const Mesh &mesh, const WeldModifierData &wmd)
|
||||
// {
|
||||
// const int defgrp_index = BKE_id_defgroup_name_index(&mesh.id, wmd.defgrp_name);
|
||||
// Span<MDeformVert> vertex_group = get_vertex_group(mesh, defgrp_index);
|
||||
// const bool invert = (wmd.flag & MOD_WELD_INVERT_VGROUP) != 0;
|
||||
|
||||
// if (wmd.mode == MOD_WELD_MODE_ALL) {
|
||||
// if (!vertex_group.is_empty()) {
|
||||
// Vector<int64_t> selected_indices = selected_indices_from_vertex_group(
|
||||
// vertex_group, defgrp_index, invert);
|
||||
// return blender::geometry::mesh_merge_by_distance_all(
|
||||
// mesh, IndexMask(selected_indices), wmd.merge_dist);
|
||||
// }
|
||||
// return blender::geometry::mesh_merge_by_distance_all(
|
||||
// mesh, IndexMask(mesh.totvert), wmd.merge_dist);
|
||||
// }
|
||||
// if (wmd.mode == MOD_WELD_MODE_CONNECTED) {
|
||||
// const bool only_loose_edges = (wmd.flag & MOD_WELD_LOOSE_EDGES) != 0;
|
||||
// if (!vertex_group.is_empty()) {
|
||||
// Array<bool> selection = selection_array_from_vertex_group(
|
||||
// vertex_group, defgrp_index, invert);
|
||||
// return blender::geometry::mesh_merge_by_distance_connected(
|
||||
// mesh, selection, wmd.merge_dist, only_loose_edges);
|
||||
// }
|
||||
// Array<bool> selection(mesh.totvert, true);
|
||||
// return blender::geometry::mesh_merge_by_distance_connected(
|
||||
// mesh, selection, wmd.merge_dist, only_loose_edges);
|
||||
// }
|
||||
|
||||
// BLI_assert_unreachable();
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
// static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
|
||||
// {
|
||||
// const WeldModifierData &wmd = reinterpret_cast<WeldModifierData &>(*md);
|
||||
|
||||
// std::optional<Mesh *> result = calculate_weld(*mesh, wmd);
|
||||
// if (!result) {
|
||||
// return mesh;
|
||||
// }
|
||||
// return *result;
|
||||
// }
|
||||
|
||||
static void initData(ModifierData *md)
|
||||
{
|
||||
WeldModifierData *wmd = (WeldModifierData *)md;
|
||||
|
||||
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier));
|
||||
|
||||
MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeldModifierData), modifier);
|
||||
}
|
||||
|
||||
static void requiredDataMask(Object *UNUSED(ob),
|
||||
ModifierData *md,
|
||||
CustomData_MeshMasks *r_cddata_masks)
|
||||
{
|
||||
WeldModifierData *wmd = (WeldModifierData *)md;
|
||||
|
||||
/* Ask for vertexgroups if we need them. */
|
||||
if (wmd->defgrp_name[0] != '\0') {
|
||||
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
|
||||
}
|
||||
}
|
||||
|
||||
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
|
||||
{
|
||||
uiLayout *layout = panel->layout;
|
||||
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
int weld_mode = RNA_enum_get(ptr, "mode");
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
uiItemR(layout, ptr, "mode", 0, nullptr, ICON_NONE);
|
||||
uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
|
||||
if (weld_mode == MOD_WELD_MODE_CONNECTED) {
|
||||
uiItemR(layout, ptr, "loose_edges", 0, nullptr, ICON_NONE);
|
||||
}
|
||||
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
|
||||
|
||||
modifier_panel_end(layout, ptr);
|
||||
}
|
||||
|
||||
static void panelRegister(ARegionType *region_type)
|
||||
{
|
||||
modifier_panel_register(region_type, eModifierType_Weld, panel_draw);
|
||||
}
|
||||
|
||||
ModifierTypeInfo modifierType_Weld = {
|
||||
/* name */ "Weld",
|
||||
/* structName */ "WeldModifierData",
|
||||
/* structSize */ sizeof(WeldModifierData),
|
||||
/* srna */ &RNA_WeldModifier,
|
||||
/* type */ eModifierTypeType_Constructive,
|
||||
/* flags */
|
||||
(ModifierTypeFlag)(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
|
||||
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
|
||||
eModifierTypeFlag_AcceptsCVs),
|
||||
/* icon */ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */
|
||||
|
||||
/* copyData */ BKE_modifier_copydata_generic,
|
||||
|
||||
/* deformVerts */ nullptr,
|
||||
/* deformMatrices */ nullptr,
|
||||
/* deformVertsEM */ nullptr,
|
||||
/* deformMatricesEM */ nullptr,
|
||||
/* modifyMesh */ modifyMesh,
|
||||
/* modifyGeometrySet */ nullptr,
|
||||
|
||||
/* initData */ initData,
|
||||
/* requiredDataMask */ requiredDataMask,
|
||||
/* freeData */ nullptr,
|
||||
/* isDisabled */ nullptr,
|
||||
/* updateDepsgraph */ nullptr,
|
||||
/* dependsOnTime */ nullptr,
|
||||
/* dependsOnNormals */ nullptr,
|
||||
/* foreachIDLink */ nullptr,
|
||||
/* foreachTexLink */ nullptr,
|
||||
/* freeRuntimeData */ nullptr,
|
||||
/* panelRegister */ panelRegister,
|
||||
/* blendWrite */ nullptr,
|
||||
/* blendRead */ nullptr,
|
||||
};
|
@@ -610,14 +610,36 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
|
||||
|
||||
Vector<int> tetVertId = createTets(tetVerts, &treedata, minTetQuality);
|
||||
|
||||
if(globalFlag){
|
||||
return mesh;
|
||||
// Creates a 2 tets to test collisions
|
||||
bool testing = true;
|
||||
|
||||
if(testing){
|
||||
tetVertId.remove(0, tetVertId.size());
|
||||
tetVerts.remove(0, tetVerts.size());
|
||||
|
||||
tetVerts.append({-1, -1, 0});
|
||||
tetVerts.append({-1, 1, 0});
|
||||
tetVerts.append({1, -1, 0});
|
||||
tetVerts.append({-1, -1, 1});
|
||||
|
||||
tetVerts.append({0, 0, 1});
|
||||
tetVerts.append({0, 0, 2});
|
||||
tetVerts.append({0, 1, 2});
|
||||
tetVerts.append({1, 0, 2});
|
||||
|
||||
for(int i = 0; i<8; i++)
|
||||
tetVertId.append(i);
|
||||
}
|
||||
|
||||
// if(globalFlag){
|
||||
// return mesh;
|
||||
// }
|
||||
|
||||
Vector<BMVert *> bmverts;
|
||||
if(oneFacePerTet){
|
||||
for(int i = 0; i<mesh->totvert; i++){
|
||||
bmverts.append(BM_vert_create(bm, mesh->mvert[i].co, NULL, BM_CREATE_NOP));
|
||||
// bmverts.append(BM_vert_create(bm, mesh->mvert[i].co, NULL, BM_CREATE_NOP));
|
||||
bmverts.append(BM_vert_create(bm, tetVerts[i], NULL, BM_CREATE_NOP));
|
||||
}
|
||||
for(int i = mesh->totvert; i<tetVerts.size()-4; i++){
|
||||
bmverts.append(BM_vert_create(bm, tetVerts[i], NULL, BM_CREATE_NOP));
|
||||
|
@@ -267,7 +267,23 @@ static int find_intersecting_face(BodyPoint *bpoint_arr, BodyPoint *curr_point,
|
||||
// Checking which is the closest face
|
||||
// float min_dist = FLT_MAX;
|
||||
// float min_face = -1;
|
||||
|
||||
// for(int facenr = 0; facenr < 4; facenr++){
|
||||
// BodyPoint *face_point0 = &bpoint_arr[curr_tet->verts[tet_faces[facenr][0]]];
|
||||
// BodyPoint *face_point1 = &bpoint_arr[curr_tet->verts[tet_faces[facenr][1]]];
|
||||
// BodyPoint *face_point2 = &bpoint_arr[curr_tet->verts[tet_faces[facenr][2]]];
|
||||
|
||||
// float coeff[4];
|
||||
// float diff10[3], diff20[3];
|
||||
// sub_v3_v3v3(diff10, face_point1->x, face_point0->x);
|
||||
// sub_v3_v3v3(diff20, face_point2->x, face_point0->x);
|
||||
// cross_v3_v3v3(coeff, diff10, diff20);
|
||||
// coeff[3] = -dot_v3v3(coeff, face_point0->x);
|
||||
// }
|
||||
|
||||
// Is the point inside tet getting detected correctly?
|
||||
// Is the intersecting face getting detected correctly?
|
||||
// Is the correction working as expected?
|
||||
}
|
||||
|
||||
void xpbd_solve_self_collision(SoftBody *sb){
|
||||
|
Reference in New Issue
Block a user