示例#1
0
// Generate a histogram from FFT data
void histogram_generate(PluginData *pd)
{
	int pw = pd->image_width/2+1, h = pd->image_height;
	for (int i=0; i<GRAPH_WIDTH; i++)
	{
		pd->histogram[i] = 0;
	}
	for(int channel=0; channel<pd->channel_count; channel++)
	{
		// add value to histogram
		for(int i=0; i<pw*h; i++)
		{
			float *pixel = (float*)(pd->image_freq[channel] + i);
			float val = sqrt(pixel[0]*pixel[0] + pixel[1]*pixel[1]);
			float dist = index_to_dist(i, pw, h);
			pd->histogram[(unsigned)(GRAPH_WIDTH*CLAMPED(dist_to_graph(dist), 0, 1))] += val/(dist+1);
		}
	}
	// remap histogram values
	float histogram_max = 0;
	for (int i=0; i<GRAPH_WIDTH; i++)
	{
		pd->histogram[i] = log(pd->histogram[i]+1.0);
		if (pd->histogram[i] > histogram_max)
			histogram_max = pd->histogram[i];
	}
	histogram_max = 1.0/histogram_max;
	for (int i=0; i<GRAPH_WIDTH; i++)
	{
		pd->histogram[i] *= histogram_max;
	}
}
示例#2
0
void fft_apply(PluginData *pd)
{
	int w = pd->image_width, h = pd->image_height,
		pw = w/2+1; // physical width
	fftwf_complex *multiplied = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * pw * h);
	float diagonal = sqrt(h*h + w*w)/2.0;
	// save current state of the curve
	curve_copy(&pd->curve_user, &pd->curve_fft);
	for(int channel=0; channel < pd->channel_count; channel++)
	{
		//skip DC value
		multiplied[0][0] = pd->image_freq[channel][0][0];
		multiplied[0][1] = pd->image_freq[channel][0][1];
		// apply convolution
		for (int i=1; i < pw*h; i++){
			float dist = index_to_dist(i, pw, h);
			float coef = curve_get_value(dist_to_graph(dist), &pd->curve_fft);
			multiplied[i][0] = pd->image_freq[channel][i][0] * coef;
			multiplied[i][1] = pd->image_freq[channel][i][1] * coef;
		}
		// apply inverse FFT
		fftwf_execute_dft_c2r(pd->plan, multiplied, pd->image[channel]);
		// pack results for GIMP
		for(int x=0; x < w; x ++)
		{
			for(int y=0; y < h; y ++)
			{
				float v = pd->image[channel][y*w + x];
				pd->img_pixels[(y*w + x)*pd->channel_count + channel] = CLAMPED(v,0,255);
			}
		}
	}
	fftwf_free(multiplied);
}
示例#3
0
void wavelet_prepare(PluginData *pd)
{
	int w = pd->image_width, h = pd->image_height,
		pw = w/2+1; // physical width
	fftwf_complex *multiplied = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * pw * h);
	float *image_temp = (float*)fftwf_malloc(sizeof(float) * w * h);
	float diagonal = sqrt(h*h + w*w)/2;
	pd->image_wavelet = (char*)fftwf_malloc(WAVELET_DEPTH * w * h * sizeof(char));
	// printf("Wavelet layers occupy %lu MB.\n", (WAVELET_DEPTH * w * h * sizeof(short)) >> 20);
	// TODO: keep only the selected part of the image (->save memory)

	int lower = 0, peak = 1, upper = scale_to_dist(1, diagonal);
	for (int scale = 0; scale < WAVELET_DEPTH; scale ++)
	{
		float above = upper-peak, below = peak-lower;
		for (int i=0; i < pw*h; i++){
			multiplied[i][0] = multiplied[i][1] = 0.0;
		}
		for (int i=0; i < pw*h; i++)
		{
			float dist = index_to_dist(i, pw, h);
			if (dist <= upper){
				if (dist > lower){
					if (dist > peak){
						for(int channel=0; channel < pd->channel_count; channel ++)
						{
							multiplied[i][0] += pd->image_freq[channel][i][0];
							multiplied[i][1] += pd->image_freq[channel][i][1];
						}
						float coef = (1.0 - (dist-peak)/above) / pd->channel_count;
						multiplied[i][0] *= coef;
						multiplied[i][1] *= coef;
					}
					else {
						for(int channel=0; channel < pd->channel_count; channel ++)
						{
							multiplied[i][0] += pd->image_freq[channel][i][0];
							multiplied[i][1] += pd->image_freq[channel][i][1];
						}
						float coef = (1.0 - (peak-dist)/below) / pd->channel_count;
						multiplied[i][0] *= coef;
						multiplied[i][1] *= coef;
					}
				}
			}
		}
		// apply inverse FFT
		fftwf_execute_dft_c2r(pd->plan, multiplied, image_temp);
		for (int i=0; i < w*h; i++)
		{
			pd->image_wavelet[i*WAVELET_DEPTH + scale] = CLAMPED(image_temp[i], -127, 127);
		}
		lower = peak;
		peak = upper;
		upper = scale_to_dist(scale+2, diagonal);
	}
	fftwf_free(multiplied);
	fftwf_free(image_temp);
}
示例#4
0
// Completely redraw the graph widget
void graph_redraw(PluginData *pd)
{
	GtkStyle *graph_style = gtk_widget_get_style (pd->graph);
	// clear the pixmap
	gdk_draw_rectangle (pd->graph_pixmap, graph_style->light_gc[GTK_STATE_NORMAL],
											TRUE, 0, 0, GRAPH_WIDTH, GRAPH_HEIGHT);
	
	// histogram
	for (int i=0; i<GRAPH_WIDTH; i++)
	{
		gdk_draw_line (pd->graph_pixmap, graph_style->mid_gc[GTK_STATE_NORMAL], i, GRAPH_HEIGHT * (1.0-pd->histogram[i]), i, GRAPH_HEIGHT);
	}
	// horizontal lines
	gdk_draw_line (pd->graph_pixmap, graph_style->dark_gc[GTK_STATE_NORMAL], 0, GRAPH_HEIGHT-1, GRAPH_WIDTH, GRAPH_HEIGHT-1);
	for (int i = 1; i < 10; i++)
	{
		int y = value_to_graph(i/2.0);
		gdk_draw_line (pd->graph_pixmap, graph_style->dark_gc[GTK_STATE_NORMAL], 0, y, GRAPH_WIDTH, y);
	}
	gdk_draw_line (pd->graph_pixmap, graph_style->dark_gc[GTK_STATE_NORMAL], 0, 0, GRAPH_WIDTH, 0);
	// vertical lines
	for (int i = 0; i < 10; i++)
	{
		int x = dist_to_graph(i)*GRAPH_WIDTH;
		gdk_draw_line (pd->graph_pixmap, graph_style->dark_gc[GTK_STATE_NORMAL], x, 0, x, GRAPH_HEIGHT);
		x = dist_to_graph(10*i)*GRAPH_WIDTH;
		gdk_draw_line (pd->graph_pixmap, graph_style->dark_gc[GTK_STATE_NORMAL], x, 0, x, GRAPH_HEIGHT);
	}
	gdk_draw_line (pd->graph_pixmap, graph_style->dark_gc[GTK_STATE_NORMAL], GRAPH_WIDTH-1, 0, GRAPH_WIDTH-1, GRAPH_HEIGHT);
	// wavelet marks
	float diagonal = sqrt(pd->image_width*pd->image_width + pd->image_height*pd->image_height)/2;
	for (int i = 0; i < WAVELET_DEPTH; i++)
	{
		int x = CLAMPED(dist_to_graph(scale_to_dist(i, diagonal))*GRAPH_WIDTH, 0, GRAPH_WIDTH-1);
		gdk_draw_line (pd->graph_pixmap, graph_style->text_gc[GTK_STATE_NORMAL], x, GRAPH_HEIGHT/2 - 2, x, GRAPH_HEIGHT/2 + 2);
	}
	// user curve
	gdk_draw_lines (pd->graph_pixmap, graph_style->text_gc[GTK_STATE_NORMAL], pd->curve_user.points, GRAPH_WIDTH);
	// user points
	for (int i = 0; i < pd->curve_user.count; i++)
	{
		gdk_draw_arc(pd->graph_pixmap, graph_style->text_gc[GTK_STATE_NORMAL], FALSE, pd->curve_user.user_points[i].x-GRAPH_HOTSPOT-1, pd->curve_user.user_points[i].y-GRAPH_HOTSPOT-1, GRAPH_HOTSPOT*2+1, GRAPH_HOTSPOT*2+1, 0, 64*360);
	}
	gdk_draw_drawable (pd->graph->window, graph_style->text_gc[GTK_STATE_NORMAL], pd->graph_pixmap, 0, 0, 0, 0, GRAPH_WIDTH, GRAPH_HEIGHT);
}
示例#5
0
void PmxMaterialMergeMorph(PMX_MATERIAL* material, MORPH_MATERIAL* morph, FLOAT_T weight)
{
	CLAMPED(weight, 0, 1);
	if(FuzzyZero((float)weight) != 0)
	{
		PmxMaterialResetMorph(material);
	}
	else
	{
		switch(morph->operation)
		{
		case 0:	// 乗算
			MaterialRGB3CalculateMultiWeight(&material->ambient, morph->ambient, weight);
			MaterialRGBA3CalculateMultiWeight(&material->diffuse, morph->diffuse, weight);
			MaterialRGB3CalculateMultiWeight(&material->specular, morph->specular, weight);
			material->shininess[1] = (float)(1 - (1 - morph->shininess) * weight);
			MaterialRGBA3CalculateMultiWeight(&material->edge_color, morph->edge_color, weight);
			material->edge_size[1] = (float)(1 - (1 - morph->edge_size) * weight);
			MaterialRGBA3CalculateMultiWeight(&material->main_texture_blend, morph->texture_weight, weight);
			MaterialRGBA3CalculateMultiWeight(&material->sphere_texture_blend, morph->sphere_texture_weight, weight);
			MaterialRGBA3CalculateMultiWeight(&material->toon_texture_blend, morph->toon_texture_weight, weight);
			break;
		case 1:	// 加算
			MaterialRGB3CalculateAddWeight(&material->ambient, morph->ambient, weight);
			MaterialRGBA3CalculateAddWeight(&material->diffuse, morph->diffuse, weight);
			MaterialRGB3CalculateAddWeight(&material->specular, morph->specular, weight);
			material->shininess[2] = (float)(morph->shininess * weight);
			MaterialRGBA3CalculateAddWeight(&material->edge_color, morph->edge_color, weight);
			material->edge_size[2] = (float)(morph->edge_size * weight);
			MaterialRGBA3CalculateAddWeight(&material->main_texture_blend, morph->texture_weight, weight);
			MaterialRGBA3CalculateAddWeight(&material->sphere_texture_blend, morph->sphere_texture_weight, weight);
			MaterialRGBA3CalculateAddWeight(&material->toon_texture_blend, morph->toon_texture_weight, weight);
			break;
		}

		MaterialRGB3Calculate(&material->ambient);
		MaterialRGBA3Calculate(&material->diffuse);
		MaterialRGB3Calculate(&material->specular);
		MaterialRGBA3Calculate(&material->edge_color);
		MaterialRGBA3Calculate(&material->main_texture_blend);
		MaterialRGBA3Calculate(&material->sphere_texture_blend);
		MaterialRGBA3Calculate(&material->toon_texture_blend);
	}
}
/* -----------------------------------------------
	calculate current quality range for table #
	----------------------------------------------- */
