Exemplo n.º 1
0
BMFace *BKE_bmbvh_ray_cast_filter(
        BMBVHTree *bmtree, const float co[3], const float dir[3], const float radius,
        float *r_dist, float r_hitout[3], float r_cagehit[3],
        BMBVHTree_FaceFilter filter_cb, void *filter_userdata)
{
	BVHTreeRayHit hit;
	struct RayCastUserData_Filter bmcb_data_filter;
	struct RayCastUserData *bmcb_data = &bmcb_data_filter.bmcb_data;

	const float dist = r_dist ? *r_dist : FLT_MAX;

	bmcb_data_filter.filter_cb = filter_cb;
	bmcb_data_filter.filter_userdata = filter_userdata;

	if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));

	hit.dist = dist;
	hit.index = -1;

	/* ok to leave 'uv' uninitialized */
	bmcb_data->looptris = (const BMLoop *(*)[3])bmtree->looptris;
	bmcb_data->cos_cage = (const float (*)[3])bmtree->cos_cage;

	BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb_filter, &bmcb_data_filter);
	if (hit.index != -1 && hit.dist != dist) {
		return bmbvh_ray_cast_handle_hit(bmtree, bmcb_data, &hit, r_dist, r_hitout, r_cagehit);
	}

	return NULL;
}
static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source)
{
	BVHTreeRayHit hit;
	BVHCallbackUserData data;
	const MLoopTri *lt;
	float end[3];
	int visible;

	lt = sys->heat.vltree[vertex];
	if (lt == NULL)
		return 1;

	data.sys = sys;
	copy_v3_v3(data.start, sys->heat.verts[vertex]);

	closest_to_line_segment_v3(end, data.start, sys->heat.root[source], sys->heat.tip[source]);

	sub_v3_v3v3(data.vec, end, data.start);
	madd_v3_v3v3fl(data.start, data.start, data.vec, 1e-5);
	mul_v3_fl(data.vec, 1.0f - 2e-5f);

	/* pass normalized vec + distance to bvh */
	hit.index = -1;
	hit.dist = normalize_v3(data.vec);

	visible = BLI_bvhtree_ray_cast(sys->heat.bvhtree, data.start, data.vec, 0.0f, &hit, bvh_callback, (void *)&data) == -1;

	return visible;
}
Exemplo n.º 3
0
/*
 * This function raycast a single vertex and updates the hit if the "hit" is considered valid.
 * Returns TRUE if "hit" was updated.
 * Opts control whether an hit is valid or not
 * Supported options are:
 *	MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
 *	MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
 */
