/* 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_length(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 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 * sqrtf(fabsf(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); } }