public override void Run(IPERunArgs args) { try { var pmx = args.Host.Connector.Pmx.GetCurrentState(); var selectedVertex = args.Host.Connector.View.PmxView.GetSelectedVertexIndices().Select(i => pmx.Vertex[i]).ToList(); var selecteMaterialIndices = args.Host.Connector.Form.GetSelectedMaterialIndices(); if (!selectedVertex.Any()) { throw new InvalidOperationException("UVを転写させたい頂点を選択してください。"); } if (!selecteMaterialIndices.Any()) { throw new InvalidOperationException("UV転写元頂点を含む面が属する材質を選択してください。"); } // 余分な頂点をtreeに入れると重くなるので選択頂点の範囲内(の反転した領域)のみを取り込む (V3 min, V3 max)bound = Utility.GetBoundingBox(selectedVertex); // 取り込み領域を拡大 bound.min.Times(1.1); bound.max.Times(1.1); var tree = new KdTree <float, IPXVertex>(3, new FloatMath(), AddDuplicateBehavior.List); var vertices = selecteMaterialIndices.SelectMany(i => Utility.GetMaterialVertices(pmx.Material[i])); foreach (var v in vertices .Where(v => v.Position.X.IsWithin(-1 * bound.max.X, -1 * bound.min.X)) .Where(v => v.Position.Y.IsWithin(bound.min.Y, bound.max.Y)) .Where(v => v.Position.Z.IsWithin(bound.min.Z, bound.max.Z)) ) { tree.Add(v.Position.ToArray(), v); } foreach (var v in selectedVertex) { var vMirror = new V3(v.Position); vMirror.X *= -1; var neighbor = tree.GetNearestNeighbours(vMirror.ToArray(), 1); v.UV = neighbor[0].Duplicate.Aggregate(new V2(0, 0), (sum, vtx) => sum + vtx.UV) / neighbor[0].Duplicate.Count; } Utility.Update(args.Host.Connector, pmx, PmxUpdateObject.Vertex); } catch (InvalidOperationException ex) { Utility.ShowExceptionMessage(ex); } catch (Exception ex) { Utility.ShowException(ex); } }