int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
{
	float tmp_co[3], tmp_no[3];
	const float *co, *no;
	BVHTreeRayHit hit_tmp;

	//Copy from hit (we need to convert hit rays from one space coordinates to the other
	memcpy(&hit_tmp, hit, sizeof(hit_tmp));

	//Apply space transform (TODO readjust dist)
	if (transf) {
		copy_v3_v3(tmp_co, vert);
		space_transform_apply(transf, tmp_co);
		co = tmp_co;

		copy_v3_v3(tmp_no, dir);
		space_transform_apply_normal(transf, tmp_no);
		no = tmp_no;

		hit_tmp.dist *= mat4_to_scale(((SpaceTransform*)transf)->local2target);
	}
	else {
		co = vert;
		no = dir;
	}

	hit_tmp.index = -1;

	BLI_bvhtree_ray_cast(tree, co, no, 0.0f, &hit_tmp, callback, userdata);

	if (hit_tmp.index != -1) {
		/* invert the normal first so face culling works on rotated objects */
		if (transf) {
			space_transform_invert_normal(transf, hit_tmp.no);
		}

		if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE|MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) {
			/* apply backface */
			const float dot= dot_v3v3(dir, hit_tmp.no);
			if (	((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
				((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot >= 0.0f)
			) {
				return FALSE; /* Ignore hit */
			}
		}

		if (transf) {
			/* Inverting space transform (TODO make coeherent with the initial dist readjust) */
			space_transform_invert(transf, hit_tmp.co);
			hit_tmp.dist = len_v3v3((float *)vert, hit_tmp.co);
		}

		memcpy(hit, &hit_tmp, sizeof(hit_tmp));
		return TRUE;
	}
	return FALSE;
}
Exemplo n.º 4
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;
	}
}
Exemplo n.º 5
0
// get visibility of a wind ray
static float eff_calc_visibility(ListBase *colliders, EffectorCache *eff, EffectorData *efd, EffectedPoint *point)
{
	ListBase *colls = colliders;
	ColliderCache *col;
	float norm[3], len = 0.0;
	float visibility = 1.0, absorption = 0.0;
	
	if(!(eff->pd->flag & PFIELD_VISIBILITY))
		return visibility;

	if(!colls)
		colls = get_collider_cache(eff->scene, eff->ob, NULL);

	if(!colls)
		return visibility;

	negate_v3_v3(norm, efd->vec_to_point);
	len = normalize_v3(norm);
	
	// check all collision objects
	for(col = colls->first; col; col = col->next)
	{
		CollisionModifierData *collmd = col->collmd;

		if(col->ob == eff->ob)
			continue;
		
		if(collmd->bvhtree)
		{
			BVHTreeRayHit hit;
			
			hit.index = -1;
			hit.dist = len + FLT_EPSILON;
			
			// check if the way is blocked
			if(BLI_bvhtree_ray_cast(collmd->bvhtree, point->loc, norm, 0.0f, &hit, eff_tri_ray_hit, NULL)>=0)
			{
				absorption= col->ob->pd->absorption;

				// visibility is only between 0 and 1, calculated from 1-absorption
				visibility *= CLAMPIS(1.0f-absorption, 0.0f, 1.0f);
				
				if(visibility <= 0.0f)
					break;
			}
		}
	}

	if(!colliders)
		free_collider_cache(&colls);
	
	return visibility;
}
Exemplo n.º 6
0
BMFace *BKE_bmbvh_find_face_segment(BMBVHTree *bmtree, const float co_a[3], const float co_b[3],
                                    float *r_fac, float r_hitout[3], float r_cagehit[3])
{
	BVHTreeRayHit hit;
	struct SegmentUserData bmcb_data;
	const float dist = len_v3v3(co_a, co_b);
	float dir[3];

	if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));

	sub_v3_v3v3(dir, co_b, co_a);

	hit.dist = dist;
	hit.index = -1;

	/* ok to leave 'uv' uninitialized */
	bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
	bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage;
	bmcb_data.co_a = co_a;
	bmcb_data.co_b = co_b;

	BLI_bvhtree_ray_cast(bmtree->tree, co_a, dir, 0.0f, &hit, bmbvh_find_face_segment_cb, &bmcb_data);
	if (hit.index != -1 && hit.dist != dist) {
		/* duplicate of BKE_bmbvh_ray_cast() */
		if (r_hitout) {
			if (bmtree->flag & BMBVH_RETURN_ORIG) {
				BMLoop **ltri = bmtree->looptris[hit.index];
				interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data.uv);
			}
			else {
				copy_v3_v3(r_hitout, hit.co);
			}

			if (r_cagehit) {
				copy_v3_v3(r_cagehit, hit.co);
			}
		}
		/* end duplicate */

		if (r_fac) {
			*r_fac = hit.dist / dist;
		}

		return bmtree->looptris[hit.index][0]->f;
	}

	return NULL;
}
Exemplo n.º 7
0
static int  RE_rayobject_blibvh_intersect(RayObject *o, Isect *isec)
{
	BVHObject *obj = (BVHObject*)o;
	BVHTreeRayHit hit;
	float dir[3];
	struct BVHCallbackUserData data;
	data.isec = isec;
	data.leafs = obj->leafs;

	copy_v3_v3(dir, isec->dir);

	hit.index = 0;
	hit.dist = isec->dist;
	
	return BLI_bvhtree_ray_cast(obj->bvh, isec->start, dir, 0.0, &hit, bvh_callback, (void*)&data);
}
Exemplo n.º 8
0
BMFace *BKE_bmbvh_ray_cast(BMBVHTree *bmtree, const float co[3], const float dir[3], const float radius,
                           float *r_dist, float r_hitout[3], float r_cagehit[3])
{
	BVHTreeRayHit hit;
	struct RayCastUserData bmcb_data;
	const float dist = r_dist ? *r_dist : FLT_MAX;

	if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));

	hit.dist = dist;
	hit.index = -1;

	/* ok to leave 'uv' uninitialized */
	bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
	bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage;
	
	BLI_bvhtree_ray_cast(bmtree->tree, co, dir, radius, &hit, bmbvh_ray_cast_cb, &bmcb_data);
	if (hit.index != -1 && hit.dist != dist) {
		if (r_hitout) {
			if (bmtree->flag & BMBVH_RETURN_ORIG) {
				BMLoop **ltri = bmtree->looptris[hit.index];
				interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data.uv);
			}
			else {
				copy_v3_v3(r_hitout, hit.co);
			}

			if (r_cagehit) {
				copy_v3_v3(r_cagehit, hit.co);
			}
		}

		if (r_dist) {
			*r_dist = hit.dist;
		}

		return bmtree->looptris[hit.index][0]->f;
	}

	return NULL;
}
Exemplo n.º 9
0
static void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start[3], float ray_end[3],
                                float r_location[3], float r_normal[3], int *index)
{
	BVHTreeFromMesh treeData = {NULL};
	
	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;
	}

	/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
	bvhtree_from_mesh_faces(&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;
		float ray_nor[3], dist;
		sub_v3_v3v3(ray_nor, ray_end, ray_start);

		dist = hit.dist = normalize_v3(ray_nor);
		hit.index = -1;
		
		if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_nor, 0.0f, &hit,
		                         treeData.raycast_callback, &treeData) != -1)
		{
			if (hit.dist <= dist) {
				copy_v3_v3(r_location, hit.co);
				copy_v3_v3(r_normal, hit.no);
				*index = dm_tessface_to_poly_index(ob->derivedFinal, hit.index);
				free_bvhtree_from_mesh(&treeData);
				return;
			}
		}
	}

	zero_v3(r_location);
	zero_v3(r_normal);
	*index = -1;
	free_bvhtree_from_mesh(&treeData);
}
Exemplo n.º 10
0
void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start[3], float ray_end[3], float r_location[3], float r_normal[3], int *index)
{
	BVHTreeFromMesh treeData= {NULL};
	
	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;
	}

	/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
	bvhtree_from_mesh_faces(&treeData, ob->derivedFinal, 0.0f, 4, 6);

	if(treeData.tree==NULL) {
		BKE_reportf(reports, RPT_ERROR, "object \"%s\" could not create internal data for ray casting", ob->id.name+2);
		return;
	}
	else {
		BVHTreeRayHit hit;
		float ray_nor[3], dist;
		sub_v3_v3v3(ray_nor, ray_end, ray_start);

		dist= hit.dist = normalize_v3(ray_nor);
		hit.index = -1;
		
		if(BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) {
			if(hit.dist<=dist) {
				copy_v3_v3(r_location, hit.co);
				copy_v3_v3(r_normal, hit.no);
				*index= hit.index;
				return;
			}
		}
	}

	zero_v3(r_location);
	zero_v3(r_normal);
	*index= -1;
}
Exemplo n.º 11
0
/**
 * This function populates pixel_array and returns TRUE if things are correct
 */
