/* get a vector, vec, that points from v1->co to wherever makes sense to * the bevel operation as a whole based on the relationship between v1 and v2 * (won't necessarily be a vec from v1->co to v2->co, though it probably will be); * the return value is -1 for failure, 0 if we used vert co's, and 1 if we used transform origins */ static int BME_bevel_get_vec(float *vec, BME_Vert *v1, BME_Vert *v2, BME_TransData_Head *td) { BME_TransData *vtd1, *vtd2; vtd1 = BME_get_transdata(td,v1); vtd2 = BME_get_transdata(td,v2); if (!vtd1 || !vtd2) { //printf("BME_bevel_get_vec() got called without proper BME_TransData\n"); return -1; } /* compare the transform origins to see if we can use the vert co's; * if they belong to different origins, then we will use the origins to determine * the vector */ if (compare_v3v3(vtd1->org,vtd2->org,0.000001f)) { VECSUB(vec,v2->co,v1->co); if (len_v3(vec) < 0.000001f) { mul_v3_fl(vec,0); } return 0; } else { VECSUB(vec,vtd2->org,vtd1->org); if (len_v3(vec) < 0.000001f) { mul_v3_fl(vec,0); } return 1; } }
static float BME_bevel_set_max(BME_Vert *v1, BME_Vert *v2, float value, BME_TransData_Head *td) { BME_TransData *vtd1, *vtd2; float max, fac1, fac2, vec1[3], vec2[3], vec3[3]; BME_bevel_get_vec(vec1,v1,v2,td); vtd1 = BME_get_transdata(td,v1); vtd2 = BME_get_transdata(td,v2); if (vtd1->loc == NULL) { fac1 = 0; } else { VECCOPY(vec2,vtd1->vec); mul_v3_fl(vec2,vtd1->factor); if (dot_v3v3(vec1, vec1)) { project_v3_v3v3(vec2,vec2,vec1); fac1 = len_v3(vec2)/value; } else { fac1 = 0; } } if (vtd2->loc == NULL) { fac2 = 0; } else { VECCOPY(vec3,vtd2->vec); mul_v3_fl(vec3,vtd2->factor); if (dot_v3v3(vec1, vec1)) { project_v3_v3v3(vec2,vec3,vec1); fac2 = len_v3(vec2)/value; } else { fac2 = 0; } } if (fac1 || fac2) { max = len_v3(vec1)/(fac1 + fac2); if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) { *vtd1->max = max; } if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) { *vtd2->max = max; } } else { max = -1; } return max; }
static void viewAxisCorrectCenter(TransInfo *t, float t_con_center[3]) { if (t->spacetype == SPACE_VIEW3D) { // View3D *v3d = t->sa->spacedata.first; const float min_dist = 1.0f; /* v3d->near; */ float dir[3]; float l; sub_v3_v3v3(dir, t_con_center, t->viewinv[3]); if (dot_v3v3(dir, t->viewinv[2]) < 0.0f) { negate_v3(dir); } project_v3_v3v3(dir, dir, t->viewinv[2]); l = len_v3(dir); if (l < min_dist) { float diff[3]; normalize_v3_v3(diff, t->viewinv[2]); mul_v3_fl(diff, min_dist - l); sub_v3_v3(t_con_center, diff); } } }
static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, DerivedMesh *deformdm, ParticleSystem *psys) { ChildParticle *cpa = NULL; int i, p; int child_nbr= psys_get_child_number(scene, psys); int totpart= psys_get_tot_child(scene, psys); alloc_child_particles(psys, totpart); cpa = psys->child; for (i=0; i<child_nbr; i++) { for (p=0; p<psys->totpart; p++,cpa++) { float length=2.0; cpa->parent=p; /* create even spherical distribution inside unit sphere */ while (length>=1.0f) { cpa->fuv[0]=2.0f*BLI_frand()-1.0f; cpa->fuv[1]=2.0f*BLI_frand()-1.0f; cpa->fuv[2]=2.0f*BLI_frand()-1.0f; length=len_v3(cpa->fuv); } cpa->num=-1; } } /* dmcache must be updated for parent particles if children from faces is used */ psys_calc_dmcache(ob, finaldm, deformdm, psys); }
static int rule_flock(BoidRule *UNUSED(rule), BoidBrainData *bbd, BoidValues *UNUSED(val), ParticleData *pa) { KDTreeNearest ptn[11]; float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; int neighbors = BLI_kdtree_find_nearest_n__normal(bbd->sim->psys->tree, pa->state.co, pa->prev_state.ave, ptn, 11); int n; int ret = 0; if (neighbors > 1) { for (n=1; n<neighbors; n++) { add_v3_v3(loc, bbd->sim->psys->particles[ptn[n].index].prev_state.co); add_v3_v3(vec, bbd->sim->psys->particles[ptn[n].index].prev_state.vel); } mul_v3_fl(loc, 1.0f/((float)neighbors - 1.0f)); mul_v3_fl(vec, 1.0f/((float)neighbors - 1.0f)); sub_v3_v3(loc, pa->prev_state.co); sub_v3_v3(vec, pa->prev_state.vel); add_v3_v3(bbd->wanted_co, vec); add_v3_v3(bbd->wanted_co, loc); bbd->wanted_speed = len_v3(bbd->wanted_co); ret = 1; } return ret; }
MINLINE float len_v3v3(const float a[3], const float b[3]) { float d[3]; sub_v3_v3v3(d, b, a); return len_v3(d); }
float effector_falloff(EffectorCache *eff, EffectorData *efd, EffectedPoint *UNUSED(point), EffectorWeights *weights) { float temp[3]; float falloff = weights ? weights->weight[0] * weights->weight[eff->pd->forcefield] : 1.0f; float fac, r_fac; fac = dot_v3v3(efd->nor, efd->vec_to_point2); if (eff->pd->zdir == PFIELD_Z_POS && fac < 0.0f) falloff=0.0f; else if (eff->pd->zdir == PFIELD_Z_NEG && fac > 0.0f) falloff=0.0f; else { switch (eff->pd->falloff) { case PFIELD_FALL_SPHERE: falloff*= falloff_func_dist(eff->pd, efd->distance); break; case PFIELD_FALL_TUBE: falloff*= falloff_func_dist(eff->pd, ABS(fac)); if (falloff == 0.0f) break; madd_v3_v3v3fl(temp, efd->vec_to_point, efd->nor, -fac); r_fac= len_v3(temp); falloff*= falloff_func_rad(eff->pd, r_fac); break; case PFIELD_FALL_CONE: falloff*= falloff_func_dist(eff->pd, ABS(fac)); if (falloff == 0.0f) break; r_fac= RAD2DEGF(saacos(fac/len_v3(efd->vec_to_point))); falloff*= falloff_func_rad(eff->pd, r_fac); break; } } return falloff; }
static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]) { float d1[3], d2[3], len_d1; sub_v3_v3v3(d1, p1, t->center_global); sub_v3_v3v3(d2, p2, t->center_global); if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { mul_m3_v3(t->con.pmtx, d1); mul_m3_v3(t->con.pmtx, d2); } project_v3_v3v3(d1, d1, d2); len_d1 = len_v3(d1); /* Use 'invalid' dist when `center == p1` (after projecting), * in this case scale will _never_ move the point in relation to the center, * so it makes no sense to take it into account when scaling. see: T46503 */ return len_d1 != 0.0f ? len_v3(d2) / len_d1 : TRANSFORM_DIST_INVALID; }
float calcArcCorrelation(BArcIterator *iter, int start, int end, float v0[3], float n[3]) { int len = 2 + abs(end - start); if (len > 2) { float avg_t = 0.0f; float s_t = 0.0f; float s_xyz = 0.0f; int i; /* First pass, calculate average */ for (i = start; i <= end; i++) { float v[3]; IT_peek(iter, i); sub_v3_v3v3(v, iter->p, v0); avg_t += dot_v3v3(v, n); } avg_t /= dot_v3v3(n, n); avg_t += 1.0f; /* adding start (0) and end (1) values */ avg_t /= len; /* Second pass, calculate s_xyz and s_t */ for (i = start; i <= end; i++) { float v[3], d[3]; float dt; IT_peek(iter, i); sub_v3_v3v3(v, iter->p, v0); project_v3_v3v3(d, v, n); sub_v3_v3(v, d); dt = len_v3(d) - avg_t; s_t += dt * dt; s_xyz += dot_v3v3(v, v); } /* adding start(0) and end(1) values to s_t */ s_t += (avg_t * avg_t) + (1 - avg_t) * (1 - avg_t); return 1.0f - s_xyz / s_t; } else { return 1.0f; } }
static float cotan_weight(float *v1, float *v2, float *v3) { float a[3], b[3], c[3], clen; sub_v3_v3v3(a, v2, v1); sub_v3_v3v3(b, v3, v1); cross_v3_v3v3(c, a, b); clen = len_v3(c); if (clen == 0.0f) return 0.0f; return dot_v3v3(a, b)/clen; }
static float cotan_weight(const float v1[3], const float v2[3], const float v3[3]) { float a[3], b[3], c[3], clen; sub_v3_v3v3(a, v2, v1); sub_v3_v3v3(b, v3, v1); cross_v3_v3v3(c, a, b); clen = len_v3(c); if (clen > FLT_EPSILON) { return dot_v3v3(a, b) / clen; } else { return 0.0f; } }
static void accum_density(void *userdata, int index, float squared_dist) { PointDensityRangeData *pdr = (PointDensityRangeData *)userdata; const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f; float density = 0.0f; if (pdr->point_data_used & POINT_DATA_VEL) { pdr->vec[0] += pdr->point_data[index*3 + 0]; // * density; pdr->vec[1] += pdr->point_data[index*3 + 1]; // * density; pdr->vec[2] += pdr->point_data[index*3 + 2]; // * density; } if (pdr->point_data_used & POINT_DATA_LIFE) { *pdr->age += pdr->point_data[pdr->offset + index]; // * density; } if (pdr->falloff_type == TEX_PD_FALLOFF_STD) density = dist; else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH) density = 3.0f*dist*dist - 2.0f*dist*dist*dist; else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT) density = pow(dist, pdr->softness); else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT) density = pdr->squared_radius; else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT) density = sqrtf(dist); else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) { if (pdr->point_data_used & POINT_DATA_LIFE) density = dist*MIN2(pdr->point_data[pdr->offset + index], 1.0f); else density = dist; } else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) { if (pdr->point_data_used & POINT_DATA_VEL) density = dist*len_v3(pdr->point_data + index*3)*pdr->velscale; else density = dist; } if (pdr->density_curve && dist != 0.0f) { curvemapping_initialize(pdr->density_curve); density = curvemapping_evaluateF(pdr->density_curve, 0, density/dist)*dist; } *pdr->density += density; }
static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3]) { int retval = 0; float col[4]; retval |= TEX_RGB; switch (pd->color_source) { case TEX_PD_COLOR_PARTAGE: if (pd->coba) { if (do_colorband(pd->coba, age, col)) { texres->talpha = true; copy_v3_v3(&texres->tr, col); texres->tin *= col[3]; texres->ta = texres->tin; } } break; case TEX_PD_COLOR_PARTSPEED: { float speed = len_v3(vec) * pd->speed_scale; if (pd->coba) { if (do_colorband(pd->coba, speed, col)) { texres->talpha = true; copy_v3_v3(&texres->tr, col); texres->tin *= col[3]; texres->ta = texres->tin; } } break; } case TEX_PD_COLOR_PARTVEL: texres->talpha = true; mul_v3_v3fl(&texres->tr, vec, pd->speed_scale); texres->ta = texres->tin; break; case TEX_PD_COLOR_CONSTANT: default: texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; break; } return retval; }
float paint_calc_object_space_radius(ViewContext *vc, const float center[3], float pixel_radius) { Object *ob = vc->obact; float delta[3], scale, loc[3]; const float mval_f[2] = {pixel_radius, 0.0f}; float zfac; mul_v3_m4v3(loc, ob->obmat, center); zfac = ED_view3d_calc_zfac(vc->rv3d, loc, NULL); ED_view3d_win_to_delta(vc->ar, mval_f, delta, zfac); scale = fabsf(mat4_to_scale(ob->obmat)); scale = (scale == 0.0f) ? 1.0f : scale; return len_v3(delta) / scale; }
static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone) { float selboneaxis[3], actboneaxis[3], length; sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head); normalize_v3(actboneaxis); sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head); length = len_v3(selboneaxis); mul_v3_fl(actboneaxis, length); add_v3_v3v3(selbone->tail, selbone->head, actboneaxis); selbone->roll = actbone->roll; /* if the bone being aligned has connected descendants they must be moved * according to their parent new position, otherwise they would be left * in an inconsistent state: connected but away from the parent*/ fix_editbone_connected_children(edbo, selbone); }
float paint_calc_object_space_radius(ViewContext *vc, float center[3], float pixel_radius) { Object *ob = vc->obact; float delta[3], scale, loc[3]; float mval_f[2]; mul_v3_m4v3(loc, ob->obmat, center); initgrabz(vc->rv3d, loc[0], loc[1], loc[2]); mval_f[0]= pixel_radius; mval_f[1]= 0.0f; ED_view3d_win_to_delta(vc->ar, mval_f, delta); scale= fabsf(mat4_to_scale(ob->obmat)); scale= (scale == 0.0f)? 1.0f: scale; return len_v3(delta)/scale; }
/* a wrapper for BME_SEMV that transfers element flags */ /*add custom data interpolation in here!*/ static BME_Vert *BME_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Edge *e, BME_Edge **ne, float percent) { BME_Vert *nv, *v2; float len; v2 = BME_edge_getothervert(e,v); nv = BME_SEMV(bm,v,e,ne); if (nv == NULL) return NULL; VECSUB(nv->co,v2->co,v->co); len = len_v3(nv->co); VECADDFAC(nv->co,v->co,nv->co,len*percent); nv->flag = v->flag; nv->bweight = v->bweight; if (ne) { (*ne)->flag = e->flag; (*ne)->h = e->h; (*ne)->crease = e->crease; (*ne)->bweight = e->bweight; } /*v->nv->v2*/ BME_data_facevert_edgesplit(bm,v2, v, nv, e, 0.75); return nv; }
static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec) { InstanceRayObject *obj = (InstanceRayObject *)o; float start[3], dir[3], idot_axis[3], dist; int changed = 0, i, res; // TODO - this is disabling self intersection on instances if (isec->orig.ob == obj->ob && obj->ob) { changed = 1; isec->orig.ob = obj->target_ob; } // backup old values copy_v3_v3(start, isec->start); copy_v3_v3(dir, isec->dir); copy_v3_v3(idot_axis, isec->idot_axis); dist = isec->dist; // transform to target coordinates system mul_m4_v3(obj->global2target, isec->start); mul_mat3_m4_v3(obj->global2target, isec->dir); isec->dist *= normalize_v3(isec->dir); // update idot_axis and bv_index for (i = 0; i < 3; i++) { isec->idot_axis[i] = 1.0f / isec->dir[i]; isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0; isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i]; isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i]; isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1]; } // raycast res = RE_rayobject_intersect(obj->target, isec); // map dist into original coordinate space if (res == 0) { isec->dist = dist; } else { // note we don't just multiply dist, because of possible // non-uniform scaling in the transform matrix float vec[3]; mul_v3_v3fl(vec, isec->dir, isec->dist); mul_mat3_m4_v3(obj->target2global, vec); isec->dist = len_v3(vec); isec->hit.ob = obj->ob; #ifdef RT_USE_LAST_HIT // TODO support for last hit optimization in instances that can jump // directly to the last hit face. // For now it jumps directly to the last-hit instance root node. isec->last_hit = RE_rayobject_unalignRayAPI((RayObject *) obj); #endif } // restore values copy_v3_v3(isec->start, start); copy_v3_v3(isec->dir, dir); copy_v3_v3(isec->idot_axis, idot_axis); if (changed) isec->orig.ob = obj->ob; // restore bv_index for (i = 0; i < 3; i++) { isec->bv_index[2 * i] = isec->idot_axis[i] < 0.0f ? 1 : 0; isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i]; isec->bv_index[2 * i] = i + 3 * isec->bv_index[2 * i]; isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1]; } return res; }
int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity) { float cfra = eff->scene->r.cfra; int ret = 0; if (eff->pd && eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd) { /* closest point in the object surface is an effector */ float vec[3]; /* using velocity corrected location allows for easier sliding over effector surface */ copy_v3_v3(vec, point->vel); mul_v3_fl(vec, point->vel_to_frame); add_v3_v3(vec, point->loc); ret = closest_point_on_surface(eff->surmd, vec, efd->loc, efd->nor, real_velocity ? efd->vel : NULL); efd->size = 0.0f; } else if (eff->pd && eff->pd->shape==PFIELD_SHAPE_POINTS) { if (eff->ob->derivedFinal) { DerivedMesh *dm = eff->ob->derivedFinal; dm->getVertCo(dm, *efd->index, efd->loc); dm->getVertNo(dm, *efd->index, efd->nor); mul_m4_v3(eff->ob->obmat, efd->loc); mul_mat3_m4_v3(eff->ob->obmat, efd->nor); normalize_v3(efd->nor); efd->size = 0.0f; /**/ ret = 1; } } else if (eff->psys) { ParticleData *pa = eff->psys->particles + *efd->index; ParticleKey state; /* exclude the particle itself for self effecting particles */ if (eff->psys == point->psys && *efd->index == point->index) { /* pass */ } else { ParticleSimulationData sim= {NULL}; sim.scene= eff->scene; sim.ob= eff->ob; sim.psys= eff->psys; /* TODO: time from actual previous calculated frame (step might not be 1) */ state.time = cfra - 1.0f; ret = psys_get_particle_state(&sim, *efd->index, &state, 0); /* TODO */ //if (eff->pd->forcefiled == PFIELD_HARMONIC && ret==0) { // if (pa->dietime < eff->psys->cfra) // eff->flag |= PE_VELOCITY_TO_IMPULSE; //} copy_v3_v3(efd->loc, state.co); /* rather than use the velocity use rotated x-axis (defaults to velocity) */ efd->nor[0] = 1.f; efd->nor[1] = efd->nor[2] = 0.f; mul_qt_v3(state.rot, efd->nor); if (real_velocity) copy_v3_v3(efd->vel, state.vel); efd->size = pa->size; } } else { /* use center of object for distance calculus */ const Object *ob = eff->ob; /* use z-axis as normal*/ normalize_v3_v3(efd->nor, ob->obmat[2]); if (eff->pd && eff->pd->shape == PFIELD_SHAPE_PLANE) { float temp[3], translate[3]; sub_v3_v3v3(temp, point->loc, ob->obmat[3]); project_v3_v3v3(translate, temp, efd->nor); /* for vortex the shape chooses between old / new force */ if (eff->pd->forcefield == PFIELD_VORTEX) add_v3_v3v3(efd->loc, ob->obmat[3], translate); else /* normally efd->loc is closest point on effector xy-plane */ sub_v3_v3v3(efd->loc, point->loc, translate); } else { copy_v3_v3(efd->loc, ob->obmat[3]); } if (real_velocity) copy_v3_v3(efd->vel, eff->velocity); efd->size = 0.0f; ret = 1; } if (ret) { sub_v3_v3v3(efd->vec_to_point, point->loc, efd->loc); efd->distance = len_v3(efd->vec_to_point); /* rest length for harmonic effector, will have to see later if this could be extended to other effectors */ if (eff->pd && eff->pd->forcefield == PFIELD_HARMONIC && eff->pd->f_size) mul_v3_fl(efd->vec_to_point, (efd->distance-eff->pd->f_size)/efd->distance); if (eff->flag & PE_USE_NORMAL_DATA) { copy_v3_v3(efd->vec_to_point2, efd->vec_to_point); copy_v3_v3(efd->nor2, efd->nor); } else { /* for some effectors we need the object center every time */ sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->obmat[3]); normalize_v3_v3(efd->nor2, eff->ob->obmat[2]); } } return ret; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, int useRenderParams, int UNUSED(isFinalCalc)) { DerivedMesh *dm= derivedData; DerivedMesh *result; ScrewModifierData *ltmd= (ScrewModifierData*) md; int *origindex; int mface_index=0; int step; int i, j; int i1,i2; int step_tot= useRenderParams ? ltmd->render_steps : ltmd->steps; const int do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0; int maxVerts=0, maxEdges=0, maxFaces=0; int totvert= dm->getNumVerts(dm); int totedge= dm->getNumEdges(dm); char axis_char= 'X', close; float angle= ltmd->angle; float screw_ofs= ltmd->screw_ofs; float axis_vec[3]= {0.0f, 0.0f, 0.0f}; float tmp_vec1[3], tmp_vec2[3]; float mat3[3][3]; float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */ float mtx_tx_inv[4][4]; /* inverted */ float mtx_tmp_a[4][4]; int vc_tot_linked= 0; short other_axis_1, other_axis_2; float *tmpf1, *tmpf2; MFace *mface_new, *mf_new; MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new; MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base; ScrewVertConnect *vc, *vc_tmp, *vert_connect= NULL; /* dont do anything? */ if (!totvert) return CDDM_from_template(dm, 0, 0, 0); switch(ltmd->axis) { case 0: other_axis_1=1; other_axis_2=2; break; case 1: other_axis_1=0; other_axis_2=2; break; default: /* 2, use default to quiet warnings */ other_axis_1=0; other_axis_2=1; break; } axis_vec[ltmd->axis]= 1.0f; if (ltmd->ob_axis) { /* calc the matrix relative to the axis object */ invert_m4_m4(mtx_tmp_a, ob->obmat); copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat); mul_m4_m4m4(mtx_tx, mtx_tx_inv, mtx_tmp_a); /* calc the axis vec */ mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */ normalize_v3(axis_vec); /* screw */ if(ltmd->flag & MOD_SCREW_OBJECT_OFFSET) { /* find the offset along this axis relative to this objects matrix */ float totlen = len_v3(mtx_tx[3]); if(totlen != 0.0f) { float zero[3]= {0.0f, 0.0f, 0.0f}; float cp[3]; screw_ofs= closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec); } else { screw_ofs= 0.0f; } } /* angle */ #if 0 // cant incluide this, not predictable enough, though quite fun,. if(ltmd->flag & MOD_SCREW_OBJECT_ANGLE) { float mtx3_tx[3][3]; copy_m3_m4(mtx3_tx, mtx_tx); float vec[3] = {0,1,0}; float cross1[3]; float cross2[3]; cross_v3_v3v3(cross1, vec, axis_vec); mul_v3_m3v3(cross2, mtx3_tx, cross1); { float c1[3]; float c2[3]; float axis_tmp[3]; cross_v3_v3v3(c1, cross2, axis_vec); cross_v3_v3v3(c2, axis_vec, c1); angle= angle_v3v3(cross1, c2); cross_v3_v3v3(axis_tmp, cross1, c2); normalize_v3(axis_tmp); if(len_v3v3(axis_tmp, axis_vec) > 1.0f) angle= -angle; } } #endif } else { /* exis char is used by i_rotate*/ axis_char += ltmd->axis; /* 'X' + axis */ /* useful to be able to use the axis vec in some cases still */ zero_v3(axis_vec); axis_vec[ltmd->axis]= 1.0f; } /* apply the multiplier */ angle *= ltmd->iter; screw_ofs *= ltmd->iter; /* multiplying the steps is a bit tricky, this works best */ step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1); /* will the screw be closed? * Note! smaller then FLT_EPSILON*100 gives problems with float precision so its never closed. */ if (fabsf(screw_ofs) <= (FLT_EPSILON*100.0f) && fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON*100.0f)) { close= 1; step_tot--; if(step_tot < 3) step_tot= 3; maxVerts = totvert * step_tot; /* -1 because we're joining back up */ maxEdges = (totvert * step_tot) + /* these are the edges between new verts */ (totedge * step_tot); /* -1 because vert edges join */ maxFaces = totedge * step_tot; screw_ofs= 0.0f; } else { close= 0; if(step_tot < 3) step_tot= 3; maxVerts = totvert * step_tot; /* -1 because we're joining back up */ maxEdges = (totvert * (step_tot-1)) + /* these are the edges between new verts */ (totedge * step_tot); /* -1 because vert edges join */ maxFaces = totedge * (step_tot-1); } result= CDDM_from_template(dm, maxVerts, maxEdges, maxFaces); /* copy verts from mesh */ mvert_orig = dm->getVertArray(dm); medge_orig = dm->getEdgeArray(dm); mvert_new = result->getVertArray(result); mface_new = result->getFaceArray(result); medge_new = result->getEdgeArray(result); origindex= result->getFaceDataArray(result, CD_ORIGINDEX); DM_copy_vert_data(dm, result, 0, 0, totvert); /* copy first otherwise this overwrites our own vertex normals */ /* Set the locations of the first set of verts */ mv_new= mvert_new; mv_orig= mvert_orig; /* Copy the first set of edges */ med_orig= medge_orig; med_new= medge_new; for (i=0; i < totedge; i++, med_orig++, med_new++) { med_new->v1= med_orig->v1; med_new->v2= med_orig->v2; med_new->crease= med_orig->crease; med_new->flag= med_orig->flag & ~ME_LOOSEEDGE; } if(ltmd->flag & MOD_SCREW_NORMAL_CALC) { /* * Normal Calculation (for face flipping) * Sort edge verts for correct face flipping * NOT REALLY NEEDED but face flipping is nice. * * */ /* Notice! * * Since we are only ordering the edges here it can avoid mallocing the * extra space by abusing the vert array berfore its filled with new verts. * The new array for vert_connect must be at least sizeof(ScrewVertConnect) * totvert * and the size of our resulting meshes array is sizeof(MVert) * totvert * 3 * so its safe to use the second 2 thrids of MVert the array for vert_connect, * just make sure ScrewVertConnect struct is no more then twice as big as MVert, * at the moment there is no chance of that being a problem, * unless MVert becomes half its current size. * * once the edges are ordered, vert_connect is not needed and it can be used for verts * * This makes the modifier faster with one less alloc. */ vert_connect= MEM_mallocN(sizeof(ScrewVertConnect) * totvert, "ScrewVertConnect"); //vert_connect= (ScrewVertConnect *) &medge_new[totvert]; /* skip the first slice of verts */ vc= vert_connect; /* Copy Vert Locations */ /* - We can do this in a later loop - only do here if no normal calc */ if (!totedge) { for (i=0; i < totvert; i++, mv_orig++, mv_new++) { copy_v3_v3(mv_new->co, mv_orig->co); normalize_v3_v3(vc->no, mv_new->co); /* no edges- this is really a dummy normal */ } } else { /*printf("\n\n\n\n\nStarting Modifier\n");*/ /* set edge users */ med_new= medge_new; mv_new= mvert_new; if (ltmd->ob_axis) { /*mtx_tx is initialized early on */ for (i=0; i < totvert; i++, mv_new++, mv_orig++, vc++) { vc->co[0]= mv_new->co[0]= mv_orig->co[0]; vc->co[1]= mv_new->co[1]= mv_orig->co[1]; vc->co[2]= mv_new->co[2]= mv_orig->co[2]; vc->flag= 0; vc->e[0]= vc->e[1]= NULL; vc->v[0]= vc->v[1]= -1; mul_m4_v3(mtx_tx, vc->co); /* length in 2d, dont sqrt because this is only for comparison */ vc->dist = vc->co[other_axis_1]*vc->co[other_axis_1] + vc->co[other_axis_2]*vc->co[other_axis_2]; /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/ } } else { for (i=0; i < totvert; i++, mv_new++, mv_orig++, vc++) { vc->co[0]= mv_new->co[0]= mv_orig->co[0]; vc->co[1]= mv_new->co[1]= mv_orig->co[1]; vc->co[2]= mv_new->co[2]= mv_orig->co[2]; vc->flag= 0; vc->e[0]= vc->e[1]= NULL; vc->v[0]= vc->v[1]= -1; /* length in 2d, dont sqrt because this is only for comparison */ vc->dist = vc->co[other_axis_1]*vc->co[other_axis_1] + vc->co[other_axis_2]*vc->co[other_axis_2]; /* printf("location %f %f %f -- %f\n", vc->co[0], vc->co[1], vc->co[2], vc->dist);*/ } } /* this loop builds connectivity info for verts */ for (i=0; i<totedge; i++, med_new++) { vc= &vert_connect[med_new->v1]; if (vc->v[0] == -1) { /* unused */ vc->v[0]= med_new->v2; vc->e[0]= med_new; } else if (vc->v[1] == -1) { vc->v[1]= med_new->v2; vc->e[1]= med_new; } else { vc->v[0]= vc->v[1]= -2; /* erro value - dont use, 3 edges on vert */ } vc= &vert_connect[med_new->v2]; /* same as above but swap v1/2 */ if (vc->v[0] == -1) { /* unused */ vc->v[0]= med_new->v1; vc->e[0]= med_new; } else if (vc->v[1] == -1) { vc->v[1]= med_new->v1; vc->e[1]= med_new; } else { vc->v[0]= vc->v[1]= -2; /* erro value - dont use, 3 edges on vert */ } } /* find the first vert */ vc= vert_connect; for (i=0; i < totvert; i++, vc++) { /* Now do search for connected verts, order all edges and flip them * so resulting faces are flipped the right way */ vc_tot_linked= 0; /* count the number of linked verts for this loop */ if (vc->flag == 0) { int v_best=-1, ed_loop_closed=0; /* vert and vert new */ ScrewVertIter lt_iter; int ed_loop_flip= 0; /* compiler complains if not initialized, but it should be initialized below */ float fl= -1.0f; /*printf("Loop on connected vert: %i\n", i);*/ for(j=0; j<2; j++) { /*printf("\tSide: %i\n", j);*/ screwvert_iter_init(<_iter, vert_connect, i, j); if (j == 1) { screwvert_iter_step(<_iter); } while (lt_iter.v_poin) { /*printf("\t\tVERT: %i\n", lt_iter.v);*/ if (lt_iter.v_poin->flag) { /*printf("\t\t\tBreaking Found end\n");*/ //endpoints[0]= endpoints[1]= -1; ed_loop_closed= 1; /* circle */ break; } lt_iter.v_poin->flag= 1; vc_tot_linked++; /*printf("Testing 2 floats %f : %f\n", fl, lt_iter.v_poin->dist);*/ if (fl <= lt_iter.v_poin->dist) { fl= lt_iter.v_poin->dist; v_best= lt_iter.v; /*printf("\t\t\tVERT BEST: %i\n", v_best);*/ } screwvert_iter_step(<_iter); if (!lt_iter.v_poin) { /*printf("\t\t\tFound End Also Num %i\n", j);*/ /*endpoints[j]= lt_iter.v_other;*/ /* other is still valid */ break; } } } /* now we have a collection of used edges. flip their edges the right way*/ /*if (v_best != -1) - */ /*printf("Done Looking - vc_tot_linked: %i\n", vc_tot_linked);*/ if (vc_tot_linked>1) { float vf_1, vf_2, vf_best; vc_tmp= &vert_connect[v_best]; tmpf1= vert_connect[vc_tmp->v[0]].co; tmpf2= vert_connect[vc_tmp->v[1]].co; /* edge connects on each side! */ if ((vc_tmp->v[0] > -1) && (vc_tmp->v[1] > -1)) { /*printf("Verts on each side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/ /* find out which is higher */ vf_1= tmpf1[ltmd->axis]; vf_2= tmpf2[ltmd->axis]; vf_best= vc_tmp->co[ltmd->axis]; if (vf_1 < vf_best && vf_best < vf_2) { ed_loop_flip= 0; } else if (vf_1 > vf_best && vf_best > vf_2) { ed_loop_flip= 1; } else { /* not so simple to work out which edge is higher */ sub_v3_v3v3(tmp_vec1, tmpf1, vc_tmp->co); sub_v3_v3v3(tmp_vec2, tmpf2, vc_tmp->co); normalize_v3(tmp_vec1); normalize_v3(tmp_vec2); if (tmp_vec1[ltmd->axis] < tmp_vec2[ltmd->axis]) { ed_loop_flip= 1; } else { ed_loop_flip= 0; } } } else if (vc_tmp->v[0] >= 0) { /*vertex only connected on 1 side */ /*printf("Verts on ONE side (%i %i)\n", vc_tmp->v[0], vc_tmp->v[1]);*/ if (tmpf1[ltmd->axis] < vc_tmp->co[ltmd->axis]) { /* best is above */ ed_loop_flip= 1; } else { /* best is below or even... in even case we cant know whet to do. */ ed_loop_flip= 0; } }/* else { printf("No Connected ___\n"); }*/ /*printf("flip direction %i\n", ed_loop_flip);*/ /* switch the flip option if set * note: flip is now done at face level so copying vgroup slizes is easier */ /* if (do_flip) ed_loop_flip= !ed_loop_flip; */ if (angle < 0.0f) ed_loop_flip= !ed_loop_flip; /* if its closed, we only need 1 loop */ for(j=ed_loop_closed; j<2; j++) { /*printf("Ordering Side J %i\n", j);*/ screwvert_iter_init(<_iter, vert_connect, v_best, j); /*printf("\n\nStarting - Loop\n");*/ lt_iter.v_poin->flag= 1; /* so a non loop will traverse the other side */ /* If this is the vert off the best vert and * the best vert has 2 edges connected too it * then swap the flip direction */ if (j == 1 && (vc_tmp->v[0] > -1) && (vc_tmp->v[1] > -1)) ed_loop_flip= !ed_loop_flip; while (lt_iter.v_poin && lt_iter.v_poin->flag != 2) { /*printf("\tOrdering Vert V %i\n", lt_iter.v);*/ lt_iter.v_poin->flag= 2; if (lt_iter.e) { if (lt_iter.v == lt_iter.e->v1) { if (ed_loop_flip == 0) { /*printf("\t\t\tFlipping 0\n");*/ SWAP(int, lt_iter.e->v1, lt_iter.e->v2); }/* else { printf("\t\t\tFlipping Not 0\n"); }*/ } else if (lt_iter.v == lt_iter.e->v2) { if (ed_loop_flip == 1) { /*printf("\t\t\tFlipping 1\n");*/ SWAP(int, lt_iter.e->v1, lt_iter.e->v2); }/* else { printf("\t\t\tFlipping Not 1\n"); }*/ }/* else { printf("\t\tIncorrect edge topology"); }*/ }/* else { printf("\t\tNo Edge at this point\n"); }*/ screwvert_iter_step(<_iter); } }
/* only valid for perspective cameras */ int camera_view_frame_fit_to_scene(Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3]) { float shift[2]; float plane_tx[4][3]; float rot_obmat[3][3]; const float zero[3]= {0,0,0}; CameraViewFrameData data_cb; unsigned int i; camera_view_frame(scene, camera_ob->data, data_cb.frame_tx); copy_m3_m4(rot_obmat, camera_ob->obmat); normalize_m3(rot_obmat); for (i= 0; i < 4; i++) { /* normalize so Z is always 1.0f*/ mul_v3_fl(data_cb.frame_tx[i], 1.0f/data_cb.frame_tx[i][2]); } /* get the shift back out of the frame */ shift[0]= (data_cb.frame_tx[0][0] + data_cb.frame_tx[1][0] + data_cb.frame_tx[2][0] + data_cb.frame_tx[3][0]) / 4.0f; shift[1]= (data_cb.frame_tx[0][1] + data_cb.frame_tx[1][1] + data_cb.frame_tx[2][1] + data_cb.frame_tx[3][1]) / 4.0f; for (i= 0; i < 4; i++) { mul_m3_v3(rot_obmat, data_cb.frame_tx[i]); } for (i= 0; i < 4; i++) { normal_tri_v3(data_cb.normal_tx[i], zero, data_cb.frame_tx[i], data_cb.frame_tx[(i + 1) % 4]); } /* initialize callback data */ data_cb.dist_vals[0]= data_cb.dist_vals[1]= data_cb.dist_vals[2]= data_cb.dist_vals[3]= FLT_MAX; data_cb.tot= 0; /* run callback on all visible points */ BKE_scene_foreach_display_point(scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb); if (data_cb.tot <= 1) { return FALSE; } else { float plane_isect_1[3], plane_isect_1_no[3], plane_isect_1_other[3]; float plane_isect_2[3], plane_isect_2_no[3], plane_isect_2_other[3]; float plane_isect_pt_1[3], plane_isect_pt_2[3]; /* apply the dist-from-plane's to the transformed plane points */ for (i= 0; i < 4; i++) { mul_v3_v3fl(plane_tx[i], data_cb.normal_tx[i], data_cb.dist_vals[i]); } isect_plane_plane_v3(plane_isect_1, plane_isect_1_no, plane_tx[0], data_cb.normal_tx[0], plane_tx[2], data_cb.normal_tx[2]); isect_plane_plane_v3(plane_isect_2, plane_isect_2_no, plane_tx[1], data_cb.normal_tx[1], plane_tx[3], data_cb.normal_tx[3]); add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no); add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no); if (isect_line_line_v3(plane_isect_1, plane_isect_1_other, plane_isect_2, plane_isect_2_other, plane_isect_pt_1, plane_isect_pt_2) == 0) { return FALSE; } else { float cam_plane_no[3]= {0.0f, 0.0f, -1.0f}; float plane_isect_delta[3]; float plane_isect_delta_len; mul_m3_v3(rot_obmat, cam_plane_no); sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1); plane_isect_delta_len= len_v3(plane_isect_delta); if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) { copy_v3_v3(r_co, plane_isect_pt_1); /* offset shift */ normalize_v3(plane_isect_1_no); madd_v3_v3fl(r_co, plane_isect_1_no, shift[1] * -plane_isect_delta_len); } else { copy_v3_v3(r_co, plane_isect_pt_2); /* offset shift */ normalize_v3(plane_isect_2_no); madd_v3_v3fl(r_co, plane_isect_2_no, shift[0] * -plane_isect_delta_len); } return TRUE; } } }
/* Evaluate spline IK for a given bone */ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan, int index, float ctime) { bSplineIKConstraint *ikData = tree->ikData; float poseHead[3], poseTail[3], poseMat[4][4]; float splineVec[3], scaleFac, radius = 1.0f; /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); copy_v3_v3(poseHead, pchan->pose_head); copy_v3_v3(poseTail, pchan->pose_tail); /* step 1: determine the positions for the endpoints of the bone */ { float vec[4], dir[3], rad; float tailBlendFac = 1.0f; /* determine if the bone should still be affected by SplineIK */ if (tree->points[index + 1] >= 1.0f) { /* spline doesn't affect the bone anymore, so done... */ pchan->flag |= POSE_DONE; return; } else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) { /* blending factor depends on the amount of the bone still left on the chain */ tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]); } /* tail endpoint */ if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) { /* apply curve's object-mode transforms to the position * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) */ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) mul_m4_v3(ikData->tar->obmat, vec); /* convert the position to pose-space, then store it */ mul_m4_v3(ob->imat, vec); interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac); /* set the new radius */ radius = rad; } /* head endpoint */ if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) { /* apply curve's object-mode transforms to the position * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) */ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) mul_m4_v3(ikData->tar->obmat, vec); /* store the position, and convert it to pose space */ mul_m4_v3(ob->imat, vec); copy_v3_v3(poseHead, vec); /* set the new radius (it should be the average value) */ radius = (radius + rad) / 2; } } /* step 2: determine the implied transform from these endpoints * - splineVec: the vector direction that the spline applies on the bone * - scaleFac: the factor that the bone length is scaled by to get the desired amount */ sub_v3_v3v3(splineVec, poseTail, poseHead); scaleFac = len_v3(splineVec) / pchan->bone->length; /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis * - this uses the same method as is used for the Damped Track Constraint (see the code there for details) */ { float dmat[3][3], rmat[3][3], tmat[3][3]; float raxis[3], rangle; /* compute the raw rotation matrix from the bone's current matrix by extracting only the * orientation-relevant axes, and normalizing them */ copy_v3_v3(rmat[0], pchan->pose_mat[0]); copy_v3_v3(rmat[1], pchan->pose_mat[1]); copy_v3_v3(rmat[2], pchan->pose_mat[2]); normalize_m3(rmat); /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */ normalize_v3(splineVec); /* calculate smallest axis-angle rotation necessary for getting from the * current orientation of the bone, to the spline-imposed direction */ cross_v3_v3v3(raxis, rmat[1], splineVec); rangle = dot_v3v3(rmat[1], splineVec); CLAMP(rangle, -1.0f, 1.0f); rangle = acosf(rangle); /* multiply the magnitude of the angle by the influence of the constraint to * control the influence of the SplineIK effect */ rangle *= tree->con->enforce; /* construct rotation matrix from the axis-angle rotation found above * - this call takes care to make sure that the axis provided is a unit vector first */ axis_angle_to_mat3(dmat, raxis, rangle); /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates, * while still maintaining roll control from the existing bone animation */ mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */ normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */ copy_m4_m3(poseMat, tmat); } /* step 4: set the scaling factors for the axes */ { /* only multiply the y-axis by the scaling factor to get nice volume-preservation */ mul_v3_fl(poseMat[1], scaleFac); /* set the scaling factors of the x and z axes from... */ switch (ikData->xzScaleMode) { case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: { /* original scales get used */ float scale; /* x-axis scale */ scale = len_v3(pchan->pose_mat[0]); mul_v3_fl(poseMat[0], scale); /* z-axis scale */ scale = len_v3(pchan->pose_mat[2]); mul_v3_fl(poseMat[2], scale); break; } case CONSTRAINT_SPLINEIK_XZS_INVERSE: { /* old 'volume preservation' method using the inverse scale */ float scale; /* calculate volume preservation factor which is * basically the inverse of the y-scaling factor */ if (fabsf(scaleFac) != 0.0f) { scale = 1.0f / fabsf(scaleFac); /* we need to clamp this within sensible values */ /* NOTE: these should be fine for now, but should get sanitised in future */ CLAMP(scale, 0.0001f, 100000.0f); } else scale = 1.0f; /* apply the scaling */ mul_v3_fl(poseMat[0], scale); mul_v3_fl(poseMat[2], scale); break; } case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: { /* improved volume preservation based on the Stretch To constraint */ float final_scale; /* as the basis for volume preservation, we use the inverse scale factor... */ if (fabsf(scaleFac) != 0.0f) { /* NOTE: The method here is taken wholesale from the Stretch To constraint */ float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge); if (bulge > 1.0f) { if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) { float bulge_max = max_ff(ikData->bulge_max, 1.0f); float hard = min_ff(bulge, bulge_max); float range = bulge_max - 1.0f; float scale = (range > 0.0f) ? 1.0f / range : 0.0f; float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2; bulge = interpf(soft, hard, ikData->bulge_smooth); } } if (bulge < 1.0f) { if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) { float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f); float hard = max_ff(bulge, bulge_min); float range = 1.0f - bulge_min; float scale = (range > 0.0f) ? 1.0f / range : 0.0f; float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2; bulge = interpf(soft, hard, ikData->bulge_smooth); } } /* compute scale factor for xz axes from this value */ final_scale = sqrtf(bulge); } else { /* no scaling, so scale factor is simple */ final_scale = 1.0f; } /* apply the scaling (assuming normalised scale) */ mul_v3_fl(poseMat[0], final_scale); mul_v3_fl(poseMat[2], final_scale); break; } } /* finally, multiply the x and z scaling by the radius of the curve too, * to allow automatic scales to get tweaked still */ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { mul_v3_fl(poseMat[0], radius); mul_v3_fl(poseMat[2], radius); } } /* step 5: set the location of the bone in the matrix */ if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) { /* when the 'no-root' option is affected, the chain can retain * the shape but be moved elsewhere */ copy_v3_v3(poseHead, pchan->pose_head); } else if (tree->con->enforce < 1.0f) { /* when the influence is too low * - blend the positions for the 'root' bone * - stick to the parent for any other */ if (pchan->parent) { copy_v3_v3(poseHead, pchan->pose_head); } else { /* FIXME: this introduces popping artifacts when we reach 0.0 */ interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce); } } copy_v3_v3(poseMat[3], poseHead); /* finally, store the new transform */ copy_m4_m4(pchan->pose_mat, poseMat); copy_v3_v3(pchan->pose_head, poseHead); /* recalculate tail, as it's now outdated after the head gets adjusted above! */ BKE_pose_where_is_bone_tail(pchan); /* done! */ pchan->flag |= POSE_DONE; }
static void setNearestAxis3d(TransInfo *t) { float zfac; float mvec[3], proj[3]; float len[3]; int i; /* calculate mouse movement */ mvec[0] = (float)(t->mval[0] - t->con.imval[0]); mvec[1] = (float)(t->mval[1] - t->con.imval[1]); mvec[2] = 0.0f; /* we need to correct axis length for the current zoomlevel of view, * this to prevent projected values to be clipped behind the camera * and to overflow the short integers. * The formula used is a bit stupid, just a simplification of the subtraction * of two 2D points 30 pixels apart (that's the last factor in the formula) after * projecting them with ED_view3d_win_to_delta and then get the length of that vector. */ zfac = mul_project_m4_v3_zfac(t->persmat, t->center); zfac = len_v3(t->persinv[0]) * 2.0f / t->ar->winx * zfac * 30.0f; for (i = 0; i < 3; i++) { float axis[3], axis_2d[2]; copy_v3_v3(axis, t->con.mtx[i]); mul_v3_fl(axis, zfac); /* now we can project to get window coordinate */ add_v3_v3(axis, t->center_global); projectFloatView(t, axis, axis_2d); sub_v2_v2v2(axis, axis_2d, t->center2d); axis[2] = 0.0f; if (normalize_v3(axis) > 1e-3f) { project_v3_v3v3(proj, mvec, axis); sub_v3_v3v3(axis, mvec, proj); len[i] = normalize_v3(axis); } else { len[i] = 1e10f; } } if (len[0] <= len[1] && len[0] <= len[2]) { if (t->modifiers & MOD_CONSTRAINT_PLANE) { t->con.mode |= (CON_AXIS1 | CON_AXIS2); BLI_snprintf(t->con.text, sizeof(t->con.text), IFACE_(" locking %s X axis"), t->spacename); } else { t->con.mode |= CON_AXIS0; BLI_snprintf(t->con.text, sizeof(t->con.text), IFACE_(" along %s X axis"), t->spacename); } } else if (len[1] <= len[0] && len[1] <= len[2]) { if (t->modifiers & MOD_CONSTRAINT_PLANE) { t->con.mode |= (CON_AXIS0 | CON_AXIS2); BLI_snprintf(t->con.text, sizeof(t->con.text), IFACE_(" locking %s Y axis"), t->spacename); } else { t->con.mode |= CON_AXIS1; BLI_snprintf(t->con.text, sizeof(t->con.text), IFACE_(" along %s Y axis"), t->spacename); } } else if (len[2] <= len[1] && len[2] <= len[0]) { if (t->modifiers & MOD_CONSTRAINT_PLANE) { t->con.mode |= (CON_AXIS0 | CON_AXIS1); BLI_snprintf(t->con.text, sizeof(t->con.text), IFACE_(" locking %s Z axis"), t->spacename); } else { t->con.mode |= CON_AXIS2; BLI_snprintf(t->con.text, sizeof(t->con.text), IFACE_(" along %s Z axis"), t->spacename); } } }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag flag) { DerivedMesh *dm = derivedData; DerivedMesh *result; ScrewModifierData *ltmd = (ScrewModifierData *) md; const int useRenderParams = flag & MOD_APPLY_RENDER; int *origindex; int mpoly_index = 0; unsigned int step; unsigned int i, j; unsigned int i1, i2; unsigned int step_tot = useRenderParams ? ltmd->render_steps : ltmd->steps; const bool do_flip = ltmd->flag & MOD_SCREW_NORMAL_FLIP ? 1 : 0; const int quad_ord[4] = { do_flip ? 3 : 0, do_flip ? 2 : 1, do_flip ? 1 : 2, do_flip ? 0 : 3, }; const int quad_ord_ofs[4] = { do_flip ? 2 : 0, do_flip ? 1 : 1, do_flip ? 0 : 2, do_flip ? 3 : 3, }; unsigned int maxVerts = 0, maxEdges = 0, maxPolys = 0; const unsigned int totvert = (unsigned int)dm->getNumVerts(dm); const unsigned int totedge = (unsigned int)dm->getNumEdges(dm); const unsigned int totpoly = (unsigned int)dm->getNumPolys(dm); unsigned int *edge_poly_map = NULL; /* orig edge to orig poly */ unsigned int *vert_loop_map = NULL; /* orig vert to orig loop */ /* UV Coords */ const unsigned int mloopuv_layers_tot = (unsigned int)CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV); MLoopUV **mloopuv_layers = BLI_array_alloca(mloopuv_layers, mloopuv_layers_tot); float uv_u_scale; float uv_v_minmax[2] = {FLT_MAX, -FLT_MAX}; float uv_v_range_inv; float uv_axis_plane[4]; char axis_char = 'X'; bool close; float angle = ltmd->angle; float screw_ofs = ltmd->screw_ofs; float axis_vec[3] = {0.0f, 0.0f, 0.0f}; float tmp_vec1[3], tmp_vec2[3]; float mat3[3][3]; float mtx_tx[4][4]; /* transform the coords by an object relative to this objects transformation */ float mtx_tx_inv[4][4]; /* inverted */ float mtx_tmp_a[4][4]; unsigned int vc_tot_linked = 0; short other_axis_1, other_axis_2; const float *tmpf1, *tmpf2; unsigned int edge_offset; MPoly *mpoly_orig, *mpoly_new, *mp_new; MLoop *mloop_orig, *mloop_new, *ml_new; MEdge *medge_orig, *med_orig, *med_new, *med_new_firstloop, *medge_new; MVert *mvert_new, *mvert_orig, *mv_orig, *mv_new, *mv_new_base; ScrewVertConnect *vc, *vc_tmp, *vert_connect = NULL; const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0; /* don't do anything? */ if (!totvert) return CDDM_from_template(dm, 0, 0, 0, 0, 0); switch (ltmd->axis) { case 0: other_axis_1 = 1; other_axis_2 = 2; break; case 1: other_axis_1 = 0; other_axis_2 = 2; break; default: /* 2, use default to quiet warnings */ other_axis_1 = 0; other_axis_2 = 1; break; } axis_vec[ltmd->axis] = 1.0f; if (ltmd->ob_axis) { /* calc the matrix relative to the axis object */ invert_m4_m4(mtx_tmp_a, ob->obmat); copy_m4_m4(mtx_tx_inv, ltmd->ob_axis->obmat); mul_m4_m4m4(mtx_tx, mtx_tmp_a, mtx_tx_inv); /* calc the axis vec */ mul_mat3_m4_v3(mtx_tx, axis_vec); /* only rotation component */ normalize_v3(axis_vec); /* screw */ if (ltmd->flag & MOD_SCREW_OBJECT_OFFSET) { /* find the offset along this axis relative to this objects matrix */ float totlen = len_v3(mtx_tx[3]); if (totlen != 0.0f) { float zero[3] = {0.0f, 0.0f, 0.0f}; float cp[3]; screw_ofs = closest_to_line_v3(cp, mtx_tx[3], zero, axis_vec); } else { screw_ofs = 0.0f; } } /* angle */ #if 0 /* cant incluide this, not predictable enough, though quite fun. */ if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) { float mtx3_tx[3][3]; copy_m3_m4(mtx3_tx, mtx_tx); float vec[3] = {0, 1, 0}; float cross1[3]; float cross2[3]; cross_v3_v3v3(cross1, vec, axis_vec); mul_v3_m3v3(cross2, mtx3_tx, cross1); { float c1[3]; float c2[3]; float axis_tmp[3]; cross_v3_v3v3(c1, cross2, axis_vec); cross_v3_v3v3(c2, axis_vec, c1); angle = angle_v3v3(cross1, c2); cross_v3_v3v3(axis_tmp, cross1, c2); normalize_v3(axis_tmp); if (len_v3v3(axis_tmp, axis_vec) > 1.0f) angle = -angle; } } #endif } else { /* exis char is used by i_rotate*/ axis_char = (char)(axis_char + ltmd->axis); /* 'X' + axis */ /* useful to be able to use the axis vec in some cases still */ zero_v3(axis_vec); axis_vec[ltmd->axis] = 1.0f; } /* apply the multiplier */ angle *= (float)ltmd->iter; screw_ofs *= (float)ltmd->iter; uv_u_scale = 1.0f / (float)(step_tot); /* multiplying the steps is a bit tricky, this works best */ step_tot = ((step_tot + 1) * ltmd->iter) - (ltmd->iter - 1); /* will the screw be closed? * Note! smaller then FLT_EPSILON * 100 gives problems with float precision so its never closed. */ if (fabsf(screw_ofs) <= (FLT_EPSILON * 100.0f) && fabsf(fabsf(angle) - ((float)M_PI * 2.0f)) <= (FLT_EPSILON * 100.0f)) { close = 1; step_tot--; if (step_tot < 3) step_tot = 3; maxVerts = totvert * step_tot; /* -1 because we're joining back up */ maxEdges = (totvert * step_tot) + /* these are the edges between new verts */ (totedge * step_tot); /* -1 because vert edges join */ maxPolys = totedge * step_tot; screw_ofs = 0.0f; } else { close = 0; if (step_tot < 3) step_tot = 3; maxVerts = totvert * step_tot; /* -1 because we're joining back up */ maxEdges = (totvert * (step_tot - 1)) + /* these are the edges between new verts */ (totedge * step_tot); /* -1 because vert edges join */ maxPolys = totedge * (step_tot - 1); } if ((ltmd->flag & MOD_SCREW_UV_STRETCH_U) == 0) { uv_u_scale = (uv_u_scale / (float)ltmd->iter) * (angle / ((float)M_PI * 2.0f)); } result = CDDM_from_template(dm, (int)maxVerts, (int)maxEdges, 0, (int)maxPolys * 4, (int)maxPolys); /* copy verts from mesh */ mvert_orig = dm->getVertArray(dm); medge_orig = dm->getEdgeArray(dm); mvert_new = result->getVertArray(result); mpoly_new = result->getPolyArray(result); mloop_new = result->getLoopArray(result); medge_new = result->getEdgeArray(result); if (!CustomData_has_layer(&result->polyData, CD_ORIGINDEX)) { CustomData_add_layer(&result->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, (int)maxPolys); } origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX); DM_copy_vert_data(dm, result, 0, 0, (int)totvert); /* copy first otherwise this overwrites our own vertex normals */ if (mloopuv_layers_tot) { float zero_co[3] = {0}; plane_from_point_normal_v3(uv_axis_plane, zero_co, axis_vec); } if (mloopuv_layers_tot) { unsigned int uv_lay; for (uv_lay = 0; uv_lay < mloopuv_layers_tot; uv_lay++) { mloopuv_layers[uv_lay] = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, (int)uv_lay); } if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) { for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) { const float v = dist_squared_to_plane_v3(mv_orig->co, uv_axis_plane); uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]); uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]); } uv_v_minmax[0] = sqrtf_signed(uv_v_minmax[0]); uv_v_minmax[1] = sqrtf_signed(uv_v_minmax[1]); } uv_v_range_inv = uv_v_minmax[1] - uv_v_minmax[0]; uv_v_range_inv = uv_v_range_inv ? 1.0f / uv_v_range_inv : 0.0f; } /* Set the locations of the first set of verts */ mv_new = mvert_new; mv_orig = mvert_orig; /* Copy the first set of edges */ med_orig = medge_orig; med_new = medge_new; for (i = 0; i < totedge; i++, med_orig++, med_new++) { med_new->v1 = med_orig->v1; med_new->v2 = med_orig->v2; med_new->crease = med_orig->crease; med_new->flag = med_orig->flag & ~ME_LOOSEEDGE; } /* build polygon -> edge map */ if (totpoly) { MPoly *mp_orig; mpoly_orig = dm->getPolyArray(dm); mloop_orig = dm->getLoopArray(dm); edge_poly_map = MEM_mallocN(sizeof(*edge_poly_map) * totedge, __func__); memset(edge_poly_map, 0xff, sizeof(*edge_poly_map) * totedge); vert_loop_map = MEM_mallocN(sizeof(*vert_loop_map) * totvert, __func__); memset(vert_loop_map, 0xff, sizeof(*vert_loop_map) * totvert); for (i = 0, mp_orig = mpoly_orig; i < totpoly; i++, mp_orig++) { unsigned int loopstart = (unsigned int)mp_orig->loopstart; unsigned int loopend = loopstart + (unsigned int)mp_orig->totloop; MLoop *ml_orig = &mloop_orig[loopstart]; unsigned int k; for (k = loopstart; k < loopend; k++, ml_orig++) { edge_poly_map[ml_orig->e] = i; vert_loop_map[ml_orig->v] = k; /* also order edges based on faces */ if (medge_new[ml_orig->e].v1 != ml_orig->v) { SWAP(unsigned int, medge_new[ml_orig->e].v1, medge_new[ml_orig->e].v2); } } } }
/* called from within the core BKE_pose_where_is loop, all animsystems and constraints * were executed & assigned. Now as last we do an IK pass */ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) { float R_parmat[3][3], identity[3][3]; float iR_parmat[3][3]; float R_bonemat[3][3]; float goalrot[3][3], goalpos[3]; float rootmat[4][4], imat[4][4]; float goal[4][4], goalinv[4][4]; float irest_basis[3][3], full_basis[3][3]; float end_pose[4][4], world_pose[4][4]; float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch = NULL; float resultinf = 0.0f; int a, flag, hasstretch = 0, resultblend = 0; bPoseChannel *pchan; IK_Segment *seg, *parent, **iktree, *iktarget; IK_Solver *solver; PoseTarget *target; bKinematicConstraint *data, *poleangledata = NULL; Bone *bone; if (tree->totchannel == 0) return; iktree = MEM_mallocN(sizeof(void *) * tree->totchannel, "ik tree"); for (a = 0; a < tree->totchannel; a++) { pchan = tree->pchan[a]; bone = pchan->bone; /* set DoF flag */ flag = 0; if (!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP)) flag |= IK_XDOF; if (!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP)) flag |= IK_YDOF; if (!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP)) flag |= IK_ZDOF; if (tree->stretch && (pchan->ikstretch > 0.0f)) { flag |= IK_TRANS_YDOF; hasstretch = 1; } seg = iktree[a] = IK_CreateSegment(flag); /* find parent */ if (a == 0) parent = NULL; else parent = iktree[tree->parent[a]]; IK_SetParent(seg, parent); /* get the matrix that transforms from prevbone into this bone */ copy_m3_m4(R_bonemat, pchan->pose_mat); /* gather transformations for this IK segment */ if (pchan->parent) copy_m3_m4(R_parmat, pchan->parent->pose_mat); else unit_m3(R_parmat); /* bone offset */ if (pchan->parent && (a > 0)) sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail); else /* only root bone (a = 0) has no parent */ start[0] = start[1] = start[2] = 0.0f; /* change length based on bone size */ length = bone->length * len_v3(R_bonemat[1]); /* compute rest basis and its inverse */ copy_m3_m3(rest_basis, bone->bone_mat); copy_m3_m3(irest_basis, bone->bone_mat); transpose_m3(irest_basis); /* compute basis with rest_basis removed */ invert_m3_m3(iR_parmat, R_parmat); mul_m3_m3m3(full_basis, iR_parmat, R_bonemat); mul_m3_m3m3(basis, irest_basis, full_basis); /* basis must be pure rotation */ normalize_m3(basis); /* transform offset into local bone space */ normalize_m3(iR_parmat); mul_m3_v3(iR_parmat, start); IK_SetTransform(seg, start, rest_basis, basis, length); if (pchan->ikflag & BONE_IK_XLIMIT) IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]); if (pchan->ikflag & BONE_IK_YLIMIT) IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]); if (pchan->ikflag & BONE_IK_ZLIMIT) IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]); IK_SetStiffness(seg, IK_X, pchan->stiffness[0]); IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]); IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]); if (tree->stretch && (pchan->ikstretch > 0.0f)) { const float ikstretch = pchan->ikstretch * pchan->ikstretch; /* this function does its own clamping */ IK_SetStiffness(seg, IK_TRANS_Y, 1.0f - ikstretch); IK_SetLimit(seg, IK_TRANS_Y, IK_STRETCH_STIFF_MIN, IK_STRETCH_STIFF_MAX); } } solver = IK_CreateSolver(iktree[0]); /* set solver goals */ /* first set the goal inverse transform, assuming the root of tree was done ok! */ pchan = tree->pchan[0]; if (pchan->parent) { /* transform goal by parent mat, so this rotation is not part of the * segment's basis. otherwise rotation limits do not work on the * local transform of the segment itself. */ copy_m4_m4(rootmat, pchan->parent->pose_mat); /* However, we do not want to get (i.e. reverse) parent's scale, as it generates [#31008] * kind of nasty bugs... */ normalize_m4(rootmat); } else unit_m4(rootmat); copy_v3_v3(rootmat[3], pchan->pose_head); mul_m4_m4m4(imat, ob->obmat, rootmat); invert_m4_m4(goalinv, imat); for (target = tree->targets.first; target; target = target->next) { float polepos[3]; int poleconstrain = 0; data = (bKinematicConstraint *)target->con->data; /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though * strictly speaking, it is a posechannel) */ BKE_constraint_target_matrix_get(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); /* and set and transform goal */ mul_m4_m4m4(goal, goalinv, rootmat); copy_v3_v3(goalpos, goal[3]); copy_m3_m4(goalrot, goal); normalize_m3(goalrot); /* same for pole vector target */ if (data->poletar) { BKE_constraint_target_matrix_get(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); if (data->flag & CONSTRAINT_IK_SETANGLE) { /* don't solve IK when we are setting the pole angle */ break; } else { mul_m4_m4m4(goal, goalinv, rootmat); copy_v3_v3(polepos, goal[3]); poleconstrain = 1; /* for pole targets, we blend the result of the ik solver * instead of the target position, otherwise we can't get * a smooth transition */ resultblend = 1; resultinf = target->con->enforce; if (data->flag & CONSTRAINT_IK_GETANGLE) { poleangledata = data; data->flag &= ~CONSTRAINT_IK_GETANGLE; } } } /* do we need blending? */ if (!resultblend && target->con->enforce != 1.0f) { float q1[4], q2[4], q[4]; float fac = target->con->enforce; float mfac = 1.0f - fac; pchan = tree->pchan[target->tip]; /* end effector in world space */ copy_m4_m4(end_pose, pchan->pose_mat); copy_v3_v3(end_pose[3], pchan->pose_tail); mul_serie_m4(world_pose, goalinv, ob->obmat, end_pose, NULL, NULL, NULL, NULL, NULL); /* blend position */ goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0]; goalpos[1] = fac * goalpos[1] + mfac * world_pose[3][1]; goalpos[2] = fac * goalpos[2] + mfac * world_pose[3][2]; /* blend rotation */ mat3_to_quat(q1, goalrot); mat4_to_quat(q2, world_pose); interp_qt_qtqt(q, q1, q2, mfac); quat_to_mat3(goalrot, q); } iktarget = iktree[target->tip]; if ((data->flag & CONSTRAINT_IK_POS) && data->weight != 0.0f) { if (poleconstrain) IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos, polepos, data->poleangle, (poleangledata == data)); IK_SolverAddGoal(solver, iktarget, goalpos, data->weight); } if ((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0f)) if ((data->flag & CONSTRAINT_IK_AUTO) == 0) IK_SolverAddGoalOrientation(solver, iktarget, goalrot, data->orientweight); } /* solve */ IK_Solve(solver, 0.0f, tree->iterations); if (poleangledata) poleangledata->poleangle = IK_SolverGetPoleAngle(solver); IK_FreeSolver(solver); /* gather basis changes */ tree->basis_change = MEM_mallocN(sizeof(float[3][3]) * tree->totchannel, "ik basis change"); if (hasstretch) ikstretch = MEM_mallocN(sizeof(float) * tree->totchannel, "ik stretch"); for (a = 0; a < tree->totchannel; a++) { IK_GetBasisChange(iktree[a], tree->basis_change[a]); if (hasstretch) { /* have to compensate for scaling received from parent */ float parentstretch, stretch; pchan = tree->pchan[a]; parentstretch = (tree->parent[a] >= 0) ? ikstretch[tree->parent[a]] : 1.0f; if (tree->stretch && (pchan->ikstretch > 0.0f)) { float trans[3], length; IK_GetTranslationChange(iktree[a], trans); length = pchan->bone->length * len_v3(pchan->pose_mat[1]); ikstretch[a] = (length == 0.0f) ? 1.0f : (trans[1] + length) / length; } else ikstretch[a] = 1.0; stretch = (parentstretch == 0.0f) ? 1.0f : ikstretch[a] / parentstretch; mul_v3_fl(tree->basis_change[a][0], stretch); mul_v3_fl(tree->basis_change[a][1], stretch); mul_v3_fl(tree->basis_change[a][2], stretch); } if (resultblend && resultinf != 1.0f) { unit_m3(identity); blend_m3_m3m3(tree->basis_change[a], identity, tree->basis_change[a], resultinf); } IK_FreeSegment(iktree[a]); } MEM_freeN(iktree); if (ikstretch) MEM_freeN(ikstretch); }
static void sphere_do( CastModifierData *cmd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) { MDeformVert *dvert = NULL; Object *ctrl_ob = NULL; int i, defgrp_index; bool has_radius = false; short flag, type; float len = 0.0f; float fac = cmd->fac; float facm = 1.0f - fac; const float fac_orig = fac; float vec[3], center[3] = {0.0f, 0.0f, 0.0f}; float mat[4][4], imat[4][4]; flag = cmd->flag; type = cmd->type; /* projection type: sphere or cylinder */ if (type == MOD_CAST_TYPE_CYLINDER) flag &= ~MOD_CAST_Z; ctrl_ob = cmd->object; /* spherify's center is {0, 0, 0} (the ob's own center in its local * space), by default, but if the user defined a control object, * we use its location, transformed to ob's local space */ if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { invert_m4_m4(imat, ctrl_ob->obmat); mul_m4_m4m4(mat, imat, ob->obmat); invert_m4_m4(imat, mat); } invert_m4_m4(ob->imat, ob->obmat); mul_v3_m4v3(center, ob->imat, ctrl_ob->obmat[3]); } /* now we check which options the user wants */ /* 1) (flag was checked in the "if (ctrl_ob)" block above) */ /* 2) cmd->radius > 0.0f: only the vertices within this radius from * the center of the effect should be deformed */ if (cmd->radius > FLT_EPSILON) has_radius = 1; /* 3) if we were given a vertex group name, * only those vertices should be affected */ modifier_get_vgroup(ob, dm, cmd->defgrp_name, &dvert, &defgrp_index); if (flag & MOD_CAST_SIZE_FROM_RADIUS) { len = cmd->radius; } else { len = cmd->size; } if (len <= 0) { for (i = 0; i < numVerts; i++) { len += len_v3v3(center, vertexCos[i]); } len /= numVerts; if (len == 0.0f) len = 10.0f; } for (i = 0; i < numVerts; i++) { float tmp_co[3]; copy_v3_v3(tmp_co, vertexCos[i]); if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(mat, tmp_co); } else { sub_v3_v3(tmp_co, center); } } copy_v3_v3(vec, tmp_co); if (type == MOD_CAST_TYPE_CYLINDER) vec[2] = 0.0f; if (has_radius) { if (len_v3(vec) > cmd->radius) continue; } if (dvert) { const float weight = defvert_find_weight(&dvert[i], defgrp_index); if (weight == 0.0f) { continue; } fac = fac_orig * weight; facm = 1.0f - fac; } normalize_v3(vec); if (flag & MOD_CAST_X) tmp_co[0] = fac * vec[0] * len + facm * tmp_co[0]; if (flag & MOD_CAST_Y) tmp_co[1] = fac * vec[1] * len + facm * tmp_co[1]; if (flag & MOD_CAST_Z) tmp_co[2] = fac * vec[2] * len + facm * tmp_co[2]; if (ctrl_ob) { if (flag & MOD_CAST_USE_OB_TRANSFORM) { mul_m4_v3(imat, tmp_co); } else { add_v3_v3(tmp_co, center); } } copy_v3_v3(vertexCos[i], tmp_co); } }
/* Edge-Length Weighted Smoothing */ static void smooth_iter__length_weight( CorrectiveSmoothModifierData *csmd, DerivedMesh *dm, float (*vertexCos)[3], unsigned int numVerts, const float *smooth_weights, unsigned int iterations) { const float eps = FLT_EPSILON * 10.0f; const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm); /* note: the way this smoothing method works, its approx half as strong as the simple-smooth, * and 2.0 rarely spikes, double the value for consistent behavior. */ const float lambda = csmd->lambda * 2.0f; const MEdge *edges = dm->getEdgeArray(dm); float *vertex_edge_count; unsigned int i; struct SmoothingData_Weighted { float delta[3]; float edge_length_sum; } *smooth_data = MEM_callocN((size_t)numVerts * sizeof(*smooth_data), __func__); /* calculate as floats to avoid int->float conversion in #smooth_iter */ vertex_edge_count = MEM_callocN((size_t)numVerts * sizeof(float), __func__); for (i = 0; i < numEdges; i++) { vertex_edge_count[edges[i].v1] += 1.0f; vertex_edge_count[edges[i].v2] += 1.0f; } /* -------------------------------------------------------------------- */ /* Main Smoothing Loop */ while (iterations--) { for (i = 0; i < numEdges; i++) { struct SmoothingData_Weighted *sd_v1; struct SmoothingData_Weighted *sd_v2; float edge_dir[3]; float edge_dist; sub_v3_v3v3(edge_dir, vertexCos[edges[i].v2], vertexCos[edges[i].v1]); edge_dist = len_v3(edge_dir); /* weight by distance */ mul_v3_fl(edge_dir, edge_dist); sd_v1 = &smooth_data[edges[i].v1]; sd_v2 = &smooth_data[edges[i].v2]; add_v3_v3(sd_v1->delta, edge_dir); sub_v3_v3(sd_v2->delta, edge_dir); sd_v1->edge_length_sum += edge_dist; sd_v2->edge_length_sum += edge_dist; } if (smooth_weights == NULL) { /* fast-path */ for (i = 0; i < numVerts; i++) { struct SmoothingData_Weighted *sd = &smooth_data[i]; /* divide by sum of all neighbour distances (weighted) and amount of neighbours, (mean average) */ const float div = sd->edge_length_sum * vertex_edge_count[i]; if (div > eps) { #if 0 /* first calculate the new location */ mul_v3_fl(sd->delta, 1.0f / div); /* then interpolate */ madd_v3_v3fl(vertexCos[i], sd->delta, lambda); #else /* do this in one step */ madd_v3_v3fl(vertexCos[i], sd->delta, lambda / div); #endif } /* zero for the next iteration (saves memset on entire array) */ memset(sd, 0, sizeof(*sd)); } } else { for (i = 0; i < numVerts; i++) { struct SmoothingData_Weighted *sd = &smooth_data[i]; const float div = sd->edge_length_sum * vertex_edge_count[i]; if (div > eps) { const float lambda_w = lambda * smooth_weights[i]; madd_v3_v3fl(vertexCos[i], sd->delta, lambda_w / div); } memset(sd, 0, sizeof(*sd)); } } } MEM_freeN(vertex_edge_count); MEM_freeN(smooth_data); }
int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) { int retval = TEX_INT; PointDensity *pd = tex->pd; PointDensityRangeData pdr; float density=0.0f, age=0.0f, time=0.0f; float vec[3] = {0.0f, 0.0f, 0.0f}, co[3]; float col[4]; float turb, noise_fac; int num=0; texres->tin = 0.0f; if ((!pd) || (!pd->point_tree)) return 0; init_pointdensityrangedata(pd, &pdr, &density, vec, &age, (pd->flag&TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL), pd->falloff_speed_scale*0.001f); noise_fac = pd->noise_fac * 0.5f; /* better default */ VECCOPY(co, texvec); if (point_data_used(pd)) { /* does a BVH lookup to find accumulated density and additional point data * * stores particle velocity vector in 'vec', and particle lifetime in 'time' */ num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); if (num > 0) { age /= num; mul_v3_fl(vec, 1.0f/num); } /* reset */ density = vec[0] = vec[1] = vec[2] = 0.0f; } if (pd->flag & TEX_PD_TURBULENCE) { if (pd->noise_influence == TEX_PD_NOISE_AGE) { turb = BLI_gTurbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth, 0, pd->noise_basis); } else if (pd->noise_influence == TEX_PD_NOISE_TIME) { time = R.cfra / (float)R.r.efra; turb = BLI_gTurbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth, 0, pd->noise_basis); //turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth); } else { turb = BLI_gTurbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth, 0, pd->noise_basis); } turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */ /* now we have an offset coordinate to use for the density lookup */ co[0] = texvec[0] + noise_fac * turb; co[1] = texvec[1] + noise_fac * turb; co[2] = texvec[2] + noise_fac * turb; } /* BVH query with the potentially perturbed coordinates */ num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); if (num > 0) { age /= num; mul_v3_fl(vec, 1.0f/num); } texres->tin = density; BRICONT; if (pd->color_source == TEX_PD_COLOR_CONSTANT) return retval; retval |= TEX_RGB; switch (pd->color_source) { case TEX_PD_COLOR_PARTAGE: if (pd->coba) { if (do_colorband(pd->coba, age, col)) { texres->talpha= 1; VECCOPY(&texres->tr, col); texres->tin *= col[3]; texres->ta = texres->tin; } } break; case TEX_PD_COLOR_PARTSPEED: { float speed = len_v3(vec) * pd->speed_scale; if (pd->coba) { if (do_colorband(pd->coba, speed, col)) { texres->talpha= 1; VECCOPY(&texres->tr, col); texres->tin *= col[3]; texres->ta = texres->tin; } } break; } case TEX_PD_COLOR_PARTVEL: texres->talpha= 1; mul_v3_fl(vec, pd->speed_scale); VECCOPY(&texres->tr, vec); texres->ta = texres->tin; break; case TEX_PD_COLOR_CONSTANT: default: texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; break; } BRICONTRGB; return retval; /* if (texres->nor!=NULL) { texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f; } */ }
/* only creates a table for a single channel in CurveMapping */ static void curvemap_make_table(CurveMap *cuma, rctf *clipr) { CurveMapPoint *cmp = cuma->curve; BezTriple *bezt; float *fp, *allpoints, *lastpoint, curf, range; int a, totpoint; if (cuma->curve == NULL) return; /* default rect also is table range */ cuma->mintable = clipr->xmin; cuma->maxtable = clipr->xmax; /* hrmf... we now rely on blender ipo beziers, these are more advanced */ bezt = MEM_callocN(cuma->totpoint * sizeof(BezTriple), "beztarr"); for (a = 0; a < cuma->totpoint; a++) { cuma->mintable = MIN2(cuma->mintable, cmp[a].x); cuma->maxtable = MAX2(cuma->maxtable, cmp[a].x); bezt[a].vec[1][0] = cmp[a].x; bezt[a].vec[1][1] = cmp[a].y; if (cmp[a].flag & CUMA_VECTOR) bezt[a].h1 = bezt[a].h2 = HD_VECT; else bezt[a].h1 = bezt[a].h2 = HD_AUTO; } for (a = 0; a < cuma->totpoint; a++) { if (a == 0) calchandle_curvemap(bezt, NULL, bezt + 1, 0); else if (a == cuma->totpoint - 1) calchandle_curvemap(bezt + a, bezt + a - 1, NULL, 0); else calchandle_curvemap(bezt + a, bezt + a - 1, bezt + a + 1, 0); } /* first and last handle need correction, instead of pointing to center of next/prev, * we let it point to the closest handle */ if (cuma->totpoint > 2) { float hlen, nlen, vec[3]; if (bezt[0].h2 == HD_AUTO) { hlen = len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */ /* clip handle point */ copy_v3_v3(vec, bezt[1].vec[0]); if (vec[0] < bezt[0].vec[1][0]) vec[0] = bezt[0].vec[1][0]; sub_v3_v3(vec, bezt[0].vec[1]); nlen = len_v3(vec); if (nlen > FLT_EPSILON) { mul_v3_fl(vec, hlen / nlen); add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]); sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec); } } a = cuma->totpoint - 1; if (bezt[a].h2 == HD_AUTO) { hlen = len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */ /* clip handle point */ copy_v3_v3(vec, bezt[a - 1].vec[2]); if (vec[0] > bezt[a].vec[1][0]) vec[0] = bezt[a].vec[1][0]; sub_v3_v3(vec, bezt[a].vec[1]); nlen = len_v3(vec); if (nlen > FLT_EPSILON) { mul_v3_fl(vec, hlen / nlen); add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]); sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec); } } } /* make the bezier curve */ if (cuma->table) MEM_freeN(cuma->table); totpoint = (cuma->totpoint - 1) * CM_RESOL; fp = allpoints = MEM_callocN(totpoint * 2 * sizeof(float), "table"); for (a = 0; a < cuma->totpoint - 1; a++, fp += 2 * CM_RESOL) { correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a + 1].vec[0], bezt[a + 1].vec[1]); BKE_curve_forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a + 1].vec[0][0], bezt[a + 1].vec[1][0], fp, CM_RESOL - 1, 2 * sizeof(float)); BKE_curve_forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a + 1].vec[0][1], bezt[a + 1].vec[1][1], fp + 1, CM_RESOL - 1, 2 * sizeof(float)); } /* store first and last handle for extrapolation, unit length */ cuma->ext_in[0] = bezt[0].vec[0][0] - bezt[0].vec[1][0]; cuma->ext_in[1] = bezt[0].vec[0][1] - bezt[0].vec[1][1]; range = sqrt(cuma->ext_in[0] * cuma->ext_in[0] + cuma->ext_in[1] * cuma->ext_in[1]); cuma->ext_in[0] /= range; cuma->ext_in[1] /= range; a = cuma->totpoint - 1; cuma->ext_out[0] = bezt[a].vec[1][0] - bezt[a].vec[2][0]; cuma->ext_out[1] = bezt[a].vec[1][1] - bezt[a].vec[2][1]; range = sqrt(cuma->ext_out[0] * cuma->ext_out[0] + cuma->ext_out[1] * cuma->ext_out[1]); cuma->ext_out[0] /= range; cuma->ext_out[1] /= range; /* cleanup */ MEM_freeN(bezt); range = CM_TABLEDIV * (cuma->maxtable - cuma->mintable); cuma->range = 1.0f / range; /* now make a table with CM_TABLE equal x distances */ fp = allpoints; lastpoint = allpoints + 2 * (totpoint - 1); cmp = MEM_callocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "dist table"); for (a = 0; a <= CM_TABLE; a++) { curf = cuma->mintable + range * (float)a; cmp[a].x = curf; /* get the first x coordinate larger than curf */ while (curf >= fp[0] && fp != lastpoint) { fp += 2; } if (fp == allpoints || (curf >= fp[0] && fp == lastpoint)) cmp[a].y = curvemap_calc_extend(cuma, curf, allpoints, lastpoint); else { float fac1 = fp[0] - fp[-2]; float fac2 = fp[0] - curf; if (fac1 > FLT_EPSILON) fac1 = fac2 / fac1; else fac1 = 0.0f; cmp[a].y = fac1 * fp[-1] + (1.0f - fac1) * fp[1]; } } MEM_freeN(allpoints); cuma->table = cmp; }
/* bone adding between selected joints */ static int armature_fill_bones_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); bArmature *arm = (obedit) ? obedit->data : NULL; Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); ListBase points = {NULL, NULL}; int count; /* sanity checks */ if (ELEM(NULL, obedit, arm)) return OPERATOR_CANCELLED; /* loop over all bones, and only consider if visible */ CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones) { if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL)) fill_add_joint(ebone, 0, &points); if (ebone->flag & BONE_TIPSEL) fill_add_joint(ebone, 1, &points); } CTX_DATA_END; /* the number of joints determines how we fill: * 1) between joint and cursor (joint=head, cursor=tail) * 2) between the two joints (order is dependent on active-bone/hierachy) * 3+) error (a smarter method involving finding chains needs to be worked out */ count = BLI_countlist(&points); if (count == 0) { BKE_report(op->reports, RPT_ERROR, "No joints selected"); return OPERATOR_CANCELLED; } else if (count == 1) { EditBonePoint *ebp; float curs[3]; /* Get Points - selected joint */ ebp = (EditBonePoint *)points.first; /* Get points - cursor (tail) */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d)); /* Create a bone */ /* newbone = */ add_points_bone(obedit, ebp->vec, curs); } else if (count == 2) { EditBonePoint *ebp, *ebp2; float head[3], tail[3]; short headtail = 0; /* check that the points don't belong to the same bone */ ebp = (EditBonePoint *)points.first; ebp2 = ebp->next; if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) { BKE_report(op->reports, RPT_ERROR, "Same bone selected..."); BLI_freelistN(&points); return OPERATOR_CANCELLED; } if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) { BKE_report(op->reports, RPT_ERROR, "Same bone selected..."); BLI_freelistN(&points); return OPERATOR_CANCELLED; } /* find which one should be the 'head' */ if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) { /* rule: whichever one is closer to 3d-cursor */ float curs[3]; float vecA[3], vecB[3]; float distA, distB; /* get cursor location */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d)); /* get distances */ sub_v3_v3v3(vecA, ebp->vec, curs); sub_v3_v3v3(vecB, ebp2->vec, curs); distA = len_v3(vecA); distB = len_v3(vecB); /* compare distances - closer one therefore acts as direction for bone to go */ headtail = (distA < distB) ? 2 : 1; } else if (ebp->head_owner) { headtail = 1; } else if (ebp2->head_owner) { headtail = 2; } /* assign head/tail combinations */ if (headtail == 2) { copy_v3_v3(head, ebp->vec); copy_v3_v3(tail, ebp2->vec); } else if (headtail == 1) { copy_v3_v3(head, ebp2->vec); copy_v3_v3(tail, ebp->vec); } /* add new bone and parent it to the appropriate end */ if (headtail) { EditBone *newbone = add_points_bone(obedit, head, tail); /* do parenting (will need to set connected flag too) */ if (headtail == 2) { /* ebp tail or head - tail gets priority */ if (ebp->tail_owner) newbone->parent = ebp->tail_owner; else newbone->parent = ebp->head_owner; } else { /* ebp2 tail or head - tail gets priority */ if (ebp2->tail_owner) newbone->parent = ebp2->tail_owner; else newbone->parent = ebp2->head_owner; } newbone->flag |= BONE_CONNECTED; } } else { /* FIXME.. figure out a method for multiple bones */ BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count); BLI_freelistN(&points); return OPERATOR_CANCELLED; } /* updates */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); /* free points */ BLI_freelistN(&points); return OPERATOR_FINISHED; }