static void rna_Object_ray_cast( Object *ob, ReportList *reports, float origin[3], float direction[3], float distance, int *r_success, float r_location[3], float r_normal[3], int *r_index) { bool success = false; if (ob->derivedFinal == NULL) { BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for ray casting", ob->id.name + 2); return; } /* Test BoundBox first (efficiency) */ BoundBox *bb = BKE_object_boundbox_get(ob); float distmin; if (!bb || (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, NULL) && distmin <= distance)) { BVHTreeFromMesh treeData = {NULL}; /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */ bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6); /* may fail if the mesh has no faces, in that case the ray-cast misses */ if (treeData.tree != NULL) { BVHTreeRayHit hit; hit.index = -1; hit.dist = distance; normalize_v3(direction); if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) { if (hit.dist <= distance) { *r_success = success = true; copy_v3_v3(r_location, hit.co); copy_v3_v3(r_normal, hit.no); *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]); } } free_bvhtree_from_mesh(&treeData); } } if (success == false) { *r_success = false; zero_v3(r_location); zero_v3(r_normal); *r_index = -1; } }
/* Create new physics sim collision shape for object and store it, * or remove the existing one first and replace... */ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild) { RigidBodyOb *rbo = ob->rigidbody_object; rbCollisionShape *new_shape = NULL; BoundBox *bb = NULL; float size[3] = {1.0f, 1.0f, 1.0f}; float radius = 1.0f; float height = 1.0f; float capsule_height; float hull_margin = 0.0f; bool can_embed = true; bool has_volume; /* sanity check */ if (rbo == NULL) return; /* don't create a new shape if we already have one and don't want to rebuild it */ if (rbo->physics_shape && !rebuild) return; /* if automatically determining dimensions, use the Object's boundbox * - assume that all quadrics are standing upright on local z-axis * - assume even distribution of mass around the Object's pivot * (i.e. Object pivot is centralized in boundbox) */ // XXX: all dimensions are auto-determined now... later can add stored settings for this /* get object dimensions without scaling */ bb = BKE_object_boundbox_get(ob); if (bb) { size[0] = (bb->vec[4][0] - bb->vec[0][0]); size[1] = (bb->vec[2][1] - bb->vec[0][1]); size[2] = (bb->vec[1][2] - bb->vec[0][2]); } mul_v3_fl(size, 0.5f); if (ELEM3(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { /* take radius as largest x/y dimension, and height as z-dimension */ radius = MAX2(size[0], size[1]); height = size[2]; } else if (rbo->shape == RB_SHAPE_SPHERE) { /* take radius to the the largest dimension to try and encompass everything */ radius = MAX3(size[0], size[1], size[2]); } /* create new shape */ switch (rbo->shape) { case RB_SHAPE_BOX: new_shape = RB_shape_new_box(size[0], size[1], size[2]); break; case RB_SHAPE_SPHERE: new_shape = RB_shape_new_sphere(radius); break; case RB_SHAPE_CAPSULE: capsule_height = (height - radius) * 2.0f; new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f); break; case RB_SHAPE_CYLINDER: new_shape = RB_shape_new_cylinder(radius, height); break; case RB_SHAPE_CONE: new_shape = RB_shape_new_cone(radius, height * 2.0f); break; case RB_SHAPE_CONVEXH: /* try to emged collision margin */ has_volume = (MIN3(size[0], size[1], size[2]) > 0.0f); if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && has_volume) hull_margin = 0.04f; new_shape = rigidbody_get_shape_convexhull_from_mesh(ob, hull_margin, &can_embed); if (!(rbo->flag & RBO_FLAG_USE_MARGIN)) rbo->margin = (can_embed && has_volume) ? 0.04f : 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */ break; case RB_SHAPE_TRIMESH: new_shape = rigidbody_get_shape_trimesh_from_mesh(ob); break; } /* assign new collision shape if creation was successful */ if (new_shape) { if (rbo->physics_shape) RB_shape_delete(rbo->physics_shape); rbo->physics_shape = new_shape; RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo)); } /* use box shape if we can't fall back to old shape */ else if (rbo->physics_shape == NULL) { rbo->shape = RB_SHAPE_BOX; rigidbody_validate_sim_shape(ob, true); } }
static void rna_Object_ray_cast(Object *ob, bContext *C, ReportList *reports, float origin[3], float direction[3], float distance, PointerRNA *rnaptr_depsgraph, bool *r_success, float r_location[3], float r_normal[3], int *r_index) { bool success = false; if (ob->runtime.mesh_eval == NULL && (ob = eval_object_ensure(ob, C, reports, rnaptr_depsgraph)) == NULL) { return; } /* Test BoundBox first (efficiency) */ BoundBox *bb = BKE_object_boundbox_get(ob); float distmin; normalize_v3( direction); /* Needed for valid distance check from isect_ray_aabb_v3_simple() call. */ if (!bb || (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, NULL) && distmin <= distance)) { BVHTreeFromMesh treeData = {NULL}; /* No need to managing allocation or freeing of the BVH data. * This is generated and freed as needed. */ BKE_bvhtree_from_mesh_get(&treeData, ob->runtime.mesh_eval, BVHTREE_FROM_LOOPTRI, 4); /* may fail if the mesh has no faces, in that case the ray-cast misses */ if (treeData.tree != NULL) { BVHTreeRayHit hit; hit.index = -1; hit.dist = distance; if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) { if (hit.dist <= distance) { *r_success = success = true; copy_v3_v3(r_location, hit.co); copy_v3_v3(r_normal, hit.no); *r_index = mesh_looptri_to_poly_index(ob->runtime.mesh_eval, &treeData.looptri[hit.index]); } } free_bvhtree_from_mesh(&treeData); } } if (success == false) { *r_success = false; zero_v3(r_location); zero_v3(r_normal); *r_index = -1; } }
static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo) { float loc[3]; float rot[4]; float scale[3]; /* only update if rigid body exists */ if (rbo->physics_object == NULL) return; if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) { DerivedMesh *dm = ob->derivedDeform; if (dm) { MVert *mvert = dm->getVertArray(dm); int totvert = dm->getNumVerts(dm); BoundBox *bb = BKE_object_boundbox_get(ob); RB_shape_trimesh_update(rbo->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]); } } mat4_decompose(loc, rot, scale, ob->obmat); /* update scale for all objects */ RB_body_set_scale(rbo->physics_object, scale); /* compensate for embedded convex hull collision margin */ if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH) RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2])); /* make transformed objects temporarily kinmatic so that they can be moved by the user during simulation */ if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) { RB_body_set_kinematic_state(rbo->physics_object, TRUE); RB_body_set_mass(rbo->physics_object, 0.0f); } /* update rigid body location and rotation for kinematic bodies */ if (rbo->flag & RBO_FLAG_KINEMATIC || (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) { RB_body_activate(rbo->physics_object); RB_body_set_loc_rot(rbo->physics_object, loc, rot); } /* update influence of effectors - but don't do it on an effector */ /* only dynamic bodies need effector update */ else if (rbo->type == RBO_TYPE_ACTIVE && ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) { EffectorWeights *effector_weights = rbw->effector_weights; EffectedPoint epoint; ListBase *effectors; /* get effectors present in the group specified by effector_weights */ effectors = pdInitEffectors(scene, ob, NULL, effector_weights); if (effectors) { float eff_force[3] = {0.0f, 0.0f, 0.0f}; float eff_loc[3], eff_vel[3]; /* create dummy 'point' which represents last known position of object as result of sim */ // XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals? RB_body_get_position(rbo->physics_object, eff_loc); RB_body_get_linear_velocity(rbo->physics_object, eff_vel); pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint); /* calculate net force of effectors, and apply to sim object * - we use 'central force' since apply force requires a "relative position" which we don't have... */ pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL); if (G.f & G_DEBUG) printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2); /* activate object in case it is deactivated */ if (!is_zero_v3(eff_force)) RB_body_activate(rbo->physics_object); RB_body_apply_central_force(rbo->physics_object, eff_force); } else if (G.f & G_DEBUG) printf("\tno forces to apply to '%s'\n", ob->id.name + 2); /* cleanup */ pdEndEffectors(&effectors); } /* NOTE: passive objects don't need to be updated since they don't move */ /* NOTE: no other settings need to be explicitly updated here, * since RNA setters take care of the rest :) */ }
static void TargetSnapClosest(TransInfo *t) { // Only valid if a snap point has been selected if (t->tsnap.status & POINT_INIT) { float dist_closest = 0.0f; TransData *closest = NULL, *td = NULL; /* Object mode */ if (t->flag & T_OBJECT) { int i; for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) { struct BoundBox *bb = BKE_object_boundbox_get(td->ob); /* use boundbox if possible */ if (bb) { int j; for (j = 0; j < 8; j++) { float loc[3]; float dist; copy_v3_v3(loc, bb->vec[j]); mul_m4_v3(td->ext->obmat, loc); dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint); if ((dist != TRANSFORM_DIST_INVALID) && (closest == NULL || fabsf(dist) < fabsf(dist_closest))) { copy_v3_v3(t->tsnap.snapTarget, loc); closest = td; dist_closest = dist; } } } /* use element center otherwise */ else { float loc[3]; float dist; copy_v3_v3(loc, td->center); dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint); if ((dist != TRANSFORM_DIST_INVALID) && (closest == NULL || fabsf(dist) < fabsf(dist_closest))) { copy_v3_v3(t->tsnap.snapTarget, loc); closest = td; } } } } else { int i; for (td = t->data, i = 0; i < t->total && td->flag & TD_SELECTED; i++, td++) { float loc[3]; float dist; copy_v3_v3(loc, td->center); if (t->flag & (T_EDIT | T_POSE)) { Object *ob = t->obedit ? t->obedit : t->poseobj; mul_m4_v3(ob->obmat, loc); } dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint); if ((dist != TRANSFORM_DIST_INVALID) && (closest == NULL || fabsf(dist) < fabsf(dist_closest))) { copy_v3_v3(t->tsnap.snapTarget, loc); closest = td; dist_closest = dist; } } } TargetSnapOffset(t, closest); t->tsnap.status |= TARGET_INIT; } }