static void rotate_ray_differentials(
    miState *state,
    miVector new_dir)
{
    /* Compute the old direction in camera space */
    miVector old_dir;
    mi_vector_to_camera(state, &old_dir, &state->dir);
    mi_vector_normalize(&old_dir);

    /* Normalize the new direction as well */
    mi_vector_normalize(&new_dir);

    /* Compute the transform matrix in camera space from 'old_dir' to 'new_dir' */
    miMatrix cs_rot_transform;
    build_rot_matrix(&old_dir, &new_dir, cs_rot_transform);

    /* Get pointers to the world-to-camera and camera-to-world transforms */
    miScalar *p_world_to_camera;
    mi_query(miQ_TRANS_WORLD_TO_CAMERA, state, 0, &p_world_to_camera);

    miScalar *p_camera_to_world;
    mi_query(miQ_TRANS_CAMERA_TO_WORLD, state, 0, &p_camera_to_world);

    /* Compute the complete transform matrix in world space   */
    /* (world-to-camera, then rotation, then camera-to-world) */
    miMatrix rot_transform;
    mi_matrix_prod(rot_transform, p_world_to_camera, cs_rot_transform);
    mi_matrix_prod(rot_transform, rot_transform, p_camera_to_world);

    /* Applies the computed transform to the ray differentials */
    mi_ray_differential_transform(state, rot_transform);
}
Example #2
0
miBoolean contour_shader_widthfromlightdir(
	miContour_endpoint  *result,
	miStdInfo	    *info_near,
	miStdInfo	    *info_far,
	miState		    *state,
	Lightdir_Parameters *paras)
{
	double		    d;
	miVector	    dir;
	miScalar	    max_width;
	miScalar	    min_width;

	/* Contour color given by a parameter */
	result->color = *mi_eval_color(&paras->color);

	/* Normalize light direction (just in case user didn't) */
	dir = *mi_eval_vector(&paras->light_dir);
	mi_vector_normalize(&dir);

	/* The contour gets wider the more the normal differs from the light
	   source direction */
	d = mi_vector_dot(&dir, &info_near->normal);

	min_width     = *mi_eval_scalar(&paras->min_width);
	max_width     = *mi_eval_scalar(&paras->max_width);
	result->width = min_width + 0.5 * (max_width - min_width) * (1.0 - d);

	miASSERT(min_width <= result->width && result->width <= max_width);
	return(miTRUE);
}
static void build_rot_matrix(
    miVector *old_dir,
    miVector *new_dir,
    miMatrix rot_transform)
{
    miVector rot_axis;
    mi_vector_prod(&rot_axis, old_dir, new_dir);
    mi_vector_normalize(&rot_axis);

    float cos_theta = mi_vector_dot(old_dir, new_dir);
    float theta = (float) acos(cos_theta);

    mi_matrix_rotate_axis(rot_transform, &rot_axis, theta);
}
Example #4
0
miBoolean contour_shader_widthfromlight(
	miContour_endpoint *result,
	miStdInfo	   *info_near,
	miStdInfo	   *info_far,
	miState		   *state,
	Light_Parameters   *paras)
{
	miVector	   orgp;	/* light source origin */
	miVector	   dirp;	/* light source direction */
	miVector	   dir;
	double		   d;
	miScalar	   min_width;
	miScalar	   max_width;

	/* Contour color given by a parameter */
	result->color = *mi_eval_color(&paras->color);

	/* Get light origin or direction */
	mi_light_info(*mi_eval_tag(&paras->light), &orgp, &dirp, 0);
	/* Now orgp or dirp is different from the null vector */

	/* Compute direction from light to point */
	if (mi_vector_dot(&orgp, &orgp) > miEPS) {   /* point light source */
		mi_vector_sub(&dir, &info_near->point, &orgp);

	} else {				/* directional light source */
		miASSERT(mi_vector_dot(&dirp, &dirp) > miEPS);
		dir = dirp;
	}
	mi_vector_normalize(&dir);

	/* The contour gets wider the more the normal is pointing in the same
	   direction as the light source */
	d = mi_vector_dot(&dir, &info_near->normal);
	min_width = *mi_eval_scalar(&paras->min_width);
	max_width = *mi_eval_scalar(&paras->max_width);
	result->width = min_width + 0.5 * (max_width - min_width) * (d+1.0);

	miASSERT(min_width <= result->width && result->width <= max_width);
	return(miTRUE);
}
DLLEXPORT miBoolean domeAFL_FOV_Stereo(
	miColor	*result,
	miState	*state,
	struct dsDomeAFL_FOV_Stereo *params)
{
	miScalar	cameras_separation_multiplier = *mi_eval_scalar(&params->Cameras_Separation_Map);
	miScalar	head_turn_multiplier = *mi_eval_scalar(&params->Head_Turn_Map);
	miScalar	head_tilt = *mi_eval_scalar(&params->Head_Tilt_Map);

	miVector	org, ray, target, htarget;
	miMatrix	tilt;
	double		x, y, r, phi, theta, rot, tmp, tmpY, tmpZ;
	double		sinP, cosP, sinT, cosT, sinR, cosR;

   	// normalize image coordinates btwn [-1,1]...
	// [rz] swap X-Y to match camera view and apply a vertical symmetry
	// [rz] basically, we rotate the cartesian axis 90deg CW
	x = -2.0*state->raster_y/state->camera->y_resolution+1.0;
	y = 2.0*state->raster_x/state->camera->x_resolution-1.0;

