/* 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 */ VECCOPY(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 */ VECCOPY(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]); 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)); 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; }
static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float ground_co[3], float ground_nor[3]) { BoidParticle *bpa = pa->boid; if(bpa->data.mode == eBoidMode_Climbing) { SurfaceModifierData *surmd = NULL; float x[3], v[3]; surmd = (SurfaceModifierData *)modifiers_findByType ( bpa->ground, eModifierType_Surface ); /* take surface velocity into account */ closest_point_on_surface(surmd, pa->state.co, x, NULL, v); add_v3_v3(x, v); /* get actual position on surface */ closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL); return bpa->ground; } else { float zvec[3] = {0.0f, 0.0f, 2000.0f}; ParticleCollision col; ColliderCache *coll; BVHTreeRayHit hit; float radius = 0.0f, t, ray_dir[3]; if(!bbd->sim->colliders) return NULL; /* first try to find below boid */ copy_v3_v3(col.co1, pa->state.co); sub_v3_v3v3(col.co2, pa->state.co, zvec); sub_v3_v3v3(ray_dir, col.co2, col.co1); col.f = 0.0f; hit.index = -1; hit.dist = col.original_ray_length = len_v3(ray_dir); col.pce.inside = 0; for(coll = bbd->sim->colliders->first; coll; coll = coll->next){ col.current = coll->ob; col.md = coll->collmd; col.fac1 = col.fac2 = 0.f; if(col.md && col.md->bvhtree) BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col); } /* then use that object */ if(hit.index>=0) { t = hit.dist/col.original_ray_length; interp_v3_v3v3(ground_co, col.co1, col.co2, t); normalize_v3_v3(ground_nor, col.pce.nor); return col.hit; } /* couldn't find below, so find upmost deflector object */ add_v3_v3v3(col.co1, pa->state.co, zvec); sub_v3_v3v3(col.co2, pa->state.co, zvec); sub_v3_v3(col.co2, zvec); sub_v3_v3v3(ray_dir, col.co2, col.co1); col.f = 0.0f; hit.index = -1; hit.dist = col.original_ray_length = len_v3(ray_dir); for(coll = bbd->sim->colliders->first; coll; coll = coll->next){ col.current = coll->ob; col.md = coll->collmd; if(col.md && col.md->bvhtree) BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col); } /* then use that object */ if(hit.index>=0) { t = hit.dist/col.original_ray_length; interp_v3_v3v3(ground_co, col.co1, col.co2, t); normalize_v3_v3(ground_nor, col.pce.nor); return col.hit; } /* default to z=0 */ copy_v3_v3(ground_co, pa->state.co); ground_co[2] = 0; ground_nor[0] = ground_nor[1] = 0.0f; ground_nor[2] = 1.0f; return NULL; } }
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) ; 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 */ Object *ob = eff->ob; Object obcopy = *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); *eff->ob = obcopy; 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 void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *psmd, DerivedMesh *dm) { ParticleSystem *psys = psmd->psys; MFace *fa = NULL, *mface = NULL; MVert *mvert = NULL; ParticleData *pa; KDTree *tree; RNG *rng; float center[3], co[3]; int *facepa = NULL, *vertpa = NULL, totvert = 0, totface = 0, totpart = 0; int i, p, v1, v2, v3, v4 = 0; mvert = dm->getVertArray(dm); mface = dm->getTessFaceArray(dm); totface = dm->getNumTessFaces(dm); totvert = dm->getNumVerts(dm); totpart = psmd->psys->totpart; rng = BLI_rng_new_srandom(psys->seed); if (emd->facepa) MEM_freeN(emd->facepa); facepa = emd->facepa = MEM_callocN(sizeof(int) * totface, "explode_facepa"); vertpa = MEM_callocN(sizeof(int) * totvert, "explode_vertpa"); /* initialize all faces & verts to no particle */ for (i = 0; i < totface; i++) facepa[i] = totpart; for (i = 0; i < totvert; i++) vertpa[i] = totpart; /* set protected verts */ if (emd->vgroup) { MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT); if (dvert) { const int defgrp_index = emd->vgroup - 1; for (i = 0; i < totvert; i++, dvert++) { float val = BLI_rng_get_float(rng); val = (1.0f - emd->protect) * val + emd->protect * 0.5f; if (val < defvert_find_weight(dvert, defgrp_index)) vertpa[i] = -1; } } } /* make tree of emitter locations */ tree = BLI_kdtree_new(totpart); for (p = 0, pa = psys->particles; p < totpart; p++, pa++) { psys_particle_on_emitter(psmd, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, NULL, NULL, NULL, NULL, NULL); BLI_kdtree_insert(tree, p, co); } BLI_kdtree_balance(tree); /* set face-particle-indexes to nearest particle to face center */ for (i = 0, fa = mface; i < totface; i++, fa++) { add_v3_v3v3(center, mvert[fa->v1].co, mvert[fa->v2].co); add_v3_v3(center, mvert[fa->v3].co); if (fa->v4) { add_v3_v3(center, mvert[fa->v4].co); mul_v3_fl(center, 0.25); } else mul_v3_fl(center, 1.0f / 3.0f); p = BLI_kdtree_find_nearest(tree, center, NULL); v1 = vertpa[fa->v1]; v2 = vertpa[fa->v2]; v3 = vertpa[fa->v3]; if (fa->v4) v4 = vertpa[fa->v4]; if (v1 >= 0 && v2 >= 0 && v3 >= 0 && (fa->v4 == 0 || v4 >= 0)) facepa[i] = p; if (v1 >= 0) vertpa[fa->v1] = p; if (v2 >= 0) vertpa[fa->v2] = p; if (v3 >= 0) vertpa[fa->v3] = p; if (fa->v4 && v4 >= 0) vertpa[fa->v4] = p; } if (vertpa) MEM_freeN(vertpa); BLI_kdtree_free(tree); BLI_rng_free(rng); }
void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint) { Material *ma; StrandBuffer *strandbuf; float *simplify; float p[4][3], data[4], cross[3], w, dx, dy, t; int type; strandbuf= sseg->buffer; ma= sseg->buffer->ma; t= spoint->t; type= (strandbuf->flag & R_STRAND_BSPLINE)? KEY_BSPLINE: KEY_CARDINAL; copy_v3_v3(p[0], sseg->v[0]->co); copy_v3_v3(p[1], sseg->v[1]->co); copy_v3_v3(p[2], sseg->v[2]->co); copy_v3_v3(p[3], sseg->v[3]->co); if (sseg->obi->flag & R_TRANSFORMED) { mul_m4_v3(sseg->obi->mat, p[0]); mul_m4_v3(sseg->obi->mat, p[1]); mul_m4_v3(sseg->obi->mat, p[2]); mul_m4_v3(sseg->obi->mat, p[3]); } if (t == 0.0f) { copy_v3_v3(spoint->co, p[1]); spoint->strandco= sseg->v[1]->strandco; spoint->dtstrandco= (sseg->v[2]->strandco - sseg->v[0]->strandco); if (sseg->v[0] != sseg->v[1]) spoint->dtstrandco *= 0.5f; } else if (t == 1.0f) { copy_v3_v3(spoint->co, p[2]); spoint->strandco= sseg->v[2]->strandco; spoint->dtstrandco= (sseg->v[3]->strandco - sseg->v[1]->strandco); if (sseg->v[3] != sseg->v[2]) spoint->dtstrandco *= 0.5f; } else { key_curve_position_weights(t, data, type); spoint->co[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; spoint->co[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; spoint->co[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; spoint->strandco= (1.0f-t)*sseg->v[1]->strandco + t*sseg->v[2]->strandco; } key_curve_tangent_weights(t, data, type); spoint->dtco[0]= data[0]*p[0][0] + data[1]*p[1][0] + data[2]*p[2][0] + data[3]*p[3][0]; spoint->dtco[1]= data[0]*p[0][1] + data[1]*p[1][1] + data[2]*p[2][1] + data[3]*p[3][1]; spoint->dtco[2]= data[0]*p[0][2] + data[1]*p[1][2] + data[2]*p[2][2] + data[3]*p[3][2]; normalize_v3_v3(spoint->tan, spoint->dtco); normalize_v3_v3(spoint->nor, spoint->co); negate_v3(spoint->nor); spoint->width= strand_eval_width(ma, spoint->strandco); /* simplification */ simplify= RE_strandren_get_simplify(strandbuf->obr, sseg->strand, 0); spoint->alpha= (simplify)? simplify[1]: 1.0f; /* outer points */ cross_v3_v3v3(cross, spoint->co, spoint->tan); w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3]; dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w; dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w; w= sqrt(dx*dx + dy*dy); if (w > 0.0f) { if (strandbuf->flag & R_STRAND_B_UNITS) { const float crosslen= len_v3(cross); w= 2.0f*crosslen*strandbuf->minwidth/w; if (spoint->width < w) { spoint->alpha= spoint->width/w; spoint->width= w; } if (simplify) /* squared because we only change width, not length */ spoint->width *= simplify[0]*simplify[0]; mul_v3_fl(cross, spoint->width*0.5f/crosslen); } else mul_v3_fl(cross, spoint->width/w); } sub_v3_v3v3(spoint->co1, spoint->co, cross); add_v3_v3v3(spoint->co2, spoint->co, cross); copy_v3_v3(spoint->dsco, cross); }
/* calculates offset for co, based on fractal, sphere or smooth settings */ static void alter_co( BMVert *v, BMEdge *UNUSED(e_orig), const SubDParams *params, const float perc, const BMVert *v_a, const BMVert *v_b) { float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp); int i; copy_v3_v3(co, v->co); if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */ normalize_v3(co); mul_v3_fl(co, params->smooth); } else if (params->use_smooth) { /* calculating twice and blending gives smoother results, * removing visible seams. */ #define USE_SPHERE_DUAL_BLEND const float eps_unit_vec = 1e-5f; float smooth; float no_dir[3]; #ifdef USE_SPHERE_DUAL_BLEND float no_reflect[3], co_a[3], co_b[3]; #endif sub_v3_v3v3(no_dir, v_a->co, v_b->co); normalize_v3(no_dir); #ifndef USE_SPHERE_DUAL_BLEND if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) { interp_v3_v3v3(co, v_a->co, v_b->co, perc); } else { interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co); } #else /* sphere-a */ reflect_v3_v3v3(no_reflect, v_a->no, no_dir); if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) { interp_v3_v3v3(co_a, v_a->co, v_b->co, perc); } else { interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a); } /* sphere-b */ reflect_v3_v3v3(no_reflect, v_b->no, no_dir); if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) { interp_v3_v3v3(co_b, v_a->co, v_b->co, perc); } else { interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b); } /* blend both spheres */ interp_v3_v3v3(co, co_a, co_b, perc); #endif /* USE_SPHERE_DUAL_BLEND */ /* apply falloff */ if (params->smooth_falloff == SUBD_FALLOFF_LIN) { smooth = 1.0f; } else { smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc)); smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth); } if (params->use_smooth_even) { smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no); } smooth *= params->smooth; if (smooth != 1.0f) { float co_flat[3]; interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc); interp_v3_v3v3(co, co_flat, co, smooth); } #undef USE_SPHERE_DUAL_BLEND } if (params->use_fractal) { float normal[3], co2[3], base1[3], base2[3], tvec[3]; const float len = len_v3v3(v_a->co, v_b->co); float fac; fac = params->fractal * len; mid_v3_v3v3(normal, v_a->no, v_b->no); ortho_basis_v3v3_v3(base1, base2, normal); add_v3_v3v3(co2, v->co, params->fractal_ofs); mul_v3_fl(co2, 10.0f); tvec[0] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 2) - 0.5f); tvec[1] = fac * (BLI_gTurbulence(1.0, co2[1], co2[0], co2[2], 15, 0, 2) - 0.5f); tvec[2] = fac * (BLI_gTurbulence(1.0, co2[1], co2[2], co2[0], 15, 0, 2) - 0.5f); /* add displacement */ madd_v3_v3fl(co, normal, tvec[0]); madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal)); madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal)); } /* apply the new difference to the rest of the shape keys, * note that this doesn't take rotations into account, we _could_ support * this by getting the normals and coords for each shape key and * re-calculate the smooth value for each but this is quite involved. * for now its ok to simply apply the difference IMHO - campbell */ if (params->shape_info.totlayer > 1) { float tvec[3]; sub_v3_v3v3(tvec, v->co, co); /* skip the last layer since its the temp */ i = params->shape_info.totlayer - 1; co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset); while (i--) { BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp)); sub_v3_v3(co += 3, tvec); } } }
static int armature_calc_roll_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_edit_object(C); eCalcRollTypes type = RNA_enum_get(op->ptr, "type"); const bool axis_only = RNA_boolean_get(op->ptr, "axis_only"); /* axis_flip when matching the active bone never makes sense */ bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") : (type >= CALC_ROLL_TAN_NEG_X) ? true : false); float imat[3][3]; bArmature *arm = ob->data; EditBone *ebone; if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) { type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X); axis_flip = true; } copy_m3_m4(imat, ob->obmat); invert_m3(imat); if (type == CALC_ROLL_CURSOR) { /* Cursor */ Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); /* can be NULL */ float cursor_local[3]; const float *cursor = ED_view3d_cursor3d_get(scene, v3d); invert_m4_m4(ob->imat, ob->obmat); copy_v3_v3(cursor_local, cursor); mul_m4_v3(ob->imat, cursor_local); /* cursor */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) { float cursor_rel[3]; sub_v3_v3v3(cursor_rel, cursor_local, ebone->head); if (axis_flip) negate_v3(cursor_rel); if (normalize_v3(cursor_rel) != 0.0f) { ebone->roll = ED_armature_ebone_roll_to_vector(ebone, cursor_rel, axis_only); } } } } else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) { for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (ebone->parent) { bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)); bool is_edit_parent = (EBONE_VISIBLE(arm, ebone->parent) && EBONE_EDITABLE(ebone->parent)); if (is_edit || is_edit_parent) { EditBone *ebone_other = ebone->parent; float dir_a[3]; float dir_b[3]; float vec[3]; bool is_vec_zero; sub_v3_v3v3(dir_a, ebone->tail, ebone->head); normalize_v3(dir_a); /* find the first bone in the chane with a different direction */ do { sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail); normalize_v3(dir_b); if (type == CALC_ROLL_TAN_POS_Z) { cross_v3_v3v3(vec, dir_a, dir_b); } else { add_v3_v3v3(vec, dir_a, dir_b); } } while ((is_vec_zero = (normalize_v3(vec) < 0.00001f)) && (ebone_other = ebone_other->parent)); if (!is_vec_zero) { if (axis_flip) negate_v3(vec); if (is_edit) { ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only); } /* parentless bones use cross product with child */ if (is_edit_parent) { if (ebone->parent->parent == NULL) { ebone->parent->roll = ED_armature_ebone_roll_to_vector(ebone->parent, vec, axis_only); } } } } } } } else { float vec[3] = {0.0f, 0.0f, 0.0f}; if (type == CALC_ROLL_VIEW) { /* View */ RegionView3D *rv3d = CTX_wm_region_view3d(C); if (rv3d == NULL) { BKE_report(op->reports, RPT_ERROR, "No region view3d available"); return OPERATOR_CANCELLED; } copy_v3_v3(vec, rv3d->viewinv[2]); mul_m3_v3(imat, vec); } else if (type == CALC_ROLL_ACTIVE) { float mat[3][3]; ebone = (EditBone *)arm->act_edbone; if (ebone == NULL) { BKE_report(op->reports, RPT_ERROR, "No active bone set"); return OPERATOR_CANCELLED; } ED_armature_ebone_to_mat3(ebone, mat); copy_v3_v3(vec, mat[2]); } else { /* Axis */ assert(type <= 5); if (type < 3) vec[type] = 1.0f; else vec[type - 2] = -1.0f; mul_m3_v3(imat, vec); normalize_v3(vec); } if (axis_flip) negate_v3(vec); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) { /* roll func is a callback which assumes that all is well */ ebone->roll = ED_armature_ebone_roll_to_vector(ebone, vec, axis_only); } } } if (arm->flag & ARM_MIRROR_EDIT) { for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) { EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone); if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) { ebone->roll = -ebone_mirr->roll; } } } } /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob); return OPERATOR_FINISHED; }
void RE_sample_point_density(Scene *scene, PointDensity *pd, int resolution, float *values) { const size_t resolution2 = resolution * resolution; Object *object = pd->object; size_t x, y, z; float min[3], max[3], dim[3], mat[4][4]; if (object == NULL) { sample_dummy_point_density(resolution, values); return; } if (pd->source == TEX_PD_PSYS) { ParticleSystem *psys; if (pd->psys == 0) { sample_dummy_point_density(resolution, values); return; } psys = BLI_findlink(&object->particlesystem, pd->psys - 1); if (psys == NULL) { sample_dummy_point_density(resolution, values); return; } particle_system_minmax(scene, object, psys, pd->radius, min, max); } else { float radius[3] = {pd->radius, pd->radius, pd->radius}; float *loc, *size; BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL); sub_v3_v3v3(min, loc, size); add_v3_v3v3(max, loc, size); /* Adjust texture space to include density points on the boundaries. */ sub_v3_v3(min, radius); add_v3_v3(max, radius); } sub_v3_v3v3(dim, max, min); if (dim[0] <= 0.0f || dim[1] <= 0.0f || dim[2] <= 0.0f) { sample_dummy_point_density(resolution, values); return; } /* Same matricies/resolution as dupli_render_particle_set(). */ unit_m4(mat); BLI_mutex_lock(&sample_mutex); cache_pointdensity_ex(scene, pd, mat, mat, 1, 1); for (z = 0; z < resolution; ++z) { for (y = 0; y < resolution; ++y) { for (x = 0; x < resolution; ++x) { size_t index = z * resolution2 + y * resolution + x; float texvec[3]; float age, vec[3]; TexResult texres; copy_v3_v3(texvec, min); texvec[0] += dim[0] * (float)x / (float)resolution; texvec[1] += dim[1] * (float)y / (float)resolution; texvec[2] += dim[2] * (float)z / (float)resolution; pointdensity(pd, texvec, &texres, &age, vec); pointdensity_color(pd, &texres, age, vec); copy_v3_v3(&values[index*4 + 0], &texres.tr); values[index*4 + 3] = texres.tin; } } } free_pointdensity(pd); BLI_mutex_unlock(&sample_mutex); }
static float bm_edge_calc_rotate_beauty__area( const float v1[3], const float v2[3], const float v3[3], const float v4[3]) { /* not a loop (only to be able to break out) */ do { float v1_xy[2], v2_xy[2], v3_xy[2], v4_xy[2]; /* first get the 2d values */ { const float eps = 1e-5; float no_a[3], no_b[3]; float no[3]; float axis_mat[3][3]; float no_scale; cross_tri_v3(no_a, v2, v3, v4); cross_tri_v3(no_b, v2, v4, v1); // printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f); BLI_assert((ELEM(v1, v2, v3, v4) == false) && (ELEM(v2, v1, v3, v4) == false) && (ELEM(v3, v1, v2, v4) == false) && (ELEM(v4, v1, v2, v3) == false)); add_v3_v3v3(no, no_a, no_b); if (UNLIKELY((no_scale = normalize_v3(no)) == 0.0f)) { break; } axis_dominant_v3_to_m3(axis_mat, no); mul_v2_m3v3(v1_xy, axis_mat, v1); mul_v2_m3v3(v2_xy, axis_mat, v2); mul_v2_m3v3(v3_xy, axis_mat, v3); mul_v2_m3v3(v4_xy, axis_mat, v4); /** * Check if input faces are already flipped. * Logic for 'signum_i' addition is: * * Accept: * - (1, 1) or (-1, -1): same side (common case). * - (-1/1, 0): one degenerate, OK since we may rotate into a valid state. * * Ignore: * - (-1, 1): opposite winding, ignore. * - ( 0, 0): both degenerate, ignore. * * \note The cross product is divided by 'no_scale' * so the rotation calculation is scale independent. */ if (!(signum_i_ex(cross_tri_v2(v2_xy, v3_xy, v4_xy) / no_scale, eps) + signum_i_ex(cross_tri_v2(v2_xy, v4_xy, v1_xy) / no_scale, eps))) { break; } } /** * Important to lock degenerate here, * since the triangle pars will be projected into different 2D spaces. * Allowing to rotate out of a degenerate state can flip the faces (when performed iteratively). */ return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true); } while (false); return FLT_MAX; }
void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], const float par_rot[4], float time, float freq, float shape, float amplitude, float flat, short type, short axis, float obmat[4][4], int smooth_start) { float kink[3] = {1.f, 0.f, 0.f}, par_vec[3], q1[4] = {1.f, 0.f, 0.f, 0.f}; float t, dt = 1.f, result[3]; if (ELEM(type, PART_KINK_NO, PART_KINK_SPIRAL)) return; CLAMP(time, 0.f, 1.f); if (shape != 0.0f && !ELEM(type, PART_KINK_BRAID)) { if (shape < 0.0f) time = (float)pow(time, 1.f + shape); else time = (float)pow(time, 1.f / (1.f - shape)); } t = time * freq * (float)M_PI; if (smooth_start) { dt = fabsf(t); /* smooth the beginning of kink */ CLAMP(dt, 0.f, (float)M_PI); dt = sinf(dt / 2.f); } if (!ELEM(type, PART_KINK_RADIAL)) { float temp[3]; kink[axis] = 1.f; if (obmat) mul_mat3_m4_v3(obmat, kink); mul_qt_v3(par_rot, kink); /* make sure kink is normal to strand */ project_v3_v3v3(temp, kink, par_vel); sub_v3_v3(kink, temp); normalize_v3(kink); } copy_v3_v3(result, state->co); sub_v3_v3v3(par_vec, par_co, state->co); switch (type) { case PART_KINK_CURL: { float curl_offset[3]; /* rotate kink vector around strand tangent */ mul_v3_v3fl(curl_offset, kink, amplitude); axis_angle_to_quat(q1, par_vel, t); mul_qt_v3(q1, curl_offset); interp_v3_v3v3(par_vec, state->co, par_co, flat); add_v3_v3v3(result, par_vec, curl_offset); break; } case PART_KINK_RADIAL: { if (flat > 0.f) { float proj[3]; /* flatten along strand */ project_v3_v3v3(proj, par_vec, par_vel); madd_v3_v3fl(result, proj, flat); } madd_v3_v3fl(result, par_vec, -amplitude * sinf(t)); break; } case PART_KINK_WAVE: { madd_v3_v3fl(result, kink, amplitude * sinf(t)); if (flat > 0.f) { float proj[3]; /* flatten along wave */ project_v3_v3v3(proj, par_vec, kink); madd_v3_v3fl(result, proj, flat); /* flatten along strand */ project_v3_v3v3(proj, par_vec, par_vel); madd_v3_v3fl(result, proj, flat); } break; } case PART_KINK_BRAID: { float y_vec[3] = {0.f, 1.f, 0.f}; float z_vec[3] = {0.f, 0.f, 1.f}; float vec_one[3], state_co[3]; float inp_y, inp_z, length; if (par_rot) { mul_qt_v3(par_rot, y_vec); mul_qt_v3(par_rot, z_vec); } negate_v3(par_vec); normalize_v3_v3(vec_one, par_vec); inp_y = dot_v3v3(y_vec, vec_one); inp_z = dot_v3v3(z_vec, vec_one); if (inp_y > 0.5f) { copy_v3_v3(state_co, y_vec); mul_v3_fl(y_vec, amplitude * cosf(t)); mul_v3_fl(z_vec, amplitude / 2.f * sinf(2.f * t)); } else if (inp_z > 0.0f) { mul_v3_v3fl(state_co, z_vec, sinf((float)M_PI / 3.f)); madd_v3_v3fl(state_co, y_vec, -0.5f); mul_v3_fl(y_vec, -amplitude * cosf(t + (float)M_PI / 3.f)); mul_v3_fl(z_vec, amplitude / 2.f * cosf(2.f * t + (float)M_PI / 6.f)); } else { mul_v3_v3fl(state_co, z_vec, -sinf((float)M_PI / 3.f)); madd_v3_v3fl(state_co, y_vec, -0.5f); mul_v3_fl(y_vec, amplitude * -sinf(t + (float)M_PI / 6.f)); mul_v3_fl(z_vec, amplitude / 2.f * -sinf(2.f * t + (float)M_PI / 3.f)); } mul_v3_fl(state_co, amplitude); add_v3_v3(state_co, par_co); sub_v3_v3v3(par_vec, state->co, state_co); length = normalize_v3(par_vec); mul_v3_fl(par_vec, MIN2(length, amplitude / 2.f)); add_v3_v3v3(state_co, par_co, y_vec); add_v3_v3(state_co, z_vec); add_v3_v3(state_co, par_vec); shape = 2.f * (float)M_PI * (1.f + shape); if (t < shape) { shape = t / shape; shape = (float)sqrt((double)shape); interp_v3_v3v3(result, result, state_co, shape); } else { copy_v3_v3(result, state_co); } break; } } /* blend the start of the kink */ if (dt < 1.f) interp_v3_v3v3(state->co, state->co, result, dt); else copy_v3_v3(state->co, result); }
static bool camera_frame_fit_calc_from_data( CameraParams *params, CameraViewFrameData *data, float r_co[3], float *r_scale) { float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][3]; unsigned int i; if (data->tot <= 1) { return false; } if (params->is_ortho) { const float *cam_axis_x = data->camera_rotmat[0]; const float *cam_axis_y = data->camera_rotmat[1]; const float *cam_axis_z = data->camera_rotmat[2]; float dists[CAMERA_VIEWFRAME_NUM_PLANES]; float scale_diff; /* apply the dist-from-plane's to the transformed plane points */ for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { dists[i] = sqrtf_signed(data->dist_vals_sq[i]); } if ((dists[0] + dists[2]) > (dists[1] + dists[3])) { scale_diff = (dists[1] + dists[3]) * (BLI_rctf_size_x(¶ms->viewplane) / BLI_rctf_size_y(¶ms->viewplane)); } else { scale_diff = (dists[0] + dists[2]) * (BLI_rctf_size_y(¶ms->viewplane) / BLI_rctf_size_x(¶ms->viewplane)); } *r_scale = params->ortho_scale - scale_diff; zero_v3(r_co); madd_v3_v3fl(r_co, cam_axis_x, (dists[2] - dists[0]) * 0.5f + params->shiftx * scale_diff); madd_v3_v3fl(r_co, cam_axis_y, (dists[1] - dists[3]) * 0.5f + params->shifty * scale_diff); madd_v3_v3fl(r_co, cam_axis_z, -(data->dist_to_cam - 1.0f - params->clipsta)); return true; } 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 < CAMERA_VIEWFRAME_NUM_PLANES; i++) { mul_v3_v3fl(plane_tx[i], data->normal_tx[i], sqrtf_signed(data->dist_vals_sq[i])); } if ((!isect_plane_plane_v3(plane_isect_1, plane_isect_1_no, plane_tx[0], data->normal_tx[0], plane_tx[2], data->normal_tx[2])) || (!isect_plane_plane_v3(plane_isect_2, plane_isect_2_no, plane_tx[1], data->normal_tx[1], plane_tx[3], data->normal_tx[3]))) { return false; } 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) { float cam_plane_no[3]; float plane_isect_delta[3]; float plane_isect_delta_len; float shift_fac = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y) / params->lens; /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */ negate_v3_v3(cam_plane_no, data->camera_rotmat[2]); 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, params->shifty * plane_isect_delta_len * shift_fac); } 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, params->shiftx * plane_isect_delta_len * shift_fac); } return true; } } return false; }
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, GPUTexture *tex, const float min[3], const float max[3], const int res[3], float dx, float UNUSED(base_scale), const float viewnormal[3], GPUTexture *tex_shadow, GPUTexture *tex_flame) { const float ob_sizei[3] = { 1.0f / fabsf(ob->size[0]), 1.0f / fabsf(ob->size[1]), 1.0f / fabsf(ob->size[2])}; int i, j, k, n, good_index; float d /*, d0 */ /* UNUSED */, dd, ds; float (*points)[3] = NULL; int numpoints = 0; float cor[3] = {1.0f, 1.0f, 1.0f}; int gl_depth = 0, gl_blend = 0; int use_fire = (sds->active_fields & SM_ACTIVE_FIRE); /* draw slices of smoke is adapted from c++ code authored * by: Johannes Schmid and Ingemar Rask, 2006, [email protected] */ float cv[][3] = { {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f} }; /* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */ float edges[12][2][3] = { {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}, {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}} }; unsigned char *spec_data; float *spec_pixels; GPUTexture *tex_spec; GPUProgram *smoke_program; int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED : GPU_PROGRAM_SMOKE; float size[3]; if (!tex) { printf("Could not allocate 3D texture for 3D View smoke drawing.\n"); return; } #ifdef DEBUG_DRAW_TIME TIMEIT_START(draw); #endif /* generate flame spectrum texture */ #define SPEC_WIDTH 256 #define FIRE_THRESH 7 #define MAX_FIRE_ALPHA 0.06f #define FULL_ON_FIRE 100 spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char)); flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000); spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float)); for (i = 0; i < 16; i++) { for (j = 0; j < 16; j++) { for (k = 0; k < SPEC_WIDTH; k++) { int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4; if (k >= FIRE_THRESH) { spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f; spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f; spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f; spec_pixels[index + 3] = MAX_FIRE_ALPHA * ( (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); } else { spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f; } } } } tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL); #undef SPEC_WIDTH #undef FIRE_THRESH #undef MAX_FIRE_ALPHA #undef FULL_ON_FIRE sub_v3_v3v3(size, max, min); /* maxx, maxy, maxz */ cv[0][0] = max[0]; cv[0][1] = max[1]; cv[0][2] = max[2]; /* minx, maxy, maxz */ cv[1][0] = min[0]; cv[1][1] = max[1]; cv[1][2] = max[2]; /* minx, miny, maxz */ cv[2][0] = min[0]; cv[2][1] = min[1]; cv[2][2] = max[2]; /* maxx, miny, maxz */ cv[3][0] = max[0]; cv[3][1] = min[1]; cv[3][2] = max[2]; /* maxx, maxy, minz */ cv[4][0] = max[0]; cv[4][1] = max[1]; cv[4][2] = min[2]; /* minx, maxy, minz */ cv[5][0] = min[0]; cv[5][1] = max[1]; cv[5][2] = min[2]; /* minx, miny, minz */ cv[6][0] = min[0]; cv[6][1] = min[1]; cv[6][2] = min[2]; /* maxx, miny, minz */ cv[7][0] = max[0]; cv[7][1] = min[1]; cv[7][2] = min[2]; copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */ copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */ copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */ copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */ copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */ copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */ copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */ copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */ copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */ copy_v3_v3(edges[11][0], cv[5]); /* minx, maxy, minz */ // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]); // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]); edges[0][1][2] = size[2]; edges[1][1][2] = size[2]; edges[2][1][2] = size[2]; edges[3][1][2] = size[2]; edges[4][1][1] = size[1]; edges[5][1][1] = size[1]; edges[6][1][1] = size[1]; edges[7][1][1] = size[1]; edges[8][1][0] = size[0]; edges[9][1][0] = size[0]; edges[10][1][0] = size[0]; edges[11][1][0] = size[0]; glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); /* find cube vertex that is closest to the viewer */ for (i = 0; i < 8; i++) { float x, y, z; x = cv[i][0] - viewnormal[0] * size[0] * 0.5f; y = cv[i][1] - viewnormal[1] * size[1] * 0.5f; z = cv[i][2] - viewnormal[2] * size[2] * 0.5f; if ((x >= min[0]) && (x <= max[0]) && (y >= min[1]) && (y <= max[1]) && (z >= min[2]) && (z <= max[2])) { break; } } if (i >= 8) { /* fallback, avoid using buffer over-run */ i = 0; } // printf("i: %d\n", i); // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]); smoke_program = GPU_shader_get_builtin_program(progtype); if (smoke_program) { GPU_program_bind(smoke_program); /* cell spacing */ GPU_program_parameter_4f(smoke_program, 0, dx, dx, dx, 1.0); /* custom parameter for smoke style (higher = thicker) */ if (sds->active_fields & SM_ACTIVE_COLORS) GPU_program_parameter_4f(smoke_program, 1, 1.0, 1.0, 1.0, 10.0); else GPU_program_parameter_4f(smoke_program, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0); } else printf("Your gfx card does not support 3D View smoke drawing.\n"); GPU_texture_bind(tex, 0); if (tex_shadow) GPU_texture_bind(tex_shadow, 1); else printf("No volume shadow\n"); if (tex_flame) { GPU_texture_bind(tex_flame, 2); GPU_texture_bind(tex_spec, 3); } if (!GPU_non_power_of_two_support()) { cor[0] = (float)res[0] / (float)power_of_2_max_u(res[0]); cor[1] = (float)res[1] / (float)power_of_2_max_u(res[1]); cor[2] = (float)res[2] / (float)power_of_2_max_u(res[2]); } cor[0] /= size[0]; cor[1] /= size[1]; cor[2] /= size[2]; /* our slices are defined by the plane equation a*x + b*y +c*z + d = 0 * (a,b,c), the plane normal, are given by viewdir * d is the parameter along the view direction. the first d is given by * inserting previously found vertex into the plane equation */ /* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */ ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]); dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f; n = 0; good_index = i; // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds); points = MEM_callocN(sizeof(*points) * 12, "smoke_points_preview"); while (1) { float p0[3]; float tmp_point[3], tmp_point2[3]; if (dd * (float)n > ds) break; copy_v3_v3(tmp_point, viewnormal); mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n)); add_v3_v3v3(tmp_point2, cv[good_index], tmp_point); d = dot_v3v3(tmp_point2, viewnormal); // printf("my d: %f\n", d); /* intersect_edges returns the intersection points of all cube edges with * the given plane that lie within the cube */ numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges); // printf("points: %d\n", numpoints); if (numpoints > 2) { copy_v3_v3(p0, points[0]); /* sort points to get a convex polygon */ for (i = 1; i < numpoints - 1; i++) { for (j = i + 1; j < numpoints; j++) { if (!convex(p0, viewnormal, points[j], points[i])) { swap_v3_v3(points[i], points[j]); } } } /* render fire slice */ if (use_fire) { if (GLEW_VERSION_1_4) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE); else glBlendFunc(GL_SRC_ALPHA, GL_ONE); GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { glTexCoord3d((points[i][0] - min[0]) * cor[0], (points[i][1] - min[1]) * cor[1], (points[i][2] - min[2]) * cor[2]); glVertex3f(points[i][0] * ob_sizei[0], points[i][1] * ob_sizei[1], points[i][2] * ob_sizei[2]); } glEnd(); } /* render smoke slice */ if (GLEW_VERSION_1_4) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 1.0, 1.0); for (i = 0; i < numpoints; i++) { glTexCoord3d((points[i][0] - min[0]) * cor[0], (points[i][1] - min[1]) * cor[1], (points[i][2] - min[2]) * cor[2]); glVertex3f(points[i][0] * ob_sizei[0], points[i][1] * ob_sizei[1], points[i][2] * ob_sizei[2]); } glEnd(); } n++; } #ifdef DEBUG_DRAW_TIME printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); TIMEIT_END(draw); #endif if (tex_shadow) GPU_texture_unbind(tex_shadow); GPU_texture_unbind(tex); if (tex_flame) { GPU_texture_unbind(tex_flame); GPU_texture_unbind(tex_spec); } GPU_texture_free(tex_spec); free(spec_data); free(spec_pixels); if (smoke_program) GPU_program_unbind(smoke_program); MEM_freeN(points); if (!gl_blend) { glDisable(GL_BLEND); } if (gl_depth) { glEnable(GL_DEPTH_TEST); } }
static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4]) { GHashIterator iter; /**** dots ****/ glPointSize(3.0f); glBegin(GL_POINTS); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); if (elem->type != SIM_DEBUG_ELEM_DOT) continue; glColor3f(elem->color[0], elem->color[1], elem->color[2]); glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); } glEnd(); /**** circles ****/ { float circle[16][2] = { {0.000000, 1.000000}, {0.382683, 0.923880}, {0.707107, 0.707107}, {0.923880, 0.382683}, {1.000000, -0.000000}, {0.923880, -0.382683}, {0.707107, -0.707107}, {0.382683, -0.923880}, {-0.000000, -1.000000}, {-0.382683, -0.923880}, {-0.707107, -0.707107}, {-0.923879, -0.382684}, {-1.000000, 0.000000}, {-0.923879, 0.382684}, {-0.707107, 0.707107}, {-0.382683, 0.923880} }; for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); float radius = elem->v2[0]; float co[3]; int i; if (elem->type != SIM_DEBUG_ELEM_CIRCLE) continue; glColor3f(elem->color[0], elem->color[1], elem->color[2]); glBegin(GL_LINE_LOOP); for (i = 0; i < 16; ++i) { co[0] = radius * circle[i][0]; co[1] = radius * circle[i][1]; co[2] = 0.0f; mul_mat3_m4_v3(imat, co); add_v3_v3(co, elem->v1); glVertex3f(co[0], co[1], co[2]); } glEnd(); } } /**** lines ****/ glBegin(GL_LINES); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); if (elem->type != SIM_DEBUG_ELEM_LINE) continue; glColor3f(elem->color[0], elem->color[1], elem->color[2]); glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); glVertex3f(elem->v2[0], elem->v2[1], elem->v2[2]); } glEnd(); /**** vectors ****/ glPointSize(2.0f); glBegin(GL_POINTS); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); if (elem->type != SIM_DEBUG_ELEM_VECTOR) continue; glColor3f(elem->color[0], elem->color[1], elem->color[2]); glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); } glEnd(); glBegin(GL_LINES); for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); float t[3]; if (elem->type != SIM_DEBUG_ELEM_VECTOR) continue; glColor3f(elem->color[0], elem->color[1], elem->color[2]); glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); add_v3_v3v3(t, elem->v1, elem->v2); glVertex3f(t[0], t[1], t[2]); } glEnd(); /**** strings ****/ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); if (elem->type != SIM_DEBUG_ELEM_STRING) continue; unsigned char col[4]; rgb_float_to_uchar(col, elem->color); col[3] = 255; view3d_cached_text_draw_add(elem->v1, elem->str, strlen(elem->str), 0, V3D_CACHE_TEXT_GLOBALSPACE, col); } }
/* axis is using another define!!! */ static int calc_curve_deform(Scene *scene, Object *par, float *co, short axis, CurveDeform *cd, float *quatp) { Curve *cu= par->data; float fac, loc[4], dir[3], new_quat[4], radius; short /*upflag, */ index; index= axis-1; if(index>2) index -= 3; /* negative */ /* to be sure, mostly after file load */ if(cu->path==NULL) { makeDispListCurveTypes(scene, par, 0); if(cu->path==NULL) return 0; // happens on append... } /* options */ if(ELEM3(axis, OB_NEGX+1, OB_NEGY+1, OB_NEGZ+1)) { /* OB_NEG# 0-5, MOD_CURVE_POS# 1-6 */ if(cu->flag & CU_STRETCH) fac= (-co[index]-cd->dmax[index])/(cd->dmax[index] - cd->dmin[index]); else fac= (cd->dloc[index])/(cu->path->totdist) - (co[index]-cd->dmax[index])/(cu->path->totdist); } else { if(cu->flag & CU_STRETCH) fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]); else fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist); } #if 0 // XXX old animation system /* we want the ipo to work on the default 100 frame range, because there's no actual time involved in path position */ // huh? by WHY!!!!???? - Aligorith if(cu->ipo) { fac*= 100.0f; if(calc_ipo_spec(cu->ipo, CU_SPEED, &fac)==0) fac/= 100.0; } #endif // XXX old animation system if( where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */ float quat[4], cent[3]; #if 0 // XXX - 2.4x Z-Up, Now use bevel tilt. if(cd->no_rot_axis) /* set by caller */ dir[cd->no_rot_axis-1]= 0.0f; /* -1 for compatibility with old track defines */ vec_to_quat( quat,dir, axis-1, upflag); /* the tilt */ if(loc[3]!=0.0) { normalize_v3(dir); q[0]= (float)cos(0.5*loc[3]); fac= (float)sin(0.5*loc[3]); q[1]= -fac*dir[0]; q[2]= -fac*dir[1]; q[3]= -fac*dir[2]; mul_qt_qtqt(quat, q, quat); } #endif if(cd->no_rot_axis) { /* set by caller */ /* this is not exactly the same as 2.4x, since the axis is having rotation removed rather than * changing the axis before calculating the tilt but serves much the same purpose */ float dir_flat[3]={0,0,0}, q[4]; copy_v3_v3(dir_flat, dir); dir_flat[cd->no_rot_axis-1]= 0.0f; normalize_v3(dir); normalize_v3(dir_flat); rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */ mul_qt_qtqt(new_quat, q, new_quat); } /* Logic for 'cent' orientation * * * The way 'co' is copied to 'cent' may seem to have no meaning, but it does. * * Use a curve modifier to stretch a cube out, color each side RGB, positive side light, negative dark. * view with X up (default), from the angle that you can see 3 faces RGB colors (light), anti-clockwise * Notice X,Y,Z Up all have light colors and each ordered CCW. * * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell * * note: moved functions into quat_apply_track/vec_apply_track * */ copy_qt_qt(quat, new_quat); copy_v3_v3(cent, co); /* zero the axis which is not used, * the big block of text above now applies to these 3 lines */ quat_apply_track(quat, axis-1, (axis==1 || axis==3) ? 1:0); /* up flag is a dummy, set so no rotation is done */ vec_apply_track(cent, axis-1); cent[axis < 4 ? axis-1 : axis-4]= 0.0f; /* scale if enabled */ if(cu->flag & CU_PATH_RADIUS) mul_v3_fl(cent, radius); /* local rotation */ normalize_qt(quat); mul_qt_v3(quat, cent); /* translation */ add_v3_v3v3(co, cent, loc); if(quatp) copy_qt_qt(quatp, quat); return 1; } return 0; }
/** * Axis calculation taking the view into account, correcting view-aligned axis. */ static void axisProjection(const TransInfo *t, const float axis[3], const float in[3], float out[3]) { float norm[3], vec[3], factor, angle; float t_con_center[3]; if (is_zero_v3(in)) { return; } copy_v3_v3(t_con_center, t->center_global); /* checks for center being too close to the view center */ viewAxisCorrectCenter(t, t_con_center); angle = fabsf(angle_v3v3(axis, t->viewinv[2])); if (angle > (float)M_PI_2) { angle = (float)M_PI - angle; } /* For when view is parallel to constraint... will cause NaNs otherwise * So we take vertical motion in 3D space and apply it to the * constraint axis. Nice for camera grab + MMB */ if (angle < DEG2RADF(5.0f)) { project_v3_v3v3(vec, in, t->viewinv[1]); factor = dot_v3v3(t->viewinv[1], vec) * 2.0f; /* Since camera distance is quite relative, use quadratic relationship. * holding shift can compensate. */ if (factor < 0.0f) { factor *= -factor; } else { factor *= factor; } /* -factor makes move down going backwards */ normalize_v3_v3_length(out, axis, -factor); } else { float v[3], i1[3], i2[3]; float v2[3], v4[3]; float norm_center[3]; float plane[3]; getViewVector(t, t_con_center, norm_center); cross_v3_v3v3(plane, norm_center, axis); project_v3_v3v3(vec, in, plane); sub_v3_v3v3(vec, in, vec); add_v3_v3v3(v, vec, t_con_center); getViewVector(t, v, norm); /* give arbitrary large value if projection is impossible */ factor = dot_v3v3(axis, norm); if (1.0f - fabsf(factor) < 0.0002f) { copy_v3_v3(out, axis); if (factor > 0) { mul_v3_fl(out, 1000000000.0f); } else { mul_v3_fl(out, -1000000000.0f); } } else { add_v3_v3v3(v2, t_con_center, axis); add_v3_v3v3(v4, v, norm); isect_line_line_v3(t_con_center, v2, v, v4, i1, i2); sub_v3_v3v3(v, i2, v); sub_v3_v3v3(out, i1, t_con_center); /* possible some values become nan when * viewpoint and object are both zero */ if (!isfinite(out[0])) { out[0] = 0.0f; } if (!isfinite(out[1])) { out[1] = 0.0f; } if (!isfinite(out[2])) { out[2] = 0.0f; } } } }
static void do_physical_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, float *total_force) { PartDeflect *pd = eff->pd; RNG *rng = pd->rng; float force[3] = {0, 0, 0}; float temp[3]; float fac; float strength = pd->f_strength; float damp = pd->f_damp; float noise_factor = pd->f_noise; if (noise_factor > 0.0f) { strength += wind_func(rng, noise_factor); if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG)) damp += wind_func(rng, noise_factor); } copy_v3_v3(force, efd->vec_to_point); switch (pd->forcefield) { case PFIELD_WIND: copy_v3_v3(force, efd->nor); mul_v3_fl(force, strength * efd->falloff); break; case PFIELD_FORCE: normalize_v3(force); mul_v3_fl(force, strength * efd->falloff); break; case PFIELD_VORTEX: /* old vortex force */ if (pd->shape == PFIELD_SHAPE_POINT) { cross_v3_v3v3(force, efd->nor, efd->vec_to_point); normalize_v3(force); mul_v3_fl(force, strength * efd->distance * efd->falloff); } else { /* new vortex force */ cross_v3_v3v3(temp, efd->nor2, efd->vec_to_point2); mul_v3_fl(temp, strength * efd->falloff); cross_v3_v3v3(force, efd->nor2, temp); mul_v3_fl(force, strength * efd->falloff); madd_v3_v3fl(temp, point->vel, -point->vel_to_sec); add_v3_v3(force, temp); } break; case PFIELD_MAGNET: if (eff->pd->shape == PFIELD_SHAPE_POINT) /* magnetic field of a moving charge */ cross_v3_v3v3(temp, efd->nor, efd->vec_to_point); else copy_v3_v3(temp, efd->nor); normalize_v3(temp); mul_v3_fl(temp, strength * efd->falloff); cross_v3_v3v3(force, point->vel, temp); mul_v3_fl(force, point->vel_to_sec); break; case PFIELD_HARMONIC: mul_v3_fl(force, -strength * efd->falloff); copy_v3_v3(temp, point->vel); mul_v3_fl(temp, -damp * 2.0f * (float)sqrt(fabs(strength)) * point->vel_to_sec); add_v3_v3(force, temp); break; case PFIELD_CHARGE: mul_v3_fl(force, point->charge * strength * efd->falloff); break; case PFIELD_LENNARDJ: fac = pow((efd->size + point->size) / efd->distance, 6.0); fac = - fac * (1.0f - fac) / efd->distance; /* limit the repulsive term drastically to avoid huge forces */ fac = ((fac>2.0f) ? 2.0f : fac); mul_v3_fl(force, strength * fac); break; case PFIELD_BOID: /* Boid field is handled completely in boids code. */ return; case PFIELD_TURBULENCE: if (pd->flag & PFIELD_GLOBAL_CO) { copy_v3_v3(temp, point->loc); } else { add_v3_v3v3(temp, efd->vec_to_point2, efd->nor2); } force[0] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[0], temp[1], temp[2], 2, 0, 2); force[1] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[1], temp[2], temp[0], 2, 0, 2); force[2] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[2], temp[0], temp[1], 2, 0, 2); mul_v3_fl(force, strength * efd->falloff); break; case PFIELD_DRAG: copy_v3_v3(force, point->vel); fac = normalize_v3(force) * point->vel_to_sec; strength = MIN2(strength, 2.0f); damp = MIN2(damp, 2.0f); mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp)); break; case PFIELD_SMOKEFLOW: zero_v3(force); if (pd->f_source) { float density; if ((density = smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) { float influence = strength * efd->falloff; if (pd->flag & PFIELD_SMOKE_DENSITY) influence *= density; mul_v3_fl(force, influence); /* apply flow */ madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence); } } break; } if (pd->flag & PFIELD_DO_LOCATION) { madd_v3_v3fl(total_force, force, 1.0f/point->vel_to_sec); if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) { madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff); } } if (point->ave) zero_v3(point->ave); if (pd->flag & PFIELD_DO_ROTATION && point->ave && point->rot) { float xvec[3] = {1.0f, 0.0f, 0.0f}; float dave[3]; mul_qt_v3(point->rot, xvec); cross_v3_v3v3(dave, xvec, force); if (pd->f_flow != 0.0f) { madd_v3_v3fl(dave, point->ave, -pd->f_flow * efd->falloff); } add_v3_v3(point->ave, dave); } }
/** * Specialized slerp that uses a sphere defined by each points normal. */ static void interp_slerp_co_no_v3( const float co_a[3], const float no_a[3], const float co_b[3], const float no_b[3], const float no_dir[3], /* caller already knows, avoid normalize */ float fac, float r_co[3]) { /* center of the sphere defined by both normals */ float center[3]; BLI_assert(len_squared_v3v3(no_a, no_b) != 0); /* calculate sphere 'center' */ { /* use point on plane to */ float plane_a[4], plane_b[4], plane_c[4]; float no_mid[3], no_ortho[3]; /* pass this as an arg instead */ #if 0 float no_dir[3]; #endif float v_a_no_ortho[3], v_b_no_ortho[3]; add_v3_v3v3(no_mid, no_a, no_b); normalize_v3(no_mid); #if 0 sub_v3_v3v3(no_dir, co_a, co_b); normalize_v3(no_dir); #endif /* axis of slerp */ cross_v3_v3v3(no_ortho, no_mid, no_dir); normalize_v3(no_ortho); /* create planes */ cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a); cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b); project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho); project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho); plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho); plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho); plane_from_point_normal_v3(plane_c, co_b, no_ortho); /* find the sphere center from 3 planes */ if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) { /* pass */ } else { mid_v3_v3v3(center, co_a, co_b); } } /* calculate the final output 'r_co' */ { float ofs_a[3], ofs_b[3], ofs_slerp[3]; float dist_a, dist_b; sub_v3_v3v3(ofs_a, co_a, center); sub_v3_v3v3(ofs_b, co_b, center); dist_a = normalize_v3(ofs_a); dist_b = normalize_v3(ofs_b); if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) { madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac)); } else { interp_v3_v3v3(r_co, co_a, co_b, fac); } } }
/* axis is using another define!!! */ static bool calc_curve_deform(Scene *scene, Object *par, float co[3], const short axis, CurveDeform *cd, float r_quat[4]) { Curve *cu = par->data; float fac, loc[4], dir[3], new_quat[4], radius; short index; const bool is_neg_axis = (axis > 2); /* to be sure, mostly after file load, also cyclic dependencies */ #ifdef CYCLIC_DEPENDENCY_WORKAROUND if (par->curve_cache == NULL) { BKE_displist_make_curveTypes(scene, par, false); } #endif if (par->curve_cache->path == NULL) { return false; /* happens on append, cyclic dependencies and empty curves */ } /* options */ if (is_neg_axis) { index = axis - 3; if (cu->flag & CU_STRETCH) fac = (-co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]); else fac = -(co[index] - cd->dmax[index]) / (par->curve_cache->path->totdist); } else { index = axis; if (cu->flag & CU_STRETCH) { fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]); } else { if (LIKELY(par->curve_cache->path->totdist > FLT_EPSILON)) { fac = +(co[index] - cd->dmin[index]) / (par->curve_cache->path->totdist); } else { fac = 0.0f; } } } if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */ float quat[4], cent[3]; if (cd->no_rot_axis) { /* set by caller */ /* this is not exactly the same as 2.4x, since the axis is having rotation removed rather than * changing the axis before calculating the tilt but serves much the same purpose */ float dir_flat[3] = {0, 0, 0}, q[4]; copy_v3_v3(dir_flat, dir); dir_flat[cd->no_rot_axis - 1] = 0.0f; normalize_v3(dir); normalize_v3(dir_flat); rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */ mul_qt_qtqt(new_quat, q, new_quat); } /* Logic for 'cent' orientation * * * The way 'co' is copied to 'cent' may seem to have no meaning, but it does. * * Use a curve modifier to stretch a cube out, color each side RGB, positive side light, negative dark. * view with X up (default), from the angle that you can see 3 faces RGB colors (light), anti-clockwise * Notice X,Y,Z Up all have light colors and each ordered CCW. * * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell * * note: moved functions into quat_apply_track/vec_apply_track * */ copy_qt_qt(quat, new_quat); copy_v3_v3(cent, co); /* zero the axis which is not used, * the big block of text above now applies to these 3 lines */ quat_apply_track(quat, axis, (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */ vec_apply_track(cent, axis); cent[index] = 0.0f; /* scale if enabled */ if (cu->flag & CU_PATH_RADIUS) mul_v3_fl(cent, radius); /* local rotation */ normalize_qt(quat); mul_qt_v3(quat, cent); /* translation */ add_v3_v3v3(co, cent, loc); if (r_quat) copy_qt_qt(r_quat, quat); return true; } return false; }
/* only valid for perspective cameras */ bool BKE_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; BKE_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]); plane_from_point_normal_v3(data_cb.plane_tx[i], data_cb.frame_tx[i], data_cb.normal_tx[i]); } /* initialize callback data */ copy_v4_fl(data_cb.dist_vals_sq, 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], sqrtf_signed(data_cb.dist_vals_sq[i])); } if ((!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]))) { return false; } 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; } } }
static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated) { GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; DupliObject *dob; ParticleDupliWeight *dw; ParticleSettings *part; ParticleData *pa; ChildParticle *cpa = NULL; ParticleKey state; ParticleCacheKey *cache; float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4], (*oldobmat)[4]; int a, b, counter, hair = 0; int totpart, totchild, totgroup = 0 /*, pa_num */; int no_draw_flag = PARS_UNEXIST; if (psys == NULL) return; /* simple preventing of too deep nested groups */ if (level > MAX_DUPLI_RECUR) return; part = psys->part; if (part == NULL) return; if (!psys_check_enabled(par, psys)) return; if (G.rendering == 0) no_draw_flag |= PARS_NO_DISP; ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */ totpart = psys->totpart; totchild = psys->totchild; BLI_srandom(31415926 + psys->seed); if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) { ParticleSimulationData sim = {NULL}; sim.scene = scene; sim.ob = par; sim.psys = psys; sim.psmd = psys_get_modifier(par, psys); /* make sure emitter imat is in global coordinates instead of render view coordinates */ invert_m4_m4(par->imat, par->obmat); /* first check for loops (particle system object used as dupli object) */ if (part->ren_as == PART_DRAW_OB) { if (ELEM(part->dup_ob, NULL, par)) return; } else { /*PART_DRAW_GR */ if (part->dup_group == NULL || part->dup_group->gobject.first == NULL) return; for (go = part->dup_group->gobject.first; go; go = go->next) if (go->ob == par) return; } /* if we have a hair particle system, use the path cache */ if (part->type == PART_HAIR) { if (psys->flag & PSYS_HAIR_DONE) hair = (totchild == 0 || psys->childcache) && psys->pathcache; if (!hair) return; /* we use cache, update totchild according to cached data */ totchild = psys->totchildcache; totpart = psys->totcached; } psys_check_group_weights(part); psys->lattice = psys_get_lattice(&sim); /* gather list of objects or single object */ if (part->ren_as == PART_DRAW_GR) { group_handle_recalc_and_update(scene, par, part->dup_group); if (part->draw & PART_DRAW_COUNT_GR) { for (dw = part->dupliweights.first; dw; dw = dw->next) totgroup += dw->count; } else { for (go = part->dup_group->gobject.first; go; go = go->next) totgroup++; } /* we also copy the actual objects to restore afterwards, since * BKE_object_where_is_calc_time will change the object which breaks transform */ oblist = MEM_callocN(totgroup * sizeof(Object *), "dupgroup object list"); obcopylist = MEM_callocN(totgroup * sizeof(Object), "dupgroup copy list"); if (part->draw & PART_DRAW_COUNT_GR && totgroup) { dw = part->dupliweights.first; for (a = 0; a < totgroup; dw = dw->next) { for (b = 0; b < dw->count; b++, a++) { oblist[a] = dw->ob; obcopylist[a] = *dw->ob; } } } else { go = part->dup_group->gobject.first; for (a = 0; a < totgroup; a++, go = go->next) { oblist[a] = go->ob; obcopylist[a] = *go->ob; } } } else { ob = part->dup_ob; obcopy = *ob; } if (totchild == 0 || part->draw & PART_DRAW_PARENT) a = 0; else a = totpart; for (pa = psys->particles, counter = 0; a < totpart + totchild; a++, pa++, counter++) { if (a < totpart) { /* handle parent particle */ if (pa->flag & no_draw_flag) continue; /* pa_num = pa->num; */ /* UNUSED */ pa_time = pa->time; size = pa->size; } else { /* handle child particle */ cpa = &psys->child[a - totpart]; /* pa_num = a; */ /* UNUSED */ pa_time = psys->particles[cpa->parent].time; size = psys_get_child_size(psys, cpa, ctime, NULL); } /* some hair paths might be non-existent so they can't be used for duplication */ if (hair && ((a < totpart && psys->pathcache[a]->steps < 0) || (a >= totpart && psys->childcache[a - totpart]->steps < 0))) { continue; } if (part->ren_as == PART_DRAW_GR) { /* prevent divide by zero below [#28336] */ if (totgroup == 0) continue; /* for groups, pick the object based on settings */ if (part->draw & PART_DRAW_RAND_GR) b = BLI_rand() % totgroup; else b = a % totgroup; ob = oblist[b]; obmat = oblist[b]->obmat; oldobmat = obcopylist[b].obmat; } else { obmat = ob->obmat; oldobmat = obcopy.obmat; } if (hair) { /* hair we handle separate and compute transform based on hair keys */ if (a < totpart) { cache = psys->pathcache[a]; psys_get_dupli_path_transform(&sim, pa, NULL, cache, pamat, &scale); } else { cache = psys->childcache[a - totpart]; psys_get_dupli_path_transform(&sim, NULL, cpa, cache, pamat, &scale); } copy_v3_v3(pamat[3], cache->co); pamat[3][3] = 1.0f; } else { /* first key */ state.time = ctime; if (psys_get_particle_state(&sim, a, &state, 0) == 0) { continue; } else { float tquat[4]; normalize_qt_qt(tquat, state.rot); quat_to_mat4(pamat, tquat); copy_v3_v3(pamat[3], state.co); pamat[3][3] = 1.0f; } } if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) { for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) { copy_m4_m4(tmat, oblist[b]->obmat); /* apply particle scale */ mul_mat3_m4_fl(tmat, size * scale); mul_v3_fl(tmat[3], size * scale); /* group dupli offset, should apply after everything else */ if (!is_zero_v3(part->dup_group->dupli_ofs)) sub_v3_v3v3(tmat[3], tmat[3], part->dup_group->dupli_ofs); /* individual particle transform */ mult_m4_m4m4(tmat, pamat, tmat); if (par_space_mat) mult_m4_m4m4(mat, par_space_mat, tmat); else copy_m4_m4(mat, tmat); dob = new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, obcopylist[b].obmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } else { /* to give ipos in object correct offset */ BKE_object_where_is_calc_time(scene, ob, ctime - pa_time); copy_v3_v3(vec, obmat[3]); obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f; /* particle rotation uses x-axis as the aligned axis, so pre-rotate the object accordingly */ if ((part->draw & PART_DRAW_ROTATE_OB) == 0) { float xvec[3], q[4]; xvec[0] = -1.f; xvec[1] = xvec[2] = 0; vec_to_quat(q, xvec, ob->trackflag, ob->upflag); quat_to_mat4(obmat, q); obmat[3][3] = 1.0f; } /* Normal particles and cached hair live in global space so we need to * remove the real emitter's transformation before 2nd order duplication. */ if (par_space_mat && GS(id->name) != ID_GR) mult_m4_m4m4(mat, psys->imat, pamat); else copy_m4_m4(mat, pamat); mult_m4_m4m4(tmat, mat, obmat); mul_mat3_m4_fl(tmat, size * scale); if (par_space_mat) mult_m4_m4m4(mat, par_space_mat, tmat); else copy_m4_m4(mat, tmat); if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); dob = new_dupli_object(lb, ob, mat, ob->lay, counter, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, oldobmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } } /* restore objects since they were changed in BKE_object_where_is_calc_time */ if (part->ren_as == PART_DRAW_GR) { for (a = 0; a < totgroup; a++) *(oblist[a]) = obcopylist[a]; } else *ob = obcopy; } /* clean up */ if (oblist) MEM_freeN(oblist); if (obcopylist) MEM_freeN(obcopylist); if (psys->lattice) { end_latt_deform(psys->lattice); psys->lattice = NULL; } }
/** * \param dm Mesh to calculate normals for. * \param face_nors Precalculated face normals. * \param r_vert_nors Return vert normals. */ static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_vert_nors)[3]) { int i, numVerts, numEdges, numFaces; MPoly *mpoly, *mp; MLoop *mloop, *ml; MEdge *medge, *ed; MVert *mvert, *mv; numVerts = dm->getNumVerts(dm); numEdges = dm->getNumEdges(dm); numFaces = dm->getNumPolys(dm); mpoly = dm->getPolyArray(dm); medge = dm->getEdgeArray(dm); mvert = dm->getVertArray(dm); mloop = dm->getLoopArray(dm); /* we don't want to overwrite any referenced layers */ /* Doesn't work here! */ #if 0 mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts); cddm->mvert = mv; #endif mv = mvert; mp = mpoly; { EdgeFaceRef *edge_ref_array = MEM_callocN(sizeof(EdgeFaceRef) * (size_t)numEdges, "Edge Connectivity"); EdgeFaceRef *edge_ref; float edge_normal[3]; /* This loop adds an edge hash if its not there, and adds the face index */ for (i = 0; i < numFaces; i++, mp++) { int j; ml = mloop + mp->loopstart; for (j = 0; j < mp->totloop; j++, ml++) { /* --- add edge ref to face --- */ edge_ref = &edge_ref_array[ml->e]; if (!edgeref_is_init(edge_ref)) { edge_ref->f1 = i; edge_ref->f2 = -1; } else if ((edge_ref->f1 != -1) && (edge_ref->f2 == -1)) { edge_ref->f2 = i; } else { /* 3+ faces using an edge, we can't handle this usefully */ edge_ref->f1 = edge_ref->f2 = -1; #ifdef USE_NONMANIFOLD_WORKAROUND medge[ml->e].flag |= ME_EDGE_TMP_TAG; #endif } /* --- done --- */ } } for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) { /* Get the edge vert indices, and edge value (the face indices that use it) */ if (edgeref_is_init(edge_ref) && (edge_ref->f1 != -1)) { if (edge_ref->f2 != -1) { /* We have 2 faces using this edge, calculate the edges normal * using the angle between the 2 faces as a weighting */ #if 0 add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]); normalize_v3(edge_normal); mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2])); #else mid_v3_v3v3_angle_weighted(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]); #endif } else { /* only one face attached to that edge */ /* an edge without another attached- the weight on this is undefined */ copy_v3_v3(edge_normal, face_nors[edge_ref->f1]); } add_v3_v3(r_vert_nors[ed->v1], edge_normal); add_v3_v3(r_vert_nors[ed->v2], edge_normal); } } MEM_freeN(edge_ref_array); } /* normalize vertex normals and assign */ for (i = 0; i < numVerts; i++, mv++) { if (normalize_v3(r_vert_nors[i]) == 0.0f) { normal_short_to_float_v3(r_vert_nors[i], mv->no); } } }
static DerivedMesh *arrayModifier_doArray( ArrayModifierData *amd, Scene *scene, Object *ob, DerivedMesh *dm, ModifierApplyFlag flag) { const float eps = 1e-6f; const MVert *src_mvert; MVert *mv, *mv_prev, *result_dm_verts; MEdge *me; MLoop *ml; MPoly *mp; int i, j, c, count; float length = amd->length; /* offset matrix */ float offset[4][4]; float scale[3]; bool offset_has_scale; float current_offset[4][4]; float final_offset[4][4]; int *full_doubles_map = NULL; int tot_doubles; const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0; const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge; const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob); /* allow pole vertices to be used by many faces */ const bool with_follow = use_offset_ob; int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0; int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0; int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0; int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys; int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts; DerivedMesh *result, *start_cap_dm = NULL, *end_cap_dm = NULL; chunk_nverts = dm->getNumVerts(dm); chunk_nedges = dm->getNumEdges(dm); chunk_nloops = dm->getNumLoops(dm); chunk_npolys = dm->getNumPolys(dm); count = amd->count; if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) { start_cap_dm = get_dm_for_modifier(amd->start_cap, flag); if (start_cap_dm) { start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm); start_cap_nedges = start_cap_dm->getNumEdges(start_cap_dm); start_cap_nloops = start_cap_dm->getNumLoops(start_cap_dm); start_cap_npolys = start_cap_dm->getNumPolys(start_cap_dm); } } if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) { end_cap_dm = get_dm_for_modifier(amd->end_cap, flag); if (end_cap_dm) { end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm); end_cap_nedges = end_cap_dm->getNumEdges(end_cap_dm); end_cap_nloops = end_cap_dm->getNumLoops(end_cap_dm); end_cap_npolys = end_cap_dm->getNumPolys(end_cap_dm); } } /* Build up offset array, cumulating all settings options */ unit_m4(offset); src_mvert = dm->getVertArray(dm); if (amd->offset_type & MOD_ARR_OFF_CONST) add_v3_v3v3(offset[3], offset[3], amd->offset); if (amd->offset_type & MOD_ARR_OFF_RELATIVE) { for (j = 0; j < 3; j++) offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, chunk_nverts, j); } if (use_offset_ob) { float obinv[4][4]; float result_mat[4][4]; if (ob) invert_m4_m4(obinv, ob->obmat); else unit_m4(obinv); mul_m4_series(result_mat, offset, obinv, amd->offset_ob->obmat); copy_m4_m4(offset, result_mat); } /* Check if there is some scaling. If scaling, then we will not translate mapping */ mat4_to_size(scale, offset); offset_has_scale = !is_one_v3(scale); if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) { Curve *cu = amd->curve_ob->data; if (cu) { #ifdef CYCLIC_DEPENDENCY_WORKAROUND if (amd->curve_ob->curve_cache == NULL) { BKE_displist_make_curveTypes(scene, amd->curve_ob, false); } #endif if (amd->curve_ob->curve_cache && amd->curve_ob->curve_cache->path) { float scale = mat4_to_scale(amd->curve_ob->obmat); length = scale * amd->curve_ob->curve_cache->path->totdist; } } } /* calculate the maximum number of copies which will fit within the * prescribed length */ if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) { float dist = len_v3(offset[3]); if (dist > eps) { /* this gives length = first copy start to last copy end * add a tiny offset for floating point rounding errors */ count = (length + eps) / dist + 1; } else { /* if the offset has no translation, just make one copy */ count = 1; } } if (count < 1) count = 1; /* The number of verts, edges, loops, polys, before eventually merging doubles */ result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts; result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges; result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops; result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys; /* Initialize a result dm */ result = CDDM_from_template(dm, result_nverts, result_nedges, 0, result_nloops, result_npolys); result_dm_verts = CDDM_get_verts(result); if (use_merge) { /* Will need full_doubles_map for handling merge */ full_doubles_map = MEM_mallocN(sizeof(int) * result_nverts, "mod array doubles map"); copy_vn_i(full_doubles_map, result_nverts, -1); } /* copy customdata to original geometry */ DM_copy_vert_data(dm, result, 0, 0, chunk_nverts); DM_copy_edge_data(dm, result, 0, 0, chunk_nedges); DM_copy_loop_data(dm, result, 0, 0, chunk_nloops); DM_copy_poly_data(dm, result, 0, 0, chunk_npolys); /* subsurf for eg wont have mesh data in the * now add mvert/medge/mface layers */ if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) { dm->copyVertArray(dm, result_dm_verts); } if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) { dm->copyEdgeArray(dm, CDDM_get_edges(result)); } if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) { dm->copyLoopArray(dm, CDDM_get_loops(result)); dm->copyPolyArray(dm, CDDM_get_polys(result)); } /* Remember first chunk, in case of cap merge */ first_chunk_start = 0; first_chunk_nverts = chunk_nverts; unit_m4(current_offset); for (c = 1; c < count; c++) { /* copy customdata to new geometry */ DM_copy_vert_data(result, result, 0, c * chunk_nverts, chunk_nverts); DM_copy_edge_data(result, result, 0, c * chunk_nedges, chunk_nedges); DM_copy_loop_data(result, result, 0, c * chunk_nloops, chunk_nloops); DM_copy_poly_data(result, result, 0, c * chunk_npolys, chunk_npolys); mv_prev = result_dm_verts; mv = mv_prev + c * chunk_nverts; /* recalculate cumulative offset here */ mul_m4_m4m4(current_offset, current_offset, offset); /* apply offset to all new verts */ for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) { mul_m4_v3(current_offset, mv->co); /* We have to correct normals too, if we do not tag them as dirty! */ if (!use_recalc_normals) { float no[3]; normal_short_to_float_v3(no, mv->no); mul_mat3_m4_v3(current_offset, no); normalize_v3(no); normal_float_to_short_v3(mv->no, no); } } /* adjust edge vertex indices */ me = CDDM_get_edges(result) + c * chunk_nedges; for (i = 0; i < chunk_nedges; i++, me++) { me->v1 += c * chunk_nverts; me->v2 += c * chunk_nverts; } mp = CDDM_get_polys(result) + c * chunk_npolys; for (i = 0; i < chunk_npolys; i++, mp++) { mp->loopstart += c * chunk_nloops; } /* adjust loop vertex and edge indices */ ml = CDDM_get_loops(result) + c * chunk_nloops; for (i = 0; i < chunk_nloops; i++, ml++) { ml->v += c * chunk_nverts; ml->e += c * chunk_nedges; } /* Handle merge between chunk n and n-1 */ if (use_merge && (c >= 1)) { if (!offset_has_scale && (c >= 2)) { /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1 * ... that is except if scaling makes the distance grow */ int k; int this_chunk_index = c * chunk_nverts; int prev_chunk_index = (c - 1) * chunk_nverts; for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) { int target = full_doubles_map[prev_chunk_index]; if (target != -1) { target += chunk_nverts; /* translate mapping */ if (full_doubles_map[target] != -1) { if (with_follow) { target = full_doubles_map[target]; } else { /* The rule here is to not follow mapping to chunk N-2, which could be too far * so if target vertex was itself mapped, then this vertex is not mapped */ target = -1; } } } full_doubles_map[this_chunk_index] = target; } } else { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, (c - 1) * chunk_nverts, chunk_nverts, c * chunk_nverts, chunk_nverts, amd->merge_dist, with_follow); } } } last_chunk_start = (count - 1) * chunk_nverts; last_chunk_nverts = chunk_nverts; copy_m4_m4(final_offset, current_offset); if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) { /* Merge first and last copies */ dm_mvert_map_doubles( full_doubles_map, result_dm_verts, last_chunk_start, last_chunk_nverts, first_chunk_start, first_chunk_nverts, amd->merge_dist, with_follow); } /* start capping */ if (start_cap_dm) { float start_offset[4][4]; int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts; invert_m4_m4(start_offset, offset); dm_merge_transform( result, start_cap_dm, start_offset, result_nverts - start_cap_nverts - end_cap_nverts, result_nedges - start_cap_nedges - end_cap_nedges, result_nloops - start_cap_nloops - end_cap_nloops, result_npolys - start_cap_npolys - end_cap_npolys, start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys); /* Identify doubles with first chunk */ if (use_merge) { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, first_chunk_start, first_chunk_nverts, start_cap_start, start_cap_nverts, amd->merge_dist, false); } } if (end_cap_dm) { float end_offset[4][4]; int end_cap_start = result_nverts - end_cap_nverts; mul_m4_m4m4(end_offset, current_offset, offset); dm_merge_transform( result, end_cap_dm, end_offset, result_nverts - end_cap_nverts, result_nedges - end_cap_nedges, result_nloops - end_cap_nloops, result_npolys - end_cap_npolys, end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys); /* Identify doubles with last chunk */ if (use_merge) { dm_mvert_map_doubles( full_doubles_map, result_dm_verts, last_chunk_start, last_chunk_nverts, end_cap_start, end_cap_nverts, amd->merge_dist, false); } } /* done capping */ /* Handle merging */ tot_doubles = 0; if (use_merge) { for (i = 0; i < result_nverts; i++) { if (full_doubles_map[i] != -1) { if (i == full_doubles_map[i]) { full_doubles_map[i] = -1; } else { tot_doubles++; } } } if (tot_doubles > 0) { result = CDDM_merge_verts(result, full_doubles_map, tot_doubles, CDDM_MERGE_VERTS_DUMP_IF_EQUAL); } MEM_freeN(full_doubles_map); } /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new dm! * TODO: we may need to set other dirty flags as well? */ if (use_recalc_normals) { result->dirty |= DM_DIRTY_NORMALS; } return result; }
/* * Function adapted from David Eberly's distance tools (LGPL) * http://www.geometrictools.com/LibFoundation/Distance/Distance.html */ float nearest_point_in_tri_surface_squared( const float v0[3], const float v1[3], const float v2[3], const float p[3], int *v, int *e, float nearest[3]) { float diff[3]; float e0[3]; float e1[3]; float A00; float A01; float A11; float B0; float B1; float C; float Det; float S; float T; float sqrDist; int lv = -1, le = -1; sub_v3_v3v3(diff, v0, p); sub_v3_v3v3(e0, v1, v0); sub_v3_v3v3(e1, v2, v0); A00 = dot_v3v3(e0, e0); A01 = dot_v3v3(e0, e1); A11 = dot_v3v3(e1, e1); B0 = dot_v3v3(diff, e0); B1 = dot_v3v3(diff, e1); C = dot_v3v3(diff, diff); Det = fabsf(A00 * A11 - A01 * A01); S = A01 * B1 - A11 * B0; T = A01 * B0 - A00 * B1; if (S + T <= Det) { if (S < 0.0f) { if (T < 0.0f) { /* Region 4 */ if (B0 < 0.0f) { T = 0.0f; if (-B0 >= A00) { S = 1.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if (fabsf(A00) > FLT_EPSILON) S = -B0 / A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } else { S = 0.0f; if (B1 >= 0.0f) { T = 0.0f; sqrDist = C; lv = 0; } else if (-B1 >= A11) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if (fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0f; sqrDist = B1 * T + C; le = 1; } } } else { /* Region 3 */ S = 0.0f; if (B1 >= 0.0f) { T = 0.0f; sqrDist = C; lv = 0; } else if (-B1 >= A11) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if (fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0; sqrDist = B1 * T + C; le = 1; } } } else if (T < 0.0f) { /* Region 5 */ T = 0.0f; if (B0 >= 0.0f) { S = 0.0f; sqrDist = C; lv = 0; } else if (-B0 >= A00) { S = 1.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if (fabsf(A00) > FLT_EPSILON) S = -B0 / A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } else { /* Region 0 */ /* Minimum at interior lv */ float invDet; if (fabsf(Det) > FLT_EPSILON) invDet = 1.0f / Det; else invDet = 0.0f; S *= invDet; T *= invDet; sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + T * (A01 * S + A11 * T + 2.0f * B1) + C; } } else { float tmp0, tmp1, numer, denom; if (S < 0.0f) { /* Region 2 */ tmp0 = A01 + B0; tmp1 = A11 + B1; if (tmp1 > tmp0) { numer = tmp1 - tmp0; denom = A00 - 2.0f * A01 + A11; if (numer >= denom) { S = 1.0f; T = 0.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if (fabsf(denom) > FLT_EPSILON) S = numer / denom; else S = 0.0f; T = 1.0f - S; sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + T * (A01 * S + A11 * T + 2.0f * B1) + C; le = 2; } } else { S = 0.0f; if (tmp1 <= 0.0f) { T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else if (B1 >= 0.0f) { T = 0.0f; sqrDist = C; lv = 0; } else { if (fabsf(A11) > FLT_EPSILON) T = -B1 / A11; else T = 0.0f; sqrDist = B1 * T + C; le = 1; } } } else if (T < 0.0f) { /* Region 6 */ tmp0 = A01 + B1; tmp1 = A00 + B0; if (tmp1 > tmp0) { numer = tmp1 - tmp0; denom = A00 - 2.0f * A01 + A11; if (numer >= denom) { T = 1.0f; S = 0.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { if (fabsf(denom) > FLT_EPSILON) T = numer / denom; else T = 0.0f; S = 1.0f - T; sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + T * (A01 * S + A11 * T + 2.0f * B1) + C; le = 2; } } else { T = 0.0f; if (tmp1 <= 0.0f) { S = 1.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else if (B0 >= 0.0f) { S = 0.0f; sqrDist = C; lv = 0; } else { if (fabsf(A00) > FLT_EPSILON) S = -B0 / A00; else S = 0.0f; sqrDist = B0 * S + C; le = 0; } } } else { /* Region 1 */ numer = A11 + B1 - A01 - B0; if (numer <= 0.0f) { S = 0.0f; T = 1.0f; sqrDist = A11 + 2.0f * B1 + C; lv = 2; } else { denom = A00 - 2.0f * A01 + A11; if (numer >= denom) { S = 1.0f; T = 0.0f; sqrDist = A00 + 2.0f * B0 + C; lv = 1; } else { if (fabsf(denom) > FLT_EPSILON) S = numer / denom; else S = 0.0f; T = 1.0f - S; sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) + T * (A01 * S + A11 * T + 2.0f * B1) + C; le = 2; } } } } /* Account for numerical round-off error */ if (sqrDist < FLT_EPSILON) sqrDist = 0.0f; { float w[3], x[3], y[3], z[3]; copy_v3_v3(w, v0); copy_v3_v3(x, e0); mul_v3_fl(x, S); copy_v3_v3(y, e1); mul_v3_fl(y, T); add_v3_v3v3(z, w, x); add_v3_v3v3(z, z, y); //sub_v3_v3v3(d, p, z); copy_v3_v3(nearest, z); //d = p - ( v0 + S * e0 + T * e1 ); } *v = lv; *e = le; return sqrDist; }
static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *args) { VectorObject *ray, *ray_off, *vec1, *vec2, *vec3; float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3]; float det, inv_det, u, v, t; int clip = 1; if (!PyArg_ParseTuple(args, "O!O!O!O!O!|i:intersect_ray_tri", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off, &clip)) { return NULL; } if (vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) { PyErr_SetString(PyExc_ValueError, "only 3D vectors for all parameters"); return NULL; } if (BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1 || BaseMath_ReadCallback(vec3) == -1 || BaseMath_ReadCallback(ray) == -1 || BaseMath_ReadCallback(ray_off) == -1) { return NULL; } copy_v3_v3(v1, vec1->vec); copy_v3_v3(v2, vec2->vec); copy_v3_v3(v3, vec3->vec); copy_v3_v3(dir, ray->vec); normalize_v3(dir); copy_v3_v3(orig, ray_off->vec); /* find vectors for two edges sharing v1 */ sub_v3_v3v3(e1, v2, v1); sub_v3_v3v3(e2, v3, v1); /* begin calculating determinant - also used to calculated U parameter */ cross_v3_v3v3(pvec, dir, e2); /* if determinant is near zero, ray lies in plane of triangle */ det = dot_v3v3(e1, pvec); if (det > -0.000001f && det < 0.000001f) { Py_RETURN_NONE; } inv_det = 1.0f / det; /* calculate distance from v1 to ray origin */ sub_v3_v3v3(tvec, orig, v1); /* calculate U parameter and test bounds */ u = dot_v3v3(tvec, pvec) * inv_det; if (clip && (u < 0.0f || u > 1.0f)) { Py_RETURN_NONE; } /* prepare to test the V parameter */ cross_v3_v3v3(qvec, tvec, e1); /* calculate V parameter and test bounds */ v = dot_v3v3(dir, qvec) * inv_det; if (clip && (v < 0.0f || u + v > 1.0f)) { Py_RETURN_NONE; } /* calculate t, ray intersects triangle */ t = dot_v3v3(e2, qvec) * inv_det; mul_v3_fl(dir, t); add_v3_v3v3(pvec, orig, dir); return Vector_CreatePyObject(pvec, 3, Py_NEW, NULL); }
static void testRadialSymmetry(BGraph *graph, BNode *root_node, RadialArc *ring, int total, float axis[3], float limit, int group) { int symmetric = 1; int i; /* sort ring by angle */ for (i = 0; i < total - 1; i++) { float minAngle = FLT_MAX; int minIndex = -1; int j; for (j = i + 1; j < total; j++) { float angle = dot_v3v3(ring[i].n, ring[j].n); /* map negative values to 1..2 */ if (angle < 0) { angle = 1 - angle; } if (angle < minAngle) { minIndex = j; minAngle = angle; } } /* swap if needed */ if (minIndex != i + 1) { RadialArc tmp; tmp = ring[i + 1]; ring[i + 1] = ring[minIndex]; ring[minIndex] = tmp; } } for (i = 0; i < total && symmetric; i++) { BNode *node1, *node2; float tangent[3]; float normal[3]; float p[3]; int j = (i + 1) % total; /* next arc in the circular list */ add_v3_v3v3(tangent, ring[i].n, ring[j].n); cross_v3_v3v3(normal, tangent, axis); node1 = BLI_otherNode(ring[i].arc, root_node); node2 = BLI_otherNode(ring[j].arc, root_node); copy_v3_v3(p, node2->p); BLI_mirrorAlongAxis(p, root_node->p, normal); /* check if it's within limit before continuing */ if (len_v3v3(node1->p, p) > limit) { symmetric = 0; } } if (symmetric) { /* mark node as symmetric physically */ copy_v3_v3(root_node->symmetry_axis, axis); root_node->symmetry_flag |= SYM_PHYSICAL; root_node->symmetry_flag |= SYM_RADIAL; /* FLAG SYMMETRY GROUP */ for (i = 0; i < total; i++) { ring[i].arc->symmetry_group = group; ring[i].arc->symmetry_flag = SYM_SIDE_RADIAL + i; } if (graph->radial_symmetry) { graph->radial_symmetry(root_node, ring, total); } } }
static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa) { BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule; KDTreeNearest *ptn = NULL; ParticleTarget *pt; BoidParticle *bpa = pa->boid; ColliderCache *coll; float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f}; float co1[3], vel1[3], co2[3], vel2[3]; float len, t, inp, t_min = 2.0f; int n, neighbors = 0, nearest = 0; int ret = 0; //check deflector objects first if(acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) { ParticleCollision col; BVHTreeRayHit hit; float radius = val->personal_space * pa->size, ray_dir[3]; copy_v3_v3(col.co1, pa->prev_state.co); add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel); sub_v3_v3v3(ray_dir, col.co2, col.co1); mul_v3_fl(ray_dir, acbr->look_ahead); col.f = 0.0f; hit.index = -1; hit.dist = col.original_ray_length = len_v3(ray_dir); /* find out closest deflector object */ for(coll = bbd->sim->colliders->first; coll; coll=coll->next) { /* don't check with current ground object */ if(coll->ob == bpa->ground) continue; col.current = coll->ob; col.md = coll->collmd; if(col.md && col.md->bvhtree) BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col); } /* then avoid that object */ if(hit.index>=0) { t = hit.dist/col.original_ray_length; /* avoid head-on collision */ if(dot_v3v3(col.pce.nor, pa->prev_state.ave) < -0.99f) { /* don't know why, but uneven range [0.0,1.0] */ /* works much better than even [-1.0,1.0] */ bbd->wanted_co[0] = BLI_frand(); bbd->wanted_co[1] = BLI_frand(); bbd->wanted_co[2] = BLI_frand(); } else { copy_v3_v3(bbd->wanted_co, col.pce.nor); } mul_v3_fl(bbd->wanted_co, (1.0f - t) * val->personal_space * pa->size); bbd->wanted_speed = sqrtf(t) * len_v3(pa->prev_state.vel); bbd->wanted_speed = MAX2(bbd->wanted_speed, val->min_speed); return 1; } } //check boids in own system if(acbr->options & BRULE_ACOLL_WITH_BOIDS) { neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, acbr->look_ahead * len_v3(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); if(neighbors > 1) for(n=1; n<neighbors; n++) { copy_v3_v3(co1, pa->prev_state.co); copy_v3_v3(vel1, pa->prev_state.vel); copy_v3_v3(co2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.co); copy_v3_v3(vel2, (bbd->sim->psys->particles + ptn[n].index)->prev_state.vel); sub_v3_v3v3(loc, co1, co2); sub_v3_v3v3(vec, vel1, vel2); inp = dot_v3v3(vec,vec); /* velocities not parallel */ if(inp != 0.0f) { t = -dot_v3v3(loc, vec)/inp; /* cpa is not too far in the future so investigate further */ if(t > 0.0f && t < t_min) { madd_v3_v3fl(co1, vel1, t); madd_v3_v3fl(co2, vel2, t); sub_v3_v3v3(vec, co2, co1); len = normalize_v3(vec); /* distance of cpa is close enough */ if(len < 2.0f * val->personal_space * pa->size) { t_min = t; mul_v3_fl(vec, len_v3(vel1)); mul_v3_fl(vec, (2.0f - t)/2.0f); sub_v3_v3v3(bbd->wanted_co, vel1, vec); bbd->wanted_speed = len_v3(bbd->wanted_co); ret = 1; } } } } } if(ptn){ MEM_freeN(ptn); ptn=NULL; } /* check boids in other systems */ for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) { ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt); if(epsys) { neighbors = BLI_kdtree_range_search(epsys->tree, acbr->look_ahead * len_v3(pa->prev_state.vel), pa->prev_state.co, pa->prev_state.ave, &ptn); if(neighbors > 0) for(n=0; n<neighbors; n++) { copy_v3_v3(co1, pa->prev_state.co); copy_v3_v3(vel1, pa->prev_state.vel); copy_v3_v3(co2, (epsys->particles + ptn[n].index)->prev_state.co); copy_v3_v3(vel2, (epsys->particles + ptn[n].index)->prev_state.vel); sub_v3_v3v3(loc, co1, co2); sub_v3_v3v3(vec, vel1, vel2); inp = dot_v3v3(vec,vec); /* velocities not parallel */ if(inp != 0.0f) { t = -dot_v3v3(loc, vec)/inp; /* cpa is not too far in the future so investigate further */ if(t > 0.0f && t < t_min) { madd_v3_v3fl(co1, vel1, t); madd_v3_v3fl(co2, vel2, t); sub_v3_v3v3(vec, co2, co1); len = normalize_v3(vec); /* distance of cpa is close enough */ if(len < 2.0f * val->personal_space * pa->size) { t_min = t; mul_v3_fl(vec, len_v3(vel1)); mul_v3_fl(vec, (2.0f - t)/2.0f); sub_v3_v3v3(bbd->wanted_co, vel1, vec); bbd->wanted_speed = len_v3(bbd->wanted_co); ret = 1; } } } } if(ptn){ MEM_freeN(ptn); ptn=NULL; } } } if(ptn && nearest==0) MEM_freeN(ptn); return ret; }