Exemplo n.º 1
0
static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz)
{
	int x, y, z, x_, y_, z_;
	int added=0;
	float tot=0.0f;
	
	for (z=-1; z <= 1; z++) {
		z_ = zz+z;
		if (z_ >= 0 && z_ <= res[2]-1) {
		
			for (y=-1; y <= 1; y++) {
				y_ = yy+y;
				if (y_ >= 0 && y_ <= res[1]-1) {
				
					for (x=-1; x <= 1; x++) {
						x_ = xx+x;
						if (x_ >= 0 && x_ <= res[0]-1) {
						
							if (cache[ V_I(x_, y_, z_, res) ] > 0.0f) {
								tot += cache[ V_I(x_, y_, z_, res) ];
								added++;
							}
							
						}
					}
				}
			}
		}
	}
	
	if (added > 0) tot /= added;
	
	return tot;
}
Exemplo n.º 2
0
vec_t mat_vmult(const mat_t *a, vec_t b){
	vec_t r;
	int i = 4;
	while(i--){
		V_I(r,i) = vec_wdot(mat_get_row(i,a),b);
	}
	return r;
}
Exemplo n.º 3
0
static void load_frame_image_sequence(VoxelData *vd, Tex *tex)
{
	ImBuf *ibuf;
	Image *ima = tex->ima;
	ImageUser *tiuser = &tex->iuser;
	ImageUser iuser = *(tiuser);
	int x=0, y=0, z=0;
	float *rf;

	if (!ima || !tiuser) return;
	if (iuser.frames == 0) return;
	
	ima->source = IMA_SRC_SEQUENCE;
	iuser.framenr = 1 + iuser.offset;

	/* find the first valid ibuf and use it to initialise the resolution of the data set */
	/* need to do this in advance so we know how much memory to allocate */
	ibuf= BKE_image_get_ibuf(ima, &iuser);
	while (!ibuf && (iuser.framenr < iuser.frames)) {
		iuser.framenr++;
		ibuf= BKE_image_get_ibuf(ima, &iuser);
	}
	if (!ibuf) return;
	if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
	
	vd->flag |= TEX_VD_STILL;
	vd->resol[0] = ibuf->x;
	vd->resol[1] = ibuf->y;
	vd->resol[2] = iuser.frames;
	vd->dataset = MEM_mapallocN(sizeof(float)*vd_resol_size(vd), "voxel dataset");
	
	for (z=0; z < iuser.frames; z++)
	{	
		/* get a new ibuf for each frame */
		if (z > 0) {
			iuser.framenr++;
			ibuf= BKE_image_get_ibuf(ima, &iuser);
			if (!ibuf) break;
			if (!ibuf->rect_float) IMB_float_from_rect(ibuf);
		}
		rf = ibuf->rect_float;
		
		for (y=0; y < ibuf->y; y++)
		{
			for (x=0; x < ibuf->x; x++)
			{
				/* currently averaged to monchrome */
				vd->dataset[ V_I(x, y, z, vd->resol) ] = (rf[0] + rf[1] + rf[2])*0.333f;
				rf +=4;
			}
		}
		
		BKE_image_free_anim_ibufs(ima, iuser.framenr);
	}
	
	vd->ok = 1;
	return;
}
Exemplo n.º 4
0
/* get the total amount of light energy in the light cache. used to normalise after multiple scattering */
static float total_ss_energy(VolumePrecache *vp)
{
	int x, y, z;
	int *res = vp->res;
	float energy=0.f;
	
	for (z=0; z < res[2]; z++) {
		for (y=0; y < res[1]; y++) {
			for (x=0; x < res[0]; x++) {
				if (vp->data_r[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_r[ V_I(x, y, z, res) ];
				if (vp->data_g[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_g[ V_I(x, y, z, res) ];
				if (vp->data_b[ V_I(x, y, z, res) ] > 0.f) energy += vp->data_b[ V_I(x, y, z, res) ];
			}
		}
	}
	
	return energy;
}
Exemplo n.º 5
0
/* function to filter the edges of the light cache, where there was no volume originally.
 * For each voxel which was originally external to the mesh, it finds the average values of
 * the surrounding internal voxels and sets the original external voxel to that average amount.
 * Works almost a bit like a 'dilate' filter */
static void lightcache_filter(VolumePrecache *vp)
{
	int x, y, z;

	for (z=0; z < vp->res[2]; z++) {
		for (y=0; y < vp->res[1]; y++) {
			for (x=0; x < vp->res[0]; x++) {
				/* trigger for outside mesh */
				if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.f)
					vp->data_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
				if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.f)
					vp->data_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
				if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.f)
					vp->data_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
			}
		}
	}
}
Exemplo n.º 6
0
/* Iterate over the 3d voxel grid, and fill the voxels with scattering information
 *
 * It's stored in memory as 3 big float grids next to each other, one for each RGB channel.
 * I'm guessing the memory alignment may work out better this way for the purposes
 * of doing linear interpolation, but I haven't actually tested this theory! :)
 */
static void *vol_precache_part(void *data)
{
	VolPrecachePart *pa =  (VolPrecachePart *)data;
	ObjectInstanceRen *obi = pa->obi;
	RayObject *tree = pa->tree;
	ShadeInput *shi = pa->shi;
	float scatter_col[3] = {0.f, 0.f, 0.f};
	float co[3];
	int x, y, z;
	const int res[3]= {pa->res[0], pa->res[1], pa->res[2]};

	for (z= pa->minz; z < pa->maxz; z++) {
		co[2] = pa->bbmin[2] + (pa->voxel[2] * (z + 0.5f));
		
		for (y= pa->miny; y < pa->maxy; y++) {
			co[1] = pa->bbmin[1] + (pa->voxel[1] * (y + 0.5f));
			
			for (x=pa->minx; x < pa->maxx; x++) {
				co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f));
				
				// don't bother if the point is not inside the volume mesh
				if (!point_inside_obi(tree, obi, co)) {
					obi->volume_precache->data_r[ V_I(x, y, z, res) ] = -1.0f;
					obi->volume_precache->data_g[ V_I(x, y, z, res) ] = -1.0f;
					obi->volume_precache->data_b[ V_I(x, y, z, res) ] = -1.0f;
					continue;
				}
				
				VecCopyf(shi->view, co);
				Normalize(shi->view);
				vol_get_scattering(shi, scatter_col, co);
			
				obi->volume_precache->data_r[ V_I(x, y, z, res) ] = scatter_col[0];
				obi->volume_precache->data_g[ V_I(x, y, z, res) ] = scatter_col[1];
				obi->volume_precache->data_b[ V_I(x, y, z, res) ] = scatter_col[2];
			}
		}
	}
	
	pa->done = 1;
	
	return 0;
}
Exemplo n.º 7
0
static void lightcache_filter2(VolumePrecache *vp)
{
	int x, y, z;
	float *new_r, *new_g, *new_b;
	int field_size = vp->res[0]*vp->res[1]*vp->res[2]*sizeof(float);
	
	new_r = MEM_mallocN(field_size, "temp buffer for light cache filter r channel");
	new_g = MEM_mallocN(field_size, "temp buffer for light cache filter g channel");
	new_b = MEM_mallocN(field_size, "temp buffer for light cache filter b channel");
	
	memcpy(new_r, vp->data_r, field_size);
	memcpy(new_g, vp->data_g, field_size);
	memcpy(new_b, vp->data_b, field_size);
	
	for (z=0; z < vp->res[2]; z++) {
		for (y=0; y < vp->res[1]; y++) {
			for (x=0; x < vp->res[0]; x++) {
				/* trigger for outside mesh */
				if (vp->data_r[ V_I(x, y, z, vp->res) ] < -0.f)
					new_r[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
				if (vp->data_g[ V_I(x, y, z, vp->res) ] < -0.f)
					new_g[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_g, vp->res, x, y, z);
				if (vp->data_b[ V_I(x, y, z, vp->res) ] < -0.f)
					new_b[ V_I(x, y, z, vp->res) ] = get_avg_surrounds(vp->data_b, vp->res, x, y, z);
			}
		}
	}
	
	SWAP(float *, vp->data_r, new_r);
	SWAP(float *, vp->data_g, new_g);
	SWAP(float *, vp->data_b, new_b);
	
	if (new_r) { MEM_freeN(new_r); new_r=NULL; }
	if (new_g) { MEM_freeN(new_g); new_g=NULL; }
	if (new_b) { MEM_freeN(new_b); new_b=NULL; }
}
Exemplo n.º 8
0
void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Material *ma)
{
	const float diff = ma->vol.ms_diff * 0.001f; 	/* compensate for scaling for a nicer UI range */
	const float simframes = ma->vol.ms_steps;
	const int shade_type = ma->vol.shade_type;
	float fac = ma->vol.ms_intensity;
	
	int x, y, z, m;
	int *n = vp->res;
	const int size = (n[0]+2)*(n[1]+2)*(n[2]+2);
	double time, lasttime= PIL_check_seconds_timer();
	float total;
	float c=1.0f;
	int i;
	float origf;	/* factor for blending in original light cache */
	float energy_ss, energy_ms;

	float *sr0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
	float *sr=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
	float *sg0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
	float *sg=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
	float *sb0=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");
	float *sb=(float *)MEM_callocN(size*sizeof(float), "temporary multiple scattering buffer");

	total = (float)(n[0]*n[1]*n[2]*simframes);
	
	energy_ss = total_ss_energy(vp);
	
	/* Scattering as diffusion pass */
	for (m=0; m<simframes; m++)
	{
		/* add sources */
		for (z=1; z<=n[2]; z++)
		{
			for (y=1; y<=n[1]; y++)
			{
				for (x=1; x<=n[0]; x++)
				{
					i = V_I((x-1), (y-1), (z-1), n);
					time= PIL_check_seconds_timer();
					c++;
										
					if (vp->data_r[i] > 0.f)
						sr[ms_I(x,y,z,n)] += vp->data_r[i];
					if (vp->data_g[i] > 0.f)
						sg[ms_I(x,y,z,n)] += vp->data_g[i];
					if (vp->data_b[i] > 0.f)
						sb[ms_I(x,y,z,n)] += vp->data_b[i];
					
					/* Displays progress every second */
					if(time-lasttime>1.0f) {
						char str[64];
						sprintf(str, "Simulating multiple scattering: %d%%", (int)
								(100.0f * (c / total)));
						re->i.infostr= str;
						re->stats_draw(re->sdh, &re->i);
						re->i.infostr= NULL;
						lasttime= time;
					}
				}
			}
		}
		SWAP(float *, sr, sr0);
		SWAP(float *, sg, sg0);
		SWAP(float *, sb, sb0);

		/* main diffusion simulation */
		ms_diffuse(0, sr0, sr, diff, n);
		ms_diffuse(0, sg0, sg, diff, n);
		ms_diffuse(0, sb0, sb, diff, n);
		
		if (re->test_break(re->tbh)) break;
	}
	
	/* normalisation factor to conserve energy */
	energy_ms = total_ms_energy(sr, sg, sb, n);
	fac *= (energy_ss / energy_ms);
	
	/* blend multiple scattering back in the light cache */
	if (shade_type == MA_VOL_SHADE_SHADEDPLUSMULTIPLE) {
		/* conserve energy - half single, half multiple */
		origf = 0.5f;
		fac *= 0.5f;
	} else {
		origf = 0.0f;
	}

	for (z=1;z<=n[2];z++)
	{
		for (y=1;y<=n[1];y++)
		{
			for (x=1;x<=n[0];x++)
			{
				int index=(x-1)*n[1]*n[2] + (y-1)*n[2] + z-1;
				vp->data_r[index] = origf * vp->data_r[index] + fac * sr[ms_I(x,y,z,n)];
				vp->data_g[index] = origf * vp->data_g[index] + fac * sg[ms_I(x,y,z,n)];
				vp->data_b[index] = origf * vp->data_b[index] + fac * sb[ms_I(x,y,z,n)];
			}
		}
	}

	MEM_freeN(sr0);
	MEM_freeN(sr);
	MEM_freeN(sg0);
	MEM_freeN(sg);
	MEM_freeN(sb0);
	MEM_freeN(sb);
}