	// Calculate the radius value
	r = MI_SQRT((x*x)+(y*y));

	if (r < 1.0) {

		// Calculate phi...
		if ((r > -EPSILON) && (r < EPSILON) ) {
			phi = 0.0;
		} else {
			phi = atan2(y,x);
		}
		// Calculate theta...
		theta = r*(fov_angle/2.0);

		// start by matching camera (center camera)
		// mi_point_to_camera(state, &org, &state->org);
		org.x = org.y = org.z = 0.0;

		// saves common used values for performance reasons
		sinP = sin(phi); cosP = cos(phi);
		sinT = sin(theta); cosT = cos(theta);

		// center camera target vector (normalized)
		target.x = (miScalar)(sinP*sinT);
		target.y = (miScalar)(-cosP*sinT);
		target.z = (miScalar)(-cosT);

		if (camera != CENTERCAM) {
			// camera selection and initial position
			// @@@ use switch?
			if (camera == LEFTCAM) {
				org.x = (miScalar)(-cameras_separation*cameras_separation_multiplier/2);
			}
			if (camera == RIGHTCAM) {
				org.x = (miScalar)(cameras_separation*cameras_separation_multiplier/2);
			}

			if (dome_tilt_compensation) {		// tilted dome mode

				// head rotation
				// @@@ need to check atan2 params for 0 values?
				// @@@ save values of sin/cos
				tmpY = target.y*cos(-dome_tilt)-target.z*sin(-dome_tilt);
				tmpZ = target.z*cos(-dome_tilt)+target.y*sin(-dome_tilt);
				rot = atan2(target.x,-tmpY)*head_turn_multiplier;
				if (vertical_mode)
					rot *= fabs(sinP);
				sinR = sin(rot); cosR = cos(rot);

				// rotate camera
				tmp = org.x*cosR-org.y*sinR;
				org.y = (miScalar)(org.y*cosR+org.x*sinR);
				org.x = (miScalar)tmp;

				// compensate for dome tilt
				// @@@ save values of sin/cos
				tmp = org.y*cos(dome_tilt)-org.z*sin(dome_tilt);
				org.z = (miScalar)(org.z*cos(dome_tilt)+org.y*sin(dome_tilt));
				org.y = (miScalar)tmp;

				// calculate head target
				tmp = sqrt(target.x*target.x+tmpY*tmpY);
				htarget.x = (miScalar)(sin(rot)*tmp);
				htarget.y = (miScalar)(-cos(rot)*tmp);
				htarget.z = (miScalar)tmpZ;

				// dome rotation again on head target
				tmp = htarget.y*cos(dome_tilt)-htarget.z*sin(dome_tilt);
				htarget.z = (miScalar)(htarget.z*cos(dome_tilt)+htarget.y*sin(dome_tilt));
				htarget.y = (miScalar)tmp;

			} else {

				if (vertical_mode) {			// vertical mode

					// head rotation
					// @@@ need to check atan2 params for 0 values?
					rot = atan2(target.x,-target.z)*head_turn_multiplier*fabs(sinP);
					sinR = sin(rot); cosR = cos(rot);

					// rotate camera
					tmp = org.x*cosR-org.z*sinR;
					org.z = (miScalar)(org.z*cosR+org.x*sinR);
					org.x = (miScalar)tmp;

					// calculate head target
					tmp = sqrt(target.x*target.x+target.z*target.z);
					htarget.x = (miScalar)(sin(rot)*tmp);
					htarget.y = (miScalar)target.y;
					htarget.z = (miScalar)(-cos(rot)*tmp);

				} else {						// horizontal mode

					// head rotation
					rot = phi*head_turn_multiplier;
					sinR = sin(rot); cosR = cos(rot);

					// rotate camera
					tmp = org.x*cosR-org.y*sinR;
					org.y = (miScalar)(org.y*cosR+org.x*sinR);
					org.x = (miScalar)tmp;

					// calculate head target
					htarget.x = (miScalar)(sin(rot)*sinT);
					htarget.y = (miScalar)(-cos(rot)*sinT);
					htarget.z = (miScalar)target.z;

				}
			}

			// head tilt
			head_tilt = (miScalar)((head_tilt-0.5)*M_PI);
			mi_matrix_ident(tilt);
			mi_matrix_rotate_axis(tilt, &htarget, head_tilt);
			mi_vector_transform(&org, &org, tilt);

			// calculate ray from camera to target
			target.x *= dome_radius;
			target.y *= dome_radius;
			target.z *= dome_radius;
			ray.x = target.x-org.x;
			ray.y = target.y-org.y;
			ray.z = target.z-org.z;
			mi_vector_normalize(&ray);

		} else {		// center camera

			ray = target;

		}


		// Account for view offset...
   		// Offset is added to y & z components because they are negative values...
		// @@@ ray.x = ray.x - viewport_offset.x;
		// @@@ ray.y = ray.y + viewport_offset.y;
		// @@@ ray.z = ray.z + viewport_offset.z;

//mi_debug("II->,Phi=%f,Theta=%f,rot=%f,camx=%f,camy=%f", (miScalar)phi, (miScalar)theta, (miScalar)rot, (miScalar)org.x, (miScalar)org.y);

		// Flip the ray direction about the y-axis
		// @@@ if(*mi_eval_boolean(&params->Flip_Ray_X)) { 
		// @@@ 	ray.x = (-ray.x);
		// @@@ }
       	// Flip the ray direction about the x-axis
		// @@@ if(*mi_eval_boolean(&params->Flip_Ray_Y)) {
		// @@@ 	ray.y = (-ray.y);		
		// @@@ }


		// Convert ray from camera space
		mi_vector_from_camera(state, &ray, &ray);
		mi_point_from_camera(state, &org, &org);

		// Trace new ray...
		return(mi_trace_eye(result, state, &org, &ray));

	} else {

		// Set the return colors to Black
		result->r = result->g = result->b = result->a = 0;
		return(miFALSE);
	}

}
Example #6
0
miBoolean contour_shader_combi(
	miContour_endpoint *result,
	miStdInfo	   *info_near,
	miStdInfo	   *info_far,
	miState		   *state,
	Combi_Parameters   *paras)
{
	miScalar	   depth = info_near->point.z;
	double		   near_z, far_z, w_near, w_far;
	miVector	   orgp;		/* light source origin */
	miVector	   dirp;		/* light source direction */
	miVector	   dir;
	double		   d;
	double		   factor;
	miTag		   light;

	/* Ensure that near_z and far_z are negative as they should be */
	near_z = -fabs(*mi_eval_scalar(&paras->near_z));
	far_z  = -fabs(*mi_eval_scalar(&paras->far_z));

	if (depth > near_z) {		/* contour is closer than near_z */
		result->color = *mi_eval_color(&paras->near_color);
		result->width = *mi_eval_scalar(&paras->near_width);

	} else if (depth < far_z) {	/* contour is more distant than far_z*/
		result->color = *mi_eval_color(&paras->far_color);
		result->width = *mi_eval_scalar(&paras->far_width);
	} else {			/* contour is betwn near_z and far_z */
		miColor near_color = *mi_eval_color(&paras->near_color);
		miColor far_color  = *mi_eval_color(&paras->far_color);
		/* Weights w_near and w_far depend on depth */
		w_near = (depth - far_z) / (near_z - far_z);
		miASSERT(0.0 <= w_near && w_near <= 1.0);
		w_far = 1.0 - w_near;

		/* Mix of near_color and far_color according to weights */
		result->color.r = w_near * near_color.r + w_far * far_color.r;
		result->color.g = w_near * near_color.g + w_far * far_color.g;
		result->color.b = w_near * near_color.b + w_far * far_color.b;
		result->color.a = w_near * near_color.a + w_far * far_color.a;

		/* Width depending on weights */
		result->width   = w_near * *mi_eval_scalar(&paras->near_width) 
				+ w_far  * *mi_eval_scalar(&paras->far_width);
	}

	/* Width decreases by factor for each refraction_level */
	factor = *mi_eval_scalar(&paras->factor);
	if (factor > miEPS)
		result->width *= pow(factor, (double)info_near->level - 1.0);

	light = *mi_eval_tag(&paras->light);
	if (light) {
		miScalar light_min_factor = 
				*mi_eval_scalar(&paras->light_min_factor);
		/* Get light origin or direction */
		mi_light_info(light, &orgp, &dirp, 0);
		/* Now orgp or dirp is different from the null vector */

		/* Compute direction from light to point */
		if (mi_vector_dot(&orgp, &orgp) > miEPS) /* point light */
			mi_vector_sub(&dir, &info_near->point, &orgp);

		else {				/* directional light source */
			miASSERT(mi_vector_dot(&dirp, &dirp) > miEPS);
			dir = dirp;
		}
		mi_vector_normalize(&dir);

		/* The contour gets wider the more the normal is pointing in
		   the same direction as the light source */
		d = mi_vector_dot(&dir, &info_near->normal);
		result->width *= 0.5 * (d + 1.0) * (1.0 - light_min_factor) +
						light_min_factor;
	}
	miASSERT(result->width <= *mi_eval_scalar(&paras->near_width));
	return(miTRUE);
}
Example #7
0
miBoolean Facade_tex_coord(miState *state, miScalar size, 
			       miBoolean cylindrical,
			       miVector *tex_point)
{
  miVector facing, facade_center, observer_center;
  miVector intersection;
  miVector fx, fy, fz;

  /* first - determine the center of the facade,
             the center of the observer, 
             and the direction of the facade */
  {

    mi_point_from_object(state, &facade_center, &zero);

    observer_center = state->org;

    mi_vector_sub(&facing, &observer_center, &facade_center);

    if (cylindrical)
      {
	miVector fix;

	mi_vector_to_object(state, &fix, &facing);
	fix.y = 0;
	mi_vector_from_object(state, &facing, &fix);
      }

    mi_vector_normalize(&facing);
  }



  /* second - compute the intersection of the ray and the facade */

  {
    miScalar l;

    l = lume_plane_ray_intersection(&intersection, 
				       &facade_center, &facing,
				       &state->point, &state->dir);



    if (l <= 0)  /* no intersection */
      return miFALSE;

  }



  /* third - build a coordinate system for the texture */
  {
    miVector object_up;

    fz = facing;

    mi_vector_from_object(state, &object_up, &up);
    mi_vector_prod(&fx, &object_up, &fz);
    mi_vector_normalize(&fx);
 
    mi_vector_prod(&fy, &fz, &fx);
    mi_vector_normalize(&fy);
 
  }


  
  /* forth - convert the intersection to the texture coordinate system */
  {
    mi_vector_sub(&intersection, &intersection, &facade_center);

    tex_point->x = mi_vector_dot(&intersection, &fx);
    tex_point->y = mi_vector_dot(&intersection, &fy);
    tex_point->z = mi_vector_dot(&intersection, &fz);

    mi_vector_div(tex_point, size);

    tex_point->x += 0.5;
    tex_point->y += 0.5;
  }
 


  
  return miTRUE;
}
DLLEXPORT miBoolean LatLong_Stereo(
	miColor	*result,
	miState	*state,
	struct dsLatLong_Stereo *params)
{
	miScalar	cameras_separation_multiplier = *mi_eval_scalar(&params->Cameras_Separation_Map);
	miScalar	head_tilt = *mi_eval_scalar(&params->Head_Tilt_Map);