void calc_quality_range( int tno, float* low, float* high )
{
	float s = 0;
	float sl = 0;
	float sh = 65536;
	int ref = -1; // # of reference table
	int cmp;
	int i;
	
	
	// decide reference table
	for ( cmp = 0; cmp < cmpc; cmp++ ) {
		if ( cmpnfo[ cmp ].qtable == qtables[ tno ] ) {
			ref = cmpnfo[ cmp ].sid;
			ref = CLAMPED( 0, 1, ref );
			break;
		}
	}
	
	// check if no reference was found
	if ( ref == -1 ) {
		(*low) = 0;
		(*high) = 0;
		return;
	}
	
	// compare tables, calculate average scaling factor s
	for ( i = 0; i < 64; i++ ) {
		s = ( ( float ) qtables[ tno ][ i ] ) / ( ( float ) std_qtables[ ref ][ unzigzag[i] ] );
		sl = ( s > sl ) ? s : sl;
		sh = ( s < sh ) ? s : sh;
	}
	
	// calculate qualities based on s
	(*low)  = ( sl < 1.0 ) ? 1.0 - (sl/2) : 1.0 / (2*sl);
	(*high) = ( sh < 1.0 ) ? 1.0 - (sh/2) : 1.0 / (2*sh);
}
示例#7
0
// GTK event handler for the graph widget
static gint graph_events (GtkWidget *widget, GdkEvent *event, PluginData *pd)
{
  static GdkCursorType cursor_type = GDK_TOP_LEFT_ARROW;
  int tx, ty, index, dist;

  gdk_window_get_pointer (pd->graph->window, &tx, &ty, NULL);
	
	if (event->type == GDK_EXPOSE)
	{
		if (pd->graph_pixmap == NULL)
			pd->graph_pixmap = gdk_pixmap_new (pd->graph->window, GRAPH_WIDTH, GRAPH_HEIGHT, -1);
		graph_redraw (pd);
	}	
	
	else if (event->type == GDK_BUTTON_PRESS)
	{
		// Button press: add or grab a point
		index = gdkpoint_bisect(tx, pd->curve_user.user_points, pd->curve_user.count);
		if (index < pd->curve_user.count)
		{
			dist = pd->curve_user.user_points[index].x - tx;
		}
		if (index > 0 && tx - pd->curve_user.user_points[index-1].x < dist)
		{
			index -= 1;
			dist = tx - pd->curve_user.user_points[index].x;
		}
		if (dist <= GRAPH_HOTSPOT || pd->curve_user.count == USER_POINT_COUNT)
			pd->point_grabbed = curve_move_point(index, tx, ty, &pd->curve_user);
		else 
			pd->point_grabbed = curve_add_point(tx, ty, &pd->curve_user);
		pd->curve_user_changed = TRUE;
		graph_redraw (pd);
		gimp_preview_invalidate(GIMP_PREVIEW(pd->preview));
	}
		
	else if (event->type == GDK_BUTTON_RELEASE)
	{
		// Button release: move a point and remove it if requested
		if (pd->point_grabbed >= 0) {
			if (tx < 0 && pd->point_grabbed > 0) // if point is not first, remove it
				curve_remove_point(pd->point_grabbed, &pd->curve_user);
			else if (tx >= GRAPH_WIDTH && pd->point_grabbed+1 < pd->curve_user.count) // if point is not last, remove it
				curve_remove_point(pd->point_grabbed, &pd->curve_user);
			else
				curve_move_point(pd->point_grabbed, CLAMPED(tx, 0,GRAPH_WIDTH-1), CLAMPED(ty, 0,GRAPH_HEIGHT-1), &pd->curve_user);
			pd->point_grabbed = -1;
			pd->curve_user_changed = TRUE;
			graph_redraw (pd);
			if (pd->do_preview_hd)
				preview_hd(NULL, pd);
			gimp_preview_invalidate(GIMP_PREVIEW(pd->preview));
		}
	}
		
	else if (event->type == GDK_MOTION_NOTIFY)
	{
		// Mouse move: move a previously grabbed point
		if (pd->point_grabbed >= 0){
			pd->point_grabbed = curve_move_point(pd->point_grabbed, CLAMPED(tx, 0,GRAPH_WIDTH-1), CLAMPED(ty, 0,GRAPH_HEIGHT-1), &pd->curve_user);
			pd->curve_user_changed = TRUE;
		  graph_redraw (pd);
			gimp_preview_invalidate(GIMP_PREVIEW(pd->preview));
		}
	}
	
	return FALSE;
}
示例#8
0
void wavelet_apply(PluginData *pd, int out_x, int out_y, int out_w, int out_h)
{
	int w = pd->image_width, h = pd->image_height;
	if (pd->curve_user_changed)
	{
		// estimate needed coefficient for each wavelet layer
		// (TODO: integrate)
		float coef[WAVELET_DEPTH];
		float diagonal = sqrt(h*h + w*w)/2;
		for (int scale=0; scale<WAVELET_DEPTH; scale++)
		{
			float x = dist_to_graph(scale_to_dist(scale, diagonal));
			coef[scale] = curve_get_value(x, &pd->curve_user) - curve_get_value(x, &pd->curve_fft);
		}
		// combine wavelet layers
		for (int y=0; y<out_h; y++)
		{
			for (int x=0; x<out_w; x++)
			{
				char *pixel_wavelets = pd->image_wavelet + WAVELET_DEPTH*((y+out_y)*w +(x+out_x));
				// calculate needed brightness change (per channel)
				float diff = 0; 
				for (int scale=0; scale<WAVELET_DEPTH; scale ++)
				{
					diff += pixel_wavelets[scale] * coef[scale];
				}
				if (diff < 0)
				{
					// darken the pixel: multiply all channels (to keep its hue)
					float value = 0; // current value of the pixel
					for (int channel = 0; channel < pd->channel_count; channel ++)
					{
						value += pd->image[channel][(y+out_y)*w+(x+out_x)];
					}
					value = value/pd->channel_count;
					for (int channel = 0; channel < pd->channel_count; channel ++)
					{
						pd->img_pixels[(y*out_w+x)*pd->channel_count + channel] = CLAMPED(pd->image[channel][(y+out_y)*w+(x+out_x)] * (1 + diff/value), 0, 255);
					}
				}
				else
				{
					// brighten the pixel: add value to all channels
					for (int channel = 0; channel < pd->channel_count; channel ++)
					{
						pd->img_pixels[(y*out_w+x)*pd->channel_count + channel] = CLAMPED(pd->image[channel][(y+out_y)*w+(x+out_x)] + diff, 0, 255);
					}
				}
			}
		}
	}
	else
	{
		// direct copy
		for (int y=0; y<out_h; y++)
		{
			for (int x=0; x<out_w; x++)
			{
				for (int channel=0; channel < pd->channel_count; channel ++)
				{
					pd->img_pixels[(y*out_w+x)*pd->channel_count + channel] = CLAMPED(pd->image[channel][(y+out_y)*w+(x+out_x)], 0, 255);
				}
			}
		}
	}
}
示例#9
0
文件: bone.c 项目: umibps/KABURAGI
void PmxBoneSolveInverseKinematics(PMX_BONE* bone)
{
	PMX_IK_CONSTRAINT *constraints = (PMX_IK_CONSTRAINT*)bone->constraints->buffer;
	float root_bone_position[3];
	const float angle_limit = bone->angle_limit;
	const int num_constraints = (int)bone->constraints->num_data;
	const int num_iteration = bone->num_iteration;
	const int num_half_of_iteration = num_iteration / 2;
	PMX_BONE *effector_bone = (PMX_BONE*)bone->interface_data.effector_bone;
	float original_target_rotation[4];
	float joint_rotation[4] = IDENTITY_QUATERNION;
	float new_joint_local_rotation[4];
	float matrix[9];
	float local_effector_position[3] = {0};
	float local_root_bone_position[3] = {0};
	float local_axis[3] = {0};
	int i, j, k;

	if((bone->flags & PMX_BONE_FLAG_HAS_INVERSE_KINEMATICS) == 0)
	{
		return;
	}

	BtTransformGetOrigin(bone->world_transform, root_bone_position);
	COPY_VECTOR4(original_target_rotation, effector_bone->local_rotation);

	for(i=0; i<num_iteration; i++)
	{
		int perform_constraint = i < num_half_of_iteration;
		for(j=0; j<num_constraints; j++)
		{
			PMX_IK_CONSTRAINT *constraint = &constraints[j];
			PMX_BONE *joint_bone = constraint->joint_bone;
			float current_effector_position[3];
			void *joint_bone_transform = BtTransformCopy(joint_bone->world_transform);
			void *inversed_joint_bone_transform = BtTransformCopy(joint_bone->world_transform);
			float dot;
			float new_angle_limit;
			float angle;
			float value;

			BtTransformGetOrigin(effector_bone->world_transform, current_effector_position);
			BtTransformInverse(inversed_joint_bone_transform);

			BtTransformMultiVector3(inversed_joint_bone_transform, root_bone_position, local_root_bone_position);
			Normalize3DVector(local_root_bone_position);
			BtTransformMultiVector3(inversed_joint_bone_transform, current_effector_position, local_effector_position);
			Normalize3DVector(local_effector_position);
			dot = Dot3DVector(local_root_bone_position, local_effector_position);
			if(FuzzyZero(dot) != 0)
			{
				break;
			}
			Cross3DVector(local_axis, local_effector_position, local_root_bone_position);
			SafeNormalize3DVector(local_axis);
			new_angle_limit = angle_limit * (j + 1) * 2;
			/*if(dot < -1)
			{
				angle = -1;
			}
			else if(dot > 1)
			{
				angle = 1;
			}
			else
			{
				angle = acosf(dot);
			}*/
			value = dot;
			value = ExtendedFuzzyZero(1.0f - value) ? 1.0f : ExtendedFuzzyZero(1.0f + value) ? -1.0f : value;
			angle = acosf(value);
			CLAMPED(angle, - new_angle_limit, new_angle_limit);
			QuaternionSetRotation(joint_rotation, local_axis, angle);
			if(constraint->has_angle_limit != FALSE && perform_constraint != FALSE)
			{
				float lower_limit[3];
				float upper_limit[3];

				COPY_VECTOR3(lower_limit, constraint->lower_limit);
				COPY_VECTOR3(upper_limit, constraint->upper_limit);

				if(i == 0)
				{
					if(FuzzyZero(lower_limit[1]) && FuzzyZero(upper_limit[1])
						&& FuzzyZero(lower_limit[2]) && FuzzyZero(upper_limit[2]))
					{
						local_axis[0] = 1;
						local_axis[1] = 0;
						local_axis[2] = 0;
					}
					else if(FuzzyZero(lower_limit[0]) && FuzzyZero(upper_limit[0])
						&& FuzzyZero(lower_limit[2]) && FuzzyZero(upper_limit[2]))
					{
						local_axis[0] = 0;
						local_axis[1] = 1;
						local_axis[2] = 0;
					}
					else if(FuzzyZero(lower_limit[0]) && FuzzyZero(upper_limit[0])
						&& FuzzyZero(lower_limit[1]) && FuzzyZero(upper_limit[1]))
					{
						local_axis[0] = 0;
						local_axis[1] = 0;
						local_axis[2] = 1;
					}
					QuaternionSetRotation(joint_rotation, local_axis, angle);
				}
				else
				{
					float x1, y1, z1, x2, y2, z2, x3, y3, z3;
					Matrix3x3SetRotation(matrix, joint_rotation);
					Matrix3x3GetEulerZYX(matrix, &z1, &y1, &x1);
					Matrix3x3SetRotation(matrix, joint_bone->local_rotation);
					Matrix3x3GetEulerZYX(matrix, &z2, &y2, &x2);
					x3 = x1 + x2,	y3 = y1 + y2,	z3 = z1 + z2;
					x1 = ClampAngle(lower_limit[0], upper_limit[0], x3, x1);
					y1 = ClampAngle(lower_limit[1], upper_limit[1], y3, y1);
					z1 = ClampAngle(lower_limit[2], upper_limit[2], z3, z1);
					QuaternionSetEulerZYX(joint_rotation, z1, y1, x1);
				}
				COPY_VECTOR4(new_joint_local_rotation, joint_rotation);
				MultiQuaternion(new_joint_local_rotation, joint_bone->local_rotation);
			}
			else if(i == 0)
			{
				//COPY_VECTOR4(new_joint_local_rotation, joint_bone->local_rotation);
				//MultiQuaternion(new_joint_local_rotation, joint_rotation);
				COPY_VECTOR4(new_joint_local_rotation, joint_rotation);
				MultiQuaternion(new_joint_local_rotation, joint_bone->local_rotation);
			}
			else
			{
				//COPY_VECTOR4(new_joint_local_rotation, joint_rotation);
				//MultiQuaternion(new_joint_local_rotation, joint_bone->local_rotation);
				COPY_VECTOR4(new_joint_local_rotation, joint_bone->local_rotation);
				MultiQuaternion(new_joint_local_rotation, joint_rotation);
			}
			PmxBoneSetLocalOrientation(joint_bone, new_joint_local_rotation);
			COPY_VECTOR4(joint_bone->joint_rotation, joint_rotation);

			for(k=j; k>=0; k--)
			{
				PMX_IK_CONSTRAINT *ik = &constraints[k];
				PMX_BONE *joint = ik->joint_bone;
				PmxBoneUpdateWorldTransformSimple(joint);
			}
			PmxBoneUpdateWorldTransformSimple(effector_bone);

			DeleteBtTransform(joint_bone_transform);
			DeleteBtTransform(inversed_joint_bone_transform);
		}
	}

	PmxBoneSetLocalOrientation(effector_bone, original_target_rotation);
}