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 = {{0}};
	float *startco, *endco;

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

	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 - rgb_to_luma_y(tr);
	shr->alpha = shr->combined[3];
}
Exemplo n.º 2
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];
}
Exemplo n.º 3
0
/* For ease of use, I've also introduced a 'reflection' and 'reflection color' parameter, which isn't 
 * physically correct. This works as an RGB tint/gain on out-scattered light, but doesn't affect the light 
 * that is transmitted through the volume. While having wavelength dependent absorption/scattering is more correct,
 * it also makes it harder to control the overall look of the volume since coloring the outscattered light results
 * in the inverse color being transmitted through the rest of the volume.
 */
static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co[3], const float endco[3])
{
	float radiance[3] = {0.f, 0.f, 0.f};
	float tr[3] = {1.f, 1.f, 1.f};
	float p[3] = {co[0], co[1], co[2]};
	float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
	const float stepsize = shi->mat->vol.stepsize;
	
	float t0 = 0.f;
	float pt0 = t0;
	float t1 = normalize_v3(step_vec);  /* returns vector length */
	
	t0 += stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
	p[0] += t0 * step_vec[0];
	p[1] += t0 * step_vec[1];
	p[2] += t0 * step_vec[2];
	mul_v3_fl(step_vec, stepsize);
	
	for (; t0 < t1; pt0 = t0, t0 += stepsize) {
		const float density = vol_get_density(shi, p);
		
		if (density > 0.00001f) {
			float scatter_col[3] = {0.f, 0.f, 0.f}, emit_col[3];
			const float stepd = (t0 - pt0) * density;
			
			/* transmittance component (alpha) */
			vol_get_transmittance_seg(shi, tr, stepsize, co, density);
			
			if (t0 > t1 * 0.25f) {
				/* only use depth cutoff after we've traced a little way into the volume */
				if (rgb_to_luma_y(tr) < shi->mat->vol.depth_cutoff) break;
			}
			
			vol_get_emission(shi, emit_col, p);
			
			if (shi->obi->volume_precache) {
				float p2[3];
				
				p2[0] = p[0] + (step_vec[0] * 0.5f);
				p2[1] = p[1] + (step_vec[1] * 0.5f);
				p2[2] = p[2] + (step_vec[2] * 0.5f);
				
				vol_get_precached_scattering(&R, shi, scatter_col, p2);
			}
			else
				vol_get_scattering(shi, scatter_col, p, shi->view);
			
			radiance[0] += stepd * tr[0] * (emit_col[0] + scatter_col[0]);
			radiance[1] += stepd * tr[1] * (emit_col[1] + scatter_col[1]);
			radiance[2] += stepd * tr[2] * (emit_col[2] + scatter_col[2]);
		}
		add_v3_v3(p, step_vec);
	}
	
	/* multiply original color (from behind volume) with transmittance over entire distance */
	mul_v3_v3v3(col, tr, col);
	add_v3_v3(col, radiance);
	
	/* alpha <-- transmission luminance */
	col[3] = 1.0f - rgb_to_luma_y(tr);
}
void ColorCorrectionOperation::executePixel(float *output, float x, float y, PixelSampler sampler)
{
	float inputImageColor[4];
	float inputMask[4];
	this->m_inputImage->read(inputImageColor, x, y, sampler);
	this->m_inputMask->read(inputMask, x, y, sampler);
	
	float level = (inputImageColor[0] + inputImageColor[1] + inputImageColor[2]) / 3.0f;
	float contrast = this->m_data->master.contrast;
	float saturation = this->m_data->master.saturation;
	float gamma = this->m_data->master.gamma;
	float gain = this->m_data->master.gain;
	float lift = this->m_data->master.lift;
	float r, g, b;
	
	float value = inputMask[0];
	value = min(1.0f, value);
	const float mvalue = 1.0f - value;
	
	float levelShadows = 0.0;
	float levelMidtones = 0.0;
	float levelHighlights = 0.0;
#define MARGIN 0.10f
#define MARGIN_DIV (0.5f / MARGIN)
	if (level < this->m_data->startmidtones - MARGIN) {
		levelShadows = 1.0f;
	}
	else if (level < this->m_data->startmidtones + MARGIN) {
		levelMidtones = ((level - this->m_data->startmidtones) * MARGIN_DIV) + 0.5f;
		levelShadows = 1.0f - levelMidtones;
	}
	else if (level < this->m_data->endmidtones - MARGIN) {
		levelMidtones = 1.0f;
	}
	else if (level < this->m_data->endmidtones + MARGIN) {
		levelHighlights = ((level - this->m_data->endmidtones) * MARGIN_DIV) + 0.5f;
		levelMidtones = 1.0f - levelHighlights;
	}
	else {
		levelHighlights = 1.0f;
	}
#undef MARGIN
#undef MARGIN_DIV
	contrast *= (levelShadows * this->m_data->shadows.contrast) + (levelMidtones * this->m_data->midtones.contrast) + (levelHighlights * this->m_data->highlights.contrast);
	saturation *= (levelShadows * this->m_data->shadows.saturation) + (levelMidtones * this->m_data->midtones.saturation) + (levelHighlights * this->m_data->highlights.saturation);
	gamma *= (levelShadows * this->m_data->shadows.gamma) + (levelMidtones * this->m_data->midtones.gamma) + (levelHighlights * this->m_data->highlights.gamma);
	gain *= (levelShadows * this->m_data->shadows.gain) + (levelMidtones * this->m_data->midtones.gain) + (levelHighlights * this->m_data->highlights.gain);
	lift += (levelShadows * this->m_data->shadows.lift) + (levelMidtones * this->m_data->midtones.lift) + (levelHighlights * this->m_data->highlights.lift);
	
	float invgamma = 1.0f / gamma;
	float luma = rgb_to_luma_y(inputImageColor);

	r = inputImageColor[0];
	g = inputImageColor[1];
	b = inputImageColor[2];

	r = (luma + saturation * (r - luma));
	g = (luma + saturation * (g - luma));
	b = (luma + saturation * (b - luma));
	
	r = 0.5f + ((r - 0.5f) * contrast);
	g = 0.5f + ((g - 0.5f) * contrast);
	b = 0.5f + ((b - 0.5f) * contrast);
	
	r = powf(r * gain + lift, invgamma);
	g = powf(g * gain + lift, invgamma);
	b = powf(b * gain + lift, invgamma);
	
	
	// mix with mask
	r = mvalue * inputImageColor[0] + value * r;
	g = mvalue * inputImageColor[1] + value * g;
	b = mvalue * inputImageColor[2] + value * b;
	
	if (this->m_redChannelEnabled) {
		output[0] = r;
	}
	else {
		output[0] = inputImageColor[0];
	}
	if (this->m_greenChannelEnabled) {
		output[1] = g;
	}
	else {
		output[1] = inputImageColor[1];
	}
	if (this->m_blueChannelEnabled) {
		output[2] = b;
	}
	else {
		output[2] = inputImageColor[2];
	}
	output[3] = inputImageColor[3];
}