	miVector	org, ray, target, htarget;
	miMatrix	tilt;
	double		x, y, phi, theta, tmp;
	double		sinP, cosP, sinT, cosT;

	miBoolean	zenithMode = *mi_eval_boolean(&params->Zenith_Mode);

	// Normalize image coordinates btwn [-1,-1] and [1,1]...
	x = 2.0*state->raster_x/state->camera->x_resolution-1.0;
	y = 2.0*state->raster_y/state->camera->y_resolution-1.0;

	// Calculate phi and theta...
	phi = x*(fov_horiz_angle/2.0);
	if (zenithMode)
		theta = M_PI_2-y*(fov_vert_angle/2.0);
	else
		theta = y*(fov_vert_angle/2.0);

	// Start by matching camera (center camera)
	// mi_point_to_camera(state, &org, &state->org);
	org.x = org.y = org.z = 0.0;

	// Saves common used values for performance reasons
	sinP = sin(phi); cosP = cos(phi);
	sinT = sin(theta); cosT = cos(theta);

	// Center camera target vector (normalized)
	if (zenithMode) {
		target.x = (miScalar)(sinP*sinT);
		target.y = (miScalar)(-cosP*sinT);
		target.z = (miScalar)(-cosT);
	} else {
		target.x = (miScalar)(sinP*cosT);
		target.y = (miScalar)(sinT);
		target.z = (miScalar)(-cosP*cosT);
	}

