/// <summary> /// メッシュを描画。 /// cameraPositionは x, y : [-∞, +∞], z : [-∞, 0) /// x, y が大きいほどカメラが右下に移動する /// zが小さいほどズームアウトする /// </summary> /// <param name="cameraPosition">x, y : [-∞, +∞], z : [-∞, 0).x, y が大きいほどカメラが右下に移動する.zが小さいほどズームアウトする</param> public void DrawMesh(PatchMesh mesh, string textureKey, PatchMeshRenderResources resources, DXColor col, Size formSize, Vector3 cameraPosition) { List <VertexPositionColorTexture> rawVertices = new List <VertexPositionColorTexture>(); for (int i = 0; i < mesh.vertices.Count; i++) { Vector3 pos = vec3(mesh.vertices[i].position); pos.Y *= -1; Vector2 coord = vec2(mesh.vertices[i].GetTexcoord(textureKey)); rawVertices.Add(new VertexPositionColorTexture(pos, col, coord)); } List <int> rawIndices = new List <int>(); for (int i = 0; i < mesh.triangles.Count; i++) { if (mesh.triangles[i].TextureKey != textureKey) { continue; } rawIndices.Add(mesh.triangles[i].Idx0); rawIndices.Add(mesh.triangles[i].Idx1); rawIndices.Add(mesh.triangles[i].Idx2); } var texture = resources.GetTexture(PatchMeshRenderResources.GenerateResourceKey(mesh, textureKey)); Draw(rawVertices, rawIndices, texture, formSize, cameraPosition, PrimitiveTopology.TriangleList); }
/// <summary> /// 2つの骨格つきメッシュをスケルトン情報を元に結合する /// 1. スケルトンに合わせて各メッシュをざっくり移動・ボーン方向にARAP /// 2. メッシュ同士が自然に繋がるように位置・角度・スケールを調整(fitting(), adjustposition()) /// 3. 繋ぎ目が重なるようにARAP(expand()) /// 4. 新しいARAP可能なひとつのメッシュを生成(combine) /// </summary> /// (5. リソースの更新。これはここでやるべきなのだろうか?) /// </summary> public static PatchSkeletalMesh Connect(PatchSkeletalMesh smesh1, PatchSkeletalMesh smesh2, PatchSkeleton refSkeleton, PatchMeshRenderResources resources) { if (refSkeleton == null) { return(null); } // メッシュ・骨格データはConnect()内で変更されうるのでコピーしたものを使う PatchSkeletalMesh smesh1_t = PatchSkeletalMesh.Copy(smesh1); PatchSkeletalMesh smesh2_t = PatchSkeletalMesh.Copy(smesh2); #if DEBUG PatchSkeletalMeshRenderer.ToBitmap(smesh1_t, smesh1_t.sections, alignment: true).Save("smesh1_t.png"); PatchSkeletalMeshRenderer.ToBitmap(smesh2_t, smesh2_t.sections, alignment: true).Save("smesh2_t.png"); #endif var refSkeleton_t = PatchSkeleton.Copy(refSkeleton); // smesh1, smesh2で同じボーンを共有している(結合すべき)切り口を探す // これらの切り口の付近を変形することでメッシュを繋げる PatchSection section1; PatchSection section2; PatchSkeletonBone crossingBone; bool canConnect = CanConnect(new List <PatchSkeletalMesh>() { smesh1, smesh2 }, refSkeleton); bool canConnect_t = CanConnect(new List <PatchSkeletalMesh>() { smesh1_t, smesh2_t }, refSkeleton_t); bool found = FindConnectingSections(smesh1_t, smesh2_t, refSkeleton_t, out section1, out section2, out crossingBone); if (!found) { return(null); } #if _DEBUG PatchSkeletalMeshRenderer.ToBitmap(smesh1_t, new List <CharacterRange>() { section1 }).Save("output/3_mesh1_t_seciton1.png"); PatchSkeletalMeshRenderer.ToBitmap(smesh2_t, new List <CharacterRange>() { section2 }).Save("output/4_mesh2_t_section2.png"); #endif // 2つのsmeshが重なるように位置調整およびARAP変形をする smesh1_t.mesh.BeginDeformation(); smesh2_t.mesh.BeginDeformation(); Deform(smesh1_t, smesh2_t, refSkeleton_t, section1, section2, crossingBone); smesh2_t.mesh.EndDeformation(); smesh1_t.mesh.EndDeformation(); #if _DEBUG PatchSkeletalMeshRenderer.ToBitmap(smesh1_t).Save("output/6_mesh1_t_deformed.png"); PatchSkeletalMeshRenderer.ToBitmap(smesh2_t).Save("output/7_mesh2_t_deformed.png"); #endif // 2つの変形済みのsmeshを1つのsmeshに結合して、ARAPできるようにする var combinedSMesh = Combine(smesh1_t, smesh2_t, section1, section2); #if _DEBUG PatchSkeletalMeshRenderer.ToBitmap(combinedSMesh, combinedSMesh.sections).Save("output/8_conbinedMesh.png"); #endif if (resources != null) { List <string> textureKeys = resources.GetResourceKeyByPatchMesh(smesh1.mesh); textureKeys.AddRange(resources.GetResourceKeyByPatchMesh(smesh2.mesh)); foreach (var key in textureKeys) { string patchKey = key.Split(':').Last(); string newKey = PatchMeshRenderResources.GenerateResourceKey(combinedSMesh.mesh, patchKey); // TODO: テクスチャはコピーしたほうが良い? resources.Add(newKey, resources.GetTexture(key)); } } return(combinedSMesh); }
public static PatchSkeletalMesh Connect(List <PatchSkeletalMesh> smeshes, PatchSkeleton refSkeleton, PatchMeshRenderResources resources) { var overlapPairs = GetOverlappedPairs(smeshes, refSkeleton); if (overlapPairs.Count <= 0) { return(null); } var newMesh = overlapPairs[0].Item1; List <PatchSkeletalMesh> aggregated = new List <PatchSkeletalMesh>(); aggregated.Add(overlapPairs[0].Item1); int _orgCnt = overlapPairs.Count; for (int j = 0; j < overlapPairs.Count; j++) { for (int i = 0; i < overlapPairs.Count; i++) { var pair = overlapPairs[i]; if (aggregated.Contains(pair.Item1) && !aggregated.Contains(pair.Item2)) { newMesh = Connect(newMesh, pair.Item2, refSkeleton, resources); aggregated.Add(pair.Item2); overlapPairs.RemoveAt(i); break; } else if (!aggregated.Contains(pair.Item1) && aggregated.Contains(pair.Item2)) { newMesh = Connect(newMesh, pair.Item1, refSkeleton, resources); aggregated.Add(pair.Item1); overlapPairs.RemoveAt(i); break; } } System.Diagnostics.Debug.Assert(aggregated.Count == j + 2); System.Diagnostics.Debug.Assert(overlapPairs.Count == _orgCnt - j - 1); } return(newMesh); }
/// <summary> /// メッシュを描画。 /// cameraPositionは x, y : [-∞, +∞], z : [-∞, 0) /// x, y が大きいほどカメラが右下に移動する /// zが小さいほどズームアウトする /// </summary> /// <param name="cameraPosition">x, y : [-∞, +∞], z : [-∞, 0).x, y が大きいほどカメラが右下に移動する.zが小さいほどズームアウトする</param> public void DrawMesh(PatchMesh mesh, string textureKey, PatchMeshRenderResources resources, Size formSize, Vector3 cameraPosition) { DrawMesh(mesh, textureKey, resources, DXColor.White, formSize, cameraPosition); }
public static PatchSkeletalMesh Connect(PatchSkeletalMesh patch1, PatchSkeletalMesh patch2, PatchSkeleton refSkeleton, PatchMeshRenderResources resources) { if (refSkeleton == null) { return(null); } if (!System.IO.Directory.Exists("output_Connector2")) { System.IO.Directory.CreateDirectory("output_Connector2"); } FLib.FileManager.OpenExplorer("output_Connector2"); #if _DEBUG PatchSkeletalMeshRenderer.ToBitmap(patch1).Save("output_Connector2/1_patch1.png"); PatchSkeletalMeshRenderer.ToBitmap(patch2).Save("output_Connector2/1_patch2.png"); #endif // 1. パッチをコピー PatchSkeletalMesh patch1_t = PatchSkeletalMesh.Copy(patch1); PatchSkeletalMesh patch2_t = PatchSkeletalMesh.Copy(patch2); var refSkeleton_t = PatchSkeleton.Copy(refSkeleton); // 2. patch1, patch2の接続面および対応するボーンを探す PatchSection section1; PatchSection section2; PatchSkeletonBone crossingBone; bool swap; bool found = ConnectableSections(patch1_t, patch2_t, refSkeleton_t, out section1, out section2, out crossingBone, out swap); if (!found) { return(null); } if (swap) { FMath.Swap(ref patch1_t, ref patch2_t); FMath.Swap(ref section1, ref section2); } #if _DEBUG PatchSkeletalMeshRenderer.ToBitmap(patch1_t, new List <CharacterRange>() { section1 }).Save("output_Connector2/2_patch1.png"); PatchSkeletalMeshRenderer.ToBitmap(patch2_t, new List <CharacterRange>() { section2 }).Save("output_Connector2/2_patch2.png"); #endif // 3. 2つのパッチが重なるように位置調整およびARAP変形 patch1_t.mesh.BeginDeformation(); patch2_t.mesh.BeginDeformation(); Deform(patch1_t, patch2_t, refSkeleton_t, section1, section2, crossingBone); patch2_t.mesh.EndDeformation(); patch1_t.mesh.EndDeformation(); #if _DEBUG PatchSkeletalMeshRenderer.ToBitmap(patch1_t, new List <CharacterRange>() { section1 }).Save("output_Connector2/3_patch1.png"); PatchSkeletalMeshRenderer.ToBitmap(patch2_t, new List <CharacterRange>() { section2 }).Save("output_Connector2/3_patch2.png"); #endif // 4. 2つのパッチのテクスチャを合成して、新しいパッチを生成 // TODO:メッシュをビットマップ画像として書き出してリサンプリング // todo var combinedSMesh = Combine(patch1_t, patch2_t, section1, section2); // 5. 新しいパッチに使うテクスチャをリソースに登録 // todo if (resources != null) { List <string> textureKeys = resources.GetResourceKeyByPatchMesh(patch1.mesh); textureKeys.AddRange(resources.GetResourceKeyByPatchMesh(patch2.mesh)); foreach (var key in textureKeys) { string patchKey = key.Split(':').Last(); string newKey = PatchMeshRenderResources.GenerateResourceKey(combinedSMesh.mesh, patchKey); resources.Add(newKey, resources.GetTexture(key)); } } return(combinedSMesh); }
/// <summary> /// /// - ざっくり位置合わせ(オーバーラップさせる) /// - 接続後の境界を計算 /// - それにあせてボーンと垂直方向に画像を変形 /// - リサンプリング /// /// ・対応する境界線を探す(2D) /// ・ざっくり重なるように移動・拡大操作(2D) /// ・seam carving method(3D?) /// ・graphcut textures(2D) /// ・poisson blending(2D) (opencvを使う) /// ・resampleしてpatchmeshに戻す(3D) /// </summary> /// <param name="patches"></param> /// <param name="refSkeleton"></param> /// <param name="resources"></param> /// <returns></returns> public static PatchSkeletalMesh Connect(List <PatchSkeletalMesh> patches, PatchSkeleton refSkeleton, PatchMeshRenderResources resources) { var overlapPairs = OverlapPatchPairs(patches, refSkeleton); if (overlapPairs.Count <= 0) { return(null); } var newPatch = overlapPairs[0].Item1; List <PatchSkeletalMesh> aggregated = new List <PatchSkeletalMesh>(); aggregated.Add(overlapPairs[0].Item1); for (int j = 0; j < overlapPairs.Count; j++) { // newPatchと接続可能なpatchをひとつ探して繋げる // O(N^2)だけど、patchesの総数はせいぜい十数個なので問題ない for (int i = 0; i < overlapPairs.Count; i++) { var pair = overlapPairs[i]; if (aggregated.Contains(pair.Item1) && !aggregated.Contains(pair.Item2)) { var connected = Connect(newPatch, pair.Item2, refSkeleton, resources); if (connected != null) { newPatch = connected; aggregated.Add(pair.Item2); overlapPairs.RemoveAt(i); break; } } else if (!aggregated.Contains(pair.Item1) && aggregated.Contains(pair.Item2)) { if (newPatch != null) { var connected = Connect(newPatch, pair.Item1, refSkeleton, resources); if (connected != null) { newPatch = connected; aggregated.Add(pair.Item1); overlapPairs.RemoveAt(i); break; } } } } } return(newPatch); }