Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/mball_tessellate.c
| Show All 24 Lines | |||||
| #include <float.h> | #include <float.h> | ||||
| #include <math.h> | #include <math.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <string.h> | #include <string.h> | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "DNA_mesh_types.h" | |||||
| #include "DNA_meshdata_types.h" | |||||
| #include "DNA_meta_types.h" | #include "DNA_meta_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_memarena.h" | #include "BLI_memarena.h" | ||||
| #include "BLI_string_utils.h" | #include "BLI_string_utils.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_displist.h" | #include "BKE_displist.h" | ||||
| #include "BKE_mball_tessellate.h" /* own include */ | #include "BKE_mball_tessellate.h" /* own include */ | ||||
| #include "BKE_mesh.h" | |||||
| #include "BKE_mesh_runtime.h" | |||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| #include "BLI_strict_flags.h" | #include "BLI_strict_flags.h" | ||||
| /* experimental (faster) normal calculation */ | /* experimental (faster) normal calculation */ | ||||
| // #define USE_ACCUM_NORMAL | #define USE_ACCUM_NORMAL | ||||
| struct MVert; | |||||
| struct MLoop; | |||||
| struct MPoly; | |||||
| /* Data types */ | /* Data types */ | ||||
| typedef struct corner { /* corner of a cube */ | typedef struct corner { /* corner of a cube */ | ||||
| int i, j, k; /* (i, j, k) is index within lattice */ | int i, j, k; /* (i, j, k) is index within lattice */ | ||||
| float co[3], value; /* location and function value */ | float co[3], value; /* location and function value */ | ||||
| struct corner *next; | struct corner *next; | ||||
| } CORNER; | } CORNER; | ||||
| typedef struct cube { /* partitioning cell (cube) */ | typedef struct cube { /* partitioning cell (cube) */ | ||||
| int i, j, k; /* lattice location of cube */ | int i, j, k, index; /* lattice location of cube + original index ? */ | ||||
| CORNER *corners[8]; /* eight corners */ | CORNER *corners[8]; /* eight corners */ | ||||
| } CUBE; | } CUBE; | ||||
| typedef struct cubes { /* linked list of cubes acting as stack */ | typedef struct cubes { /* linked list of cubes acting as stack */ | ||||
| CUBE cube; /* a single cube */ | CUBE cube; /* a single cube */ | ||||
| struct cubes *next; /* remaining elements */ | struct cubes *next; /* remaining elements */ | ||||
| } CUBES; | } CUBES; | ||||
| ▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | typedef struct process { /* parameters, storage */ | ||||
| int (*indices)[4]; /* output indices */ | int (*indices)[4]; /* output indices */ | ||||
| unsigned int totindex; /* size of memory allocated for indices */ | unsigned int totindex; /* size of memory allocated for indices */ | ||||
| unsigned int curindex; /* number of currently added indices */ | unsigned int curindex; /* number of currently added indices */ | ||||
| float (*co)[3], (*no)[3]; /* surface vertices - positions and normals */ | float (*co)[3], (*no)[3]; /* surface vertices - positions and normals */ | ||||
| unsigned int totvertex; /* memory size */ | unsigned int totvertex; /* memory size */ | ||||
| unsigned int curvertex; /* currently added vertices */ | unsigned int curvertex; /* currently added vertices */ | ||||
| int *orig_index; /* map new vertices to original ones */ | |||||
| /* memory allocation from common pool */ | /* memory allocation from common pool */ | ||||
| MemArena *pgn_elements; | MemArena *pgn_elements; | ||||
| } PROCESS; | } PROCESS; | ||||
| /* Forward declarations */ | /* Forward declarations */ | ||||
| static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2); | static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2, int index); | ||||
| static void add_cube(PROCESS *process, int i, int j, int k); | static void add_cube(PROCESS *process, int i, int j, int k, int index); | ||||
| static void make_face(PROCESS *process, int i1, int i2, int i3, int i4); | static void make_face(PROCESS *process, int i1, int i2, int i3, int i4); | ||||
| static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3]); | static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3]); | ||||
| /* ******************* SIMPLE BVH ********************* */ | /* ******************* SIMPLE BVH ********************* */ | ||||
| static void make_box_union(const BoundBox *a, const Box *b, Box *r_out) | static void make_box_union(const BoundBox *a, const Box *b, Box *r_out) | ||||
| { | { | ||||
| r_out->min[0] = min_ff(a->vec[0][0], b->min[0]); | r_out->min[0] = min_ff(a->vec[0][0], b->min[0]); | ||||
| ▲ Show 20 Lines • Show All 456 Lines • ▼ Show 20 Lines | static void docube(PROCESS *process, CUBE *cube) | ||||
| for (i = 0; i < 8; i++) { | for (i = 0; i < 8; i++) { | ||||
| if (cube->corners[i]->value > 0.0f) { | if (cube->corners[i]->value > 0.0f) { | ||||
| index += (1 << i); | index += (1 << i); | ||||
| } | } | ||||
| } | } | ||||
| /* Using faces[] table, adds neighboring cube if surface intersects face in this direction. */ | /* Using faces[] table, adds neighboring cube if surface intersects face in this direction. */ | ||||
| if (MB_BIT(faces[index], 0)) { | if (MB_BIT(faces[index], 0)) { | ||||
| add_cube(process, cube->i - 1, cube->j, cube->k); | add_cube(process, cube->i - 1, cube->j, cube->k, cube->index); | ||||
| } | } | ||||
| if (MB_BIT(faces[index], 1)) { | if (MB_BIT(faces[index], 1)) { | ||||
| add_cube(process, cube->i + 1, cube->j, cube->k); | add_cube(process, cube->i + 1, cube->j, cube->k, cube->index); | ||||
| } | } | ||||
| if (MB_BIT(faces[index], 2)) { | if (MB_BIT(faces[index], 2)) { | ||||
| add_cube(process, cube->i, cube->j - 1, cube->k); | add_cube(process, cube->i, cube->j - 1, cube->k, cube->index); | ||||
| } | } | ||||
| if (MB_BIT(faces[index], 3)) { | if (MB_BIT(faces[index], 3)) { | ||||
| add_cube(process, cube->i, cube->j + 1, cube->k); | add_cube(process, cube->i, cube->j + 1, cube->k, cube->index); | ||||
| } | } | ||||
| if (MB_BIT(faces[index], 4)) { | if (MB_BIT(faces[index], 4)) { | ||||
| add_cube(process, cube->i, cube->j, cube->k - 1); | add_cube(process, cube->i, cube->j, cube->k - 1, cube->index); | ||||
| } | } | ||||
| if (MB_BIT(faces[index], 5)) { | if (MB_BIT(faces[index], 5)) { | ||||
| add_cube(process, cube->i, cube->j, cube->k + 1); | add_cube(process, cube->i, cube->j, cube->k + 1, cube->index); | ||||
| } | } | ||||
| /* Using cubetable[], determines polygons for output. */ | /* Using cubetable[], determines polygons for output. */ | ||||
| for (polys = cubetable[index]; polys; polys = polys->next) { | for (polys = cubetable[index]; polys; polys = polys->next) { | ||||
| INTLIST *edges; | INTLIST *edges; | ||||
| count = 0; | count = 0; | ||||
| /* Sets needed vertex id's lying on the edges. */ | /* Sets needed vertex id's lying on the edges. */ | ||||
| for (edges = polys->list; edges; edges = edges->next) { | for (edges = polys->list; edges; edges = edges->next) { | ||||
| c1 = cube->corners[corner1[edges->i]]; | c1 = cube->corners[corner1[edges->i]]; | ||||
| c2 = cube->corners[corner2[edges->i]]; | c2 = cube->corners[corner2[edges->i]]; | ||||
| indexar[count] = vertid(process, c1, c2); | indexar[count] = vertid(process, c1, c2, cube->index); | ||||
| count++; | count++; | ||||
| } | } | ||||
| /* Adds faces to output. */ | /* Adds faces to output. */ | ||||
| if (count > 2) { | if (count > 2) { | ||||
| switch (count) { | switch (count) { | ||||
| case 3: | case 3: | ||||
| make_face(process, indexar[2], indexar[1], indexar[0], indexar[0]); /* triangle */ | make_face(process, indexar[2], indexar[1], indexar[0], indexar[0]); /* triangle */ | ||||
| ▲ Show 20 Lines • Show All 293 Lines • ▼ Show 20 Lines | for (; q != NULL; q = q->next) { | ||||
| } | } | ||||
| } | } | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| /** | /** | ||||
| * Adds a vertex, expands memory if needed. | * Adds a vertex, expands memory if needed. | ||||
| */ | */ | ||||
| static void addtovertices(PROCESS *process, const float v[3], const float no[3]) | static void addtovertices(PROCESS *process, const float v[3], const float no[3], int index) | ||||
| { | { | ||||
| if (process->curvertex == process->totvertex) { | if (process->curvertex == process->totvertex) { | ||||
| process->totvertex += 4096; | process->totvertex += 4096; | ||||
| process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3])); | process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3])); | ||||
| process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3])); | process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3])); | ||||
| process->orig_index = MEM_reallocN(process->orig_index, process->totvertex * sizeof(int)); | |||||
| } | } | ||||
| copy_v3_v3(process->co[process->curvertex], v); | copy_v3_v3(process->co[process->curvertex], v); | ||||
| copy_v3_v3(process->no[process->curvertex], no); | copy_v3_v3(process->no[process->curvertex], no); | ||||
| process->orig_index[process->curvertex] = index; | |||||
| process->curvertex++; | process->curvertex++; | ||||
| } | } | ||||
| #ifndef USE_ACCUM_NORMAL | #ifndef USE_ACCUM_NORMAL | ||||
| /** | /** | ||||
| * Computes normal from density field at given point. | * Computes normal from density field at given point. | ||||
| * | * | ||||
| Show All 10 Lines | |||||
| } | } | ||||
| #endif /* USE_ACCUM_NORMAL */ | #endif /* USE_ACCUM_NORMAL */ | ||||
| /** | /** | ||||
| * \return the id of vertex between two corners. | * \return the id of vertex between two corners. | ||||
| * | * | ||||
| * If it wasn't previously computed, does #converge() and adds vertex to process. | * If it wasn't previously computed, does #converge() and adds vertex to process. | ||||
| */ | */ | ||||
| static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2) | static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2, int index) | ||||
| { | { | ||||
| float v[3], no[3]; | float v[3], no[3]; | ||||
| int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k); | int vid = getedge(process->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k); | ||||
| if (vid != -1) { | if (vid != -1) { | ||||
| return vid; /* previously computed */ | return vid; /* previously computed */ | ||||
| } | } | ||||
| converge(process, c1, c2, v); /* position */ | converge(process, c1, c2, v); /* position */ | ||||
| #ifdef USE_ACCUM_NORMAL | #ifdef USE_ACCUM_NORMAL | ||||
| zero_v3(no); | zero_v3(no); | ||||
| #else | #else | ||||
| vnormal(process, v, no); | vnormal(process, v, no); | ||||
| #endif | #endif | ||||
| addtovertices(process, v, no); /* save vertex */ | addtovertices(process, v, no, index); /* save vertex */ | ||||
| vid = (int)process->curvertex - 1; | vid = (int)process->curvertex - 1; | ||||
| setedge(process, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid); | setedge(process, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid); | ||||
| return vid; | return vid; | ||||
| } | } | ||||
| /** | /** | ||||
| * Given two corners, computes approximation of surface intersection point between them. | * Given two corners, computes approximation of surface intersection point between them. | ||||
| Show All 35 Lines | static void converge(PROCESS *process, const CORNER *c1, const CORNER *c2, float r_p[3]) | ||||
| tmp = -c1_value / (c2_value - c1_value); | tmp = -c1_value / (c2_value - c1_value); | ||||
| interp_v3_v3v3(r_p, c1_co, c2_co, tmp); | interp_v3_v3v3(r_p, c1_co, c2_co, tmp); | ||||
| } | } | ||||
| /** | /** | ||||
| * Adds cube at given lattice position to cube stack of process. | * Adds cube at given lattice position to cube stack of process. | ||||
| */ | */ | ||||
| static void add_cube(PROCESS *process, int i, int j, int k) | static void add_cube(PROCESS *process, int i, int j, int k, int index) | ||||
| { | { | ||||
| CUBES *ncube; | CUBES *ncube; | ||||
| int n; | int n; | ||||
| /* test if cube has been found before */ | /* test if cube has been found before */ | ||||
| if (setcenter(process, process->centers, i, j, k) == 0) { | if (setcenter(process, process->centers, i, j, k) == 0) { | ||||
| /* push cube on stack: */ | /* push cube on stack: */ | ||||
| ncube = BLI_memarena_alloc(process->pgn_elements, sizeof(CUBES)); | ncube = BLI_memarena_alloc(process->pgn_elements, sizeof(CUBES)); | ||||
| ncube->next = process->cubes; | ncube->next = process->cubes; | ||||
| process->cubes = ncube; | process->cubes = ncube; | ||||
| ncube->cube.i = i; | ncube->cube.i = i; | ||||
| ncube->cube.j = j; | ncube->cube.j = j; | ||||
| ncube->cube.k = k; | ncube->cube.k = k; | ||||
| ncube->cube.index = index; | |||||
| /* set corners of initial cube: */ | /* set corners of initial cube: */ | ||||
| for (n = 0; n < 8; n++) { | for (n = 0; n < 8; n++) { | ||||
| ncube->cube.corners[n] = setcorner( | ncube->cube.corners[n] = setcorner( | ||||
| process, i + MB_BIT(n, 2), j + MB_BIT(n, 1), k + MB_BIT(n, 0)); | process, i + MB_BIT(n, 2), j + MB_BIT(n, 1), k + MB_BIT(n, 0)); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | for (dir[1] = -1; dir[1] <= 1; dir[1]++) { | ||||
| a = b; | a = b; | ||||
| b = setcorner(process, it[0], it[1], it[2])->value; | b = setcorner(process, it[0], it[1], it[2])->value; | ||||
| if (a * b < 0.0f) { | if (a * b < 0.0f) { | ||||
| add[0] = it[0] - dir[0]; | add[0] = it[0] - dir[0]; | ||||
| add[1] = it[1] - dir[1]; | add[1] = it[1] - dir[1]; | ||||
| add[2] = it[2] - dir[2]; | add[2] = it[2] - dir[2]; | ||||
| DO_MIN(it, add); | DO_MIN(it, add); | ||||
| add_cube(process, add[0], add[1], add[2]); | add_cube(process, add[0], add[1], add[2], (int)em); | ||||
| break; | break; | ||||
| } | } | ||||
| } while ((it[0] > lbn[0]) && (it[1] > lbn[1]) && (it[2] > lbn[2]) && (it[0] < rtf[0]) && | } while ((it[0] > lbn[0]) && (it[1] > lbn[1]) && (it[2] > lbn[2]) && (it[0] < rtf[0]) && | ||||
| (it[1] < rtf[1]) && (it[2] < rtf[2])); | (it[1] < rtf[1]) && (it[2] < rtf[2])); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 321 Lines • ▼ Show 20 Lines | if (ob->scale[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) || | ||||
| dl->verts = (float *)process.co; | dl->verts = (float *)process.co; | ||||
| dl->nors = (float *)process.no; | dl->nors = (float *)process.no; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| freepolygonize(&process); | freepolygonize(&process); | ||||
| } | } | ||||
| static void init_meta_dm(PROCESS *process, | |||||
| Mesh *dm, | |||||
| float stiffness, | |||||
| float radius, | |||||
| float size[3], | |||||
| bool override_size, | |||||
| int defgrp_size) | |||||
| { | |||||
| float quat[4]; | |||||
| unsigned int i; | |||||
| int totvert = dm->totvert, j; | |||||
| MVert *mvert = dm->mvert; | |||||
| float *psize = CustomData_get_layer_named(&dm->vdata, CD_PROP_FLOAT, "psize"); | |||||
| MDeformVert *dvert = CustomData_get_layer(&dm->vdata, CD_MDEFORMVERT); | |||||
| unit_qt(quat); | |||||
campbellbarton: Why not use the vertex normal to calculate the rotation? | |||||
| /* make main array */ | |||||
| for (j = 0; j < totvert; j++, mvert++) { | |||||
| MetaElem *new_ml; | |||||
| // float size[3] = {1.0f, 1.0f, 1.0f}; | |||||
| float expx, expy, expz; | |||||
| float tempmin[3], tempmax[3]; | |||||
| float sz[3]; | |||||
| if (psize != NULL && psize[j] > 0.0f && override_size) { | |||||
| mul_v3_v3fl(sz, size, psize[j]); | |||||
| } | |||||
| else { | |||||
| copy_v3_v3(sz, size); | |||||
| } | |||||
| /* make a copy because of duplicates */ | |||||
| new_ml = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem)); | |||||
| new_ml->bb = BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox)); | |||||
| new_ml->mat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); | |||||
| new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); | |||||
| // init new_ml | |||||
| new_ml->type = MB_BALL; | |||||
| new_ml->flag = MB_SCALE_RAD; | |||||
| /* too big stiffness seems only ugly due to linear interpolation | |||||
| * no need to have possibility for too big stiffness */ | |||||
| // if (ml->s > 10.0f) new_ml->s = 10.0f; | |||||
| // else new_ml->s = ml->s; | |||||
| new_ml->s = stiffness; | |||||
| /* if metaball is negative, set stiffness negative */ | |||||
| // if (new_ml->flag & MB_NEGATIVE) new_ml->s = -new_ml->s; | |||||
| if (dvert && defgrp_size > -1) { | |||||
| MDeformVert *dv = dvert + j; | |||||
| if (dv && dv->dw) { | |||||
| float w = dv->dw[defgrp_size].weight - 0.5f; | |||||
| // map 0..1 weights to -0.5f ... + 0.5f size factor, to allow also negative sizes... 0.5f | |||||
| // weight is 0 size | |||||
| mul_v3_fl(sz, w); | |||||
| /* if metaball is negative, set stiffness negative, indicated by weight < 0.5f here */ | |||||
| if (w < 0.5f) { | |||||
| new_ml->s = -new_ml->s; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* Translation of MetaElem */ | |||||
| /*unit_m4(pos); | |||||
| pos[3][0] = mvert->co[0]; | |||||
| pos[3][1] = mvert->co[1]; | |||||
| pos[3][2] = mvert->co[2];*/ | |||||
| new_ml->x = mvert->co[0]; | |||||
| new_ml->y = mvert->co[1]; | |||||
| new_ml->z = mvert->co[2]; | |||||
| /* Rotation of MetaElem is stored in quat */ | |||||
| // quat_to_mat4(rot, quat); | |||||
| loc_quat_size_to_mat4((float(*)[4])new_ml->mat, mvert->co, quat, sz); | |||||
| invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat); | |||||
| #if 0 | |||||
| /* basis object space -> world -> ml object space -> position -> rotation -> ml local space */ | |||||
| mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot); | |||||
| /* ml local space -> basis object space */ | |||||
| invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat); | |||||
| #endif | |||||
| /* rad2 is inverse of squared radius */ | |||||
| new_ml->rad = radius; | |||||
| new_ml->rad2 = 1 / (radius * radius); | |||||
| /* initial dimensions = radius */ | |||||
| expx = radius; | |||||
| expy = radius; | |||||
| expz = radius; | |||||
| new_ml->expx = expx; | |||||
| new_ml->expy = expy; | |||||
| new_ml->expz = expz; | |||||
| #if 0 | |||||
| switch (ml->type) { | |||||
| case MB_BALL: | |||||
| break; | |||||
| case MB_CUBE: /* cube is "expanded" by expz, expy and expx */ | |||||
| expz += ml->expz; | |||||
| ATTR_FALLTHROUGH; | |||||
| case MB_PLANE: /* plane is "expanded" by expy and expx */ | |||||
| expy += ml->expy; | |||||
| ATTR_FALLTHROUGH; | |||||
| case MB_TUBE: /* tube is "expanded" by expx */ | |||||
| expx += ml->expx; | |||||
| break; | |||||
| case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */ | |||||
| expx *= ml->expx; | |||||
| expy *= ml->expy; | |||||
| expz *= ml->expz; | |||||
| break; | |||||
| } | |||||
| #endif | |||||
| /* untransformed Bounding Box of MetaElem */ | |||||
| /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */ | |||||
| copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz); /* 0 */ | |||||
| copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz); /* 1 */ | |||||
| copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz); /* 2 */ | |||||
| copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz); /* 3 */ | |||||
| copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz); /* 4 */ | |||||
| copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz); /* 5 */ | |||||
| copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */ | |||||
| copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */ | |||||
| /* transformation of Metalem bb */ | |||||
| for (i = 0; i < 8; i++) | |||||
| mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]); | |||||
| /* find max and min of transformed bb */ | |||||
| INIT_MINMAX(tempmin, tempmax); | |||||
| for (i = 0; i < 8; i++) { | |||||
| DO_MINMAX(new_ml->bb->vec[i], tempmin, tempmax); | |||||
| } | |||||
| /* set only point 0 and 6 - AABB of Metaelem */ | |||||
| copy_v3_v3(new_ml->bb->vec[0], tempmin); | |||||
| copy_v3_v3(new_ml->bb->vec[6], tempmax); | |||||
| /* add new_ml to mainb[] */ | |||||
| if (UNLIKELY(process->totelem == process->mem)) { | |||||
| process->mem = process->mem * 2 + 10; | |||||
| process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem); | |||||
| } | |||||
| process->mainb[process->totelem++] = new_ml; | |||||
| } | |||||
| /* compute AABB of all Metaelems */ | |||||
| if (process->totelem > 0) { | |||||
| copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]); | |||||
| copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]); | |||||
| for (i = 1; i < process->totelem; i++) | |||||
| make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb); | |||||
| } | |||||
| } | |||||
| static void BKE_dm_from_metaball(DispList *dl, | |||||
| Mesh *dm, | |||||
| Mesh *UNUSED(odm), | |||||
| int *UNUSED(orig_index)) | |||||
| { | |||||
| MVert *mvert; | |||||
| MLoop *mloop, *allloop; | |||||
| MPoly *mpoly; | |||||
| const float *nors, *verts; | |||||
| int a, *index; | |||||
| /* int totvert = 0; */ /* UNUSED */ | |||||
| if (dl == NULL) | |||||
| return; | |||||
| if (dl->type == DL_INDEX4) { | |||||
| /* totvert = dm->totvert; */ /* UNUSED */ | |||||
| mvert = dm->mvert; | |||||
| allloop = mloop = dm->mloop; | |||||
| mpoly = dm->mpoly; | |||||
| // this will be recalculated here | |||||
| dm->totloop = 0; | |||||
| a = dl->nr; | |||||
| nors = dl->nors; | |||||
| verts = dl->verts; | |||||
| while (a--) { | |||||
| copy_v3_v3(mvert->co, verts); | |||||
| normal_float_to_short_v3(mvert->no, nors); | |||||
| mvert++; | |||||
| nors += 3; | |||||
| verts += 3; | |||||
| } | |||||
| a = dl->parts; | |||||
| index = dl->index; | |||||
| while (a--) { | |||||
| int count = index[2] != index[3] ? 4 : 3; | |||||
| mloop[0].v = (unsigned int)index[0]; | |||||
| mloop[1].v = (unsigned int)index[1]; | |||||
| mloop[2].v = (unsigned int)index[2]; | |||||
| if (count == 4) | |||||
| mloop[3].v = (unsigned int)index[3]; | |||||
| mpoly->totloop = count; | |||||
| mpoly->loopstart = (int)(mloop - allloop); | |||||
| // mpoly->flag = ME_SMOOTH; | |||||
| mpoly++; | |||||
| mloop += count; | |||||
| dm->totloop += count; | |||||
| index += 4; | |||||
| } | |||||
| BKE_mesh_calc_edges(dm, true, true); | |||||
| BKE_mesh_calc_normals(dm); | |||||
| BKE_mesh_tessface_ensure(dm); | |||||
| BKE_mesh_runtime_looptri_ensure(dm); | |||||
| dm->runtime.cd_dirty_vert |= CD_MASK_NORMAL; | |||||
| } | |||||
| } | |||||
| Mesh *BKE_repolygonize_dm(Mesh *dm, | |||||
| float thresh, | |||||
| float basesize[3], | |||||
| float wiresize, | |||||
| float rendersize, | |||||
| bool render, | |||||
| bool override_size, | |||||
| int defgrp_size) | |||||
| { | |||||
| Mesh *result = NULL; | |||||
| DispList *dl; | |||||
| unsigned int a; | |||||
| PROCESS process = {0}; | |||||
| process.thresh = thresh; | |||||
| if (process.thresh < 0.001f) | |||||
| process.converge_res = 16; | |||||
| else if (process.thresh < 0.01f) | |||||
| process.converge_res = 8; | |||||
| else if (process.thresh < 0.1f) | |||||
| process.converge_res = 4; | |||||
| else | |||||
| process.converge_res = 2; | |||||
| // if ((!render) && (mb->flag == MB_UPDATE_NEVER)) return; | |||||
| // if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return; | |||||
| if (render) { | |||||
| process.size = rendersize; | |||||
| } | |||||
| else { | |||||
| process.size = wiresize; | |||||
| /*if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_HALFRES) { | |||||
| process.size *= 2.0f; | |||||
| }*/ | |||||
| } | |||||
| process.delta = process.size * 0.001f; | |||||
| process.pgn_elements = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Metaball memarena"); | |||||
| /* initialize from DM */ | |||||
| init_meta_dm(&process, dm, 2.0f, 2.0f, basesize, override_size, defgrp_size); | |||||
| if (process.totelem > 0) { | |||||
| build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb); | |||||
| process.orig_index = MEM_callocN(process.totelem * sizeof(int), "process origindex"); | |||||
| /* don't polygonize metaballs with too high resolution (base mball to small) | |||||
| * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using | |||||
| * 0.00001f */ | |||||
| if (basesize[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) || | |||||
| basesize[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) || | |||||
| basesize[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2])) { | |||||
| polygonize(&process); | |||||
| /* add resulting surface to displist */ | |||||
| if (process.curindex) { | |||||
| dl = MEM_callocN(sizeof(DispList), "mballdisp"); | |||||
| dl->type = DL_INDEX4; | |||||
| dl->nr = (int)process.curvertex; | |||||
| dl->parts = (int)process.curindex; | |||||
| dl->index = (int *)process.indices; | |||||
| for (a = 0; a < process.curvertex; a++) { | |||||
| normalize_v3(process.no[a]); | |||||
| } | |||||
| dl->verts = (float *)process.co; | |||||
| dl->nors = (float *)process.no; | |||||
| result = BKE_mesh_new_nomain(dl->nr, 0, 0, dl->parts * 4, dl->parts); | |||||
| BKE_dm_from_metaball(dl, result, dm, process.orig_index); | |||||
| BKE_displist_elem_free(dl); | |||||
| } | |||||
| } | |||||
| } | |||||
| if (!result) | |||||
| result = BKE_mesh_new_nomain(0, 0, 0, 0, 0); // return an empty mesh | |||||
| freepolygonize(&process); | |||||
| if (process.orig_index) { | |||||
| MEM_freeN(process.orig_index); | |||||
| } | |||||
| return result; | |||||
| } | |||||
Why not use the vertex normal to calculate the rotation?