	if (camera != CENTERCAM) {
		// Camera selection and initial position
		if (camera == LEFTCAM) {
			org.x = (miScalar)(-cameras_separation*cameras_separation_multiplier/2);
		} else if (camera == RIGHTCAM) {
			org.x = (miScalar)(cameras_separation*cameras_separation_multiplier/2);
		}

		// Head rotation = phi
		// Rotate camera
		if (zenithMode) {
			tmp = org.x*cosP-org.y*sinP;
			org.y = (miScalar)(org.y*cosP+org.x*sinP);
			org.x = (miScalar)tmp;
		} else {
			tmp = org.x*cosP-org.z*sinP;
			org.z = (miScalar)(org.z*cosP+org.x*sinP);
			org.x = (miScalar)tmp;
		}

		// Calculate head target
		htarget.x = (miScalar)(sinP*sinT);
		htarget.y = (miScalar)(-cosP*sinT);
		htarget.z = (miScalar)target.z;

		// Head tilt
		head_tilt = (miScalar)((head_tilt-0.5)*M_PI);
		mi_matrix_ident(tilt);
		mi_matrix_rotate_axis(tilt, &htarget, head_tilt);
		mi_vector_transform(&org, &org, tilt);

		// Calculate ray from camera to target
		target.x *= parallax_distance;
		target.y *= parallax_distance;
		target.z *= parallax_distance;
		ray.x = target.x-org.x;
		ray.y = target.y-org.y;
		ray.z = target.z-org.z;
		mi_vector_normalize(&ray);
	} else{		
    // Center camera
    ray = target;
	}

//mi_debug("II->,Phi=%f,Theta=%f,rot=%f,camx=%f,camy=%f", (miScalar)phi, (miScalar)theta, (miScalar)rot, (miScalar)org.x, (miScalar)org.y);

	// Flip the X ray direction about the Y-axis
	if(*mi_eval_boolean(&params->Flip_Ray_X)) { 
		org.x = (-org.x);
		ray.x = (-ray.x);
	}
	// Flip the Y ray direction about the X-axis
	if(*mi_eval_boolean(&params->Flip_Ray_Y)) {
		if(zenithMode) {
			org.z = (-org.z);
			ray.z = (-ray.z);
		} else {
			org.y = (-org.y);
			ray.y = (-ray.y);
		}
	}

  #if 1
    /* Adjust the ray differentials */
    rotate_ray_differentials(state, ray);
  #endif
  
	// Convert ray from camera space
	mi_vector_from_camera(state, &ray, &ray);
	mi_point_from_camera(state, &org, &org);

	// Trace new ray...
	return(mi_trace_eye(result, state, &org, &ray));

}
Example #9
0
extern "C" DLLEXPORT miBoolean physical_light(
	miColor			*result,
	miState			*state,
	struct physical_light	*parms)
{
	struct physical_light	p, *paras = &p;	/* mi_eval'ed parameters */
	miTag			light = 0;
	miColor			visibility = {1.0, 1.0, 1.0};
	miVector		normal, u, v, axis, spotdir, dir;
	miScalar		cosine, r=state->dist, r2, f, d, area, radius;
	miScalar		exponent, spread;
	miScalar		maxcolor;
	int			type, areatype;

