コード例 #1
0
ファイル: boids.c プロジェクト: Andrewson3D/blender-for-vray
/* determines the velocity the boid wants to have */
void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
{
	BoidRule *rule;
	BoidSettings *boids = bbd->part->boids;
	BoidValues val;
	BoidState *state = get_boid_state(boids, pa);
	BoidParticle *bpa = pa->boid;
	ParticleSystem *psys = bbd->sim->psys;
	int rand;
	//BoidCondition *cond;

	if (bpa->data.health <= 0.0f) {
		pa->alive = PARS_DYING;
		pa->dietime = bbd->cfra;
		return;
	}

	//planned for near future
	//cond = state->conditions.first;
	//for (; cond; cond=cond->next) {
	//	if (boid_condition_is_true(cond)) {
	//		pa->boid->state_id = cond->state_id;
	//		state = get_boid_state(boids, pa);
	//		break; /* only first true condition is used */
	//	}
	//}

	zero_v3(bbd->wanted_co);
	bbd->wanted_speed = 0.0f;

	/* create random seed for every particle & frame */
	rand = (int)(psys_frand(psys, psys->seed + p) * 1000);
	rand = (int)(psys_frand(psys, (int)bbd->cfra + rand) * 1000);

	set_boid_values(&val, bbd->part->boids, pa);

	/* go through rules */
	switch (state->ruleset_type) {
		case eBoidRulesetType_Fuzzy:
		{
			for (rule = state->rules.first; rule; rule = rule->next) {
				if (apply_boid_rule(bbd, rule, &val, pa, state->rule_fuzziness))
					break; /* only first nonzero rule that comes through fuzzy rule is applied */
			}
			break;
		}
		case eBoidRulesetType_Random:
		{
			/* use random rule for each particle (always same for same particle though) */
			rule = BLI_findlink(&state->rules, rand % BLI_listbase_count(&state->rules));

			apply_boid_rule(bbd, rule, &val, pa, -1.0);
			break;
		}
		case eBoidRulesetType_Average:
		{
			float wanted_co[3] = {0.0f, 0.0f, 0.0f}, wanted_speed = 0.0f;
			int n = 0;
			for (rule = state->rules.first; rule; rule=rule->next) {
				if (apply_boid_rule(bbd, rule, &val, pa, -1.0f)) {
					add_v3_v3(wanted_co, bbd->wanted_co);
					wanted_speed += bbd->wanted_speed;
					n++;
					zero_v3(bbd->wanted_co);
					bbd->wanted_speed = 0.0f;
				}
			}

			if (n > 1) {
				mul_v3_fl(wanted_co, 1.0f/(float)n);
				wanted_speed /= (float)n;
			}

			copy_v3_v3(bbd->wanted_co, wanted_co);
			bbd->wanted_speed = wanted_speed;
			break;
		}

	}

	/* decide on jumping & liftoff */
	if (bpa->data.mode == eBoidMode_OnLand) {
		/* fuzziness makes boids capable of misjudgement */
		float mul = 1.0f + state->rule_fuzziness;
		
		if (boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) {
			float cvel[3], dir[3];

			copy_v3_v3(dir, pa->prev_state.ave);
			normalize_v2(dir);

			copy_v3_v3(cvel, bbd->wanted_co);
			normalize_v2(cvel);

			if (dot_v2v2(cvel, dir) > 0.95f / mul)
				bpa->data.mode = eBoidMode_Liftoff;
		}
		else if (val.jump_speed > 0.0f) {
			float jump_v[3];
			int jump = 0;

			/* jump to get to a location */
			if (bbd->wanted_co[2] > 0.0f) {
				float cvel[3], dir[3];
				float z_v, ground_v, cur_v;
				float len;

				copy_v3_v3(dir, pa->prev_state.ave);
				normalize_v2(dir);

				copy_v3_v3(cvel, bbd->wanted_co);
				normalize_v2(cvel);

				len = len_v2(pa->prev_state.vel);

				/* first of all, are we going in a suitable direction? */
				/* or at a suitably slow speed */
				if (dot_v2v2(cvel, dir) > 0.95f / mul || len <= state->rule_fuzziness) {
					/* try to reach goal at highest point of the parabolic path */
					cur_v = len_v2(pa->prev_state.vel);
					z_v = sasqrt(-2.0f * bbd->sim->scene->physics_settings.gravity[2] * bbd->wanted_co[2]);
					ground_v = len_v2(bbd->wanted_co)*sasqrt(-0.5f * bbd->sim->scene->physics_settings.gravity[2] / bbd->wanted_co[2]);

					len = sasqrt((ground_v-cur_v)*(ground_v-cur_v) + z_v*z_v);

					if (len < val.jump_speed * mul || bbd->part->boids->options & BOID_ALLOW_FLIGHT) {
						jump = 1;

						len = MIN2(len, val.jump_speed);

						copy_v3_v3(jump_v, dir);
						jump_v[2] = z_v;
						mul_v3_fl(jump_v, ground_v);

						normalize_v3(jump_v);
						mul_v3_fl(jump_v, len);
						add_v2_v2v2(jump_v, jump_v, pa->prev_state.vel);
					}
				}
			}

			/* jump to go faster */
			if (jump == 0 && val.jump_speed > val.max_speed && bbd->wanted_speed > val.max_speed) {
				
			}

			if (jump) {
				copy_v3_v3(pa->prev_state.vel, jump_v);
				bpa->data.mode = eBoidMode_Falling;
			}
		}
	}
}
コード例 #2
0
static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
{
	ParticleData *pa=NULL;
	float min[3], max[3], delta[3], d;
	MVert *mv, *mvert = dm->getVertDataArray(dm,0);
	int totvert=dm->getNumVerts(dm), from=psys->part->from;
	int i, j, k, p, res=psys->part->grid_res, size[3], axis;

	/* find bounding box of dm */
	if (totvert > 0) {
		mv=mvert;
		copy_v3_v3(min, mv->co);
		copy_v3_v3(max, mv->co);
		mv++;
		for (i = 1; i < totvert; i++, mv++) {
			minmax_v3v3_v3(min, max, mv->co);
		}
	}
	else {
		zero_v3(min);
		zero_v3(max);
	}

	sub_v3_v3v3(delta, max, min);

	/* determine major axis */
	axis = axis_dominant_v3_single(delta);

	d = delta[axis]/(float)res;

	size[axis] = res;
	size[(axis+1)%3] = (int)ceil(delta[(axis+1)%3]/d);
	size[(axis+2)%3] = (int)ceil(delta[(axis+2)%3]/d);

	/* float errors grrr.. */
	size[(axis+1)%3] = MIN2(size[(axis+1)%3],res);
	size[(axis+2)%3] = MIN2(size[(axis+2)%3],res);

	size[0] = MAX2(size[0], 1);
	size[1] = MAX2(size[1], 1);
	size[2] = MAX2(size[2], 1);

	/* no full offset for flat/thin objects */
	min[0]+= d < delta[0] ? d/2.f : delta[0]/2.f;
	min[1]+= d < delta[1] ? d/2.f : delta[1]/2.f;
	min[2]+= d < delta[2] ? d/2.f : delta[2]/2.f;

	for (i=0,p=0,pa=psys->particles; i<res; i++) {
		for (j=0; j<res; j++) {
			for (k=0; k<res; k++,p++,pa++) {
				pa->fuv[0] = min[0] + (float)i*d;
				pa->fuv[1] = min[1] + (float)j*d;
				pa->fuv[2] = min[2] + (float)k*d;
				pa->flag |= PARS_UNEXIST;
				pa->hair_index = 0; /* abused in volume calculation */
			}
		}
	}

	/* enable particles near verts/edges/faces/inside surface */
	if (from==PART_FROM_VERT) {
		float vec[3];

		pa=psys->particles;

		min[0] -= d/2.0f;
		min[1] -= d/2.0f;
		min[2] -= d/2.0f;

		for (i=0,mv=mvert; i<totvert; i++,mv++) {
			sub_v3_v3v3(vec,mv->co,min);
			vec[0]/=delta[0];
			vec[1]/=delta[1];
			vec[2]/=delta[2];
			pa[((int)(vec[0] * (size[0] - 1))  * res +
			    (int)(vec[1] * (size[1] - 1))) * res +
			    (int)(vec[2] * (size[2] - 1))].flag &= ~PARS_UNEXIST;
		}
	}
	else if (ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
		float co1[3], co2[3];

		MFace *mface= NULL, *mface_array;
		float v1[3], v2[3], v3[3], v4[4], lambda;
		int a, a1, a2, a0mul, a1mul, a2mul, totface;
		int amax= from==PART_FROM_FACE ? 3 : 1;

		totface=dm->getNumTessFaces(dm);
		mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE);

		for (a=0; a<amax; a++) {
			if (a==0) { a0mul=res*res; a1mul=res; a2mul=1; }
			else if (a==1) { a0mul=res; a1mul=1; a2mul=res*res; }
			else { a0mul=1; a1mul=res*res; a2mul=res; }

			for (a1=0; a1<size[(a+1)%3]; a1++) {
				for (a2=0; a2<size[(a+2)%3]; a2++) {
					mface= mface_array;

					pa = psys->particles + a1*a1mul + a2*a2mul;
					copy_v3_v3(co1, pa->fuv);
					co1[a] -= d < delta[a] ? d/2.f : delta[a]/2.f;
					copy_v3_v3(co2, co1);
					co2[a] += delta[a] + 0.001f*d;
					co1[a] -= 0.001f*d;

					struct IsectRayPrecalc isect_precalc;
					float ray_direction[3];
					sub_v3_v3v3(ray_direction, co2, co1);
					isect_ray_tri_watertight_v3_precalc(&isect_precalc, ray_direction);

					/* lets intersect the faces */
					for (i=0; i<totface; i++,mface++) {
						copy_v3_v3(v1, mvert[mface->v1].co);
						copy_v3_v3(v2, mvert[mface->v2].co);
						copy_v3_v3(v3, mvert[mface->v3].co);

						bool intersects_tri = isect_ray_tri_watertight_v3(co1,
						                                                  &isect_precalc,
						                                                  v1, v2, v3,
						                                                  &lambda, NULL);
						if (intersects_tri) {
							if (from==PART_FROM_FACE)
								(pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
							else /* store number of intersections */
								(pa+(int)(lambda*size[a])*a0mul)->hair_index++;
						}

						if (mface->v4 && (!intersects_tri || from==PART_FROM_VOLUME)) {
							copy_v3_v3(v4, mvert[mface->v4].co);

							if (isect_ray_tri_watertight_v3(
							            co1,
							            &isect_precalc,
							            v1, v3, v4,
							            &lambda, NULL))
							{
								if (from==PART_FROM_FACE)
									(pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
								else
									(pa+(int)(lambda*size[a])*a0mul)->hair_index++;
							}
						}
					}

					if (from==PART_FROM_VOLUME) {
						int in=pa->hair_index%2;
						if (in) pa->hair_index++;
						for (i=0; i<size[0]; i++) {
							if (in || (pa+i*a0mul)->hair_index%2)
								(pa+i*a0mul)->flag &= ~PARS_UNEXIST;
							/* odd intersections == in->out / out->in */
							/* even intersections -> in stays same */
							in=(in + (pa+i*a0mul)->hair_index) % 2;
						}
					}
				}
			}
		}
	}

	if (psys->part->flag & PART_GRID_HEXAGONAL) {
		for (i=0,p=0,pa=psys->particles; i<res; i++) {
			for (j=0; j<res; j++) {
				for (k=0; k<res; k++,p++,pa++) {
					if (j%2)
						pa->fuv[0] += d/2.f;

					if (k%2) {
						pa->fuv[0] += d/2.f;
						pa->fuv[1] += d/2.f;
					}
				}
			}
		}
	}

	if (psys->part->flag & PART_GRID_INVERT) {
		for (i=0; i<size[0]; i++) {
			for (j=0; j<size[1]; j++) {
				pa=psys->particles + res*(i*res + j);
				for (k=0; k<size[2]; k++, pa++) {
					pa->flag ^= PARS_UNEXIST;
				}
			}
		}
	}

	if (psys->part->grid_rand > 0.f) {
		float rfac = d * psys->part->grid_rand;
		for (p=0,pa=psys->particles; p<psys->totpart; p++,pa++) {
			if (pa->flag & PARS_UNEXIST)
				continue;

			pa->fuv[0] += rfac * (psys_frand(psys, p + 31) - 0.5f);
			pa->fuv[1] += rfac * (psys_frand(psys, p + 32) - 0.5f);
			pa->fuv[2] += rfac * (psys_frand(psys, p + 33) - 0.5f);
		}
	}
}
コード例 #3
0
ファイル: particle_child.c プロジェクト: Ichthyostega/blender
static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, const float parent_orco[3],
                           ChildParticle *cpa, const float orco[3], float hairmat[4][4],
                           ParticleCacheKey *keys, ParticleCacheKey *parent_keys, int *r_totkeys, float *r_max_length)
{
	struct ParticleSettings *part = ctx->sim.psys->part;
	const int seed = ctx->sim.psys->child_seed + (int)(cpa - ctx->sim.psys->child);
	const int totkeys = ctx->segments + 1;
	const int extrakeys = ctx->extra_segments;

	float kink_amp_random = part->kink_amp_random;
	float kink_amp = part->kink_amp * (1.0f - kink_amp_random * psys_frand(ctx->sim.psys, 93541 + seed));
	float kink_freq = part->kink_freq;
	float kink_shape = part->kink_shape;
	float kink_axis_random = part->kink_axis_random;
	float rough1 = part->rough1;
	float rough2 = part->rough2;
	float rough_end = part->rough_end;

	ParticlePathIterator iter;
	ParticleCacheKey *key;
	int k;

	float dir[3];
	float spiral_start[3] = {0.0f, 0.0f, 0.0f};
	float spiral_start_time = 0.0f;
	float spiral_par_co[3] = {0.0f, 0.0f, 0.0f};
	float spiral_par_vel[3] = {0.0f, 0.0f, 0.0f};
	float spiral_par_rot[4] = {1.0f, 0.0f, 0.0f, 0.0f};
	float totlen;
	float cut_time;
	int start_index = 0, end_index = 0;
	float kink_base[3];

	if (ptex) {
		kink_amp *= ptex->kink_amp;
		kink_freq *= ptex->kink_freq;
		rough1 *= ptex->rough1;
		rough2 *= ptex->rough2;
		rough_end *= ptex->roughe;
	}

	cut_time = (totkeys - 1) * ptex->length;
	zero_v3(spiral_start);

	for (k = 0, key = keys; k < totkeys-1; k++, key++) {
		if ((float)(k + 1) >= cut_time) {
			float fac = cut_time - (float)k;
			ParticleCacheKey *par = parent_keys + k;

			start_index = k + 1;
			end_index = start_index + extrakeys;

			spiral_start_time = ((float)k + fac) / (float)(totkeys - 1);
			interp_v3_v3v3(spiral_start, key->co, (key+1)->co, fac);

			interp_v3_v3v3(spiral_par_co, par->co, (par+1)->co, fac);
			interp_v3_v3v3(spiral_par_vel, par->vel, (par+1)->vel, fac);
			interp_qt_qtqt(spiral_par_rot, par->rot, (par+1)->rot, fac);

			break;
		}
	}

	zero_v3(dir);

	zero_v3(kink_base);
	kink_base[part->kink_axis] = 1.0f;
	mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base);

	/* Fill in invariant part of modifier context. */
	ParticleChildModifierContext modifier_ctx = {NULL};
	modifier_ctx.thread_ctx = ctx;
	modifier_ctx.sim = &ctx->sim;
	modifier_ctx.ptex = ptex;
	modifier_ctx.cpa = cpa;
	modifier_ctx.orco = orco;
	modifier_ctx.parent_keys = parent_keys;

	for (k = 0, key = keys; k < end_index; k++, key++) {
		float par_time;
		float *par_co, *par_vel, *par_rot;

		psys_path_iter_get(&iter, keys, end_index, NULL, k);
		if (k < start_index) {
			sub_v3_v3v3(dir, (key+1)->co, key->co);
			normalize_v3(dir);

			par_time = (float)k / (float)(totkeys - 1);
			par_co = parent_keys[k].co;
			par_vel = parent_keys[k].vel;
			par_rot = parent_keys[k].rot;
		}
		else {
			float spiral_time = (float)(k - start_index) / (float)(extrakeys-1);
			float kink[3], tmp[3];

			/* use same time value for every point on the spiral */
			par_time = spiral_start_time;
			par_co = spiral_par_co;
			par_vel = spiral_par_vel;
			par_rot = spiral_par_rot;

			project_v3_v3v3(tmp, kink_base, dir);
			sub_v3_v3v3(kink, kink_base, tmp);
			normalize_v3(kink);

			if (kink_axis_random > 0.0f) {
				float a = kink_axis_random * (psys_frand(ctx->sim.psys, 7112 + seed) * 2.0f - 1.0f) * (float)M_PI;
				float rot[3][3];

				axis_angle_normalized_to_mat3(rot, dir, a);
				mul_m3_v3(rot, kink);
			}

			do_kink_spiral_deform((ParticleKey *)key, dir, kink, spiral_time, kink_freq, kink_shape, kink_amp, spiral_start);
		}

		/* Fill in variant part of modifier context. */
		modifier_ctx.par_co = par_co;
		modifier_ctx.par_vel = par_vel;
		modifier_ctx.par_rot = par_rot;
		modifier_ctx.par_orco = parent_orco;

		/* Apply different deformations to the child path/ */
		do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, par_time);
	}

	totlen = 0.0f;
	for (k = 0, key = keys; k < end_index-1; k++, key++)
		totlen += len_v3v3((key+1)->co, key->co);

	*r_totkeys = end_index;
	*r_max_length = totlen;
}