Ejemplo n.º 1
0
void
error(char * format, ...)
{
  va_list ap;
  char text[512];
  char text1[512];

  sprintf(text1, "ERROR: ");
  va_start(ap, format);
  vsprintf(text, format, ap);
  va_end(ap);
  strcat(text1, text);
  mi_error(text1);
}
Ejemplo n.º 2
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);
}
miTag createNativeParticles(miState *state, mrParticleGeoShader_paras *paras, PartioContainer& pc)
{
	miBoolean useAllAttributes = *mi_eval_boolean(&paras->useAllAttributes);
	int i_a = *mi_eval_integer(&paras->i_attributeNames);
	int n_a = *mi_eval_integer(&paras->n_attributeNames);
	miTag *attributeNames = mi_eval_tag(paras->attributeNames) + i_a;

	if( !pc.good())
	{
		mi_info("createNativeParticles: Invalid patioContainer");
		return miNULLTAG;
	}

	Partio::ParticleAttribute posAttr;
	if(!pc.assertAttribute("position", posAttr))
	{
		mi_info("createNativeParticles: partioContainer: no position.");
		return miNULLTAG;
	}

	Partio::ParticleAttribute idAttr;
	bool hasId = true;
	if(!pc.assertAttribute("id", idAttr))
		hasId = false;

	Partio::ParticleAttribute radiusPPAttr;
	bool hasRadiusPP = true;
	if(!pc.assertAttribute("radiusPP", radiusPPAttr))
		hasRadiusPP = false;

	Partio::ParticleAttribute radiusRGBPPAttr;
	bool hasRgbPP = true;
	if(!pc.assertAttribute("rgbPP", radiusRGBPPAttr))
		hasRgbPP = false;

	mi_info("Creating native particles for cache file: %s", pc.cacheFileName.c_str());

	// declare the map as a 3-dimensional map
	mi_api_map_decl_dim ( 3 );

	// the 'mi_api_map_field_decl' function takes four arguments:
	//
	// miParam_type type: basic type of the field (miTYPE_SCALAR or miTYPE_INTEGER)
	// char *name : field name
	// int dimension : dimension of the field, 0 for single values, > 0 for arrays
	// miBoolean global : miTRUE if it's a global field, miFALSE otherwise

	// add the "extension" field as a single float
	miParameter *extension_field = mi_api_map_field_decl (
	miTYPE_SCALAR , mi_mem_strdup("extension") , 0 , miFALSE );

	// add the "color" field as an array of 1 color
	miParameter *color_field = mi_api_map_field_decl (
	miTYPE_SCALAR , mi_mem_strdup("color") , 3 , miFALSE );

	// append the color to the extension for the declaration
	// (this also frees the 'color_field' miParameter)
	miParameter *fields_list = mi_api_map_field_append ( extension_field , color_field );

	// create a declaration called "particles" with the given fields list
	// (this also frees the 'fields_list' miParameter)
	miMap_decl *decl = mi_api_map_decl_begin ( mi_mem_strdup("particles") , fields_list );

	// ends the declaration
	mi_api_map_decl_end ();

//	Then you begin the object definition, by calling 'mi_api_object_begin' and possibly setting the object flags as needed, then you begin the definition of the particle object as a set of spheres:
	miObject *obj = mi_api_object_begin(mi_mem_strdup("TestParticleObject"));
	obj->visible = miTRUE;

	// begin the definition of the particle object as spheres
	mi_api_map_obj_type ( mi_mem_strdup("spheres") );

	// the 'mi_api_map_obj_field' function takes 2 arguments:
	//
	// char *field_name : name of the field to map ("radius" in this case)
	// char *mapped_name : name of the mapped field ("extension" in this case)

	// maps the "radius" field to the "extension" field of this map
	mi_api_map_obj_field( mi_mem_strdup("radius") , mi_mem_strdup("extension") );	

	// begins the definition of the map, taking "particles" as the declaration name
	mi_api_map_begin ( mi_mem_strdup("particles") );

	int num_elements = pc.data->numParticles();

	for ( int i = 0 ; i < num_elements ; ++i ) 
	{
		
		float pos[3];
		pc.getPosition(i, pos);

		// define the position of this element
		mi_api_map_value ( miTYPE_SCALAR , &pos[0] );
		mi_api_map_value ( miTYPE_SCALAR , &pos[1] );
		mi_api_map_value ( miTYPE_SCALAR , &pos[2] );
		mi_api_map_field_end ();

		float radiusPP = 1.0f;
		if( hasRadiusPP )
			radiusPP = *pc.data->data<float>(radiusPPAttr, i);
		radiusPP = rnd() * 0.3;
		// define the radius of this element
		mi_api_map_value ( miTYPE_SCALAR , &radiusPP );
		mi_api_map_field_end ();

		//
		// compute the color in r, g and b
		//
		miScalar r = rnd();
		miScalar g = rnd();
		miScalar b = rnd();
		miColor col;
		col.r = r;
		col.g = g;
		col.b = b;
		// define the color of this element
		//mi_api_map_value ( miTYPE_COLOR , &col );
		mi_api_map_value ( miTYPE_SCALAR , &r );
		mi_api_map_value ( miTYPE_SCALAR , &g );
		mi_api_map_value ( miTYPE_SCALAR , &b );
		mi_api_map_field_end();

		// end the definition of this element
		mi_api_map_element_end ();
	}

	// terminates the map definition and stores it in the DB
	miTag map_tag = mi_api_map_end ( 0 );

	miTag particleObjTag = mi_api_object_end();

	miEchoOptions options;
	memset(&options, 0, sizeof(options));
	options.ascii_output = true;
	options.compressed_output = false;
	options.dont_echo = false;
	
	mi_info("Writing to geodump.mi file.");
	const char *mode = "w";
	FILE *fh = fopen("C:/daten/3dprojects/Maya2013/scenes/geodump.mi", mode);
	//mi_geoshader_echo_tag(fh, particleObjTag, &options);
	fclose(fh);

	mi::shader::Access_map  map(map_tag);
	mi::shader::Map_status	    status;
	mi::shader::Map_declaration map_declaration(map, &status);
	mi::shader::Map_field_id field_id = map_declaration->get_field_id(mi_mem_strdup("color"), &status);
	if (!status.is_ok())
	{
		mi_error("problems getting field_id for color");
		return particleObjTag;
	}
	mi_info("Field id %d", field_id);
	mi::shader::Map_field_type f_type;
	miUint f_dimension;
	bool f_is_global;
	status = map_declaration->get_field_info(field_id, f_type, f_dimension, f_is_global);
	if (!status.is_ok())
	{
		mi_error("problems get_field_info");
		return particleObjTag;
	}
	mi_info("Field type %d is global %d", f_type.type(), f_is_global);
	return particleObjTag;
}
miTag createMeshParticles(miState *state, mrParticleGeoShader_paras *paras, PartioContainer& pc)
{
	mi_info("Creating mesh particles for cache file: %s", pc.cacheFileName.c_str());
	if( ! pc.good())
	{
		mi_error("Invalid PartioContainer.");
		return miNULLTAG;
	}

	Partio::ParticleAttribute posAttr;
	if(!pc.assertAttribute("position", posAttr))
		return miNULLTAG;

	Partio::ParticleAttribute idAttr;
	bool hasId = true;
	if(!pc.assertAttribute("id", idAttr))
		hasId = false;

	Partio::ParticleAttribute radiusPPAttr;
	bool hasRadiusPP = true;
	if(!pc.assertAttribute("radiusPP", radiusPPAttr))
		hasRadiusPP = false;

	Partio::ParticleAttribute velocityAttr;
	bool hasVelocity = true;
	if(!pc.assertAttribute("velocity", velocityAttr))
		hasVelocity = false;
	
	miObject *obj = beginObject();

	float *fpos;
	srand(123345);
	int numParticles = pc.data->numParticles();
	float sizeMultiplier = *mi_eval_scalar(&paras->sizeMultiplier);
	float density = *mi_eval_scalar(&paras->density);
	float size = *mi_eval_scalar(&paras->size);
	float sizeVariation = *mi_eval_scalar(&paras->sizeVariation);

	// particle number can vary because of density value
	int numWrittenParticles = 0;

	// define vectors
	for(int vtxId = 0; vtxId < numParticles; vtxId++)
	{
		miVector pos;
		fpos = (float *)pc.data->data<float>(posAttr, vtxId);

		int id = vtxId;
		if( hasId)
			id = *pc.data->data<int>(idAttr, vtxId);

		float radiusPP = 1.0f;
		if( hasRadiusPP )
			radiusPP = *pc.data->data<float>(radiusPPAttr, vtxId);

		miVector vel = {0.0, 0.0, 0.0};
		if(hasVelocity)
		{
			float *v;
			v = (float *)pc.data->data<float>(velocityAttr, vtxId);
			vel.x = v[0];
			vel.y = v[1];
			vel.z = v[2];
			// velocity ist distance/sekunde, eine velocity von 24 legt also eine Distanz von 1 Einheit pro frame bei 24fps zurück
			// zusätzlich muss man noch den shutter angle beachten, bei 140° sind das -.2 -> 0.2 also 0.4 * 1 und damit grob .4 Einheiten
			float factor = 1.0f/24.0f * 0.4f;
			mi_vector_mul(&vel, factor);
		}

		pos.x = fpos[0];
		pos.y = fpos[1];
		pos.z = fpos[2];

		miVector camPos = pos;

		// ich transformiere das particle in camera space und gehe dann einfach size/2 nach rechts und oben
		miMatrix matrix;
		mi_matrix_ident(matrix);
		miInstance *inst = (miInstance *)mi_db_access(state->instance);
		mi_matrix_copy(matrix, inst->tf.global_to_local);
		mi_db_unpin(state->instance);
		
		mi_point_from_world(state, &camPos, &pos);
		mi_point_from_world(state, &camPos, &camPos);
		mi_point_to_camera(state, &camPos, &camPos);

		float psize = radiusPP * sizeMultiplier;
		int pId = vtxId;
		double rndVal = rnd(id * state->camera->frame + 5);
		if( rndVal > density)
			continue;
		
		float srndVal = (rndVal - 0.5f) * 2.0f;
		psize *= size + (size * srndVal * sizeVariation * 0.5f);
		psize = fabs(psize);
		if(psize == 0.0f)
			continue;

		miVector upRight, bottomLeft;
		upRight = camPos;
		upRight.x += psize/2.0f;
		upRight.y += psize/2.0f;
		bottomLeft = camPos;
		bottomLeft.x -= psize/2.0f;
		bottomLeft.y -= psize/2.0f;

		// checkScreenSpace in Screenspace und testet auf minPixelSize. 
		if(!checkScreenSpace(state, paras, camPos, bottomLeft, upRight) )
			continue;
		numWrittenParticles++;

		miVector v0, v1, v2, v3;
		v0 = bottomLeft;
		v2 = upRight;
		v1 = bottomLeft;
		v1.y = upRight.y;
		v3 = upRight;
		v3.y = bottomLeft.y;

		mi_point_from_camera(state, &v0, &v0);
		mi_point_from_camera(state, &v1, &v1);
		mi_point_from_camera(state, &v2, &v2);
		mi_point_from_camera(state, &v3, &v3);

		mi_point_to_world(state, &v0, &v0);
		mi_point_to_world(state, &v1, &v1);
		mi_point_to_world(state, &v2, &v2);
		mi_point_to_world(state, &v3, &v3);

		miVector v01, v02, v03;
		mi_vector_sub(&v01, &v0, &v1);
		mi_vector_sub(&v02, &v0, &v2);
		mi_vector_sub(&v03, &v0, &v3);
		mi_vector_transform(&v01, &v01, matrix);
		mi_vector_transform(&v02, &v02, matrix);
		mi_vector_transform(&v03, &v03, matrix);
		mi_vector_add(&v1, &v0, &v01);
		mi_vector_add(&v2, &v0, &v02);
		mi_vector_add(&v3, &v0, &v03);

		// add geometry vectors 
		// e.g. -0.5 -0.5 0.5
		add_vector(v0.x, v0.y, v0.z);
		add_vector(v1.x, v1.y, v1.z);
		add_vector(v2.x, v2.y, v2.z);
		add_vector(v3.x, v3.y, v3.z);

		// single motion vector per particle
		add_vector(vel.x, vel.y, vel.z);

	}

	// uv coordinates
	miVector uvw;
	uvw.x = uvw.y = uvw.z = 0.0f;
	uvw.z = 123.0f;
	mi_api_vector_xyz_add( &uvw );
	uvw.x = 1.0;
	mi_api_vector_xyz_add( &uvw );
	uvw.y = 1.0;
	mi_api_vector_xyz_add( &uvw );
	uvw.x = 0.0;
	mi_api_vector_xyz_add( &uvw );


	// define vertices
	// depending on the attributes we have x vectors per vertex:
	// 0: pos1
	// 1: pos2
	// 2: pos3
	// 3: pos4
	// 4: vel
	// tex0 = numWrittenParticles * 5 - 4

	// num done particles für rnd density
	int texIndex = numWrittenParticles * 5;
	for(int vtxId = 0; vtxId < numWrittenParticles; vtxId++)
	{
		int vertexIndex = vtxId * 5;
		int mvIndex = vtxId * 5 + 4;
		// add vertex definitions
		// e.g. v 0 n 8 t 32 m 46
		mi_api_vertex_add(vertexIndex);
		mi_api_vertex_tex_add( texIndex, -1, -1);
		mi_api_vertex_motion_add(mvIndex);

		mi_api_vertex_add(vertexIndex + 1);
		mi_api_vertex_tex_add( texIndex + 1, -1, -1);
		mi_api_vertex_motion_add(mvIndex);

		mi_api_vertex_add(vertexIndex + 2);
		mi_api_vertex_tex_add( texIndex + 2, -1, -1);
		mi_api_vertex_motion_add(mvIndex);

		mi_api_vertex_add(vertexIndex + 3);
		mi_api_vertex_tex_add( texIndex + 3, -1, -1);
		mi_api_vertex_motion_add(mvIndex);
	}


	// add poly for every particle

	for( int pId = 0; pId < numWrittenParticles; pId++)
	{
		int vtxId = pId * 4;
		mi_api_poly_begin_tag(1, miNULLTAG);

		mi_api_poly_index_add(vtxId);
		mi_api_poly_index_add(vtxId + 1);
		mi_api_poly_index_add(vtxId + 2);
		mi_api_poly_index_add(vtxId + 3);

		mi_api_poly_end();

	}
	miTag objTag = finishObject();
	return objTag;
   
}