	p.color     = *mi_eval_color (&parms->color);
	p.cone      = *mi_eval_scalar(&parms->cone);
	p.threshold = *mi_eval_scalar(&parms->threshold);
	p.cos_exp   = *mi_eval_scalar(&parms->cos_exp);

	miASSERT(paras->color.r >= 0.0 && paras->color.g >= 0.0 &&
		 paras->color.b >= 0.0);   /* no 'light suckers', please */

	mi_query(miQ_INST_ITEM,  state, state->light_instance,	&light);
	mi_query(miQ_LIGHT_TYPE, state, light,			&type);
	mi_query(miQ_LIGHT_AREA, state, light,			&areatype);

	if (state->type == miRAY_LIGHT) {
		/*
		 * compute irradiance from this light source at the surface of
		 * object
		 */
		mi_query(miQ_LIGHT_EXPONENT, state, light, &exponent);
		r2 = exponent == 0 || exponent == 2 ? r*r : pow(r, exponent);

		switch(areatype) {
		  case miLIGHT_NONE:		/* point, spot or directional*/
			/*
			 * distance attenuation: 4 Pi r^2 is the area of a
			 * sphere around the point. Same normalization as for
			 * spherical light
			 */
			f = type==miLIGHT_DIRECTION ? 1 : 1 / (4 * M_PI * r2);
			break;

		  case miLIGHT_RECTANGLE:	/* rectangular area light */
			mi_query(miQ_LIGHT_AREA_R_EDGE_U, state, light, &u);
			mi_query(miQ_LIGHT_AREA_R_EDGE_V, state, light, &v);
			mi_vector_prod(&normal, &u, &v);
			mi_vector_normalize(&normal);
			mi_vector_to_light(state, &dir, &state->dir);
			mi_vector_normalize(&dir);
			/*
			 * Compute area-to-point form factor (except cos at
			 * the receiver). <cosine> is cos at sender. Returning
			 * 2 means "no color and stop sampling".
			 */
			cosine = mi_vector_dot(&normal, &dir);
			if (cosine <= 0)
				return((miBoolean)2);
			if (paras->cos_exp != 0 && paras->cos_exp != 1)
				cosine = pow(cosine, paras->cos_exp);
			/*
			 * cos term and distance attenuation. No area term
			 * since "color" of the light is energy, not radiance.
			 */
			f = cosine / (M_PI * r2);
			break;

		  case miLIGHT_DISC:		/* disc area light */
			mi_query(miQ_LIGHT_AREA_D_NORMAL, state,light,&normal);
			mi_vector_to_light(state, &dir, &state->dir);
			mi_vector_normalize(&dir);

			cosine = mi_vector_dot(&normal, &dir);
			if (cosine <= 0)
				return((miBoolean)2);
			if (paras->cos_exp != 0 && paras->cos_exp != 1)
				cosine = pow(cosine, paras->cos_exp);
			f = cosine / (M_PI * r2);
			break;

		  case miLIGHT_SPHERE:		/* spherical area light */
		  case miLIGHT_CYLINDER:	/* cylindrical area light */
			f = 1 / (4 * M_PI * r2);
			break;

		  case miLIGHT_OBJECT:
		        /* two sided */
			/*
			 * this is legal for object lights only: state->child
			 * is set according to the intersection with the light
			 * geometry itself
			 */
		        cosine = -state->child->dot_nd;
			if (cosine <= 0)
				return(miFALSE);
			if (paras->cos_exp != 0 && paras->cos_exp != 1)
				cosine = pow(cosine, paras->cos_exp);
		        f = cosine / (4 * M_PI * r2);
			break;

		  default:
			mi_error("physical_light: unknown light source type");
		}
		if (type == miLIGHT_SPOT) {	/* spot light source */
			mi_query(miQ_LIGHT_DIRECTION, state, light, &spotdir);
			miASSERT(fabs(mi_vector_norm(&spotdir) - 1.) < miEPS);
			mi_vector_to_light(state, &dir, &state->dir);
			mi_vector_normalize(&dir);
			d = mi_vector_dot(&dir, &spotdir);
			if (d <= 0)
				return(miFALSE);
			mi_query(miQ_LIGHT_SPREAD, state, light, &spread);
			if (d < spread)
				return(miFALSE);
			if (d < paras->cone)
				f *= 1 - (d - paras->cone) /
					 (spread - paras->cone);
		}

		/*
		 * Return false without checking occlusion (shadow ray) if
		 * color is very dark. (This introduces bias which could be
		 * avoided if probabilities were used to decide whether to
		 * carry on or return here.)
		 */
		maxcolor = mi_MAX3(paras->color.r, paras->color.g,
							paras->color.b);
		if (f * maxcolor < paras->threshold)
			return(miFALSE);

		/*
		 * Check for occlusion by an opaque object and compute
		 * visibility
		 */
		if (!mi_trace_shadow(&visibility, state) || BLACK(visibility))
			return(miFALSE);

		/*
		 * Compute result. Visibility is always (1 1 1) here for
		 * dgs_material() so the multiplication by visibility could be
		 * avoided. But for base light shaders visibility can be less.
		 */
		result->r = f * paras->color.r * visibility.r;
		result->g = f * paras->color.g * visibility.g;
		result->b = f * paras->color.b * visibility.b;
	} else {		/* Visible area light source: return radiance*/
		switch (areatype) {
		  case miLIGHT_RECTANGLE:	/* rectangular area light */
			mi_query(miQ_LIGHT_AREA_R_EDGE_U, state, light, &u);
			mi_query(miQ_LIGHT_AREA_R_EDGE_V, state, light, &v);
			mi_vector_prod(&normal, &u, &v);
			/* Compute radiance: result = paras->color / area */
			mi_normal_to_light(state, &dir, &state->normal);
			if (mi_vector_dot(&normal, &dir) > 0) {
				area = 4.0 * mi_vector_norm(&normal);
				miASSERT(area > 0.0);
				result->r = paras->color.r / area;
				result->g = paras->color.g / area;
				result->b = paras->color.b / area;
			} else
				*result = black;   /* back side is black */
			break;

		  case miLIGHT_DISC:		/* disc area light source */
			mi_query(miQ_LIGHT_AREA_D_NORMAL, state,light,&normal);
			mi_normal_to_light(state, &dir, &state->normal);
			if (mi_vector_dot(&normal, &dir) > 0) {
				mi_query(miQ_LIGHT_AREA_D_RADIUS, state,
							light, &radius);
				area = M_PI * radius * radius;
				miASSERT(area > 0.0);
				result->r = paras->color.r / area;
				result->g = paras->color.g / area;
				result->b = paras->color.b / area;
			} else
				*result = black;
			break;

		  case miLIGHT_SPHERE:		/* spherical area light */
			mi_query(miQ_LIGHT_AREA_S_RADIUS, state,light,&radius);
			area = 4.0 * M_PI * radius * radius;
			miASSERT(area > 0.0);
			result->r = paras->color.r / area;
			result->g = paras->color.g / area;
			result->b = paras->color.b / area;
			break;

		  case miLIGHT_CYLINDER:	/* cylindrical area light */
			mi_query(miQ_LIGHT_AREA_C_RADIUS, state,light,&radius);
			mi_query(miQ_LIGHT_AREA_C_AXIS, state, light, &axis);
			/* area = pi*radius^2 * h = pi*radius^2 * 2 * |axis| */
			area = 2 * M_PI * radius * radius *
						mi_vector_norm(&axis);
			miASSERT(area > 0.0);
			result->r = paras->color.r / area;
			result->g = paras->color.g / area;
			result->b = paras->color.b / area;
			break;

		  case miLIGHT_OBJECT:
		        mi_query(miQ_INST_AREA, state,
				 state->light_instance, &area);
			result->r = paras->color.r / area;
			result->g = paras->color.g / area;
			result->b = paras->color.b / area;
			break;

		  case miLIGHT_NONE:		/* point, spot or directional*/
			miASSERT(0);
			break;

		  default:
			mi_error("physical_light: unknown light source type");
		}
	}
	miASSERT(result->r >= 0 && result->g >= 0 && result->b >= 0);
	return(miTRUE);
}
Example #10
0
extern "C" DLLEXPORT miBoolean mib_bent_normal_env(
	miColor     *result,
	miState     *state,
	struct mib_bent_normal_env_p *paras)
{
	miTag  original_env = state->environment;
	miTag  environment  = *mi_eval_tag(&paras->environment);
	miColor   normal    = *mi_eval_color(&paras->bent_normals);
	miColor   occlus    = *mi_eval_color(&paras->occlusion);
	miScalar  strength  = *mi_eval_scalar(&paras->strength);
	miColor   color;      /* Work color */
	miVector  bent;       /* Bent normals */
	miVector  bent_i;     /* Bent normals in internal space */
	miUint	  samples;    /* # of samples */