static bool cast_ray_highpoly(
        BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakePixel *pixel_array, BakeHighPolyData *highpoly,
        const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly,
        const float du_dx, const float du_dy, const float dv_dx, const float dv_dy)
{
	int i;
	int primitive_id = -1;
	float uv[2];
	int hit_mesh = -1;
	float hit_distance = FLT_MAX;

	BVHTreeRayHit *hits;
	hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays");

	for (i = 0; i < tot_highpoly; i++) {
		float co_high[3], dir_high[3];

		hits[i].index = -1;
		/* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
		hits[i].dist = 10000.0f;

		/* transform the ray from the world space to the highpoly space */
		mul_v3_m4v3(co_high, highpoly[i].imat, co);

		/* rotates */
		mul_v3_mat3_m4v3(dir_high, highpoly[i].imat, dir);
		normalize_v3(dir_high);

		/* cast ray */
		if (treeData[i].tree) {
			BLI_bvhtree_ray_cast(treeData[i].tree, co_high, dir_high, 0.0f, &hits[i], treeData[i].raycast_callback, &treeData[i]);
		}

		if (hits[i].index != -1) {
			/* cull backface */
			const float dot = dot_v3v3(dir_high, hits[i].no);
			if (dot < 0.0f) {
				float distance;
				float hit_world[3];

				/* distance comparison in world space */
				mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
				distance = len_squared_v3v3(hit_world, co);

				if (distance < hit_distance) {
					hit_mesh = i;
					hit_distance = distance;
				}
			}
		}
	}

	if (hit_mesh != -1) {
		calc_barycentric_from_point(triangles[hit_mesh], hits[hit_mesh].index, hits[hit_mesh].co, &primitive_id, uv);
		pixel_array[pixel_id].primitive_id = primitive_id;
		pixel_array[pixel_id].object_id = hit_mesh;
		copy_v2_v2(pixel_array[pixel_id].uv, uv);

		/* the differentials are relative to the UV/image space, so the highpoly differentials
		 * are the same as the low poly differentials */
		pixel_array[pixel_id].du_dx = du_dx;
		pixel_array[pixel_id].du_dy = du_dy;
		pixel_array[pixel_id].dv_dx = dv_dx;
		pixel_array[pixel_id].dv_dy = dv_dy;
	}
	else {
		pixel_array[pixel_id].primitive_id = -1;
		pixel_array[pixel_id].object_id = -1;
	}

	MEM_freeN(hits);
	return hit_mesh != -1;
}
Exemplo n.º 12
0
/*
 * This function raycast a single vertex and updates the hit if the "hit" is considered valid.
 * Returns true if "hit" was updated.
 * Opts control whether an hit is valid or not
 * Supported options are:
 *	MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
 *	MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
 */
