{"id":1586,"date":"2024-08-18T20:49:37","date_gmt":"2024-08-18T20:49:37","guid":{"rendered":"https:\/\/summergeometry.org\/sgi2024\/?p=1586"},"modified":"2024-12-01T04:58:42","modified_gmt":"2024-12-01T04:58:42","slug":"loop-subdivision-for-tetsphere-splatting","status":"publish","type":"post","link":"https:\/\/summergeometry.org\/sgi2024\/loop-subdivision-for-tetsphere-splatting\/","title":{"rendered":"Loop Subdivision for  Tetsphere Splatting"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>SGI Fellows: <\/strong>Harini Rammohan, Dianlun Luo, Idil Sulo<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Project Mentor:<\/strong> Minghao Guo <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>SGI Volunteer:<\/strong> Shanthika Naik<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Introduction:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>TetSphere Splatting<\/strong>&nbsp;[Guo et al., 2024] is a cutting-edge technique for high-quality 3D shape reconstruction using tetrahedral meshes. This method stands out by delivering superior geometry without relying on neural networks or post-processing. Unlike traditional Eulerian methods, TetSphere Splatting excels in applications such as single-view 3D reconstruction and text-to-3D generation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Our project aimed to enhance TetSphere Splatting through two key improvements:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Geometry Optimization<\/strong>: We integrated subdivision and remeshing techniques to refine the geometry optimization process, enabling the capture of finer details and better tessellation.<\/li>\n\n\n\n<li><strong>Adaptive TetSphere Modification<\/strong>: We developed adaptive mechanisms for splitting and merging tetrahedral spheres, enhancing flexibility and detail in the optimization process.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Setting up the Code Base:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Our mentor, Minghao, facilitated the setup of the codebase in a cloud environment equipped with GPU support. Using a VSCode tunnel, we were able to work remotely and make modifications within the same environment. Following the instructions in the TetSphere Splatting GitHub README file, we successfully initialized the TetSpheres and executed the TetSphere Splatting process for our input images, including those of a white dog and a cartoon boy.<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"352\" height=\"356\" data-id=\"1639\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-12.10.35.png\" alt=\"\" class=\"wp-image-1639\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-12.10.35.png 352w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-12.10.35-297x300.png 297w\" sizes=\"auto, (max-width: 352px) 100vw, 352px\" \/><figcaption class=\"wp-element-caption\">Input Image of a White Dog<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"830\" height=\"816\" data-id=\"1643\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.48.51.png\" alt=\"\" class=\"wp-image-1643\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.48.51.png 830w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.48.51-300x295.png 300w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.48.51-768x755.png 768w\" sizes=\"auto, (max-width: 830px) 100vw, 830px\" \/><figcaption class=\"wp-element-caption\">TetSphere Initialization<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"828\" height=\"824\" data-id=\"1651\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.58.17-1.png\" alt=\"\" class=\"wp-image-1651\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.58.17-1.png 828w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.58.17-1-300x300.png 300w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.58.17-1-150x150.png 150w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.58.17-1-768x764.png 768w\" sizes=\"auto, (max-width: 828px) 100vw, 828px\" \/><figcaption class=\"wp-element-caption\">Tetsphere Splatting<\/figcaption><\/figure>\n<\/figure>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"233\" height=\"414\" data-id=\"1649\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-12.10.17-edited.png\" alt=\"\" class=\"wp-image-1649\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-12.10.17-edited.png 233w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-12.10.17-edited-169x300.png 169w\" sizes=\"auto, (max-width: 233px) 100vw, 233px\" \/><figcaption class=\"wp-element-caption\">Input Image of a Cartoon Boy<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"804\" height=\"808\" data-id=\"1646\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.52.04.png\" alt=\"\" class=\"wp-image-1646\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.52.04.png 804w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.52.04-300x300.png 300w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.52.04-150x150.png 150w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.52.04-768x772.png 768w\" sizes=\"auto, (max-width: 804px) 100vw, 804px\" \/><figcaption class=\"wp-element-caption\">Tetsphere Initialization<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"420\" height=\"746\" data-id=\"1650\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.59.30-edited.png\" alt=\"\" class=\"wp-image-1650\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.59.30-edited.png 420w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-14.59.30-edited-169x300.png 169w\" sizes=\"auto, (max-width: 420px) 100vw, 420px\" \/><figcaption class=\"wp-element-caption\">Tetsphere Splatting<\/figcaption><\/figure>\n<\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Geometry Optimization:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To improve the geometry optimization in TetSphere Splatting, we explored various algorithms for adaptive remeshing and subdivision. Initially, we considered parametrization-based remeshing using Centroidal Voronoi Tessellation (CVT) but opted for direct surface remeshing due to its efficiency and simplicity. For subdivision, we chose the Loop subdivision algorithm, as it is specifically designed for triangle meshes and better suited for our application compared to Catmull-Clark.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Implementing Loop Subdivision:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In the second week of the project, I worked on implementing the loop subdivision algorithm and incorporating it into the Geometry Optimization pipeline. Below is a detailed explanation of the algorithm and the method of implementation using the example of the example of the white dog mesh after TetSphere splatting.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">1. Importing the required libraries, loading and initializing the mesh:<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of working throughout with numpy arrays, I chose to use defaultdict, a subclass of Python dictionaries to reduce the running time of the program. unique_edges defined below ensures that the list of edges doesn&#8217;t count each edge twice, once as (e<sub>1<\/sub>, e<sub>2<\/sub>) and once as (e<sub>2<\/sub>, e<sub>1<\/sub>).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import trimesh\nimport numpy as np\nfrom collections import defaultdict\n\ninit_mesh = trimesh.load(\".\/results\/a_white_dog\/final\/final_surface_mesh.obj\")\nV = init_mesh.vertices\nF = init_mesh.faces\nE = init_mesh.edges\n\ndef unique_edges(edges): \n    sorted_edges = np.sort(edges, axis=1)\n    unique_edges = np.unique(sorted_edges, axis=0)\n    return unique_edges<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">2. <strong>Edge-Face Adjacency Mapping<\/strong><\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">This maps edges to the faces they belong to, which will later help to identify boundary and interior edges.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def compute_edge_face_adjacency(faces):\n    edge_face_map = defaultdict(list)\n    for i, face in enumerate(faces):\n        v0, v1, v2 = face\n        edges = &#091;(min(v0, v1), max(v0, v1)),\n                 (min(v1, v2), max(v1, v2)),\n                 (min(v2, v0), max(v2, v0))]\n        for edge in edges:\n            edge_face_map&#091;edge].append(i)\n    return edge_face_map<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">3. <strong>Computing New Vertices:<\/strong><\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">If an edge is a boundary edge (it belongs to only one face), then the new vertex is simply the midpoint of the two vertices at the ends of the edge. If not, the edge belongs to two faces and the new vertex is found to be a weighted average of the four vertices which make the two faces, with a weight of 3\/8 for the vertices on the edge and 1\/8 for the vertices not on the edge. The function also produces indices for the new vertices.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"410\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-20.55.27-1024x410.png\" alt=\"\" class=\"wp-image-1655\" style=\"width:609px;height:auto\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-20.55.27-1024x410.png 1024w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-20.55.27-300x120.png 300w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-20.55.27-768x307.png 768w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-20.55.27-1200x480.png 1200w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-20.55.27.png 1404w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">(a) The weights for an interior edge; (b)&nbsp;the weights for a boundary edge.                 Image from <a href=\"https:\/\/www.pbr-book.org\/3ed-2018\/Shapes\/Subdivision_Surfaces\">https:\/\/www.pbr-book.org\/3ed-2018\/Shapes\/Subdivision_Surfaces<\/a><\/figcaption><\/figure>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><code>def compute_new_vertices(edge_face_map, vertices, faces):\n    new_vertices = defaultdict(list)\n    i = vertices.shape&#091;0] - 1\n    for edge, facess in edge_face_map.items():\n        v0, v1 = edge\n        if len(facess) == 1:  # Boundary edge\n            i += 1\n            new_vertices&#091;edge].append(((vertices&#091;v0] + vertices&#091;v1]) \/ 2, i))\n        elif len(facess) == 2:  # Internal edge\n            i += 1\n            adjacent_vertices = &#091;]\n            for face_index in facess:\n                face = faces&#091;face_index]\n                for vertex in face:\n                    if vertex != v0 and vertex != v1:\n                        adjacent_vertices.append(vertex)\n            v2 = adjacent_vertices&#091;0]\n            v3 = adjacent_vertices&#091;1]\n            new_vertices&#091;edge].append(((1 \/ 8) * (vertices&#091;v2] + vertices&#091;v3]) + \n                                       (3 \/ 8) * (vertices&#091;v0] + vertices&#091;v1]), i))\n    return new_vertices<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">4. Create a dictionary of updated vertices:<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">This generates updated vertices that include both old and newly created vertices.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def generate_updated_vertices(new_vertices, vertices, edges):\n    updated_vertices = defaultdict(list)\n    for i in range(vertices.shape&#091;0]):\n        vertex = vertices&#091;i, :]\n        updated_vertices&#091;i].append(vertex)\n    for i in range(edges.shape&#091;0]):\n        e1, e2 = edges&#091;i, :]\n        edge = (min(e1, e2), max(e1, e2))\n        vertex, index = new_vertices&#091;edge]&#091;0]\n        updated_vertices&#091;index].append(vertex)\n    return updated_vertices<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">5. Construct New Faces:<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">This constructs new faces using the updated vertices. Each old face is split into four new faces.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"432\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-21.02.42-1024x432.png\" alt=\"\" class=\"wp-image-1656\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-21.02.42-1024x432.png 1024w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-21.02.42-300x126.png 300w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-21.02.42-768x324.png 768w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-21.02.42.png 1072w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">The four child faces created, ordered such that the&nbsp;ith child face is adjacent to the&nbsp;ith vertex of the original face and the fourth child face is in the center of the subdivided face. Image from <a href=\"https:\/\/www.pbr-book.org\/3ed-2018\/Shapes\/Subdivision_Surfaces\">https:\/\/www.pbr-book.org\/3ed-2018\/Shapes\/Subdivision_Surfaces<\/a><\/figcaption><\/figure>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><code>def create_new_faces(faces, new_vertices):\n    new_faces = &#091;]\n    for face in faces:\n        v0, v1, v2 = face\n        edge_0 = tuple(sorted((v0, v1)))\n        edge_1 = tuple(sorted((v1, v2)))\n        edge_2 = tuple(sorted((v2, v0)))\n\n        e0 = new_vertices&#091;edge_0]&#091;0]&#091;1]\n        e1 = new_vertices&#091;edge_1]&#091;0]&#091;1]\n        e2 = new_vertices&#091;edge_2]&#091;0]&#091;1]\n\n        new_faces.append(&#091;v0, e0, e2])\n        new_faces.append(&#091;v1, e1, e0])\n        new_faces.append(&#091;v2, e2, e1])\n        new_faces.append(&#091;e0, e1, e2])\n    \n    return np.array(new_faces)<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">6. Modifying Old Vertices Based on Adjacency:<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">First, the function compute_vertex_adjacency finds the neighbors of each vertex. Then modify_vertices weights each of the neighbor vertices of each old vertex by a weight\u00a0\u03b2 (defined in the code below) and weights the old vertex by 1-n\u03b2, where n is the degree of the old vertex. It does not change the new vertices.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"490\" height=\"532\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-21.20.03.png\" alt=\"\" class=\"wp-image-1658\" style=\"width:361px;height:auto\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-21.20.03.png 490w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-21.20.03-276x300.png 276w\" sizes=\"auto, (max-width: 490px) 100vw, 490px\" \/><figcaption class=\"wp-element-caption\">Computing the new position of the old vertex v. Image from <a href=\"https:\/\/www.pbr-book.org\/3ed-2018\/Shapes\/Subdivision_Surfaces\">https:\/\/www.pbr-book.org\/3ed-2018\/Shapes\/Subdivision_Surfaces<\/a><\/figcaption><\/figure>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><code>def compute_vertex_adjacency(faces):\n    vertex_adj_map = defaultdict(set)\n    for face in faces:\n        v0, v1, v2 = face\n        vertex_adj_map&#091;v0].add(v1)\n        vertex_adj_map&#091;v0].add(v2)\n        vertex_adj_map&#091;v1].add(v0)\n        vertex_adj_map&#091;v1].add(v2)\n        vertex_adj_map&#091;v2].add(v0)\n        vertex_adj_map&#091;v2].add(v1)\n    return vertex_adj_map\n\ndef modify_vertices(vertices, updated_vertices, vertex_adj_map):\n    modified_vertices = defaultdict(list)\n    for i in range(len(updated_vertices)):\n        if i in range(vertices.shape&#091;0]):\n            vertex = vertices&#091;i,:]\n            neighbors = vertex_adj_map&#091;i]\n            n = len(neighbors)\n            beta = (5 \/ 8 - (3 \/ 8 + 1 \/ 4 * np.cos(2 * np.pi \/ n)) ** 2)\/n\n            weight_v = 1 - beta * n\n            modified_vertex = weight_v * vertex\n            for neighbor in neighbors:\n                neighbor_point = updated_vertices&#091;neighbor]&#091;0]\n                modified_vertex += beta * neighbor_point\n            modified_vertices&#091;i].append(modified_vertex)\n        else:\n            modified_vertices&#091;i].append(updated_vertices&#091;i]&#091;0])\n    return modified_vertices<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">7. Generating the Final Subdivided Mesh:<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">Now, all that is left is to collect the modified vertices and faces as numpy arrays and create the final subdivided mesh. The function loop_subdivision_iter simply applies the loop subdivision iteratively &#8216;n&#8217; times, further refining the loop each time.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def create_vertices_array(modified_vertices):\n    vertices_list = &#091;modified_vertices&#091;i]&#091;0] for i in range(len(modified_vertices))]\n    return np.array(vertices_list)\n\ndef loop_subdivision(vertices, faces, edges):\n    edges = unique_edges(edges)\n    edge_face_map = compute_edge_face_adjacency(faces)\n    new_vertices = compute_new_vertices(edge_face_map, vertices, faces)\n    updated_vertices = generate_updated_vertices(new_vertices, vertices, edges)\n    new_faces = create_new_faces(faces, new_vertices)\n    vertex_adj_map = compute_vertex_adjacency(new_faces)\n    modified_vertices = modify_vertices(vertices, updated_vertices, vertex_adj_map)\n    vertices_array = create_vertices_array(modified_vertices)\n    return vertices_array, new_faces\n\ndef loop_subdivision_iter(vertices, faces, n):\n    def unique_edges(faces): \n            edges = np.vstack(&#091;\n            np.column_stack((faces&#091;:, 0], faces&#091;:, 1])),\n            np.column_stack((faces&#091;:, 1], faces&#091;:, 2])),\n            np.column_stack((faces&#091;:, 2], faces&#091;:, 0]))\n                ])\n            sorted_edges = np.sort(edges, axis=1)\n            unique_edges = np.unique(sorted_edges, axis=0)\n            return unique_edges\n    if n == 0:\n        edges = unique_edges(faces)\n        return loop_subdivision(V, F, E)\n    else:\n        edges = unique_edges(faces)\n        vertices, faces = loop_subdivision(vertices, faces, edges)\n        output = loop_subdivision_iter(vertices, faces, n-1)\n        return output\n\nnew_V, new_F = loop_subdivision_iter(V, F, 1)\nsubdivided_mesh = trimesh.Trimesh(vertices=new_V, faces=new_F)\nsubdivided_mesh.export(\".\/a_white_dog_subdivided.obj\")\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Results:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I used the above code to obtain the subdivided meshes for four input meshes &#8211; a white dog, a cartoon boy, a camel, and a horse. The results for each of these are displayed below.<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"948\" height=\"966\" data-id=\"1661\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.07.38.png\" alt=\"\" class=\"wp-image-1661\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.07.38.png 948w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.07.38-294x300.png 294w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.07.38-768x783.png 768w\" sizes=\"auto, (max-width: 948px) 100vw, 948px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"944\" height=\"982\" data-id=\"1662\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.08.01.png\" alt=\"\" class=\"wp-image-1662\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.08.01.png 944w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.08.01-288x300.png 288w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.08.01-768x799.png 768w\" sizes=\"auto, (max-width: 944px) 100vw, 944px\" \/><\/figure>\n<figcaption class=\"blocks-gallery-caption wp-element-caption\">Subdivision of the white dog mesh<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"450\" height=\"926\" data-id=\"1663\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.10.23.png\" alt=\"\" class=\"wp-image-1663\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.10.23.png 450w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.10.23-146x300.png 146w\" sizes=\"auto, (max-width: 450px) 100vw, 450px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"418\" height=\"918\" data-id=\"1664\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.10.59.png\" alt=\"\" class=\"wp-image-1664\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.10.59.png 418w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.10.59-137x300.png 137w\" sizes=\"auto, (max-width: 418px) 100vw, 418px\" \/><\/figure>\n<figcaption class=\"blocks-gallery-caption wp-element-caption\">Subdivision of the cartoon boy mesh<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-5 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"926\" height=\"1018\" data-id=\"1665\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.13.15.png\" alt=\"\" class=\"wp-image-1665\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.13.15.png 926w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.13.15-273x300.png 273w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.13.15-768x844.png 768w\" sizes=\"auto, (max-width: 926px) 100vw, 926px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"934\" height=\"1008\" data-id=\"1666\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.13.32.png\" alt=\"\" class=\"wp-image-1666\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.13.32.png 934w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.13.32-278x300.png 278w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.13.32-768x829.png 768w\" sizes=\"auto, (max-width: 934px) 100vw, 934px\" \/><\/figure>\n<figcaption class=\"blocks-gallery-caption wp-element-caption\">Subdivision of the camel mesh<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-6 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1018\" height=\"1024\" data-id=\"1659\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.28-1018x1024.png\" alt=\"\" class=\"wp-image-1659\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.28-1018x1024.png 1018w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.28-298x300.png 298w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.28-150x150.png 150w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.28-768x773.png 768w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.28.png 1020w\" sizes=\"auto, (max-width: 1018px) 100vw, 1018px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1020\" data-id=\"1660\" src=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.59-1024x1020.png\" alt=\"\" class=\"wp-image-1660\" srcset=\"https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.59-1024x1020.png 1024w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.59-300x300.png 300w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.59-150x150.png 150w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.59-768x765.png 768w, https:\/\/summergeometry.org\/sgi2024\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-17-at-22.03.59.png 1028w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<figcaption class=\"blocks-gallery-caption wp-element-caption\">Subdivision of the horse mesh<\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Conclusion: <\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The project successfully enhanced the TetSphere Splatting method through geometry optimization and adaptive TetSphere modification. The implementation of Loop subdivision refined mesh detail and smoothness, as evidenced by the improved results for the test meshes. The adaptive mechanisms introduced greater flexibility, contributing to more precise and detailed 3D reconstructions. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Through this project I learned a lot about TetSphere Splatting, Geometry Optimization and Loop Subdivion. I am very grateful to Minghao and Shanthika who supported and guided us in our progress.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">References:<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">{1} Guo, Minghao, et al. &#8220;TetSphere Splatting: Representing High-Quality Geometry with Lagrangian Volumetric Meshes&#8221;, <a href=\"https:\/\/doi.org\/10.48550\/arXiv.2405.20283\">https:\/\/doi.org\/10.48550\/arXiv.2405.20283<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">{2} Kerbl, Bernhard, et al.&nbsp;&#8220;3D Gaussian Splatting&nbsp;<br>for Real-Time Radiance Field Rendering&#8221; <em>SIGGRAPH 2023<\/em>, <a href=\"https:\/\/doi.org\/10.48550\/arXiv.2308.04079\">https:\/\/doi.org\/10.48550\/arXiv.2308.04079<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">{3} &#8220;Remeshing I&#8221;, <a href=\"https:\/\/graphics.stanford.edu\/courses\/cs468-12-spring\/LectureSlides\/13_Remeshing1.pdf\">https:\/\/graphics.stanford.edu\/courses\/cs468-12-spring\/LectureSlides\/13_Remeshing1.pdf<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">{4} &#8220;Subdivision&#8221;, <a href=\"https:\/\/www.cs.cmu.edu\/afs\/cs\/academic\/class\/15462-s14\/www\/lec_slides\/Subdivision.pdf\">https:\/\/www.cs.cmu.edu\/afs\/cs\/academic\/class\/15462-s14\/www\/lec_slides\/Subdivision.pdf<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">{5} Pharr, Matt, et al. &#8220;<em>Physically Based Rendering: From Theory To Implementation<\/em> &#8211; 3.8 Subdivision Surfaces&#8221;, <a href=\"https:\/\/www.pbr-book.org\/3ed-2018\/Shapes\/Subdivision_Surfaces\">https:\/\/www.pbr-book.org\/3ed-2018\/Shapes\/Subdivision_Surfaces<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>SGI Fellows: Harini Rammohan, Dianlun Luo, Idil Sulo Project Mentor: Minghao Guo SGI Volunteer: Shanthika Naik Introduction: TetSphere Splatting&nbsp;[Guo et al., 2024] is a cutting-edge technique for high-quality 3D shape reconstruction using tetrahedral meshes. This method stands out by delivering superior geometry without relying on neural networks or post-processing. Unlike traditional Eulerian methods, TetSphere Splatting [&hellip;]<\/p>\n","protected":false},"author":73,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[37],"tags":[],"ppma_author":[17],"class_list":["post-1586","post","type-post","status-publish","format-standard","hentry","category-research"],"authors":[{"term_id":17,"user_id":0,"is_guest":1,"slug":"cap-harini","display_name":"harini","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","author_category":"","first_name":"","last_name":"","user_url":"","job_title":"","description":""}],"_links":{"self":[{"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/posts\/1586","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/users\/73"}],"replies":[{"embeddable":true,"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/comments?post=1586"}],"version-history":[{"count":5,"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/posts\/1586\/revisions"}],"predecessor-version":[{"id":3646,"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/posts\/1586\/revisions\/3646"}],"wp:attachment":[{"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/media?parent=1586"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/categories?post=1586"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/tags?post=1586"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/summergeometry.org\/sgi2024\/wp-json\/wp\/v2\/ppma_author?post=1586"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}