	/* Displace or light - makes no sense */
	if (state->type == miRAY_DISPLACE || state->type == miRAY_LIGHT)
	    return miFALSE;

	if (strength == 0.0) {
	    result->r = result->g = result->b = 0.0;
	    result->a = 1.0;
	    return miTRUE;
	}

	color.r = color.b = color.g = 0.0;

	/* Does occlusion live in "alpha" component of bn data? */
	if (*mi_eval_boolean(&paras->occlusion_in_alpha))
	    strength *= normal.a;
    
	bent.x = (normal.r * 2.0) - 1.0;
	bent.y = (normal.g * 2.0) - 1.0;
	bent.z = (normal.b * 2.0) - 1.0;

	mi_vector_normalize(&bent);

	/* The different coordinate spaces */
	switch(*mi_eval_integer(&paras->coordinate_space)) {
		case 0: /* No change */
			bent_i = bent;
			break;
		case 1: /* By matrix */
			mi_vector_transform(&bent_i,
				&bent,
				mi_eval_transform(&paras->matrix));
			break;
		case 2: /* World */
			mi_normal_from_world(state, &bent_i, &bent);
			break;
		case 3: /* Camera */
			mi_normal_from_camera(state, &bent_i, &bent);
			break;
		case 4: /* Object */
			mi_normal_from_object(state, &bent_i, &bent);
			break;
	}
    
	samples = *mi_eval_integer(&paras->env_samples);