bool BKE_shrinkwrap_project_normal(
        char options, const float vert[3],
        const float dir[3], const SpaceTransform *transf,
        BVHTree *tree, BVHTreeRayHit *hit,
        BVHTree_RayCastCallback callback, void *userdata)
{
	/* don't use this because this dist value could be incompatible
	 * this value used by the callback for comparing prev/new dist values.
	 * also, at the moment there is no need to have a corrected 'dist' value */
// #define USE_DIST_CORRECT

	float tmp_co[3], tmp_no[3];
	const float *co, *no;
	BVHTreeRayHit hit_tmp;

	/* Copy from hit (we need to convert hit rays from one space coordinates to the other */
	memcpy(&hit_tmp, hit, sizeof(hit_tmp));

	/* Apply space transform (TODO readjust dist) */
	if (transf) {
		copy_v3_v3(tmp_co, vert);
		space_transform_apply(transf, tmp_co);
		co = tmp_co;

		copy_v3_v3(tmp_no, dir);
		space_transform_apply_normal(transf, tmp_no);
		no = tmp_no;

#ifdef USE_DIST_CORRECT
		hit_tmp.dist *= mat4_to_scale(((SpaceTransform *)transf)->local2target);
#endif
	}
	else {
		co = vert;
		no = dir;
	}

	hit_tmp.index = -1;

	BLI_bvhtree_ray_cast(tree, co, no, 0.0f, &hit_tmp, callback, userdata);

	if (hit_tmp.index != -1) {
		/* invert the normal first so face culling works on rotated objects */
		if (transf) {
			space_transform_invert_normal(transf, hit_tmp.no);
		}

		if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) {
			/* apply backface */
			const float dot = dot_v3v3(dir, hit_tmp.no);
			if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
			    ((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)  && dot >= 0.0f))
			{
				return false;  /* Ignore hit */
			}
		}

		if (transf) {
			/* Inverting space transform (TODO make coeherent with the initial dist readjust) */
			space_transform_invert(transf, hit_tmp.co);
#ifdef USE_DIST_CORRECT
			hit_tmp.dist = len_v3v3(vert, hit_tmp.co);
#endif
		}

		BLI_assert(hit_tmp.dist <= hit->dist);

		memcpy(hit, &hit_tmp, sizeof(hit_tmp));
		return true;
	}
	return false;
}
Exemplo n.º 13
0
static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const float co1[3], const float co2[3])
{
	BVHTreeRayHit hit;
	MeshDeformIsect isect_mdef;
	struct MeshRayCallbackData data = {
		mdb,
		&isect_mdef,
	};
	float end[3], vec_normal[3];

	/* happens binding when a cage has no faces */
	if (UNLIKELY(mdb->bvhtree == NULL))
		return NULL;

	/* setup isec */
	memset(&isect_mdef, 0, sizeof(isect_mdef));
	isect_mdef.lambda = 1e10f;

	copy_v3_v3(isect_mdef.start, co1);
	copy_v3_v3(end, co2);
	sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start);
	isect_mdef.vec_length = normalize_v3_v3(vec_normal, isect_mdef.vec);

	hit.index = -1;
	hit.dist = BVH_RAYCAST_DIST_MAX;
	if (BLI_bvhtree_ray_cast(mdb->bvhtree, isect_mdef.start, vec_normal,
	                         0.0, &hit, harmonic_ray_callback, &data) != -1)
	{
		const MLoop *mloop = mdb->cagedm_cache.mloop;
		const MLoopTri *lt = &mdb->cagedm_cache.looptri[hit.index];
		const MPoly *mp = &mdb->cagedm_cache.mpoly[lt->poly];
		const float (*cagecos)[3] = mdb->cagecos;
		const float len = isect_mdef.lambda;
		MDefBoundIsect *isect;

		float (*mp_cagecos)[3] = BLI_array_alloca(mp_cagecos, mp->totloop);
		int i;

		/* create MDefBoundIsect, and extra for 'poly_weights[]' */
		isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect) + (sizeof(float) * mp->totloop));

		/* compute intersection coordinate */
		madd_v3_v3v3fl(isect->co, co1, isect_mdef.vec, len);

		isect->facing = isect_mdef.isect;

		isect->poly_index = lt->poly;

		isect->len = max_ff(len_v3v3(co1, isect->co), MESHDEFORM_LEN_THRESHOLD);

		/* compute mean value coordinates for interpolation */
		for (i = 0; i < mp->totloop; i++) {
			copy_v3_v3(mp_cagecos[i], cagecos[mloop[mp->loopstart + i].v]);
		}

		interp_weights_poly_v3(isect->poly_weights, mp_cagecos, mp->totloop, isect->co);

		return isect;
	}

	return NULL;
}
Exemplo n.º 14
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;
  }
}
Exemplo n.º 15
0
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;

		memset(&col, 0, sizeof(ParticleCollision));

		/* 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;
	}
}
Exemplo n.º 16
0
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];

		memset(&col, 0, sizeof(ParticleCollision));

		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_rng_get_float(bbd->rng);
				bbd->wanted_co[1] = BLI_rng_get_float(bbd->rng);
				bbd->wanted_co[2] = BLI_rng_get_float(bbd->rng);
			}
			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__normal(
		        bbd->sim->psys->tree, pa->prev_state.co, pa->prev_state.ave,
		        &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel));
		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__normal(
			        epsys->tree, pa->prev_state.co, pa->prev_state.ave,
			        &ptn, acbr->look_ahead * len_v3(pa->prev_state.vel));

			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;
}