예제 #1
0
파일: divers.c 프로젝트: BHCLL/blendocv
/* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */
void IMB_partial_rect_from_float(struct ImBuf *ibuf,float *buffer, int x, int y, int w, int h)
{
	/* indices to source and destination image pixels */
	float *srcFloatPxl;
	unsigned char *dstBytePxl;
	/* buffer index will fill buffer */
	float *bufferIndex;

	/* convenience pointers to start of image buffers */
	float *init_srcFloatPxl = (float *)ibuf->rect_float;
	unsigned char *init_dstBytePxl = (unsigned char *) ibuf->rect;

	/* Dithering factor */
	float dither= ibuf->dither / 255.0f;
	/* respective attributes of image */
	short profile= ibuf->profile;
	int channels= ibuf->channels;
	
	int i, j;
	
	/*
		if called -only- from GPU_paint_update_image this test will never fail
		but leaving it here for better or worse
	*/
	if(init_srcFloatPxl==NULL || (buffer == NULL)){
		return;
	}
	if(init_dstBytePxl==NULL) {
		imb_addrectImBuf(ibuf);
		init_dstBytePxl = (unsigned char *) ibuf->rect;
	}
	if(channels==1) {
			for (j = 0; j < h; j++){
				bufferIndex = buffer + w*j*4;
				dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
				srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x);
				for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl++, bufferIndex+=4) {
					dstBytePxl[1]= dstBytePxl[2]= dstBytePxl[3]= dstBytePxl[0] = FTOCHAR(srcFloatPxl[0]);
					bufferIndex[0] = bufferIndex[1] = bufferIndex[2] = bufferIndex[3] = srcFloatPxl[0];
				}
			}
	}
	else if (profile == IB_PROFILE_LINEAR_RGB) {
		if(channels == 3) {
			for (j = 0; j < h; j++){
				bufferIndex = buffer + w*j*4;
				dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
				srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*3;
				for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=3, bufferIndex += 4) {
					linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl);
					F3TOCHAR4(bufferIndex, dstBytePxl);
					bufferIndex[3]= 1.0;
				}
			}
		}
		else if (channels == 4) {
			if (dither != 0.f) {
				for (j = 0; j < h; j++){
					bufferIndex = buffer + w*j*4;
					dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
					srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
					for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
						const float d = (BLI_frand()-0.5f)*dither;
						linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl);
						bufferIndex[3] = srcFloatPxl[3];
						add_v4_fl(bufferIndex, d);
						F4TOCHAR4(bufferIndex, dstBytePxl);
					}
				}
			} else {
				for (j = 0; j < h; j++){
					bufferIndex = buffer + w*j*4;
					dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
					srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
					for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
						linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl);
						bufferIndex[3]= srcFloatPxl[3];
						F4TOCHAR4(bufferIndex, dstBytePxl);
					}
				}
			}
		}
	}
	else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) {
		if(channels==3) {
			for (j = 0; j < h; j++){
				bufferIndex = buffer + w*j*4;
				dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
				srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*3;
				for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=3, bufferIndex+=4) {
					copy_v3_v3(bufferIndex, srcFloatPxl);
					F3TOCHAR4(bufferIndex, dstBytePxl);
					bufferIndex[3] = 1.0;
				}
			}
		}
		else {
			if (dither != 0.f) {
				for (j = 0; j < h; j++){
					bufferIndex = buffer + w*j*4;
					dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
					srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
					for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
						const float d = (BLI_frand()-0.5f)*dither;
						copy_v4_v4(bufferIndex, srcFloatPxl);
						add_v4_fl(bufferIndex,d);
						F4TOCHAR4(bufferIndex, dstBytePxl);
					}
				}
			} else {
				for (j = 0; j < h; j++){
					bufferIndex = buffer + w*j*4;
					dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
					srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
					for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
						copy_v4_v4(bufferIndex, srcFloatPxl);
						F4TOCHAR4(bufferIndex, dstBytePxl);
					}
				}
			}
		}
	}
	/* ensure user flag is reset */
	ibuf->userflags &= ~IB_RECT_INVALID;
}
예제 #2
0
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                  DerivedMesh *derivedData,
                                  ModifierApplyFlag UNUSED(flag))
{
	DerivedMesh *dm = derivedData, *result;
	ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
	ParticleSimulationData sim;
	ParticleSystem *psys = NULL;
	ParticleData *pa = NULL, *pars = NULL;
	MFace *mface, *orig_mface;
	MVert *mvert, *orig_mvert;
	int i, totvert, totpart = 0, totface, maxvert, maxface, first_particle = 0;
	short track = ob->trackflag % 3, trackneg, axis = pimd->axis;
	float max_co = 0.0, min_co = 0.0, temp_co[3], cross[3];
	float *size = NULL;

	DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */

	trackneg = ((ob->trackflag > 2) ? 1 : 0);

	if (pimd->ob == ob) {
		pimd->ob = NULL;
		return derivedData;
	}

	if (pimd->ob) {
		psys = BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1);
		if (psys == NULL || psys->totpart == 0)
			return derivedData;
	}
	else return derivedData;

	if (pimd->flag & eParticleInstanceFlag_Parents)
		totpart += psys->totpart;
	if (pimd->flag & eParticleInstanceFlag_Children) {
		if (totpart == 0)
			first_particle = psys->totpart;
		totpart += psys->totchild;
	}

	if (totpart == 0)
		return derivedData;

	sim.scene = md->scene;
	sim.ob = pimd->ob;
	sim.psys = psys;
	sim.psmd = psys_get_modifier(pimd->ob, psys);

	if (pimd->flag & eParticleInstanceFlag_UseSize) {
		int p;
		float *si;
		si = size = MEM_callocN(totpart * sizeof(float), "particle size array");

		if (pimd->flag & eParticleInstanceFlag_Parents) {
			for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++)
				*si = pa->size;
		}

		if (pimd->flag & eParticleInstanceFlag_Children) {
			ChildParticle *cpa = psys->child;

			for (p = 0; p < psys->totchild; p++, cpa++, si++) {
				*si = psys_get_child_size(psys, cpa, 0.0f, NULL);
			}
		}
	}

	pars = psys->particles;

	totvert = dm->getNumVerts(dm);
	totface = dm->getNumTessFaces(dm);

	maxvert = totvert * totpart;
	maxface = totface * totpart;

	psys->lattice = psys_get_lattice(&sim);

	if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) {

		float min_r[3], max_r[3];
		INIT_MINMAX(min_r, max_r);
		dm->getMinMax(dm, min_r, max_r);
		min_co = min_r[track];
		max_co = max_r[track];
	}

	result = CDDM_from_template(dm, maxvert, dm->getNumEdges(dm) * totpart, maxface, 0, 0);

	mvert = result->getVertArray(result);
	orig_mvert = dm->getVertArray(dm);

	for (i = 0; i < maxvert; i++) {
		MVert *inMV;
		MVert *mv = mvert + i;
		ParticleKey state;

		inMV = orig_mvert + i % totvert;
		DM_copy_vert_data(dm, result, i % totvert, i, 1);
		*mv = *inMV;

		/*change orientation based on object trackflag*/
		copy_v3_v3(temp_co, mv->co);
		mv->co[axis] = temp_co[track];
		mv->co[(axis + 1) % 3] = temp_co[(track + 1) % 3];
		mv->co[(axis + 2) % 3] = temp_co[(track + 2) % 3];

		if ((psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) &&
		    (pimd->flag & eParticleInstanceFlag_Path))
		{
			float ran = 0.0f;
			if (pimd->random_position != 0.0f) {
				BLI_srandom(psys->seed + (i / totvert) % totpart);
				ran = pimd->random_position * BLI_frand();
			}

			if (pimd->flag & eParticleInstanceFlag_KeepShape) {
				state.time = pimd->position * (1.0f - ran);
			}
			else {
				state.time = (mv->co[axis] - min_co) / (max_co - min_co) * pimd->position * (1.0f - ran);

				if (trackneg)
					state.time = 1.0f - state.time;

				mv->co[axis] = 0.0;
			}

			psys_get_particle_on_path(&sim, first_particle + i / totvert, &state, 1);

			normalize_v3(state.vel);

			/* TODO: incremental rotations somehow */
			if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) {
				state.rot[0] = 1;
				state.rot[1] = state.rot[2] = state.rot[3] = 0.0f;
			}
			else {
				float temp[3] = {0.0f, 0.0f, 0.0f};
				temp[axis] = 1.0f;

				cross_v3_v3v3(cross, temp, state.vel);

				/* state.vel[axis] is the only component surviving from a dot product with the axis */
				axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis]));
			}

		}
		else {
			state.time = -1.0;
			psys_get_particle_state(&sim, first_particle + i / totvert, &state, 1);
		}

		mul_qt_v3(state.rot, mv->co);
		if (pimd->flag & eParticleInstanceFlag_UseSize)
			mul_v3_fl(mv->co, size[i / totvert]);
		add_v3_v3(mv->co, state.co);
	}

	mface = result->getTessFaceArray(result);
	orig_mface = dm->getTessFaceArray(dm);

	for (i = 0; i < maxface; i++) {
		MFace *inMF;
		MFace *mf = mface + i;

		if (pimd->flag & eParticleInstanceFlag_Parents) {
			if (i / totface >= psys->totpart) {
				if (psys->part->childtype == PART_CHILD_PARTICLES) {
					pa = psys->particles + (psys->child + i / totface - psys->totpart)->parent;
				}
				else {
					pa = NULL;
				}
			}
			else {
				pa = pars + i / totface;
			}
		}
		else {
			if (psys->part->childtype == PART_CHILD_PARTICLES) {
				pa = psys->particles + (psys->child + i / totface)->parent;
			}
			else {
				pa = NULL;
			}
		}

		if (pa) {
			if (pa->alive == PARS_UNBORN && (pimd->flag & eParticleInstanceFlag_Unborn) == 0) continue;
			if (pa->alive == PARS_ALIVE && (pimd->flag & eParticleInstanceFlag_Alive) == 0) continue;
			if (pa->alive == PARS_DEAD && (pimd->flag & eParticleInstanceFlag_Dead) == 0) continue;
		}

		inMF = orig_mface + i % totface;
		DM_copy_poly_data(dm, result, i % totface, i, 1);
		*mf = *inMF;

		mf->v1 += (i / totface) * totvert;
		mf->v2 += (i / totface) * totvert;
		mf->v3 += (i / totface) * totvert;
		if (mf->v4) {
			mf->v4 += (i / totface) * totvert;
		}
	}

	CDDM_calc_edges_tessface(result);

	if (psys->lattice) {
		end_latt_deform(psys->lattice);
		psys->lattice = NULL;
	}

	if (size)
		MEM_freeN(size);

	CDDM_tessfaces_to_faces(result); /*builds ngon faces from tess (mface) faces*/
	CDDM_calc_normals(result);

	return result;
}
예제 #3
0
파일: divers.c 프로젝트: BHCLL/blendocv
/* assume converting from linear float to sRGB byte */
void IMB_rect_from_float(struct ImBuf *ibuf)
{
	/* quick method to convert floatbuf to byte */
	float *tof = (float *)ibuf->rect_float;
//	int do_dither = ibuf->dither != 0.f;
	float dither= ibuf->dither / 255.0f;
	float srgb[4];
	int i, channels= ibuf->channels;
	short profile= ibuf->profile;
	unsigned char *to = (unsigned char *) ibuf->rect;
	
	if(tof==NULL) return;
	if(to==NULL) {
		imb_addrectImBuf(ibuf);
		to = (unsigned char *) ibuf->rect;
	}
	
	if(channels==1) {
		for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof++)
			to[1]= to[2]= to[3]= to[0] = FTOCHAR(tof[0]);
	}
	else if (profile == IB_PROFILE_LINEAR_RGB) {
		if(channels == 3) {
			for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) {
				srgb[0]= linearrgb_to_srgb(tof[0]);
				srgb[1]= linearrgb_to_srgb(tof[1]);
				srgb[2]= linearrgb_to_srgb(tof[2]);

				to[0] = FTOCHAR(srgb[0]);
				to[1] = FTOCHAR(srgb[1]);
				to[2] = FTOCHAR(srgb[2]);
				to[3] = 255;
			}
		}
		else if (channels == 4) {
			if (dither != 0.f) {
				for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
					const float d = (BLI_frand()-0.5f)*dither;
					
					srgb[0]= d + linearrgb_to_srgb(tof[0]);
					srgb[1]= d + linearrgb_to_srgb(tof[1]);
					srgb[2]= d + linearrgb_to_srgb(tof[2]);
					srgb[3]= d + tof[3]; 
					
					to[0] = FTOCHAR(srgb[0]);
					to[1] = FTOCHAR(srgb[1]);
					to[2] = FTOCHAR(srgb[2]);
					to[3] = FTOCHAR(srgb[3]);
				}
			} else {
				floatbuf_to_srgb_byte(tof, to, 0, ibuf->x, 0, ibuf->y, ibuf->x);
			}
		}
	}
	else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) {
		if(channels==3) {
			for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) {
				to[0] = FTOCHAR(tof[0]);
				to[1] = FTOCHAR(tof[1]);
				to[2] = FTOCHAR(tof[2]);
				to[3] = 255;
			}
		}
		else {
			if (dither != 0.f) {
				for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
					const float d = (BLI_frand()-0.5f)*dither;
					float col[4];

					col[0]= d + tof[0];
					col[1]= d + tof[1];
					col[2]= d + tof[2];
					col[3]= d + tof[3];

					to[0] = FTOCHAR(col[0]);
					to[1] = FTOCHAR(col[1]);
					to[2] = FTOCHAR(col[2]);
					to[3] = FTOCHAR(col[3]);
				}
			} else {
				for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
					to[0] = FTOCHAR(tof[0]);
					to[1] = FTOCHAR(tof[1]);
					to[2] = FTOCHAR(tof[2]);
					to[3] = FTOCHAR(tof[3]);
				}
			}
		}
	}
	/* ensure user flag is reset */
	ibuf->userflags &= ~IB_RECT_INVALID;
}
예제 #4
0
static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) {
	ParticleThreadContext *ctx= thread->ctx;
	DerivedMesh *dm= ctx->dm;
	float *v1, *v2, *v3, *v4, nor[3], co[3];
	float cur_d, min_d, randu, randv;
	int distr= ctx->distr;
	int i, intersect, tot;
	int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
	
	MFace *mface;
	MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
	
	pa->num = i = ctx->index[p];
	mface = dm->getTessFaceData(dm,i,CD_MFACE);
	
	switch (distr) {
		case PART_DISTR_JIT:
			if (ctx->jitlevel == 1) {
				if (mface->v4)
					psys_uv_to_w(0.5f, 0.5f, mface->v4, pa->fuv);
				else
					psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
			}
			else {
				float offset = fmod(ctx->jitoff[i] + (float)p, (float)ctx->jitlevel);
				if (!isnan(offset)) {
					psys_uv_to_w(ctx->jit[2*(int)offset], ctx->jit[2*(int)offset+1], mface->v4, pa->fuv);
				}
			}
			break;
		case PART_DISTR_RAND:
			randu= BLI_rng_get_float(thread->rng);
			randv= BLI_rng_get_float(thread->rng);
			rng_skip_tot -= 2;
			
			psys_uv_to_w(randu, randv, mface->v4, pa->fuv);
			break;
	}
	pa->foffset= 0.0f;
	
	/* experimental */
	tot=dm->getNumTessFaces(dm);
	
	psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0);
	
	normalize_v3(nor);
	negate_v3(nor);
	
	min_d=FLT_MAX;
	intersect=0;
	
	for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
		if (i==pa->num) continue;
		
		v1=mvert[mface->v1].co;
		v2=mvert[mface->v2].co;
		v3=mvert[mface->v3].co;
		
		if (isect_ray_tri_v3(co, nor, v2, v3, v1, &cur_d, NULL)) {
			if (cur_d<min_d) {
				min_d=cur_d;
				pa->foffset=cur_d*0.5f; /* to the middle of volume */
				intersect=1;
			}
		}
		if (mface->v4) {
			v4=mvert[mface->v4].co;
			
			if (isect_ray_tri_v3(co, nor, v4, v1, v3, &cur_d, NULL)) {
				if (cur_d<min_d) {
					min_d=cur_d;
					pa->foffset=cur_d*0.5f; /* to the middle of volume */
					intersect=1;
				}
			}
		}
	}
	if (intersect==0)
		pa->foffset=0.0;
	else {
		switch (distr) {
			case PART_DISTR_JIT:
				pa->foffset *= ctx->jit[p % (2 * ctx->jitlevel)];
				break;
			case PART_DISTR_RAND:
				pa->foffset *= BLI_frand();
				break;
		}
	}
	
	if (rng_skip_tot > 0) /* should never be below zero */
		BLI_rng_skip(thread->rng, rng_skip_tot);
}
예제 #5
0
파일: boids.c 프로젝트: mik0001/Blender
static int rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, ParticleData *pa)
{
	BoidRuleFight *fbr = (BoidRuleFight*)rule;
	KDTreeNearest *ptn = NULL;
	ParticleTarget *pt;
	ParticleData *epars;
	ParticleData *enemy_pa = NULL;
	BoidParticle *bpa;
	/* friends & enemies */
	float closest_enemy[3] = {0.0f,0.0f,0.0f};
	float closest_dist = fbr->distance + 1.0f;
	float f_strength = 0.0f, e_strength = 0.0f;
	float health = 0.0f;
	int n, ret = 0;

	/* calculate own group strength */
	int neighbors = BLI_kdtree_range_search(bbd->sim->psys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn);
	for(n=0; n<neighbors; n++) {
		bpa = bbd->sim->psys->particles[ptn[n].index].boid;
		health += bpa->data.health;
	}

	f_strength += bbd->part->boids->strength * health;

	if(ptn){ MEM_freeN(ptn); ptn=NULL; }

	/* add other friendlies and calculate enemy strength and find closest enemy */
	for(pt=bbd->sim->psys->targets.first; pt; pt=pt->next) {
		ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
		if(epsys) {
			epars = epsys->particles;

			neighbors = BLI_kdtree_range_search(epsys->tree, fbr->distance, pa->prev_state.co, NULL, &ptn);
			
			health = 0.0f;

			for(n=0; n<neighbors; n++) {
				bpa = epars[ptn[n].index].boid;
				health += bpa->data.health;

				if(n==0 && pt->mode==PTARGET_MODE_ENEMY && ptn[n].dist < closest_dist) {
					copy_v3_v3(closest_enemy, ptn[n].co);
					closest_dist = ptn[n].dist;
					enemy_pa = epars + ptn[n].index;
				}
			}
			if(pt->mode==PTARGET_MODE_ENEMY)
				e_strength += epsys->part->boids->strength * health;
			else if(pt->mode==PTARGET_MODE_FRIEND)
				f_strength += epsys->part->boids->strength * health;

			if(ptn){ MEM_freeN(ptn); ptn=NULL; }
		}
	}
	/* decide action if enemy presence found */
	if(e_strength > 0.0f) {
		sub_v3_v3v3(bbd->wanted_co, closest_enemy, pa->prev_state.co);

		/* attack if in range */
		if(closest_dist <= bbd->part->boids->range + pa->size + enemy_pa->size) {
			float damage = BLI_frand();
			float enemy_dir[3];

			normalize_v3_v3(enemy_dir, bbd->wanted_co);

			/* fight mode */
			bbd->wanted_speed = 0.0f;

			/* must face enemy to fight */
			if(dot_v3v3(pa->prev_state.ave, enemy_dir)>0.5f) {
				bpa = enemy_pa->boid;
				bpa->data.health -= bbd->part->boids->strength * bbd->timestep * ((1.0f-bbd->part->boids->accuracy)*damage + bbd->part->boids->accuracy);
			}
		}
		else {
			/* approach mode */
			bbd->wanted_speed = val->max_speed;
		}

		/* check if boid doesn't want to fight */
		bpa = pa->boid;
		if(bpa->data.health/bbd->part->boids->health * bbd->part->boids->aggression < e_strength / f_strength) {
			/* decide to flee */
			if(closest_dist < fbr->flee_distance * fbr->distance) {
				negate_v3(bbd->wanted_co);
				bbd->wanted_speed = val->max_speed;
			}
			else { /* wait for better odds */
				bbd->wanted_speed = 0.0f;
			}
		}

		ret = 1;
	}

	return ret;
}
예제 #6
0
파일: boids.c 프로젝트: mik0001/Blender
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;
}
예제 #7
0
파일: boids.c 프로젝트: mik0001/Blender
/* tries to realize the wanted velocity taking all constraints into account */
void boid_body(BoidBrainData *bbd, ParticleData *pa)
{
	BoidSettings *boids = bbd->part->boids;
	BoidParticle *bpa = pa->boid;
	BoidValues val;
	EffectedPoint epoint;
	float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3];
	float dvec[3], bvec[3];
	float new_dir[3], new_speed;
	float old_dir[3], old_speed;
	float wanted_dir[3];
	float q[4], mat[3][3]; /* rotation */
	float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f};
	float force[3] = {0.0f, 0.0f, 0.0f};
	float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep;

	set_boid_values(&val, boids, pa);

	/* make sure there's something in new velocity, location & rotation */
	copy_particle_key(&pa->state,&pa->prev_state,0);

	if(bbd->part->flag & PART_SIZEMASS)
		pa_mass*=pa->size;

	/* if boids can't fly they fall to the ground */
	if((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && psys_uses_gravity(bbd->sim))
		bpa->data.mode = eBoidMode_Falling;

	if(bpa->data.mode == eBoidMode_Falling) {
		/* Falling boids are only effected by gravity. */
		acc[2] = bbd->sim->scene->physics_settings.gravity[2];
	}
	else {
		/* figure out acceleration */
		float landing_level = 2.0f;
		float level = landing_level + 1.0f;
		float new_vel[3];

		if(bpa->data.mode == eBoidMode_Liftoff) {
			bpa->data.mode = eBoidMode_InAir;
			bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
		}
		else if(bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) {
			/* auto-leveling & landing if close to ground */

			bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);
			
			/* level = how many particle sizes above ground */
			level = (pa->prev_state.co[2] - ground_co[2])/(2.0f * pa->size) - 0.5f;

			landing_level = - boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass;

			if(pa->prev_state.vel[2] < 0.0f) {
				if(level < 1.0f) {
					bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f;
					bbd->wanted_speed = 0.0f;
					bpa->data.mode = eBoidMode_Falling;
				}
				else if(level < landing_level) {
					bbd->wanted_speed *= (level - 1.0f)/landing_level;
					bbd->wanted_co[2] *= (level - 1.0f)/landing_level;
				}
			}
		}

		copy_v3_v3(old_dir, pa->prev_state.ave);
		new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co);

		/* first check if we have valid direction we want to go towards */
		if(new_speed == 0.0f) {
			copy_v3_v3(new_dir, old_dir);
		}
		else {
			float old_dir2[2], wanted_dir2[2], nor[3], angle;
			copy_v2_v2(old_dir2, old_dir);
			normalize_v2(old_dir2);
			copy_v2_v2(wanted_dir2, wanted_dir);
			normalize_v2(wanted_dir2);

			/* choose random direction to turn if wanted velocity */
			/* is directly behind regardless of z-coordinate */
			if(dot_v2v2(old_dir2, wanted_dir2) < -0.99f) {
				wanted_dir[0] = 2.0f*(0.5f - BLI_frand());
				wanted_dir[1] = 2.0f*(0.5f - BLI_frand());
				wanted_dir[2] = 2.0f*(0.5f - BLI_frand());
				normalize_v3(wanted_dir);
			}

			/* constrain direction with maximum angular velocity */
			angle = saacos(dot_v3v3(old_dir, wanted_dir));
			angle = MIN2(angle, val.max_ave);

			cross_v3_v3v3(nor, old_dir, wanted_dir);
			axis_angle_to_quat( q,nor, angle);
			copy_v3_v3(new_dir, old_dir);
			mul_qt_v3(q, new_dir);
			normalize_v3(new_dir);

			/* save direction in case resulting velocity too small */
			axis_angle_to_quat( q,nor, angle*dtime);
			copy_v3_v3(pa->state.ave, old_dir);
			mul_qt_v3(q, pa->state.ave);
			normalize_v3(pa->state.ave);
		}

		/* constrain speed with maximum acceleration */
		old_speed = len_v3(pa->prev_state.vel);
		
		if(bbd->wanted_speed < old_speed)
			new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc);
		else
			new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc);

		/* combine direction and speed */
		copy_v3_v3(new_vel, new_dir);
		mul_v3_fl(new_vel, new_speed);

		/* maintain minimum flying velocity if not landing */
		if(level >= landing_level) {
			float len2 = dot_v2v2(new_vel,new_vel);
			float root;

			len2 = MAX2(len2, val.min_speed*val.min_speed);
			root = sasqrt(new_speed*new_speed - len2);

			new_vel[2] = new_vel[2] < 0.0f ? -root : root;

			normalize_v2(new_vel);
			mul_v2_fl(new_vel, sasqrt(len2));
		}

		/* finally constrain speed to max speed */
		new_speed = normalize_v3(new_vel);
		mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed));

		/* get acceleration from difference of velocities */
		sub_v3_v3v3(acc, new_vel, pa->prev_state.vel);

		/* break acceleration to components */
		project_v3_v3v3(tan_acc, acc, pa->prev_state.ave);
		sub_v3_v3v3(nor_acc, acc, tan_acc);
	}

	/* account for effectors */
	pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
	pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);

	if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
		float length = normalize_v3(force);

		length = MAX2(0.0f, length - boids->land_stick_force);

		mul_v3_fl(force, length);
	}
	
	add_v3_v3(acc, force);

	/* store smoothed acceleration for nice banking etc. */
	madd_v3_v3fl(bpa->data.acc, acc, dtime);
	mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime));

	/* integrate new location & velocity */

	/* by regarding the acceleration as a force at this stage we*/
	/* can get better control allthough it's a bit unphysical	*/
	mul_v3_fl(acc, 1.0f/pa_mass);

	copy_v3_v3(dvec, acc);
	mul_v3_fl(dvec, dtime*dtime*0.5f);
	
	copy_v3_v3(bvec, pa->prev_state.vel);
	mul_v3_fl(bvec, dtime);
	add_v3_v3(dvec, bvec);
	add_v3_v3(pa->state.co, dvec);

	madd_v3_v3fl(pa->state.vel, acc, dtime);

	//if(bpa->data.mode != eBoidMode_InAir)
	bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor);

	/* change modes, constrain movement & keep track of down vector */
	switch(bpa->data.mode) {
		case eBoidMode_InAir:
		{
			float grav[3];

			grav[0]= 0.0f;
			grav[1]= 0.0f;
			grav[2]= bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;

			/* don't take forward acceleration into account (better banking) */
			if(dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) {
				project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
				sub_v3_v3v3(dvec, bpa->data.acc, dvec);
			}
			else {
				copy_v3_v3(dvec, bpa->data.acc);
			}

			/* gather apparent gravity */
			madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
			normalize_v3(bpa->gravity);

			/* stick boid on goal when close enough */
			if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
				bpa->data.mode = eBoidMode_Climbing;
				bpa->ground = bbd->goal_ob;
				boid_find_ground(bbd, pa, ground_co, ground_nor);
				boid_climb(boids, pa, ground_co, ground_nor);
			}
			else if(pa->state.co[2] <= ground_co[2] + pa->size * boids->height) {
				/* land boid when below ground */
				if(boids->options & BOID_ALLOW_LAND) {
					pa->state.co[2] = ground_co[2] + pa->size * boids->height;
					pa->state.vel[2] = 0.0f;
					bpa->data.mode = eBoidMode_OnLand;
				}
				/* fly above ground */
				else if(bpa->ground) {
					pa->state.co[2] = ground_co[2] + pa->size * boids->height;
					pa->state.vel[2] = 0.0f;
				}
			}
			break;
		}
		case eBoidMode_Falling:
		{
			float grav[3];

			grav[0]= 0.0f;
			grav[1]= 0.0f;
			grav[2]= bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f;


			/* gather apparent gravity */
			madd_v3_v3fl(bpa->gravity, grav, dtime);
			normalize_v3(bpa->gravity);

			if(boids->options & BOID_ALLOW_LAND) {
				/* stick boid on goal when close enough */
				if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
					bpa->data.mode = eBoidMode_Climbing;
					bpa->ground = bbd->goal_ob;
					boid_find_ground(bbd, pa, ground_co, ground_nor);
					boid_climb(boids, pa, ground_co, ground_nor);
				}
				/* land boid when really near ground */
				else if(pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height){
					pa->state.co[2] = ground_co[2] + pa->size * boids->height;
					pa->state.vel[2] = 0.0f;
					bpa->data.mode = eBoidMode_OnLand;
				}
				/* if we're falling, can fly and want to go upwards lets fly */
				else if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f)
					bpa->data.mode = eBoidMode_InAir;
			}
			else
				bpa->data.mode = eBoidMode_InAir;
			break;
		}
		case eBoidMode_Climbing:
		{
			boid_climb(boids, pa, ground_co, ground_nor);
			//float nor[3];
			//copy_v3_v3(nor, ground_nor);

			///* gather apparent gravity to r_ve */
			//madd_v3_v3fl(pa->r_ve, ground_nor, -1.0);
			//normalize_v3(pa->r_ve);

			///* raise boid it's size from surface */
			//mul_v3_fl(nor, pa->size * boids->height);
			//add_v3_v3v3(pa->state.co, ground_co, nor);

			///* remove normal component from velocity */
			//project_v3_v3v3(v, pa->state.vel, ground_nor);
			//sub_v3_v3v3(pa->state.vel, pa->state.vel, v);
			break;
		}
		case eBoidMode_OnLand:
		{
			/* stick boid on goal when close enough */
			if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) {
				bpa->data.mode = eBoidMode_Climbing;
				bpa->ground = bbd->goal_ob;
				boid_find_ground(bbd, pa, ground_co, ground_nor);
				boid_climb(boids, pa, ground_co, ground_nor);
			}
			/* ground is too far away so boid falls */
			else if(pa->state.co[2]-ground_co[2] > 1.1f * pa->size * boids->height)
				bpa->data.mode = eBoidMode_Falling;
			else {
				/* constrain to surface */
				pa->state.co[2] = ground_co[2] + pa->size * boids->height;
				pa->state.vel[2] = 0.0f;
			}

			if(boids->banking > 0.0f) {
				float grav[3];
				/* Don't take gravity's strength in to account, */
				/* otherwise amount of banking is hard to control. */
				negate_v3_v3(grav, ground_nor);

				project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel);
				sub_v3_v3v3(dvec, bpa->data.acc, dvec);

				/* gather apparent gravity */
				madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking);
				normalize_v3(bpa->gravity);
			}
			else {
				/* gather negative surface normal */
				madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f);
				normalize_v3(bpa->gravity);
			}
			break;
		}
	}

	/* save direction to state.ave unless the boid is falling */
	/* (boids can't effect their direction when falling) */
	if(bpa->data.mode!=eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f*pa->size) {
		copy_v3_v3(pa->state.ave, pa->state.vel);
		pa->state.ave[2] *= bbd->part->boids->pitch;
		normalize_v3(pa->state.ave);
	}

	/* apply damping */
	if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing))
		mul_v3_fl(pa->state.vel, 1.0f - 0.2f*bbd->part->dampfac);

	/* calculate rotation matrix based on forward & down vectors */
	if(bpa->data.mode == eBoidMode_InAir) {
		copy_v3_v3(mat[0], pa->state.ave);

		project_v3_v3v3(dvec, bpa->gravity, pa->state.ave);
		sub_v3_v3v3(mat[2], bpa->gravity, dvec);
		normalize_v3(mat[2]);
	}
	else {
		project_v3_v3v3(dvec, pa->state.ave, bpa->gravity);
		sub_v3_v3v3(mat[0], pa->state.ave, dvec);
		normalize_v3(mat[0]);

		copy_v3_v3(mat[2], bpa->gravity);
	}
	negate_v3(mat[2]);
	cross_v3_v3v3(mat[1], mat[2], mat[0]);
	
	/* apply rotation */
	mat3_to_quat_is_ok( q,mat);
	copy_qt_qt(pa->state.rot, q);
}