	/* Temporarily override the environment */
	if (environment)
	    state->environment = environment;

	if (samples <= 1) {
		/* Single sampling */		      
		mi_trace_environment(&color, state, &bent_i);
	} else {
		/* Multisampling */
		double	 sample[3];
		int	 counter = 0;
		miScalar spread  = *mi_eval_scalar(&paras->samples_spread);
		miColor  work_color;

		/* Clear color */
		color.r = color.g = color.b = 0.0;
			
		while (mi_sample(sample, &counter, state, 3, &samples)) {
			miVector trace_dir;
			trace_dir.x = bent_i.x + (sample[0] - 0.5) * spread;
			trace_dir.y = bent_i.y + (sample[1] - 0.5) * spread;
			trace_dir.z = bent_i.z + (sample[2] - 0.5) * spread;
			
			mi_vector_normalize(&trace_dir);

			mi_trace_environment(&work_color, state, &trace_dir);
			color.r += work_color.r;
			color.g += work_color.g;
			color.b += work_color.b;
		}

		color.r /= samples;
		color.g /= samples;
		color.b /= samples;
	}

	/* Reset original environment */
	state->environment = original_env;

	result->r = color.r * occlus.r * strength;
	result->g = color.g * occlus.g * strength;
	result->b = color.b * occlus.b * strength;
	result->a = 1.0;

	return miTRUE;
}
Example #11
0
extern "C" DLLEXPORT miBoolean mib_amb_occlusion(
	miColor     *result,
	miState     *state,
	struct mib_amb_occlusion_p *paras)
{
	double sample[3], near_clip, far_clip;
	int	  counter  = 0;
	miUint	  samples  = *mi_eval_integer(&paras->samples);
	miScalar  clipdist = *mi_eval_scalar(&paras->max_distance);
	miBoolean reflecto = *mi_eval_boolean(&paras->reflective);
	miBoolean ret_type = *mi_eval_integer(&paras->return_type);

	miTag	   org_env = state->environment; /* Original environ. */

	miVector orig_normal, trace_dir;
	miScalar output      = 0.0, 
		 samplesdone = 0.0;
	miScalar spread     = *mi_eval_scalar(&paras->spread);
	miScalar o_m_spread = 1.0f - spread;
	
	miColor   env_total;	/* environment Total */ 	
	miVector  norm_total;	/* Used for adding up normals */
	miBoolean occ_alpha = *mi_eval_boolean(&paras->occlusion_in_alpha);

        miScalar  falloff   = 1.0;
        miao_trace_info ti;
        int       version = 1;

	/* If called as user area light source, return "no more samples" for	
	   any call beyond the first */
	if (state->type == miRAY_LIGHT && state->count > 0) 
		return (miBoolean)2;

        /* Figure out the call version */
        mi_query(miQ_DECL_VERSION, 0, state->shader->function_decl, &version); 
        if (version >= 2)
        {
            falloff = *mi_eval_scalar(&paras->falloff);
            if (falloff <= 0.0) 
                falloff = 1.0;
            ti.id_inclexcl   = *mi_eval_integer(&paras->id_includeexclude);
            ti.id_nonself    = *mi_eval_integer(&paras->id_nonself);

            /* None of these options used, go into compatible mode */
            ti.compatible = (ti.id_inclexcl   == 0 && 
                             ti.id_nonself    == 0 
                             );
        }
        else
        {
            ti.compatible = miTRUE;
        }

	/* Used for adding up environment */
	env_total.r = env_total.g = env_total.b = env_total.a = 0;

	far_clip = near_clip = clipdist;

	orig_normal  = state->normal;
	norm_total   = state->normal; /* Begin by standard normal */

	/* Displacement? Shadow? Makes no sense */
	if (state->type == miRAY_DISPLACE ||
            state->type == miRAY_SHADOW) {
		result->r = result->g = result->b = result->a = 0.0;
		return (miTRUE); 
	}

	if (clipdist > 0.0) 
		mi_ray_falloff(state, &near_clip, &far_clip);

	/* Avoid recursion: If we are designated as environment shader,
	   we will be called with rays of type miRAY_ENVIRON, and if so
	   we switch the environment to the global environment */

	if (state->type == miRAY_ENVIRONMENT)
	    state->environment = state->camera->environment;

