/// スクリーン座標からエフェクタを見つけます。 /// 衝突するエフェクタの中で最も近い位置にあるエフェクタを返します。 private bool FindEffectorOnScreenPoint(float x, float y, out TMONode effector) { effector = null; Figure fig; if (TryGetFigure(out fig)) { Debug.Assert(fig.Tmo.nodemap != null, "fig.Tmo.nodemap should not be null"); float min_time = 1e12f; foreach (string effector_path in solver.EachEffecterNames) { TMONode bone; if (fig.Tmo.nodemap.TryGetValue(effector_path, out bone)) { Vector3 collisionPoint; float collisionTime; if (FindBoneOnScreenPoint(lastScreenPoint.X, lastScreenPoint.Y, bone, out collisionPoint, out collisionTime)) { if (collisionTime < min_time) { min_time = collisionTime; effector = bone; } } } } if (effector != null) { return(true); } } return(false); }
/// node操作を生成します。 public NodeCommand(Figure fig, TMONode node) { this.fig = fig; this.node = node; this.old_attr.rotation = node.Rotation; this.old_attr.translation = node.Translation; }
/// <summary> /// 指定スクリーン座標に指定ボーンがあるか。 /// </summary> /// <param name="x">スクリーンX座標</param> /// <param name="y">スクリーンY座標</param> /// <param name="bone">ボーン</param> /// <returns>ボーンを見つけたか</returns> public bool FindBoneOnScreenPoint(float x, float y, TMONode bone) { float collisionTime; Vector3 collisionPoint; return(FindBoneOnScreenPoint(x, y, bone, out collisionPoint, out collisionTime)); }
/// おっぱい変形:貧乳を行います。 public void TransformChichiFlat(TMONode tmo_node, ref Matrix m) { Matrix c = Matrix.Identity; GetMinChichi(tmo_node.Name, ref c); GetMatrixRatio(out m, ref c, ref m, oppai_ratio / FlatRatio); }
Vector3 GetNodePositionOnScreen(TMONode node) { Vector3 position = GetMatrixTranslation(ref node.combined_matrix); Vector3 screen_position = WorldToScreen(position); return(screen_position); }
void CopyChildrenMatFrom_0(TMONode motion, List <string> except_names) { List <TMONode> select_children = new List <TMONode>(); foreach (TMONode child_node in children) { bool found = false; foreach (string except_name in except_names) { if (child_node.name == except_name) { found = true; break; } } if (found) { except_names.Remove(child_node.name); } else { select_children.Add(child_node); } } foreach (TMONode child_node in select_children) { TMONode motion_child = motion.FindChildByName(child_node.name); child_node.CopyThisMatFrom(motion_child); child_node.CopyChildrenMatFrom_0(motion_child, except_names); } }
bool HiddenNode(TMONode node) { Vector3 position = GetMatrixTranslation(ref node.combined_matrix); Vector3 view_position = Vector3.TransformCoordinate(position, Transform_View); return(view_position.Z > 0.0f); }
/// <summary> /// bone行列を更新します。 /// </summary> protected void UpdateBoneMatrices(TMONode tmo_node, TMOFrame tmo_frame) { matrixStack.Push(); if (tmo_frame != null) { // tmo animation tmo_node.TransformationMatrix = tmo_frame.matrices[tmo_node.Id].m; } Matrix m = tmo_node.TransformationMatrix; if (slider_matrix != null) { bool chichi_p = re_chichi.IsMatch(tmo_node.Name); if (chichi_p) { slider_matrix.ScaleChichi(tmo_node, ref m); if (slider_matrix.Flat()) { if (clothed) { slider_matrix.TransformChichiFlatClothed(tmo_node, ref m); } else { slider_matrix.TransformChichiFlat(tmo_node, ref m); } } } else { slider_matrix.TransformFace(tmo_node, ref m); } matrixStack.MultiplyMatrixLocal(m); m = matrixStack.Top; if (!chichi_p) { slider_matrix.Scale(tmo_node, ref m); } } else { matrixStack.MultiplyMatrixLocal(m); m = matrixStack.Top; } tmo_node.combined_matrix = m; foreach (TMONode child_node in tmo_node.children) { UpdateBoneMatrices(child_node, tmo_frame); } matrixStack.Pop(); }
static void AddTreeNodes(List <TMONode> select_nodes, TMONode root_node) { select_nodes.Add(root_node); foreach (TMONode node in root_node.children) { AddTreeNodes(select_nodes, node); } }
/// <summary> /// 指定nodeから行列を複写します。 /// </summary> /// <param name="motion">node</param> public void CopyMatFrom(TMONode motion) { CopyThisMatFrom(motion); foreach (TMONode child_node in children) { child_node.CopyMatFrom(motion.FindChildByName(child_node.name)); } }
Vector3 GetNodeDirZPositionOnScreen(TMONode node) { Vector3 p1 = GetMatrixDirZTranslation(ref node.combined_matrix, 1); Vector3 p2 = WorldToScreen(p1); p2.Z = 0.0f; //表面に固定 return(p2); }
/// <summary> /// フィギュアに含まれるnode treeを描画する。 /// </summary> /// <param name="fig"></param> void DrawNodeTree(Figure fig) { TMOFile tmo = fig.Tmo; Line line = new Line(device); foreach (TMONode node in tmo.nodes) { if (HiddenNode(node)) { continue; } Vector3 p0 = GetNodePositionOnScreen(node); p0.Z = 0.0f; TMONode parent_node = node.parent; if (parent_node != null) { if (HiddenNode(parent_node)) { continue; } Vector3 p1 = GetNodePositionOnScreen(parent_node); p1.Z = 0.0f; Vector3 pd = p0 - p1; float len = Vector3.Length(pd); float scale = 4.0f / len; Vector2 p3 = new Vector2(p1.X + pd.Y * scale, p1.Y - pd.X * scale); Vector2 p4 = new Vector2(p1.X - pd.Y * scale, p1.Y + pd.X * scale); Vector2[] vertices = new Vector2[3]; vertices[0] = new Vector2(p3.X, p3.Y); vertices[1] = new Vector2(p0.X, p0.Y); vertices[2] = new Vector2(p4.X, p4.Y); line.Draw(vertices, LineColor); } } line.Dispose(); line = null; Rectangle rect = new Rectangle(0, 16, 15, 15); //node circle Vector3 rect_center = new Vector3(7, 7, 0); sprite.Begin(SpriteFlags.None); foreach (TMONode node in tmo.nodes) { if (HiddenNode(node)) { continue; } Vector3 p0 = GetNodePositionOnScreen(node); p0.Z = 0.0f; sprite.Draw(dot_texture, rect, rect_center, p0, Color.White); } sprite.End(); }
private void LimitRotationZXY(TMONode node) { TMOConstraintItem item = constraint_zxy.GetItem(node.Name); Vector3 angle1 = TMOMat.ToAngleZXY(node.Rotation); Vector3 angle0 = item.Limit(angle1); node.Rotation = TMOMat.ToQuaternionZXY(angle0); //Console.WriteLine("node {0} x {1:F2} y {2:F2} z {3:F2}", node.Name, angle0.X, angle0.Y, angle0.Z); }
public void CopyMatFrom(TMONode motion) { CopyThisMatFrom(motion); foreach (TMONode child in children) { TMONode motion_child = motion.FindChildByShortName(child.sname); child.CopyMatFrom(motion_child); } }
private void LimitRotationXYZ(TMONode node) { TMOConstraintItem item = constraint_xyz.GetItem(node.Name); Vector3 angle1 = Helper.ToAngleXYZ(node.Rotation); Vector3 angle0 = item.Limit(angle1); node.Rotation = Helper.ToQuaternionXYZ(angle0); //Console.WriteLine("node {0} x {1:F2} y {2:F2} z {3:F2}", node.Name, angle0.X, angle0.Y, angle0.Z); }
/// 体型変形を行います。 public void Scale(TMONode tmo_node, ref Matrix m) { switch (tmo_node.Name) { case "W_Spine_Dummy": Scale1(ref m, this.SpineDummy); break; case "W_Spine1": case "W_Spine2": Scale1(ref m, this.Spine1); break; case "W_LeftHips_Dummy": case "W_RightHips_Dummy": Scale1(ref m, this.HipsDummy); break; case "W_LeftUpLeg": case "W_RightUpLeg": Scale1(ref m, this.UpLeg); break; case "W_LeftUpLegRoll": case "W_RightUpLegRoll": case "W_LeftLeg": case "W_RightLeg": Scale1(ref m, this.UpLegRoll); break; case "W_LeftLegRoll": case "W_RightLegRoll": case "W_LeftFoot": case "W_RightFoot": case "W_LeftToeBase": case "W_RightToeBase": Scale1(ref m, this.LegRoll); break; case "W_LeftArm_Dummy": case "W_RightArm_Dummy": Scale1(ref m, this.ArmDummy); break; case "W_LeftArm": case "W_RightArm": case "W_LeftArmRoll": case "W_RightArmRoll": case "W_LeftForeArm": case "W_RightForeArm": case "W_LeftForeArmRoll": case "W_RightForeArmRoll": Scale1(ref m, this.Arm); break; } }
/// <summary> /// 指定nodeから行列を複写します。 /// ただし複写の対象は子node以降です。指定nodeは複写しません。 /// また、除外node以降のnodeは複写しません。 /// </summary> /// <param name="motion">node</param> /// <param name="except_names">除外node名称(短い形式)リスト</param> public void CopyChildrenMatFrom(TMONode motion, List <string> except_names) { List <string> dup_except_names = new List <string>(); foreach (string except_name in except_names) { dup_except_names.Add(except_name); } CopyChildrenMatFrom_0(motion, dup_except_names); }
/// <summary> /// 指定nodeから行列を複写します。 /// </summary> /// <param name="motion">node</param> public void CopyThisMatFrom(TMONode motion) { //Console.WriteLine("copy mat {0} {1}", name, motion.Name); int i = 0; foreach (TMOMat mat in matrices) { mat.m = motion.matrices[i % motion.matrices.Count].m; i++; } }
/// <summary> /// ワールド座標系での回転を得る /// </summary> public static Quaternion GetWorldRotation(this TDCG.TMONode node) { TMONode n = node; Quaternion q = Quaternion.Identity; while (n != null) { q.Multiply(n.Rotation); n = n.parent; } return(q); }
/// <summary> /// bone行列を更新します。 /// </summary> protected void UpdateBoneMatrices(TMONode tmo_node, TMOFrame tmo_frame) { if (tmo_frame != null) { // TMO animation tmo_node.TransformationMatrix = tmo_frame.matrices[tmo_node.ID].m; } Matrix m = tmo_node.TransformationMatrix; bool chichi_p = re_chichi.IsMatch(tmo_node.Name); if (chichi_p) { if (slider_matrix.Flat()) { slider_matrix.TransformChichiFlat(tmo_node, ref m); } else { slider_matrix.TranslateChichi(ref m); } } else { // todo: face_p slider_matrix.TransformFace(tmo_node, ref m); } matrixStack.Push(m * matrixStack.Peek()); m = matrixStack.Peek(); if (chichi_p) { if (!slider_matrix.Flat()) { slider_matrix.ScaleChichi(ref m); } } else { // todo: scale1map slider_matrix.Scale(tmo_node, ref m); } tmo_node.combined_matrix = m; foreach (TMONode child_node in tmo_node.children) { UpdateBoneMatrices(child_node, tmo_frame); } matrixStack.Pop(); }
public Matrix GetWorldCoordinate() { Matrix m = Matrix.Identity; TMONode node = this; while (node != null) { m.Multiply(node.frame_matrices[0].m); node = node.parent; } return(m); }
/// <summary> /// ワールド座標系での位置を得ます。 /// </summary> /// <returns></returns> public Vector3 GetWorldPosition() { TMONode node = this; Vector3 v = Vector3.Empty; while (node != null) { v = Vector3.TransformCoordinate(v, node.TransformationMatrix); node = node.parent; } return(v); }
/// <summary> /// ワールド座標系での位置と向きを得ます。 /// </summary> /// <returns></returns> public Matrix GetWorldCoordinate() { TMONode node = this; Matrix m = Matrix.Identity; while (node != null) { m.Multiply(node.TransformationMatrix); node = node.parent; } return(m); }
private void LimitRotation(TMONode node) { if (LimitRotationEnabled) { if (re_legnode.IsMatch(node.Name)) { LimitRotationXYZ(node); } else { LimitRotationZXY(node); } } }
/// <summary> /// モーフ変形の対象となるノードを選択します。 /// </summary> /// <param name="tmo">対象tmo</param> /// <returns>ノードリスト</returns> public List <TMONode> SelectNodes(TMOFile tmo) { List <TMONode> select_nodes = new List <TMONode>(); foreach (string root_name in nodes_range.root_names) { TMONode root_node = tmo.FindNodeByName(root_name); if (root_node != null) { AddTreeNodes(select_nodes, root_node); } } return(select_nodes); }
/// <summary> /// bone行列を更新します。 /// </summary> protected void UpdateBoneMatrices(TMONode tmo_node, TMOFrame tmo_frame) { matrixStack.Push(); if (tmo_frame != null) { // TMO animation tmo_node.TransformationMatrix = tmo_frame.matrices[tmo_node.ID].m; } Matrix m = tmo_node.TransformationMatrix; bool is_chichi = re_chichi.IsMatch(tmo_node.Name); if (is_chichi) { if (slide_matrices.Flat()) { slide_matrices.TransformChichiFlat(tmo_node, ref m); } } else { slide_matrices.TransformFace(tmo_node, ref m); } matrixStack.MultiplyMatrixLocal(m); m = matrixStack.Top; if (is_chichi) { if (!slide_matrices.Flat()) { slide_matrices.ScaleChichi(ref m); } } else { slide_matrices.Scale(tmo_node, ref m); } tmo_node.combined_matrix = m; foreach (TMONode child_node in tmo_node.children) { UpdateBoneMatrices(child_node, tmo_frame); } matrixStack.Pop(); }
/// <summary> /// 指定tmoにある指定名称(短い形式)のnodeを同じ名称のnodeに複写します。 /// ただし複写の対象は子node以降です。指定nodeは複写しません。 /// また、除外node以降のnodeは複写しません。 /// </summary> /// <param name="motion">tmo</param> /// <param name="name">node名称(短い形式)</param> /// <param name="except_names">除外node名称(短い形式)リスト</param> public void CopyChildrenNodeFrom(TMOFile motion, string name, List <string> except_names) { TMONode node = this.FindNodeByName(name); if (node == null) { return; } TMONode motion_node = motion.FindNodeByName(name); if (motion_node == null) { return; } node.CopyChildrenMatFrom(motion_node, except_names); }
/// <summary> /// 指定tmoにある指定名称(短い形式)のnodeを同じ名称のnodeに複写します。 /// </summary> /// <param name="motion">tmo</param> /// <param name="name">node名称(短い形式)</param> public void CopyNodeFrom(TMOFile motion, string name) { TMONode node = this.FindNodeByName(name); if (node == null) { return; } TMONode motion_node = motion.FindNodeByName(name); if (motion_node == null) { return; } node.CopyMatFrom(motion_node); }
/// おっぱい変形を行います。 public void ScaleChichi(TMONode tmo_node, ref Matrix m) { switch (tmo_node.Name) { case "Chichi_Right1": case "Chichi_Left1": Helper.Scale1(ref m, this.Chichi); break; default: m.M41 /= this.Chichi.X; m.M42 /= this.Chichi.Y; m.M43 /= this.Chichi.Z; break; } }
void DrawNodeAxis(TMONode bone) { Vector3 p1 = GetNodePositionOnScreen(bone); p1.Z = 0.0f; Vector3 position = GetMatrixTranslation(ref bone.combined_matrix); Vector3 dirx = GetMatrixDirX(ref bone.combined_matrix); Vector3 diry = GetMatrixDirY(ref bone.combined_matrix); Vector3 dirz = GetMatrixDirZ(ref bone.combined_matrix); Vector3 view_position_dirx = Vector3.TransformCoordinate(position + dirx, Transform_View); Vector3 view_position_diry = Vector3.TransformCoordinate(position + diry, Transform_View); Vector3 view_position_dirz = Vector3.TransformCoordinate(position + dirz, Transform_View); bool hidden_dirx = view_position_dirx.Z > 0.0f; bool hidden_diry = view_position_diry.Z > 0.0f; bool hidden_dirz = view_position_dirz.Z > 0.0f; Line line = new Line(device); line.Width = 3; Vector2[] vertices = new Vector2[2]; vertices[0] = new Vector2(p1.X, p1.Y); if (!hidden_dirx) { Vector3 px = WorldToScreen(position + dirx); vertices[1] = new Vector2(px.X, px.Y); line.Draw(vertices, Color.FromArgb(255, 0, 0));//R } if (!hidden_diry) { Vector3 py = WorldToScreen(position + diry); vertices[1] = new Vector2(py.X, py.Y); line.Draw(vertices, Color.FromArgb(0, 255, 0));//G } if (!hidden_dirz) { Vector3 pz = WorldToScreen(position + dirz); vertices[1] = new Vector2(pz.X, pz.Y); line.Draw(vertices, Color.FromArgb(0, 0, 255));//B } line.Dispose(); line = null; }
/// おっぱい変形:貧乳を行います。 public void TransformChichiFlat(TMONode tmo_node, ref Matrix m) { float ratio = bust_ratio / FlatRatio; switch (tmo_node.Name) { case "Chichi_Right1": m = GetMatrixRatio(GetMinChichiR1(), m, ratio); break; case "Chichi_Right2": m = GetMatrixRatio(GetMinChichiR2(), m, ratio); break; case "Chichi_Right3": m = GetMatrixRatio(GetMinChichiR3(), m, ratio); break; case "Chichi_Right4": m = GetMatrixRatio(GetMinChichiR4(), m, ratio); break; case "Chichi_Right5": m = GetMatrixRatio(GetMinChichiR5(), m, ratio); break; case "Chichi_Right5_end": m = GetMatrixRatio(GetMinChichiR5E(), m, ratio); break; case "Chichi_Left1": m = GetMatrixRatio(GetMinChichiL1(), m, ratio); break; case "Chichi_Left2": m = GetMatrixRatio(GetMinChichiL2(), m, ratio); break; case "Chichi_Left3": m = GetMatrixRatio(GetMinChichiL3(), m, ratio); break; case "Chichi_Left4": m = GetMatrixRatio(GetMinChichiL4(), m, ratio); break; case "Chichi_Left5": m = GetMatrixRatio(GetMinChichiL5(), m, ratio); break; case "Chichi_Left5_End": m = GetMatrixRatio(GetMinChichiL5E(), m, ratio); break; } // translationを維持する必要があるため // translationに対してscalingを打ち消す演算を行う。 Vector3 scaling = this.Chichi; m.M41 /= scaling.X; m.M42 /= scaling.Y; m.M43 /= scaling.Z; switch (tmo_node.Name) { case "Chichi_Right1": case "Chichi_Left1": m *= Matrix.Scaling(scaling); break; } }
void CopyChildrenMatFrom_0(TMONode motion, List<string> except_names) { List<TMONode> select_children = new List<TMONode>(); foreach (TMONode child_node in children) { bool found = false; foreach (string except_name in except_names) { if (child_node.name == except_name) { found = true; break; } } if (found) except_names.Remove(child_node.name); else select_children.Add(child_node); } foreach (TMONode child_node in select_children) { TMONode motion_child = motion.FindChildByName(child_node.name); child_node.CopyThisMatFrom(motion_child); child_node.CopyChildrenMatFrom_0(motion_child, except_names); } }
/// 表情変形を行います。 public void TransformFace(TMONode tmo_node, ref Matrix m) { switch (tmo_node.Name) { case "face_oya": Scale1(ref m, this.FaceOya); break; case "eyeline_sita_L": case "L_eyeline_oya_L": case "Me_Right_Futi": m *= this.EyeR; break; case "eyeline_sita_R": case "R_eyeline_oya_R": case "Me_Left_Futi": m *= this.EyeL; break; } }
/// <summary> /// 指定ストリームから読み込みます。 /// </summary> /// <param name="source_stream">ストリーム</param> public void Load(Stream source_stream) { this.reader = new BinaryReader(source_stream, System.Text.Encoding.Default); byte[] magic = reader.ReadBytes(4); if (magic[0] != (byte)'T' || magic[1] != (byte)'M' || magic[2] != (byte)'O' || magic[3] != (byte)'1') throw new Exception("File is not TMO"); this.header = reader.ReadBytes(8); this.opt0 = reader.ReadInt32(); this.opt1 = reader.ReadInt32(); int node_count = reader.ReadInt32(); nodes = new TMONode[node_count]; for (int i = 0; i < node_count; i++) { nodes[i] = new TMONode(i); nodes[i].Read(reader); } GenerateNodemapAndTree(); int frame_count = reader.ReadInt32(); frames = new TMOFrame[frame_count]; for (int i = 0; i < frame_count; i++) { frames[i] = new TMOFrame(i); frames[i].Read(reader); } foreach (TMONode node in nodes) node.LinkMatrices(frames); this.footer = reader.ReadBytes(4); }
/// <summary> /// bone行列を更新します(体型変更なし)。 /// </summary> protected void UpdateBoneMatricesWithoutSlideMatrices(TMONode tmo_node, TMOFrame tmo_frame) { //matrixStack.Push(); if (tmo_frame != null) { // TMO animation tmo_node.TransformationMatrix = tmo_frame.matrices[tmo_node.ID].m; } Matrix m = tmo_node.TransformationMatrix; matrixStack.Push(m * matrixStack.Peek()); m = matrixStack.Peek(); tmo_node.combined_matrix = m; foreach (TMONode child_node in tmo_node.children) UpdateBoneMatrices(child_node, tmo_frame); matrixStack.Pop(); }
/// <summary> /// bone行列を更新します。 /// </summary> protected void UpdateBoneMatrices(TMONode tmo_node, TMOFrame tmo_frame) { if (tmo_frame != null) { // TMO animation tmo_node.TransformationMatrix = tmo_frame.matrices[tmo_node.ID].m; } Matrix m = tmo_node.TransformationMatrix; bool chichi_p = re_chichi.IsMatch(tmo_node.Name); if (chichi_p) { if (slider_matrix.Flat()) slider_matrix.TransformChichiFlat(tmo_node, ref m); else slider_matrix.TranslateChichi(ref m); } else // todo: face_p slider_matrix.TransformFace(tmo_node, ref m); matrixStack.Push(m * matrixStack.Peek()); m = matrixStack.Peek(); if (chichi_p) { if (! slider_matrix.Flat()) { slider_matrix.ScaleChichi(ref m); } } else // todo: scale1map slider_matrix.Scale(tmo_node, ref m); tmo_node.combined_matrix = m; foreach (TMONode child_node in tmo_node.children) UpdateBoneMatrices(child_node, tmo_frame); matrixStack.Pop(); }
static void AddTreeNodes(List<TMONode> select_nodes, TMONode root_node) { select_nodes.Add(root_node); foreach (TMONode node in root_node.children) AddTreeNodes(select_nodes, node); }
/// <summary> /// 指定nodeから行列を複写します。 /// ただし複写の対象は子node以降です。指定nodeは複写しません。 /// また、除外node以降のnodeは複写しません。 /// </summary> /// <param name="motion">node</param> /// <param name="except_names">除外node名称(短い形式)リスト</param> public void CopyChildrenMatFrom(TMONode motion, List<string> except_names) { List<string> dup_except_names = new List<string>(); foreach (string except_name in except_names) { dup_except_names.Add(except_name); } CopyChildrenMatFrom_0(motion, dup_except_names); }
/// <summary> /// 指定スクリーン座標に指定ボーンがあるか。 /// </summary> /// <param name="x">スクリーンX座標</param> /// <param name="y">スクリーンY座標</param> /// <param name="bone">ボーン</param> /// <returns>ボーンを見つけたか</returns> public bool FindBoneOnScreenPoint(float x, float y, TMONode bone) { float collisionTime; Vector3 collisionPoint; return FindBoneOnScreenPoint(x, y, bone, out collisionPoint, out collisionTime); }
internal void GenerateNodemapAndTree() { nodemap = new Dictionary<string, TMONode>(); for (int i = 0; i < nodes.Length; i++) { nodemap.Add(nodes[i].Path, nodes[i]); } List<TMONode> root_nodes = new List<TMONode>(); for (int i = 0; i < nodes.Length; i++) { int index = nodes[i].Path.LastIndexOf('|'); if (index == 0) root_nodes.Add(nodes[i]); if (index <= 0) continue; string path = nodes[i].Path.Substring(0, index); nodes[i].parent = nodemap[path]; nodes[i].parent.children.Add(nodes[i]); } root_nodes_except_w_hips = new List<TMONode>(); foreach (TMONode node in root_nodes) { if (node.Path == "|W_Hips") w_hips_node = node; else root_nodes_except_w_hips.Add(node); } }
/// <summary> /// 指定スクリーン座標に指定ボーンがあるか。 /// </summary> /// <param name="x">スクリーンX座標</param> /// <param name="y">スクリーンY座標</param> /// <param name="bone">ボーン</param> /// <param name="collisionPoint"></param> /// <param name="collisionTime"></param> /// <returns>ボーンを見つけたか</returns> public bool FindBoneOnScreenPoint(float x, float y, TMONode bone, out Vector3 collisionPoint, out float collisionTime) { collisionTime = 0.0f; collisionPoint = Vector3.Zero; Figure fig; if (figures.TryGetFigure(out fig)) { Matrix m = bone.combined_matrix; float sphereRadius = 1.25f; Vector3 sphereCenter = new Vector3(m.M41, m.M42, m.M43); Vector3 rayStart = ScreenToLocal(x, y, 0.0f); Vector3 rayEnd = ScreenToLocal(x, y, 1.0f); Vector3 rayOrientation = rayEnd - rayStart; return DetectSphereRayCollision(sphereRadius, ref sphereCenter, ref rayStart, ref rayOrientation, out collisionPoint, out collisionTime); } return false; }