Exemplo n.º 1
0
/* Traces a shadow through the object, 
 * pretty much gets the transmission over a ray path */
void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
{
	float hitco[3];
	float tr[3] = {1.0,1.0,1.0};
	Isect is;
	float *startco, *endco;
	float density=0.f;

	memset(shr, 0, sizeof(ShadeResult));
	
	/* if 1st hit normal is facing away from the camera, 
	 * then we're inside the volume already. */
	if (shi->flippednor) {
		startco = last_is->start;
		endco = shi->co;
	}
	/* trace to find a backface, the other side bounds of the volume */
	/* (ray intersect ignores front faces here) */
	else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
		startco = shi->co;
		endco = hitco;
	}
	else {
		shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f;
		shr->alpha = shr->combined[3] = 1.f;
		return;
	}
	
	density = vol_get_density(shi, startco);
	vol_get_transmittance(shi, tr, startco, endco);
	
	VecCopyf(shr->combined, tr);
	shr->combined[3] = 1.0f - luminance(tr);
}
Exemplo n.º 2
0
/* Traces a shadow through the object, 
 * pretty much gets the transmission over a ray path */
void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
{
	float hitco[3];
	float tr[3] = {1.0,1.0,1.0};
	Isect is= {{0}};
	float *startco, *endco;
	int intersect_type = VOL_BOUNDS_DEPTH;

	memset(shr, 0, sizeof(ShadeResult));
	
	/* if 1st hit normal is facing away from the camera, 
	 * then we're inside the volume already. */
	if (shi->flippednor) {
		startco = last_is->start;
		endco = shi->co;
		intersect_type = VOL_BOUNDS_SS;
	}
	
	/* trace to find a backface, the other side bounds of the volume */
	/* (ray intersect ignores front faces here) */
	else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, intersect_type)) {
		startco = shi->co;
		endco = hitco;
	}
	else {
		shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f;
		shr->alpha = shr->combined[3] = 1.f;
		return;
	}

	vol_get_transmittance(shi, tr, startco, endco);

	
	/* if we hit another face in the same volume bounds */
	/* shift raytrace coordinates to the hit point, to avoid shading volume twice */
	/* due to idiosyncracy in ray_trace_shadow_tra() */
	if (is.hit.ob == shi->obi) {
		copy_v3_v3(shi->co, hitco);
		last_is->dist -= is.dist;
		shi->vlr = (VlakRen *)is.hit.face;
	}

	
	copy_v3_v3(shr->combined, tr);
	shr->combined[3] = 1.0f - luminance(tr);
	shr->alpha = shr->combined[3];
}
Exemplo n.º 3
0
/* the main entry point for volume shading */
static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume)
{
	float hitco[3], col[4] = {0.f, 0.f, 0.f, 0.f};
	float *startco, *endco;
	int trace_behind = 1;
	const int ztransp = ((shi->depth == 0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP));
	Isect is;

	/* check for shading an internal face a volume object directly */
	if (inside_volume == VOL_SHADE_INSIDE)
		trace_behind = 0;
	else if (inside_volume == VOL_SHADE_OUTSIDE) {
		if (shi->flippednor)
			inside_volume = VOL_SHADE_INSIDE;
	}
	
	if (ztransp && inside_volume == VOL_SHADE_INSIDE) {
		MatInside *mi;
		int render_this = 0;
		
		/* don't render the backfaces of ztransp volume materials.
		 *
		 * volume shading renders the internal volume from between the
		 * ' view intersection of the solid volume to the
		 * intersection on the other side, as part of the shading of
		 * the front face.
		 *
		 * Because ztransp renders both front and back faces independently
		 * this will double up, so here we prevent rendering the backface as well, 
		 * which would otherwise render the volume in between the camera and the backface
		 * --matt */
		
		for (mi = R.render_volumes_inside.first; mi; mi = mi->next) {
			/* weak... */
			if (mi->ma == shi->mat) render_this = 1;
		}
		if (!render_this) return;
	}
	

	if (inside_volume == VOL_SHADE_INSIDE) {
		startco = shi->camera_co;
		endco = shi->co;
		
		if (trace_behind) {
			if (!ztransp)
				/* trace behind the volume object */
				vol_trace_behind(shi, shi->vlr, endco, col);
		}
		else {
			/* we're tracing through the volume between the camera 
			 * and a solid surface, so use that pre-shaded radiance */
			copy_v4_v4(col, shr->combined);
		}
		
		/* shade volume from 'camera' to 1st hit point */
		volumeintegrate(shi, col, startco, endco);
	}
	/* trace to find a backface, the other side bounds of the volume */
	/* (ray intersect ignores front faces here) */
	else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
		VlakRen *vlr = (VlakRen *)is.hit.face;
		
		startco = shi->co;
		endco = hitco;
		
		if (!ztransp) {
			/* if it's another face in the same material */
			if (vlr->mat == shi->mat) {
				/* trace behind the 2nd (raytrace) hit point */
				vol_trace_behind(shi, (VlakRen *)is.hit.face, endco, col);
			}
			else {
				shade_intersection(shi, col, &is);
			}
		}
		
		/* shade volume from 1st hit point to 2nd hit point */
		volumeintegrate(shi, col, startco, endco);
	}
	
	if (ztransp)
		col[3] = col[3] > 1.f ? 1.f : col[3];
	else
		col[3] = 1.f;
	
	copy_v3_v3(shr->combined, col);
	shr->alpha = col[3];
	
	copy_v3_v3(shr->diff, shr->combined);
}
Exemplo n.º 4
0
static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const float view[3], LampRen *lar, float lacol[3])
{
	float visifac, lv[3], lampdist;
	float tr[3] = {1.0, 1.0, 1.0};
	float hitco[3], *atten_co;
	float p, ref_col[3];
	
	if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay) == 0) return;
	if ((lar->lay & shi->lay) == 0) return;
	if (lar->energy == 0.0f) return;
	
	if ((visifac = lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return;
	
	copy_v3_v3(lacol, &lar->r);
	
	if (lar->mode & LA_TEXTURE) {
		shi->osatex = 0;
		do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
	}

	mul_v3_fl(lacol, visifac);

	if (ELEM(lar->type, LA_SUN, LA_HEMI))
		copy_v3_v3(lv, lar->vec);
	negate_v3(lv);
	
	if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) {
		mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
	}
	else if (ELEM3(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) {
		Isect is;
		
		if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) {
			mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
			if (rgb_to_luma_y(lacol) < 0.001f) return;
		}
		
		/* find minimum of volume bounds, or lamp coord */
		if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
			float dist = len_v3v3(co, hitco);
			VlakRen *vlr = (VlakRen *)is.hit.face;
			
			/* simple internal shadowing */
			if (vlr->mat->material_type == MA_TYPE_SURFACE) {
				lacol[0] = lacol[1] = lacol[2] = 0.0f;
				return;
			}

			if (ELEM(lar->type, LA_SUN, LA_HEMI))
				/* infinite lights, can never be inside volume */
				atten_co = hitco;
			else if (lampdist < dist) {
				atten_co = lar->co;
			}
			else
				atten_co = hitco;
			
			vol_get_transmittance(shi, tr, co, atten_co);
			
			mul_v3_v3v3(lacol, lacol, tr);
		}
		else {
			/* Point is on the outside edge of the volume,
			 * therefore no attenuation, full transmission.
			 * Radiance from lamp remains unchanged */
		}
	}
	
	if (rgb_to_luma_y(lacol) < 0.001f) return;
	
	normalize_v3(lv);
	p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv);
	
	/* physically based scattering with non-physically based RGB gain */
	vol_get_reflection_color(shi, ref_col, co);
	
	lacol[0] *= p * ref_col[0];
	lacol[1] *= p * ref_col[1];
	lacol[2] *= p * ref_col[2];
}