	while (mi_sample(sample, &counter, state, 2, &samples)) {
		mi_reflection_dir_diffuse_x(&trace_dir, state, sample);
		trace_dir.x = orig_normal.x*o_m_spread + trace_dir.x*spread;
		trace_dir.y = orig_normal.y*o_m_spread + trace_dir.y*spread;
		trace_dir.z = orig_normal.z*o_m_spread + trace_dir.z*spread;
	
		mi_vector_normalize(&trace_dir);

		if (reflecto) {
			miVector ref;
			miScalar nd = state->dot_nd;
			/* Calculate the reflection direction */
			state->normal = trace_dir;
			state->dot_nd = mi_vector_dot(
						&state->dir,
						&state->normal);
			/* Bugfix: mi_reflection_dir(&ref, state);
			   for some reason gives me the wrong result,
			   doing it "manually" works better */
			ref    = state->dir;
			ref.x -= state->normal.x*state->dot_nd*2.0f;
			ref.y -= state->normal.y*state->dot_nd*2.0f;
			ref.z -= state->normal.z*state->dot_nd*2.0f;
			state->normal = orig_normal;
			state->dot_nd = nd;
			trace_dir = ref;
		}

		if (mi_vector_dot(&trace_dir, &state->normal_geom) < 0.0) 
			continue;

		output	    += 1.0; /* Add one */
		samplesdone += 1.0;

		if (state->options->shadow &&
		    miao_trace_the_ray(state, &trace_dir, &state->point, &ti)) {
			/* we hit something */
    
			if (clipdist == 0.0) 
				output -= 1.0;
			else if (state->child->dist < clipdist) {
				miScalar f = pow(state->child->dist / clipdist,
                                                 (double) falloff);

				output -= (1.0 - f);

				norm_total.x += trace_dir.x * f;
				norm_total.y += trace_dir.y * f;
				norm_total.z += trace_dir.z * f;

				switch (ret_type) {
					case 1: 
					  { 
					    /* Environment sampling */
					    miColor envsample;
					    mi_trace_environment(&envsample, 
						state, &trace_dir);

					    env_total.r += envsample.r * f;
					    env_total.g += envsample.g * f;
					    env_total.b += envsample.b * f;
					  }
					  break;
					
					default: 
					  /* Most return types need no 
						special stuff */
					  break;
				}
			}
		}
		else {
			/* We hit nothing */
			norm_total.x += trace_dir.x;
			norm_total.y += trace_dir.y;
			norm_total.z += trace_dir.z;

			switch (ret_type) {
				case 1: /* Environment sampling */
					{
					   miColor envsample;

					   mi_trace_environment(&envsample, 
						   state, &trace_dir);

					   env_total.r += envsample.r;
					   env_total.g += envsample.g;
					   env_total.b += envsample.b;
					}
					break;
				default:
					/* Most return types need no 
						special treatment */
					break; 
			}
		}
	}

	if (clipdist > 0.0) 
		mi_ray_falloff(state, &near_clip, &far_clip);
    
	if (samplesdone <= 0.0) /* No samples? */
		samplesdone = 1.0;  /* 1.0 to not to break divisons below */

	switch (ret_type) {
		case -1:  /* Plain old occlusion with untouched normal*/
		case 0:   /* Plain old occlusion */
		default:  /* (also the default for out-of-bounds values) */
		{
			miVector old_dir = state->dir;
			output /= (miScalar) samplesdone;

			if (ret_type == -1)
				norm_total = state->normal;
			else {
				mi_vector_normalize(&norm_total);

				/* If the color shaders use the normal....
					give them the bent one... */
				state->normal = norm_total;  
				state->dir    = norm_total;
			}
			if (output == 0.0)
				*result = *mi_eval_color(&paras->dark);
			else if (output >= 1.0)
				*result = *mi_eval_color(&paras->bright);
			else {
				miColor bright, dark;
				bright = *mi_eval_color(&paras->bright);
				dark   = *mi_eval_color(&paras->dark);

				result->r = bright.r * output + dark.r * 
					(1.0 - output);
				result->g = bright.g * output + dark.g * 
					(1.0 - output);
				result->b = bright.b * output + dark.b * 
					(1.0 - output);

				if (occ_alpha)
					result->a = output;
				else
					result->a = bright.a * output 
						   + dark.a * (1.0 - output);
			}

			state->normal = orig_normal;
			state->dir    = old_dir;
		}
		break;
		case 1: /* Sampled environment */
		{
			miColor br	= *mi_eval_color(&paras->bright),
				drk	= *mi_eval_color(&paras->dark);

			result->r = drk.r + (br.r * env_total.r / samplesdone);
			result->g = drk.g + (br.g * env_total.g / samplesdone);
			result->b = drk.b + (br.b * env_total.b / samplesdone);
			if (occ_alpha)
				result->a = output/ samplesdone;
			else
				result->a = 1.0;
		}
		break;
		case 2: /* Bent normals, world */
		case 3: /* Bent normals, camera */
		case 4: /* Bent normals, object */
		{
			miVector retn; /* returned Normal */

			mi_vector_normalize(&norm_total);

			if (ret_type == 2)
				mi_normal_to_world(state, &retn, &norm_total);
			if (ret_type == 3)
				mi_normal_to_camera(state, &retn, &norm_total);
			if (ret_type == 4)
				mi_normal_to_object(state, &retn, &norm_total);

			result->r = (retn.x + 1.0) / 2.0;
			result->g = (retn.y + 1.0) / 2.0;
			result->b = (retn.z + 1.0) / 2.0;
		
			if (occ_alpha)
				result->a = output/ samplesdone;
			else
				result->a = 1.0;
		}
		break;
	}

	if (state->type == miRAY_LIGHT) {
		 /* Are we a light shader? */
		int type;
		mi_query(miQ_FUNC_CALLTYPE, state, 0, &type);

		/* Make sure we are called as light shader */
		if (type == miSHADER_LIGHT) {
			/* If so, move ourselves to above the point... */
			state->org.x = state->point.x + state->normal.x;
			state->org.y = state->point.y + state->normal.y;
			state->org.z = state->point.z + state->normal.z;
			/* ...and set dot_nd to 1.0 to illuminate fully */
			state->dot_nd = 1.0;
		}
	}
	/* Reset environment, if we changed it */
	state->environment = org_env;
	return miTRUE;
}