void miaux_define_hair_object( miTag name_tag, miaux_bbox_function bbox_function, void *params, miTag *geoshader_result, miApi_object_callback callback) { miTag tag; miObject *obj; char *name = miaux_tag_to_string(name_tag, "::hair"); obj = mi_api_object_begin(mi_mem_strdup(name)); obj->visible = miTRUE; obj->shadow = obj->reflection = obj->refraction = 3; bbox_function(obj, params); if (geoshader_result != NULL && callback != NULL) { mi_api_object_callback(callback, params); tag = mi_api_object_end(); mi_geoshader_add_result(geoshader_result, tag); obj = (miObject *)mi_scene_edit(tag); obj->geo.placeholder_list.type = miOBJECT_HAIR; mi_scene_edit_end(tag); } } char* miaux_tag_to_string(miTag tag, char *default_value) { char *result = default_value; if (tag != 0) { result = (char*)mi_db_access(tag); mi_db_unpin(tag); } return result; } result->r += miaux_random_range(-red_variance, red_variance); result->r = miaux_clamp(result->r, 0.0, 1.0); result->g += miaux_random_range(-green_variance, green_variance); result->g = miaux_clamp(result->g, 0.0, 1.0); result->b += miaux_random_range(-blue_variance, blue_variance); result->b = miaux_clamp(result->b, 0.0, 1.0); } double miaux_fit( double v, double oldmin, double oldmax, double newmin, double newmax) { return newmin + ((v - oldmin) / (oldmax - oldmin)) * (newmax - newmin); } void miaux_random_point_on_sphere( miVector *result, miVector *center, miScalar radius) { miMatrix transform; result->x = radius; result->y = result->z = 0.0; mi_matrix_rotate(transform, 0, miaux_random_range(0, M_PI * 2), miaux_random_range(0, M_PI * 2)); mi_vector_transform(result, result, transform); mi_vector_add(result, result, center); } void miaux_hair_spiral( miScalar** scalar_array, miVector *start_point, miVector *end_point, float turns, int point_count, float angle_offset, float spiral_radius, miScalar root_radius, miScalar tip_radius) { miVector base_point, spiral_axis, spiral_point; miVector axis_point; miMatrix matrix; float angle, pi_2 = 2 * M_PI, max_index = point_count - 1; int i; mi_vector_sub(&spiral_axis, end_point, start_point); mi_vector_normalize(&spiral_axis); miaux_perpendicular_point(&axis_point, &spiral_axis, spiral_radius); for (i = 0; i < point_count; i++) { float fraction = i / max_index; miaux_point_between(&base_point, start_point, end_point, fraction); angle = angle_offset + fraction * turns * pi_2; mi_matrix_rotate_axis(matrix, &spiral_axis, angle); mi_point_transform(&spiral_point, &axis_point, matrix); mi_vector_add(&spiral_point, &spiral_point, &base_point); *(*scalar_array)++ = spiral_point.x; *(*scalar_array)++ = spiral_point.y; *(*scalar_array)++ = spiral_point.z; *(*scalar_array)++ = miaux_fit_clamp(i, 0, max_index, root_radius, tip_radius); } } void miaux_perpendicular_point(miVector *result, miVector *v, float distance) { result->x = -v->y; result->y = v->x; result->z = 0; mi_vector_normalize(result); mi_vector_mul(result, distance); } void miaux_point_between( miVector *result, miVector *u, miVector *v, float fraction) { result->x = miaux_fit(fraction, 0, 1, u->x, v->x); result->y = miaux_fit(fraction, 0, 1, u->y, v->y); result->z = miaux_fit(fraction, 0, 1, u->z, v->z); } double miaux_fit_clamp( double v, double oldmin, double oldmax, double newmin, double newmax) { if (oldmin > oldmax) { double temp = oldmin; oldmin = oldmax; oldmax = oldmin; temp = newmin; newmin = newmax; newmax = newmin; } if (v < oldmin) return newmin; else if (v > oldmax) return newmax; else return miaux_fit(v, oldmin, oldmax, newmin, newmax); }