Example #1
0
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;
	}
}
Example #2
0
/* 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);
	}
}
Example #3
0
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;
  }
}
Example #4
0
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 :)
	 */
}
Example #5
0
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;
	}
}