DLLEXPORT miBoolean texture_worleynoise3d(
    miColor *result,
    miState *state,
    texture_worleynoise3d_t *param)
{
  worley_context3 *context;
  mi_query(miQ_FUNC_TLS_GET, state, miNULLTAG, &context);
  if (!context) {
    context = mi_mem_allocate( sizeof(worley_context3) );
    mi_query(miQ_FUNC_TLS_SET, state, miNULLTAG, &context);
    context->cache_initialized = 0;
  }
  
  
  miScalar val = worleynoise3d_val(state,param);
  
  if(val < 0) {
    miColor gap = *mi_eval_color(&param->gap);
    result->r = gap.r;
    result->g = gap.g;
    result->b = gap.b;
    result->a = gap.a;
  }
  else {
    miColor *inner = mi_eval_color(&param->inner);
    miColor *outer = mi_eval_color(&param->outer);
    
    grey_to_color(val, inner, outer, result);
  }
  
  return(miTRUE);
}
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);
}
DLLEXPORT miBoolean texture_worleynoise3d_exit(
    miState *state,
    texture_worleynoise3d_t *param)
{
  if (param) { /* shader instance exit */
    // note: is is indeed correct to release the contexts during shader instance exit!!!
    // (TODO: explain why)
    int num;
    worley_context3 **contexts;
    mi_query(miQ_FUNC_TLS_GETALL, state, miNULLTAG, &contexts, &num);
    for(int i=0; i < num; i++) {
      mi_mem_release(contexts[i]);
    }
  } else {
    /* shader exit */
  }
  return(miTRUE);
}
void point_distances3(miState *state,texture_worleynoise3d_t *param, 
                      miVector *pt,
                      miScalar *f1, miVector *p1,
                      miScalar *f2, miVector *p2,
                      miScalar *f3, miVector *p3) {  
  miScalar cube_dist = CUBE_DIST * (*mi_eval_scalar(&param->scale));
  miVector cube = point_cube3(pt,cube_dist);
  
  worley_context3 *context;
  mi_query(miQ_FUNC_TLS_GET, state, miNULLTAG, &context);
  
  miInteger dist_measure = *mi_eval_integer(&param->distance_measure);
  *f3 = FLT_MAX;
  *f2 = *f3 - 1;
  *f1 = *f2 - 1;

  update_cache3(context, &cube, cube_dist);
  
  miVector *cache = context->cacheVals;
  
  for(int i=0; i < CACHE_SIZE; ++i) { 
    miVector p = cache[i];
    miScalar d = distance3(dist_measure, pt, &p);
    if(d < *f3) {
      if(d < *f2) {
        *f3 = *f2; *p3 = *p2;
        if(d < *f1) {
          *f2 = *f1; *p2 = *p1;
          *f1 = d; *p1 = p;
        }
        else {
          *f2 = d; *p2 = p;
        }
      }
      else {
        *f3 = d; *p3 = p;
      }
    }
  }
}
Beispiel #5
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);
}
Beispiel #6
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;
}