Ejemplo n.º 1
0
/* 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;
}
Ejemplo n.º 2
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;

		/* 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;
	}
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 5
0
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);
}
Ejemplo n.º 6
0
/* 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);
		}
	}
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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);
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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);
}
Ejemplo n.º 11
0
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(&params->viewplane) / BLI_rctf_size_y(&params->viewplane));
		}
		else {
			scale_diff = (dists[0] + dists[2]) *
			             (BLI_rctf_size_y(&params->viewplane) / BLI_rctf_size_x(&params->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;
}
Ejemplo n.º 12
0
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);
	}
}
Ejemplo n.º 13
0
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);
	}
}
Ejemplo n.º 14
0
	/* 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;
}
Ejemplo n.º 15
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;
      }
    }
  }
}
Ejemplo n.º 16
0
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);
	}
}
Ejemplo n.º 17
0
/**
 * 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);
		}
	}
}
Ejemplo n.º 18
0
/* 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;
}
Ejemplo n.º 19
0
/* 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;
		}
	}
}
Ejemplo n.º 20
0
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;
	}
}
Ejemplo n.º 21
0
/**
 * \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);
		}
	}
}
Ejemplo n.º 22
0
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;
}
Ejemplo n.º 23
0
/*
 * 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;
}
Ejemplo n.º 24
0
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);
}
Ejemplo n.º 25
0
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);
		}
	}
}
Ejemplo n.º 26
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];

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