Commit fb20ee76 authored by allai5's avatar allai5
Browse files

add data and site info

parent 20d39ee3
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <title>Isotropic Remeshing - </title> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> <link rel="stylesheet" href="/assets/css/just-the-docs-default.css"> <script type="text/javascript" src="/assets/js/vendor/lunr.min.js"></script> <script type="text/javascript" src="/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.7.1 --> <title>Isotropic Remeshing</title> <meta name="generator" content="Jekyll v4.2.0" /> <meta property="og:title" content="Isotropic Remeshing" /> <meta property="og:locale" content="en_US" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="Isotropic Remeshing" /> <script type="application/ld+json"> {"headline":"Isotropic Remeshing","@type":"WebPage","url":"/meshedit/global/remesh/","@context":"https://schema.org"}</script> <!-- End Jekyll SEO tag --> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> </svg> <div class="side-bar"> <div class="site-header"> <a href="/" class="site-title lh-tight"> </a> <a href="#" id="menu-button" class="site-button"> <svg viewBox="0 0 24 24" class="icon"><use xlink:href="#svg-menu"></use></svg> </a> </div> <nav role="navigation" aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/" class="nav-list-link">Home</a></li><li class="nav-list-item"><a href="/git/" class="nav-list-link">GitHub Setup</a></li><li class="nav-list-item"><a href="/build/" class="nav-list-link">Building Scotty3D</a></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/guide/" class="nav-list-link">User Guide</a><ul class="nav-list "><li class="nav-list-item "><a href="/guide/animate_mode/" class="nav-list-link">Animate</a></li><li class="nav-list-item "><a href="/guide/layout_mode/" class="nav-list-link">Layout</a></li><li class="nav-list-item "><a href="/guide/model_mode/" class="nav-list-link">Model</a></li><li class="nav-list-item "><a href="/guide/render_mode/" class="nav-list-link">Render</a></li><li class="nav-list-item "><a href="/guide/rigging_mode/" class="nav-list-link">Rig</a></li><li class="nav-list-item "><a href="/guide/simulate_mode/" class="nav-list-link">Simulate</a></li></ul></li><li class="nav-list-item active"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/" class="nav-list-link">A2: MeshEdit</a><ul class="nav-list "><li class="nav-list-item "><a href="/meshedit/halfedge" class="nav-list-link">Halfedge Mesh</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/local/" class="nav-list-link">Local Operations</a><ul class="nav-list"><li class="nav-list-item "> <a href="/meshedit/local/edge_flip" class="nav-list-link">Edge Flip Tutorial</a> </li><li class="nav-list-item "> <a href="/meshedit/local/bevel/" class="nav-list-link">Bevelling</a> </li></ul></li><li class="nav-list-item active"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/global/" class="nav-list-link">Global Operations</a><ul class="nav-list"><li class="nav-list-item "> <a href="/meshedit/global/catmull/" class="nav-list-link">Catmull-Clark Subdivision</a> </li><li class="nav-list-item active"> <a href="/meshedit/global/remesh/" class="nav-list-link active">Isotropic Remeshing</a> </li><li class="nav-list-item "> <a href="/meshedit/global/linear/" class="nav-list-link">Linear Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/loop/" class="nav-list-link">Loop Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/simplify/" class="nav-list-link">Simplification</a> </li><li class="nav-list-item "> <a href="/meshedit/global/triangulate/" class="nav-list-link">Triangulation</a> </li></ul></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/" class="nav-list-link">A3: Pathtracer</a><ul class="nav-list "><li class="nav-list-item "><a href="/pathtracer/camera_rays" class="nav-list-link">(Task 1) Camera Rays</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/intersecting_objects" class="nav-list-link">(Task 2) Intersections</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/ray_triangle_intersection" class="nav-list-link">Ray Triangle Intersection</a> </li><li class="nav-list-item "> <a href="/pathtracer/ray_sphere_intersection" class="nav-list-link">Ray Sphere Intersection</a> </li></ul></li><li class="nav-list-item "><a href="/pathtracer/bounding_volume_hierarchy" class="nav-list-link">(Task 3) BVH</a></li><li class="nav-list-item "><a href="/pathtracer/shadow_rays" class="nav-list-link">(Task 4) Shadow Rays</a></li><li class="nav-list-item "><a href="/pathtracer/path_tracing" class="nav-list-link">(Task 5) Path Tracing</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/materials" class="nav-list-link">(Task 6) Materials</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/dielectrics_and_transmission" class="nav-list-link">Dielectrics and Transmission</a> </li></ul></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/environment_lighting" class="nav-list-link">(Task 7) Environment Lighting</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/importance_sampling" class="nav-list-link">Environment Light Importance Sampling</a> </li></ul></li><li class="nav-list-item "><a href="/pathtracer/visualization_of_normals" class="nav-list-link">Visualization of normals</a></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/animation/" class="nav-list-link">A4: Animation</a><ul class="nav-list "><li class="nav-list-item "><a href="/animation/splines" class="nav-list-link">Splines</a></li><li class="nav-list-item "><a href="/animation/skeleton_kinematics" class="nav-list-link">Skeleton Kinematics</a></li><li class="nav-list-item "><a href="/animation/skinning" class="nav-list-link">Skinning</a></li><li class="nav-list-item "><a href="/animation/particles" class="nav-list-link">Particles</a></li></ul></li></ul> </nav> <footer class="site-footer"> This site uses <a href="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer> </div> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search " aria-label="Search " autocomplete="off"> <label for="search-input" class="search-label"><svg viewBox="0 0 24 24" class="search-icon"><use xlink:href="#svg-search"></use></svg></label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div id="main-content-wrap" class="main-content-wrap"> <nav aria-label="Breadcrumb" class="breadcrumb-nav"> <ol class="breadcrumb-nav-list"> <li class="breadcrumb-nav-list-item"><a href="/meshedit/">A2: MeshEdit</a></li> <li class="breadcrumb-nav-list-item"><a href="/meshedit/global/">Global Operations</a></li> <li class="breadcrumb-nav-list-item"><span>Isotropic Remeshing</span></li> </ol> </nav> <div id="main-content" class="main-content" role="main"> <h1 id="isotropic-remeshing"> <a href="#isotropic-remeshing" class="anchor-heading" aria-labelledby="isotropic-remeshing"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Isotropic Remeshing </h1> <p>For an in-practice example, see the <a href="/Scotty3D/guide/model">User Guide</a>.</p> <p>Scotty3D also supports remeshing, an operation that keeps the number of samples roughly the same while improving the shape of individual triangles. The isotropic remeshing algorithm tries to make the mesh as “uniform” as possible, i.e., triangles as close as possible to equilateral triangles of equal size, and vertex degrees as close as possible to 6 (note: this algorithm is for <strong>triangle meshes only</strong>). The algorithm to be implemented is based on the paper <a href="http://graphics.uni-bielefeld.de/publications/disclaimer.php?dlurl=sgp04.pdf">Botsch and Kobbelt, “A Remeshing Approach to Multiresolution Modeling”</a> (Section 4), and can be summarized in just a few simple steps:</p> <ol> <li>If an edge is too long, split it.</li> <li>If an edge is too short, collapse it.</li> <li>If flipping an edge improves the degree of neighboring vertices, flip it.</li> <li>Move vertices toward the average of their neighbors.</li> </ol> <p>Repeating this simple process several times typically produces a mesh with fairly uniform triangle areas, angles, and vertex degrees. However, each of the steps deserves slightly more explanation.</p> <h3 id="edge-splitting--collapsing"> <a href="#edge-splitting--collapsing" class="anchor-heading" aria-labelledby="edge-splitting--collapsing"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Edge Splitting / Collapsing </h3> <p>Ultimately we want all of our triangles to be about the same size, which means we want edges to all have roughly the same length. As suggested in the paper by Botsch and Kobbelt, we will aim to keep our edges no longer than 4/3rds of the <strong>mean</strong> edge length <em>L</em> in the input mesh, and no shorter than 4/5ths of <em>L</em>. In other words, if an edge is longer than 4L/3, split it; if it is shorter than 4L/5, collapse it. We recommend performing all of the splits first, then doing all of the collapses (though as usual, you should be careful to think about when and how mesh elements are being allocated/deallocated).</p> <h3 id="edge-flipping"> <a href="#edge-flipping" class="anchor-heading" aria-labelledby="edge-flipping"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Edge Flipping </h3> <p>We want to flip an edge any time it reduces the total deviation from regular degree (degree 6). In particular, let <em>a1</em>, <em>a2</em> be the degrees of an edge that we’re thinking about flipping, and let <em>b1</em>, <em>b2</em> be the degrees of the two vertices across from this edge. The total deviation in the initial configuration is <code class="language-plaintext highlighter-rouge">|a1-6| + |a2-6| + |b1-6| + |b2-6|</code>. You should be able to easily compute the deviation after the edge flip <strong>without actually performing the edge flip</strong>; if this number decreases, then the edge flip should be performed. We recommend flipping all edges in a single pass, after the edge collapse step.</p> <h3 id="vertex-averaging"> <a href="#vertex-averaging" class="anchor-heading" aria-labelledby="vertex-averaging"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Vertex Averaging </h3> <p>Finally, we also want to optimize the geometry of the vertices. A very simple heuristic is that a mesh will have reasonably well-shaped elements if each vertex is located at the center of its neighbors. To keep your code clean and simple, we recommend using the method <code class="language-plaintext highlighter-rouge">Vertex::neighborhood_center()</code>, which computes the average position of the vertex’s neighbors. Note that you should not use this to immediately replace the current position: we don’t want to be taking averages of vertices that have already been averaged. Doing so can yield some bizarre behavior that depends on the order in which vertices are traversed (if you’re interested in learning more about this issue, Google around for the terms “Jacobi iterations” and “Gauss-Seidel). So, the code should (i) first compute the new positions (stored in <code class="language-plaintext highlighter-rouge">Vertex::new_pos</code>) for all vertices using their neighborhood centroids, and (ii) <em>then</em> update the vertices with new positions (copy <code class="language-plaintext highlighter-rouge">new_pos</code> to <code class="language-plaintext highlighter-rouge">pos</code>).</p> <center><img src="laplacian_smoothing.png" style="height:200px" /></center> <p>How exactly should the positions be updated? One idea is to simply replace each vertex position with its centroid. We can make the algorithm slightly more stable by moving <em>gently</em> toward the centroid, rather than immediately snapping the vertex to the center. For instance, if <em>p</em> is the original vertex position and <em>c</em> is the centroid, we might compute the new vertex position as <em>q</em> = <em>p</em> + <em>w</em>(<em>c</em> - <em>p</em>) where <em>w</em> is some weighting factor between 0 and 1 (we use 1/5 in the examples below). In other words, we start out at <em>p</em> and move a little bit in the update direction <em>v</em> = <em>c</em> - <em>p</em>.</p> <p>Another important issue arises if the update direction <em>v</em> has a large <em>normal</em> component, then we’ll end up pushing the surface in or out, rather than just sliding our sample points around on the surface. As a result, the shape of the surface will change much more than we’d like (try it!). To ameliorate this issue, we will move the vertex only in the <em>tangent</em> direction, which we can do by projecting out the normal component, i.e., by replacing <em>v</em> with <em>v</em> - dot(<em>N</em>,<em>v</em>)<em>N</em>, where <em>N</em> is the unit normal at the vertex. To get this normal, you will implement the method <code class="language-plaintext highlighter-rouge">Vertex::normal()</code>, which computes the vertex normal as the area-weighted average of the incident triangle normals. In other words, at a vertex i the normal points in the direction</p> <center><img src="vert_normal_eq.png" style="height:80px" /></center> <p>where A_ijk is the area of triangle ijk, and N_ijk is its unit normal; this quantity can be computed directly by just taking the cross product of two of the triangle’s edge vectors (properly oriented).</p> <h3 id="implementation"> <a href="#implementation" class="anchor-heading" aria-labelledby="implementation"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Implementation </h3> <p>The final implementation requires very little information beyond the description above; the basic recipe is:</p> <ol> <li>Compute the mean edge length <em>L</em> of the input.</li> <li>Split all edges that are longer than 4L/3.</li> <li>Collapse all edges that are shorter than 4L/5.</li> <li>Flip all edges that decrease the total deviation from degree 6.</li> <li>Compute the centroids for all the vertices.</li> <li>Move each vertex in the tangent direction toward its centroid.</li> </ol> <p>Repeating this procedure about 5 or 6 times should yield results like the ones seen below; you may want to repeat the smoothing step 10-20 times for each “outer” iteration.</p> <center><img src="remesh_example.png" style="height:420px" /></center> </div> </div> <div class="search-overlay"></div> </div> </body> </html>
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <title>Simplification - </title> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> <link rel="stylesheet" href="/assets/css/just-the-docs-default.css"> <script type="text/javascript" src="/assets/js/vendor/lunr.min.js"></script> <script type="text/javascript" src="/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.7.1 --> <title>Simplification</title> <meta name="generator" content="Jekyll v4.2.0" /> <meta property="og:title" content="Simplification" /> <meta property="og:locale" content="en_US" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="Simplification" /> <script type="application/ld+json"> {"headline":"Simplification","@type":"WebPage","url":"/meshedit/global/simplify/","@context":"https://schema.org"}</script> <!-- End Jekyll SEO tag --> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> </svg> <div class="side-bar"> <div class="site-header"> <a href="/" class="site-title lh-tight"> </a> <a href="#" id="menu-button" class="site-button"> <svg viewBox="0 0 24 24" class="icon"><use xlink:href="#svg-menu"></use></svg> </a> </div> <nav role="navigation" aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/" class="nav-list-link">Home</a></li><li class="nav-list-item"><a href="/git/" class="nav-list-link">GitHub Setup</a></li><li class="nav-list-item"><a href="/build/" class="nav-list-link">Building Scotty3D</a></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/guide/" class="nav-list-link">User Guide</a><ul class="nav-list "><li class="nav-list-item "><a href="/guide/animate_mode/" class="nav-list-link">Animate</a></li><li class="nav-list-item "><a href="/guide/layout_mode/" class="nav-list-link">Layout</a></li><li class="nav-list-item "><a href="/guide/model_mode/" class="nav-list-link">Model</a></li><li class="nav-list-item "><a href="/guide/render_mode/" class="nav-list-link">Render</a></li><li class="nav-list-item "><a href="/guide/rigging_mode/" class="nav-list-link">Rig</a></li><li class="nav-list-item "><a href="/guide/simulate_mode/" class="nav-list-link">Simulate</a></li></ul></li><li class="nav-list-item active"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/" class="nav-list-link">A2: MeshEdit</a><ul class="nav-list "><li class="nav-list-item "><a href="/meshedit/halfedge" class="nav-list-link">Halfedge Mesh</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/local/" class="nav-list-link">Local Operations</a><ul class="nav-list"><li class="nav-list-item "> <a href="/meshedit/local/edge_flip" class="nav-list-link">Edge Flip Tutorial</a> </li><li class="nav-list-item "> <a href="/meshedit/local/bevel/" class="nav-list-link">Bevelling</a> </li></ul></li><li class="nav-list-item active"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/global/" class="nav-list-link">Global Operations</a><ul class="nav-list"><li class="nav-list-item "> <a href="/meshedit/global/catmull/" class="nav-list-link">Catmull-Clark Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/remesh/" class="nav-list-link">Isotropic Remeshing</a> </li><li class="nav-list-item "> <a href="/meshedit/global/linear/" class="nav-list-link">Linear Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/loop/" class="nav-list-link">Loop Subdivision</a> </li><li class="nav-list-item active"> <a href="/meshedit/global/simplify/" class="nav-list-link active">Simplification</a> </li><li class="nav-list-item "> <a href="/meshedit/global/triangulate/" class="nav-list-link">Triangulation</a> </li></ul></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/" class="nav-list-link">A3: Pathtracer</a><ul class="nav-list "><li class="nav-list-item "><a href="/pathtracer/camera_rays" class="nav-list-link">(Task 1) Camera Rays</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/intersecting_objects" class="nav-list-link">(Task 2) Intersections</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/ray_triangle_intersection" class="nav-list-link">Ray Triangle Intersection</a> </li><li class="nav-list-item "> <a href="/pathtracer/ray_sphere_intersection" class="nav-list-link">Ray Sphere Intersection</a> </li></ul></li><li class="nav-list-item "><a href="/pathtracer/bounding_volume_hierarchy" class="nav-list-link">(Task 3) BVH</a></li><li class="nav-list-item "><a href="/pathtracer/shadow_rays" class="nav-list-link">(Task 4) Shadow Rays</a></li><li class="nav-list-item "><a href="/pathtracer/path_tracing" class="nav-list-link">(Task 5) Path Tracing</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/materials" class="nav-list-link">(Task 6) Materials</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/dielectrics_and_transmission" class="nav-list-link">Dielectrics and Transmission</a> </li></ul></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/environment_lighting" class="nav-list-link">(Task 7) Environment Lighting</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/importance_sampling" class="nav-list-link">Environment Light Importance Sampling</a> </li></ul></li><li class="nav-list-item "><a href="/pathtracer/visualization_of_normals" class="nav-list-link">Visualization of normals</a></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/animation/" class="nav-list-link">A4: Animation</a><ul class="nav-list "><li class="nav-list-item "><a href="/animation/splines" class="nav-list-link">Splines</a></li><li class="nav-list-item "><a href="/animation/skeleton_kinematics" class="nav-list-link">Skeleton Kinematics</a></li><li class="nav-list-item "><a href="/animation/skinning" class="nav-list-link">Skinning</a></li><li class="nav-list-item "><a href="/animation/particles" class="nav-list-link">Particles</a></li></ul></li></ul> </nav> <footer class="site-footer"> This site uses <a href="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer> </div> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search " aria-label="Search " autocomplete="off"> <label for="search-input" class="search-label"><svg viewBox="0 0 24 24" class="search-icon"><use xlink:href="#svg-search"></use></svg></label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div id="main-content-wrap" class="main-content-wrap"> <nav aria-label="Breadcrumb" class="breadcrumb-nav"> <ol class="breadcrumb-nav-list"> <li class="breadcrumb-nav-list-item"><a href="/meshedit/">A2: MeshEdit</a></li> <li class="breadcrumb-nav-list-item"><a href="/meshedit/global/">Global Operations</a></li> <li class="breadcrumb-nav-list-item"><span>Simplification</span></li> </ol> </nav> <div id="main-content" class="main-content" role="main"> <h1 id="simplification"> <a href="#simplification" class="anchor-heading" aria-labelledby="simplification"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Simplification </h1> <p><img src="quad_simplify.png" alt="Surface simplification via quadric error metric" /></p> <p>For an in-practice example, see the <a href="/Scotty3D/guide/model">User Guide</a>.</p> <p>Just as with images, meshes often have far more samples than we really need. The simplification method in Scotty3D simplifies a given triangle mesh by applying <em>quadric error simplification</em> (note that this method is for <strong>triangle meshes only</strong>!). This method was originally developed at CMU by Michael Garland and Paul Heckbert, in their paper <a href="http://www.cs.cmu.edu/~./garland/quadrics/quadrics.html">Surface Simplification Using Quadric Error Metrics</a>. (Looking at this paper – or the many slides and presentations online that reference it – may be very helpful in understanding and implementing this part of the assignment!)</p> <p>The basic idea is to iteratively collapse edges until we reach the desired number of triangles. The more edges we collapse, the simpler the mesh becomes. The only question is: which edges should we collapse? And where should we put the new vertex when we collapse an edge? Finding the sequence of edge collapses (and vertex positions) that give an <em>optimal</em> approximation of the surface would be very difficult – likely impossible! Garland and Heckbert instead proposed a simple, greedy scheme that works quite well in practice, and is the basis of many mesh simplification tools today. Roughly speaking, we’re going to write down a function that measures the distance to a given triangle, and then “accumulate” this function as many triangles get merged together.</p> <p>More precisely, we can write the distance d of a point <em>x</em> to a plane with normal <em>N</em> passing through a point <em>p</em> as dist(<em>x</em>) = dot(<em>N</em>, <em>x</em> - <em>p</em>)</p> <center><img src="plane_normal.png" style="height:360px" /></center> <p>In other words, we measure the extent of the vector from <em>p</em> to <em>x</em> along the normal direction. This quantity gives us a value that is either <em>positive</em> (above the plane), or <em>negative</em> (below the plane). Suppose that <em>x</em> has coordinates (<em>x</em>,<em>y</em>,<em>z</em>), <em>N</em> has coordinates (<em>a</em>,<em>b</em>,<em>c</em>), and let <em>d</em>(<em>x</em>) = -dot(<em>N</em>, <em>p</em>), then in <em>homogeneous</em> coordinates, the distance to the plane is just</p> <p>dot(<em>u</em>, <em>v</em>)</p> <p>where <em>u</em> = (<em>x</em>,<em>y</em>,<em>z</em>,<em>1</em>) and <em>v</em> = (<em>a</em>,<em>b</em>,<em>c</em>,<em>d</em>). When we’re measuring the quality of an approximation, we don’t care whether we’re above or below the surface; just how <em>far away</em> we are from the original surface. Therefore, we’re going to consider the <em>square</em> of the distance, which we can write in homogeneous coordinates as</p> <center><img src="homogeneous_coord.png" style="height:40px" /></center> <p>where T denotes the transpose of a vector. The term <em>vv</em>^T is an <a href="https://en.wikipedia.org/wiki/Outer_product">outer product</a> of the vector <em>v</em> with itself, which gives us a symmetric matrix <em>K</em> = <em>vv</em>^T. In components, this matrix would look like</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>a^2 ab ac ad
ab b^2 bc bd
ac bc c^2 cd
ad bd cd d^2
</code></pre></div></div> <p>but in Scotty3D it can be constructed by simply calling the method <code class="language-plaintext highlighter-rouge">outer( Vec4, Vec4 )</code> in <code class="language-plaintext highlighter-rouge">lib/mat4.h</code> that takes a pair of vectors in homogeneous coordinates and returns the outer product as a 4x4 matrix. We will refer to this matrix as a “quadric,” because it also describes a <a href="https://en.wikipedia.org/wiki/Quadric">quadric surface</a>.</p> <p>The matrix <em>K</em> tells us something about the distance to a plane. We can also get some idea of how far we are from a <em>vertex</em> by considering the sum of the squared distances to the planes passing through all triangles that touch that vertex. In other words, we will say that the distance to a small neighborhood around the vertex i can be approximated by the sum of the quadrics on the incident faces ijk:</p> <center><img src="K_sum.png" style="height:100px" /></center> <center><img src="vert_normals.png" style="height:360px" /></center> <p>Likewise, the distance to an <em>edge</em> ij will be approximated by the sum of the quadrics at its two endpoints:</p> <center><img src="edge_k_sum.png" style="height:50px" /></center> <p>The sums above should then be easy to compute – you can just add up the <code class="language-plaintext highlighter-rouge">Mat4</code> objects around a vertex or along an edge using the usual “+” operator. You do not need to write an explicit loop over the 16 entries of the matrix.</p> <p>Once you have a quadric <em>K</em> associated with an edge <em>ij</em>, you can ask the following question: if we collapse the edge to a point <em>x</em>, where should we put the new point so that it minimizes the (approximate) distance to the original surface? In other words, where should it go so that it minimizes the quantity <em>x</em>^T <em>K x</em>?</p> <p>Just like any other function, we can look for the minimum by taking the derivative with respect to <em>x</em> and setting it equal to zero. (By the way, in this case we’re always going to get a <em>minimum</em> and not a <em>maximum</em> because the matrices K are all <a href="https://en.wikipedia.org/wiki/Positive-definite_matrix">positive-definite</a>.) In other words, we want to solve the small (4x4) linear system</p> <p><em>K u</em> = <em>0</em></p> <p>for the optimal position <em>u</em>, expressed in homogeneous coordinates. We can simplify this situation a bit by remembering that the homogeneous coordinate for a point in 3-space is just 1. After a few simple manipulations, then, we can rewrite this same system as an even smaller 3x3 linear system</p> <p><em>Ax</em> = <em>b</em></p> <p>where A is the upper-left 3x3 block of K, and b is <em>minus</em> the upper-right 3x1 column. In other words, the entries of A are just</p> <center><img src="K_A_block.png" style="height:100px" /></center> <p>and the entries of b are</p> <center><img src="b_vec.png" style="height:100px" /></center> <p>The cost associated with this solution can be found by plugging <em>x</em> back into our original expression, i.e., the cost is just</p> <p><em>x</em>^T <em>K</em> <em>x</em></p> <p>where <em>K</em> is the quadric associated with the edge. Fortunately, <em>you do not need to write any code to solve this linear system</em>. It can be solved using the method <code class="language-plaintext highlighter-rouge">Mat4::inverse()</code> which computes the inverse of a 4x4 matrix. Note that while we really want to work with a 3x3 matrix here, using the upper left 3x3 block of a 4x4 matrix is equivalent, given that the 4th row/column remain as in the identity matrix. In particular, you can write something like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Mat4 A; // computed by accumulating quadrics and then extacting the upper-left 3x3 block
Vec3 b; // computed by extracting minus the upper-right 3x1 column from the same matrix
Vec3 x = A.inverse() * b; // solve Ax = b for x by hitting both sides with the inverse of A
</code></pre></div></div> <p>However, A might not always be invertible: consider the case where the mesh is composed of points all on the same plane. In this case, you need to select an optimal point along the original edge. Please read <a href="http://reports-archive.adm.cs.cmu.edu/anon/1999/CMU-CS-99-105.pdf">Garland’s paper</a> on page 62 section 3.5 for more details.</p> <p>If you’re a bit lost at this point, don’t worry! There are a lot of details to go through, and we’ll summarize everything again in the implementation section. The main idea to keep in mind right now is:</p> <ul> <li>we’re storing a matrix at every vertex that encodes (roughly) the distance to the surface, and</li> <li>for each edge, we want to find the point that is (roughly) as close as possible to the surface, according to the matrices at its endpoints.</li> </ul> <p>As we collapse edges, the matrices at endpoints will be combined by just adding them together. So, as we perform more and more edge collapses, these matrices will try to capture the distance to a larger and larger region of the original surface.</p> <p>The one final thing we want to think about is performance. At each iteration, we want to collapse the edge that results in the <em>least</em> deviation from our original surface. But testing every edge, every single iteration sounds pretty expensive! (Something like O(n^2).) Instead, we’re going to put all our edges into a <a href="https://en.wikipedia.org/wiki/Priority_queue">priority queue</a> that efficiently keeps track of the “best” edge for us, even as we add and remove edges from our mesh. In the code framework, we actually introduce a new class called an <code class="language-plaintext highlighter-rouge">Edge_Record</code> that encodes all the essential information about our edge:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// An edge record keeps track of all the information about edges
// that we need while applying our mesh simplification algorithm.
class Edge_Record {
public:
Edge_Record() {}
Edge_Record(std::unordered_map&lt;Halfedge_Mesh::VertexRef, Mat4&gt;&amp; vertex_quadrics,
Halfedge_Mesh::EdgeRef e) : edge(e) {
// The second constructor takes a dictionary mapping vertices
// to quadric error matrices and an edge reference. It then
// computes the sum of the quadrics at the two endpoints
// and solves for the optimal midpoint position as measured
// by this quadric. It also stores the value of this quadric
// as the "score" used by the priority queue.
}
EdgeRef edge; // the edge referred to by this record
Vec3 optimal; // the optimal point, if we were
// to collapse this edge next
float cost; // the cost associated with collapsing this edge,
// which is very (very!) roughly something like
// the distance we'll deviate from the original
// surface if this edge is collapsed
};
</code></pre></div></div> <p>Within <code class="language-plaintext highlighter-rouge">Halfedge_Mesh::simplify</code>, you will create a dictionary <code class="language-plaintext highlighter-rouge">vertex_quadrics</code> mapping vertices to quadric error matrices. We will use a <code class="language-plaintext highlighter-rouge">std::unordered_map</code> for this purpose, which is the hash map provided by the STL. Its usage is detailed in the <a href="https://en.cppreference.com/w/cpp/container/unordered_map">C++ documentation</a>. To initialize the record for a given edge <code class="language-plaintext highlighter-rouge">e</code>, you can use this dictionary to write</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Edge_Record record(vertex_quadrics, e);
</code></pre></div></div> <p>Similarly to how we created a dictionary mapping vertices to quadric matrices, we will also want to associate this record with its edge using the <code class="language-plaintext highlighter-rouge">edge_records</code> dictionary:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>edge_records[e] = record;
</code></pre></div></div> <p>Further, we will want to add the record to a priority queue, which is always sorted according to the cost of collapsing each edge. The starter code also provides the helper class <code class="language-plaintext highlighter-rouge">PQueue</code> for this purpose. For example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PQueue&lt;Edge_Record&gt; queue;
queue.insert(record);
</code></pre></div></div> <p>If we ever want to know what the best edge is to collapse, we can just look at the top of the priority queue:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Edge_Record bestEdge = queue.top();
</code></pre></div></div> <p>More documentation is provided inline in <code class="language-plaintext highlighter-rouge">student/meshedit.cpp</code>.</p> <p>Though conceptually sophisticated, quadric error simplification is actually not too hard to implement. It basically boils down to two methods:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Edge_Record::Edge_Record(std::unordered_map&lt;Halfedge_Mesh::VertexRef, Mat4&gt;&amp; vertex_quadrics, EdgeIter e);
Halfedge_Mesh::simplify();
</code></pre></div></div> <p>As discussed above, the edge record initializer should:</p> <ol> <li>Compute a quadric for the edge as the sum of the quadrics at endpoints.</li> <li>Build a 3x3 linear system for the optimal collapsed point, as described above.</li> <li>Solve this system and store the optimal point in <code class="language-plaintext highlighter-rouge">Edge_Record::optimal</code>.</li> <li>Compute the corresponding error value and store it in <code class="language-plaintext highlighter-rouge">Edge_Record::cost</code>.</li> <li>Store the edge in <code class="language-plaintext highlighter-rouge">Edge_Record::edge</code>.</li> </ol> <p>The downsampling routine can then be implemented by following this basic recipe:</p> <ol> <li>Compute quadrics for each face by simply writing the plane equation for that face in homogeneous coordinates, and building the corresponding quadric matrix using <code class="language-plaintext highlighter-rouge">outer()</code>. This matrix should be stored in the yet-unmentioned dictionary <code class="language-plaintext highlighter-rouge">face_quadrics</code>.</li> <li>Compute an initial quadric for each vertex by adding up the quadrics at all the faces touching that vertex. This matrix should be stored in <code class="language-plaintext highlighter-rouge">vertex_quadrics</code>. (Note that these quadrics must be updated as edges are collapsed.)</li> <li>For each edge, create an <code class="language-plaintext highlighter-rouge">Edge_Record</code>, insert it into the <code class="language-plaintext highlighter-rouge">edge_records</code> dictionary, and add it to one global <code class="language-plaintext highlighter-rouge">PQueue&lt;Edge_Record&gt;</code> queue.</li> <li>Until a target number of triangles is reached, collapse the best/cheapest edge (as determined by the priority queue) and set the quadric at the new vertex to the sum of the quadrics at the endpoints of the original edge. You will also have to update the cost of any edge connected to this vertex.</li> </ol> <p>The algorithm should terminate when a target number of triangles is reached – for the purpose of this assignment, you should set this number to 1/4th the number of triangles in the input (since subdivision will give you a factor of 4 in the opposite direction). Note that to <em>get</em> the best element from the queue you call <code class="language-plaintext highlighter-rouge">PQueue::top()</code>, whereas to <em>remove</em> the best element from the top you must call <code class="language-plaintext highlighter-rouge">PQueue::pop()</code> (the separation of these two tasks is fairly standard in STL-like data structures).</p> <p>As with subdivision, it is critical that you carefully reason about which mesh elements get added/deleted in what order – particularly in Step 4. A good way to implement Step 4 would be:</p> <ol> <li>Get the cheapest edge from the queue.</li> <li><strong>Remove the cheapest edge from the queue by calling <code class="language-plaintext highlighter-rouge">pop()</code>.</strong></li> <li>Compute the new quadric by summing the quadrics at its two endpoints.</li> <li><strong>Remove any edge touching either of its endpoints from the queue.</strong></li> <li>Collapse the edge.</li> <li>Set the quadric of the new vertex to the quadric computed in Step 3.</li> <li><strong>Insert any edge touching the new vertex into the queue, creating new edge records for each of them.</strong></li> </ol> <p>Steps 4 and 7 are highlighted because it is easy to get these steps wrong. For instance, if you collapse the edge first, you may no longer be able to access the edges that need to be removed from the queue.</p> <p>A working implementation should look something like the examples below. You may find it easiest to implement this algorithm in stages. For instance, <em>first</em> get the edge collapses working, using just the edge midpoint rather than the optimal point, <em>then</em> worry about solving for the point that minimizes quadric error.</p> <!--![Quadric error simplification examples](quad_example.png)--> <center><img src="quad_example.png" style="height:480px" /></center> </div> </div> <div class="search-overlay"></div> </div> </body> </html>
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <title>Triangulation - </title> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> <link rel="stylesheet" href="/assets/css/just-the-docs-default.css"> <script type="text/javascript" src="/assets/js/vendor/lunr.min.js"></script> <script type="text/javascript" src="/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.7.1 --> <title>Triangulation</title> <meta name="generator" content="Jekyll v4.2.0" /> <meta property="og:title" content="Triangulation" /> <meta property="og:locale" content="en_US" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="Triangulation" /> <script type="application/ld+json"> {"headline":"Triangulation","@type":"WebPage","url":"/meshedit/global/triangulate/","@context":"https://schema.org"}</script> <!-- End Jekyll SEO tag --> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> </svg> <div class="side-bar"> <div class="site-header"> <a href="/" class="site-title lh-tight"> </a> <a href="#" id="menu-button" class="site-button"> <svg viewBox="0 0 24 24" class="icon"><use xlink:href="#svg-menu"></use></svg> </a> </div> <nav role="navigation" aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/" class="nav-list-link">Home</a></li><li class="nav-list-item"><a href="/git/" class="nav-list-link">GitHub Setup</a></li><li class="nav-list-item"><a href="/build/" class="nav-list-link">Building Scotty3D</a></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/guide/" class="nav-list-link">User Guide</a><ul class="nav-list "><li class="nav-list-item "><a href="/guide/animate_mode/" class="nav-list-link">Animate</a></li><li class="nav-list-item "><a href="/guide/layout_mode/" class="nav-list-link">Layout</a></li><li class="nav-list-item "><a href="/guide/model_mode/" class="nav-list-link">Model</a></li><li class="nav-list-item "><a href="/guide/render_mode/" class="nav-list-link">Render</a></li><li class="nav-list-item "><a href="/guide/rigging_mode/" class="nav-list-link">Rig</a></li><li class="nav-list-item "><a href="/guide/simulate_mode/" class="nav-list-link">Simulate</a></li></ul></li><li class="nav-list-item active"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/" class="nav-list-link">A2: MeshEdit</a><ul class="nav-list "><li class="nav-list-item "><a href="/meshedit/halfedge" class="nav-list-link">Halfedge Mesh</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/local/" class="nav-list-link">Local Operations</a><ul class="nav-list"><li class="nav-list-item "> <a href="/meshedit/local/edge_flip" class="nav-list-link">Edge Flip Tutorial</a> </li><li class="nav-list-item "> <a href="/meshedit/local/bevel/" class="nav-list-link">Bevelling</a> </li></ul></li><li class="nav-list-item active"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/global/" class="nav-list-link">Global Operations</a><ul class="nav-list"><li class="nav-list-item "> <a href="/meshedit/global/catmull/" class="nav-list-link">Catmull-Clark Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/remesh/" class="nav-list-link">Isotropic Remeshing</a> </li><li class="nav-list-item "> <a href="/meshedit/global/linear/" class="nav-list-link">Linear Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/loop/" class="nav-list-link">Loop Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/simplify/" class="nav-list-link">Simplification</a> </li><li class="nav-list-item active"> <a href="/meshedit/global/triangulate/" class="nav-list-link active">Triangulation</a> </li></ul></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/" class="nav-list-link">A3: Pathtracer</a><ul class="nav-list "><li class="nav-list-item "><a href="/pathtracer/camera_rays" class="nav-list-link">(Task 1) Camera Rays</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/intersecting_objects" class="nav-list-link">(Task 2) Intersections</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/ray_triangle_intersection" class="nav-list-link">Ray Triangle Intersection</a> </li><li class="nav-list-item "> <a href="/pathtracer/ray_sphere_intersection" class="nav-list-link">Ray Sphere Intersection</a> </li></ul></li><li class="nav-list-item "><a href="/pathtracer/bounding_volume_hierarchy" class="nav-list-link">(Task 3) BVH</a></li><li class="nav-list-item "><a href="/pathtracer/shadow_rays" class="nav-list-link">(Task 4) Shadow Rays</a></li><li class="nav-list-item "><a href="/pathtracer/path_tracing" class="nav-list-link">(Task 5) Path Tracing</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/materials" class="nav-list-link">(Task 6) Materials</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/dielectrics_and_transmission" class="nav-list-link">Dielectrics and Transmission</a> </li></ul></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/environment_lighting" class="nav-list-link">(Task 7) Environment Lighting</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/importance_sampling" class="nav-list-link">Environment Light Importance Sampling</a> </li></ul></li><li class="nav-list-item "><a href="/pathtracer/visualization_of_normals" class="nav-list-link">Visualization of normals</a></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/animation/" class="nav-list-link">A4: Animation</a><ul class="nav-list "><li class="nav-list-item "><a href="/animation/splines" class="nav-list-link">Splines</a></li><li class="nav-list-item "><a href="/animation/skeleton_kinematics" class="nav-list-link">Skeleton Kinematics</a></li><li class="nav-list-item "><a href="/animation/skinning" class="nav-list-link">Skinning</a></li><li class="nav-list-item "><a href="/animation/particles" class="nav-list-link">Particles</a></li></ul></li></ul> </nav> <footer class="site-footer"> This site uses <a href="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer> </div> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search " aria-label="Search " autocomplete="off"> <label for="search-input" class="search-label"><svg viewBox="0 0 24 24" class="search-icon"><use xlink:href="#svg-search"></use></svg></label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div id="main-content-wrap" class="main-content-wrap"> <nav aria-label="Breadcrumb" class="breadcrumb-nav"> <ol class="breadcrumb-nav-list"> <li class="breadcrumb-nav-list-item"><a href="/meshedit/">A2: MeshEdit</a></li> <li class="breadcrumb-nav-list-item"><a href="/meshedit/global/">Global Operations</a></li> <li class="breadcrumb-nav-list-item"><span>Triangulation</span></li> </ol> </nav> <div id="main-content" class="main-content" role="main"> <h1 id="triangulation"> <a href="#triangulation" class="anchor-heading" aria-labelledby="triangulation"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Triangulation </h1> <p>For an in-practice example, see the <a href="/Scotty3D/guide/model">User Guide</a>.</p> <p>A variety of geometry processing algorithms become easier to implement (or are only well defined) when the input consists purely of triangles. The method <code class="language-plaintext highlighter-rouge">Halfedge_Mesh::triangulate</code> converts any polygon mesh into a triangle mesh by splitting each polygon into triangles.</p> <p>This transformation is performed in-place, i.e., the original mesh data is replaced with the new, triangulated data (rather than making a copy). The implementation of this method will look much like the implementation of the local mesh operations, with the addition of looping over every face in the mesh.</p> <p>There is more than one way to split a polygon into triangles. Two common patterns are to connect every vertex to a single vertex, or to “zig-zag” the triangulation across the polygon:</p> <center><img src="triangulate.png" style="height:300px" /></center> <p>The <code class="language-plaintext highlighter-rouge">triangulate</code> routine is not required to produce any particular triangulation so long as:</p> <ul> <li>all polygons in the output are triangles,</li> <li>the vertex positions remain unchanged, and</li> <li>the output is a valid, manifold halfedge mesh.</li> </ul> <p>Note that triangulation of nonconvex or nonplanar polygons may lead to geometry that is unattractive or difficult to interpret. However, the purpose of this method is simply to produce triangular <em>connectivity</em> for a given polygon mesh, and correct halfedge connectivity is the only invariant that must be preserved by the implementation. The <em>geometric</em> quality of the triangulation can later be improved by running other global algorithms (e.g., isotropic remeshing); ambitious developers may also wish to consult the following reference:</p> <ul> <li>Zou et al, <a href="http://www.cs.wustl.edu/~taoju/research/triangulate_final.pdf">“An Algorithm for Triangulating Multiple 3D Polygons”</a></li> </ul> </div> </div> <div class="search-overlay"></div> </div> </body> </html>
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <title>Halfedge Mesh - </title> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> <link rel="stylesheet" href="/assets/css/just-the-docs-default.css"> <script type="text/javascript" src="/assets/js/vendor/lunr.min.js"></script> <script type="text/javascript" src="/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.7.1 --> <title>Halfedge Mesh</title> <meta name="generator" content="Jekyll v4.2.0" /> <meta property="og:title" content="Halfedge Mesh" /> <meta property="og:locale" content="en_US" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="Halfedge Mesh" /> <script type="application/ld+json"> {"headline":"Halfedge Mesh","@type":"WebPage","url":"/meshedit/halfedge","@context":"https://schema.org"}</script> <!-- End Jekyll SEO tag --> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> </svg> <div class="side-bar"> <div class="site-header"> <a href="/" class="site-title lh-tight"> </a> <a href="#" id="menu-button" class="site-button"> <svg viewBox="0 0 24 24" class="icon"><use xlink:href="#svg-menu"></use></svg> </a> </div> <nav role="navigation" aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/" class="nav-list-link">Home</a></li><li class="nav-list-item"><a href="/git/" class="nav-list-link">GitHub Setup</a></li><li class="nav-list-item"><a href="/build/" class="nav-list-link">Building Scotty3D</a></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/guide/" class="nav-list-link">User Guide</a><ul class="nav-list "><li class="nav-list-item "><a href="/guide/animate_mode/" class="nav-list-link">Animate</a></li><li class="nav-list-item "><a href="/guide/layout_mode/" class="nav-list-link">Layout</a></li><li class="nav-list-item "><a href="/guide/model_mode/" class="nav-list-link">Model</a></li><li class="nav-list-item "><a href="/guide/render_mode/" class="nav-list-link">Render</a></li><li class="nav-list-item "><a href="/guide/rigging_mode/" class="nav-list-link">Rig</a></li><li class="nav-list-item "><a href="/guide/simulate_mode/" class="nav-list-link">Simulate</a></li></ul></li><li class="nav-list-item active"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/" class="nav-list-link">A2: MeshEdit</a><ul class="nav-list "><li class="nav-list-item active"><a href="/meshedit/halfedge" class="nav-list-link active">Halfedge Mesh</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/local/" class="nav-list-link">Local Operations</a><ul class="nav-list"><li class="nav-list-item "> <a href="/meshedit/local/edge_flip" class="nav-list-link">Edge Flip Tutorial</a> </li><li class="nav-list-item "> <a href="/meshedit/local/bevel/" class="nav-list-link">Bevelling</a> </li></ul></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/global/" class="nav-list-link">Global Operations</a><ul class="nav-list"><li class="nav-list-item "> <a href="/meshedit/global/catmull/" class="nav-list-link">Catmull-Clark Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/remesh/" class="nav-list-link">Isotropic Remeshing</a> </li><li class="nav-list-item "> <a href="/meshedit/global/linear/" class="nav-list-link">Linear Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/loop/" class="nav-list-link">Loop Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/simplify/" class="nav-list-link">Simplification</a> </li><li class="nav-list-item "> <a href="/meshedit/global/triangulate/" class="nav-list-link">Triangulation</a> </li></ul></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/" class="nav-list-link">A3: Pathtracer</a><ul class="nav-list "><li class="nav-list-item "><a href="/pathtracer/camera_rays" class="nav-list-link">(Task 1) Camera Rays</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/intersecting_objects" class="nav-list-link">(Task 2) Intersections</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/ray_triangle_intersection" class="nav-list-link">Ray Triangle Intersection</a> </li><li class="nav-list-item "> <a href="/pathtracer/ray_sphere_intersection" class="nav-list-link">Ray Sphere Intersection</a> </li></ul></li><li class="nav-list-item "><a href="/pathtracer/bounding_volume_hierarchy" class="nav-list-link">(Task 3) BVH</a></li><li class="nav-list-item "><a href="/pathtracer/shadow_rays" class="nav-list-link">(Task 4) Shadow Rays</a></li><li class="nav-list-item "><a href="/pathtracer/path_tracing" class="nav-list-link">(Task 5) Path Tracing</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/materials" class="nav-list-link">(Task 6) Materials</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/dielectrics_and_transmission" class="nav-list-link">Dielectrics and Transmission</a> </li></ul></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/environment_lighting" class="nav-list-link">(Task 7) Environment Lighting</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/importance_sampling" class="nav-list-link">Environment Light Importance Sampling</a> </li></ul></li><li class="nav-list-item "><a href="/pathtracer/visualization_of_normals" class="nav-list-link">Visualization of normals</a></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/animation/" class="nav-list-link">A4: Animation</a><ul class="nav-list "><li class="nav-list-item "><a href="/animation/splines" class="nav-list-link">Splines</a></li><li class="nav-list-item "><a href="/animation/skeleton_kinematics" class="nav-list-link">Skeleton Kinematics</a></li><li class="nav-list-item "><a href="/animation/skinning" class="nav-list-link">Skinning</a></li><li class="nav-list-item "><a href="/animation/particles" class="nav-list-link">Particles</a></li></ul></li></ul> </nav> <footer class="site-footer"> This site uses <a href="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer> </div> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search " aria-label="Search " autocomplete="off"> <label for="search-input" class="search-label"><svg viewBox="0 0 24 24" class="search-icon"><use xlink:href="#svg-search"></use></svg></label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div id="main-content-wrap" class="main-content-wrap"> <nav aria-label="Breadcrumb" class="breadcrumb-nav"> <ol class="breadcrumb-nav-list"> <li class="breadcrumb-nav-list-item"><a href="/meshedit/">A2: MeshEdit</a></li> <li class="breadcrumb-nav-list-item"><span>Halfedge Mesh</span></li> </ol> </nav> <div id="main-content" class="main-content" role="main"> <h1 id="halfedge-mesh"> <a href="#halfedge-mesh" class="anchor-heading" aria-labelledby="halfedge-mesh"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Halfedge Mesh </h1> <h2 id="geometric-data-structures"> <a href="#geometric-data-structures" class="anchor-heading" aria-labelledby="geometric-data-structures"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Geometric Data Structures </h2> <p>Scotty3D uses a variety of geometric data structures, depending on the task. Some operations (e.g., ray tracing) use a simple list of triangles that can be compactly encoded and efficiently cached. For more sophisticated geometric tasks like mesh editing and sampling, a simple triangle list is no longer sufficient (or leads to unnecessarily poor asymptotic performance). Most actions in MeshEdit mode therefore use a topological data structure called a <em>halfedge mesh</em> (also known as a <em>doubly-connected</em> edge list), which provides a good tradeoff between simplicity and sophistication.</p> <h3 id="the-halfedge-data-structure"> <a href="#the-halfedge-data-structure" class="anchor-heading" aria-labelledby="the-halfedge-data-structure"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> The Halfedge Data Structure </h3> <p>The basic idea behind the halfedge data structure is that, in addition to the usual vertices, edges, and faces that make up a polygonal mesh, we also have an entity called a <em>halfedge</em> that acts like “glue” connecting the different elements. It is this glue that allow us to easily “navigate” the mesh, i.e., easily access mesh elements adjacent to a given element.</p> <center><img src="halfedge_pointers.png" style="height:240px" /></center> <p>In particular, there are two halfedges associated with each edge (see picture above). For an edge connecting two vertices i and j, one of its halfedges points from i to j; the other one points from j to i. In other words, we say that the two halfedges are <em>oppositely oriented</em>. On of the halfedges is associated with the face to the “left” of the edge; the other is associated with the face to the “right.” Each halfedge knows about the opposite halfedge, which we call its <em>twin</em>. It also knows about the <em>next</em> halfedge around its face, as well as its associated edge, face, and vertex.</p> <p>In contrast, the standard mesh elements (vertices, edges, and faces) know only about <em>one</em> of their halfedges. In particular:</p> <ul> <li>a vertex knows about one of its “outgoing” halfedges,</li> <li>an edge knows about one of its two halfedges, and</li> <li>a face knows about one of the many halfedges circulating around its interior.</li> </ul> <p>In summary, we have the following relationships:</p> <div class="table-wrapper"><table> <thead> <tr> <th>Mesh Element</th> <th>Pointers</th> </tr> </thead> <tbody> <tr> <td>Vertex</td> <td>halfedge (just one)</td> </tr> <tr> <td>Edge</td> <td>halfedge (just one)</td> </tr> <tr> <td>Face</td> <td>halfedge (just one)</td> </tr> <tr> <td>Halfedge</td> <td>next, twin, vertex, edge, face</td> </tr> </tbody> </table></div> <p>This list emphasizes that it is really the <strong>halfedges</strong> that connect everything up. An easy example is if we want to visit all the vertices of a given face. We can start at the face’s halfedge, and follow the “next” pointer until we’re back at the beginning. A more interesting example is visiting all the vertices adjacent to a given vertex v. We can start by getting its outgoing halfedge, then its twin, then its next halfedge; this final halfedge will also point out of vertex v, but it will point <strong>toward</strong> a different vertex than the first halfedge. By repeating this process, we can visit all the neighboring vertices:</p> <center><img src="vertex_traversal.png" style="height:360px" /></center> <p>In some sense, a halfedge mesh is kind of like a supercharged linked list. For instance, the halfedges around a given face (connected by <code class="language-plaintext highlighter-rouge">next</code> pointers) form a sort of “cyclic” linked list, where the tail points back to the head.</p> <p>A nice consequence of the halfedge representation is that any valid halfedge mesh <strong>must</strong> be manifold and orientable. Scotty3D will therefore only produce manifold, oriented meshes as output (and will complain if the input does not satisfy these criteria).</p> <h3 id="the-halfedge_mesh-class"> <a href="#the-halfedge_mesh-class" class="anchor-heading" aria-labelledby="the-halfedge_mesh-class"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> The <code class="language-plaintext highlighter-rouge">Halfedge_Mesh</code> Class </h3> <p>The Scotty3D skeleton code already provides a fairly sophisticated implementation of the half edge data structure, in the <code class="language-plaintext highlighter-rouge">Halfedge_Mesh</code> class (see <code class="language-plaintext highlighter-rouge">geometry/halfedge.h</code> and <code class="language-plaintext highlighter-rouge">geometry/halfedge.cpp</code>). Although the detailed implementation may appear a bit complicated, the basic interface is not much different from the abstract description given above. For instance, suppose we have a face f and want to print out the positions of all its vertices. We would write a routine like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void printVertexPositions(FaceRef f) {
HalfEdgeRef h = f-&gt;halfedge(); // get the first halfedge of the face
do {
VertexRef v = h-&gt;vertex(); // get the vertex of the current halfedge
cout &lt;&lt; v-&gt;pos &lt;&lt; endl; // print the vertex position
h = h-&gt;next(); // move to the next halfedge around the face
} while (h != f-&gt;halfedge()); // keep going until we're back at the beginning
}
</code></pre></div></div> <p>Notice that we refer to a face as a <code class="language-plaintext highlighter-rouge">FaceRef</code> rather than just a <code class="language-plaintext highlighter-rouge">Face</code>. You can think of a <code class="language-plaintext highlighter-rouge">Ref</code> as a kind of <em>pointer</em>. Note that members of an iterator are accessed with an arrow <code class="language-plaintext highlighter-rouge">-&gt;</code> rather than a dot <code class="language-plaintext highlighter-rouge">.</code>, just as with pointers. (A more in-depth explanation of some of these details can be found in the inline documentation.) Similarly, to print out the positions of all the neighbors of a given vertex we could write a routine like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void printNeighborPositions(VertexRef v) {
HalfEdgeRef h = v-&gt;halfedge(); // get one of the outgoing halfedges of the vertex
do {
HalfEdgeRef h_twin = h-&gt;twin(); // get the vertex of the current halfedge
VertexRef vN = h_twin-&gt;vertex(); // vertex is 'source' of the half edge.
// so h-&gt;vertex() is v,
// whereas h_twin-&gt;vertex() is the neighbor vertex.
cout &lt;&lt; vN-&gt;pos &lt;&lt; endl; // print the vertex position
h = h_twin-&gt;next(); // move to the next outgoing halfedge of the vertex.
} while(h != v-&gt;halfedge()); // keep going until we're back at the beginning
}
</code></pre></div></div> <p>To iterate over <strong>all</strong> the vertices in a halfedge mesh, we could write a loop like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for(VertexRef v = mesh.vertices_begin(); v != mesh.vertices_end(); v++) {
printNeighborPositions(v); // do something interesting here
}
</code></pre></div></div> <p>Internally, the lists of vertices, edges, faces, and halfedges are stored as <strong>linked lists</strong>, which allows us to easily add or delete elements to our mesh. For instance, to add a new vertex we can write</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>VertexRef v = mesh.new_vertex();
</code></pre></div></div> <p>Likewise, to delete a vertex we can write</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mesh.erase(v);
</code></pre></div></div> <p>Note, however, that one should be <strong>very, very careful</strong> when adding or deleting mesh elements. New mesh elements must be properly linked to the mesh – for instance, this new vertex must be pointed to one of its associated halfedges by writing something like</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>v-&gt;halfedge() = h;
</code></pre></div></div> <p>Likewise, if we delete a mesh element, we must be certain that no existing elements still point to it; the halfedge data structure does not take care of these relationships for you automatically. In fact, that is exactly the point of this assignment: to get some practice directly manipulating the halfedge data structure. Being able to perform these low-level manipulations will enable you to write useful and interesting mesh code far beyond the basic operations in this assignment. The <code class="language-plaintext highlighter-rouge">Halfedge_Mesh</code> class provides a helper function called <code class="language-plaintext highlighter-rouge">validate</code> that checks whether the mesh iterators are valid. You might find it worthwhile calling this function to debug your implementation (please note that <code class="language-plaintext highlighter-rouge">validate</code> only checks that your mesh is valid - passing it does not imply that your specific operation is correct).</p> <p>Finally, the <strong>boundary</strong> of the surface (e.g., the ankles and waist of a pair of pants) requires special care in our halfedge implementation. At first glance, it would seem that the routine <code class="language-plaintext highlighter-rouge">printNeighborPositions()</code> above might break if the vertex <code class="language-plaintext highlighter-rouge">v</code> is on the boundary, because at some point we worry that we have no <code class="language-plaintext highlighter-rouge">twin()</code> element to visit. Fortunately, our implementation has been designed to avoid this kind of catastrophe. In particular, rather than having an actual hole in the mesh, we create a “virtual” boundary face whose edges are all the edges of the boundary loop. This way, we can iterate over boundary elements just like any other mesh element. If we ever need to check whether an element is on the boundary, we have the methods.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Vertex::on_boundary()
Edge::on_boundary()
Face::is_boundary()
Halfedge::is_boundary()
</code></pre></div></div> <p>These methods return true if and only if the element is contained in the domain boundary. Additionally, we store an explicit list of boundary faces, which we can iterate over like any other type of mesh element:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for(FaceRef b = mesh.boundaries_begin(); b != mesh.boundaries_end(); b++) {
// do something interesting with this boundary loop
}
</code></pre></div></div> <p>These virtual faces are not stored in the usual face list, i.e., they will not show up when iterating over faces. The figure below should help to further explain the behavior of <code class="language-plaintext highlighter-rouge">Halfedge_Mesh</code> for surfaces with boundary:</p> <center><img src="boundary_conventions.png" style="height:360px" /></center> <p>Dark blue regions indicate interior faces, whereas light blue regions indicate virtual boundary faces. Note that for vertices and edges, <code class="language-plaintext highlighter-rouge">on_boundary()</code> will return true if the element is attached to a boundary face, but <code class="language-plaintext highlighter-rouge">is_boundary()</code> for halfedges is only true if the halfedge is ‘inside’ the boundary face. For example, in the figure above the region <code class="language-plaintext highlighter-rouge">b</code> is a virtual boundary face, which means that vertex <code class="language-plaintext highlighter-rouge">v'</code>, edge <code class="language-plaintext highlighter-rouge">e'</code>, and halfedge <code class="language-plaintext highlighter-rouge">h'</code> are all part of the boundary; their methods will return true. In contrast, vertex <code class="language-plaintext highlighter-rouge">v</code>, edge <code class="language-plaintext highlighter-rouge">e</code>, face <code class="language-plaintext highlighter-rouge">f</code>, and halfedge <code class="language-plaintext highlighter-rouge">h</code> are not part of the boundary, and their methods will return false. Notice also that the boundary face b is a polygon with 12 edges.</p> <p><em>Note:</em> <em>the edge degree and face degree of a boundary vertex is not the same!</em> Notice, for instance, that vertex <code class="language-plaintext highlighter-rouge">v'</code> is contained in three edges but only two interior faces. By convention, <code class="language-plaintext highlighter-rouge">Vertex::degree()</code> returns the face degree, not the edge degree. The edge degree can be computed by finding the face degree, and adding 1 if the vertex is a boundary vertex.</p> <p>Please refer to the inline comments (e.g. of <code class="language-plaintext highlighter-rouge">geometry/halfedge.h</code>) for further details about the <code class="language-plaintext highlighter-rouge">Halfedge_Mesh</code> data structure.</p> </div> </div> <div class="search-overlay"></div> </div> </body> </html>
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <title>A2: MeshEdit - </title> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> <link rel="stylesheet" href="/assets/css/just-the-docs-default.css"> <script type="text/javascript" src="/assets/js/vendor/lunr.min.js"></script> <script type="text/javascript" src="/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.7.1 --> <title>A2: MeshEdit</title> <meta name="generator" content="Jekyll v4.2.0" /> <meta property="og:title" content="A2: MeshEdit" /> <meta property="og:locale" content="en_US" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="A2: MeshEdit" /> <script type="application/ld+json"> {"headline":"A2: MeshEdit","@type":"WebPage","url":"/meshedit/","@context":"https://schema.org"}</script> <!-- End Jekyll SEO tag --> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> </svg> <div class="side-bar"> <div class="site-header"> <a href="/" class="site-title lh-tight"> </a> <a href="#" id="menu-button" class="site-button"> <svg viewBox="0 0 24 24" class="icon"><use xlink:href="#svg-menu"></use></svg> </a> </div> <nav role="navigation" aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="/" class="nav-list-link">Home</a></li><li class="nav-list-item"><a href="/git/" class="nav-list-link">GitHub Setup</a></li><li class="nav-list-item"><a href="/build/" class="nav-list-link">Building Scotty3D</a></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/guide/" class="nav-list-link">User Guide</a><ul class="nav-list "><li class="nav-list-item "><a href="/guide/animate_mode/" class="nav-list-link">Animate</a></li><li class="nav-list-item "><a href="/guide/layout_mode/" class="nav-list-link">Layout</a></li><li class="nav-list-item "><a href="/guide/model_mode/" class="nav-list-link">Model</a></li><li class="nav-list-item "><a href="/guide/render_mode/" class="nav-list-link">Render</a></li><li class="nav-list-item "><a href="/guide/rigging_mode/" class="nav-list-link">Rig</a></li><li class="nav-list-item "><a href="/guide/simulate_mode/" class="nav-list-link">Simulate</a></li></ul></li><li class="nav-list-item active"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/" class="nav-list-link active">A2: MeshEdit</a><ul class="nav-list "><li class="nav-list-item "><a href="/meshedit/halfedge" class="nav-list-link">Halfedge Mesh</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/local/" class="nav-list-link">Local Operations</a><ul class="nav-list"><li class="nav-list-item "> <a href="/meshedit/local/edge_flip" class="nav-list-link">Edge Flip Tutorial</a> </li><li class="nav-list-item "> <a href="/meshedit/local/bevel/" class="nav-list-link">Bevelling</a> </li></ul></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/meshedit/global/" class="nav-list-link">Global Operations</a><ul class="nav-list"><li class="nav-list-item "> <a href="/meshedit/global/catmull/" class="nav-list-link">Catmull-Clark Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/remesh/" class="nav-list-link">Isotropic Remeshing</a> </li><li class="nav-list-item "> <a href="/meshedit/global/linear/" class="nav-list-link">Linear Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/loop/" class="nav-list-link">Loop Subdivision</a> </li><li class="nav-list-item "> <a href="/meshedit/global/simplify/" class="nav-list-link">Simplification</a> </li><li class="nav-list-item "> <a href="/meshedit/global/triangulate/" class="nav-list-link">Triangulation</a> </li></ul></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/" class="nav-list-link">A3: Pathtracer</a><ul class="nav-list "><li class="nav-list-item "><a href="/pathtracer/camera_rays" class="nav-list-link">(Task 1) Camera Rays</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/intersecting_objects" class="nav-list-link">(Task 2) Intersections</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/ray_triangle_intersection" class="nav-list-link">Ray Triangle Intersection</a> </li><li class="nav-list-item "> <a href="/pathtracer/ray_sphere_intersection" class="nav-list-link">Ray Sphere Intersection</a> </li></ul></li><li class="nav-list-item "><a href="/pathtracer/bounding_volume_hierarchy" class="nav-list-link">(Task 3) BVH</a></li><li class="nav-list-item "><a href="/pathtracer/shadow_rays" class="nav-list-link">(Task 4) Shadow Rays</a></li><li class="nav-list-item "><a href="/pathtracer/path_tracing" class="nav-list-link">(Task 5) Path Tracing</a></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/materials" class="nav-list-link">(Task 6) Materials</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/dielectrics_and_transmission" class="nav-list-link">Dielectrics and Transmission</a> </li></ul></li><li class="nav-list-item "><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/pathtracer/environment_lighting" class="nav-list-link">(Task 7) Environment Lighting</a><ul class="nav-list"><li class="nav-list-item "> <a href="/pathtracer/importance_sampling" class="nav-list-link">Environment Light Importance Sampling</a> </li></ul></li><li class="nav-list-item "><a href="/pathtracer/visualization_of_normals" class="nav-list-link">Visualization of normals</a></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="/animation/" class="nav-list-link">A4: Animation</a><ul class="nav-list "><li class="nav-list-item "><a href="/animation/splines" class="nav-list-link">Splines</a></li><li class="nav-list-item "><a href="/animation/skeleton_kinematics" class="nav-list-link">Skeleton Kinematics</a></li><li class="nav-list-item "><a href="/animation/skinning" class="nav-list-link">Skinning</a></li><li class="nav-list-item "><a href="/animation/particles" class="nav-list-link">Particles</a></li></ul></li></ul> </nav> <footer class="site-footer"> This site uses <a href="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer> </div> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search " aria-label="Search " autocomplete="off"> <label for="search-input" class="search-label"><svg viewBox="0 0 24 24" class="search-icon"><use xlink:href="#svg-search"></use></svg></label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div id="main-content-wrap" class="main-content-wrap"> <div id="main-content" class="main-content" role="main"> <h1 id="meshedit-overview"> <a href="#meshedit-overview" class="anchor-heading" aria-labelledby="meshedit-overview"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> MeshEdit Overview </h1> <p>MeshEdit is the first major component of Scotty3D, which performs 3D modeling, subdivision, and mesh processing. When implementation of this tool is completed, it will enable the user to transform a simple cube model into beautiful, organic 3D surfaces described by high-quality polygon meshes. This tool can import, modify, and export industry-standard COLLADA files, allowing Scotty3D to interact with the broader ecosystem of computer graphics software.</p> <p>The <code class="language-plaintext highlighter-rouge">media/</code> subdirectory of the project contains a variety of meshes and scenes on which the implementation may be tested. The simple <code class="language-plaintext highlighter-rouge">cube.dae</code> input should be treated as the primary test case – when properly implemented MeshEdit contains all of the modeling tools to transform this starting mesh into a variety of functional and beautiful geometries. For further testing, a collection of other models are also included in this directory, but it is not necessarily reasonable to expect every algorithm to be effective on every input. The implementer must use judgement in selecting meaningful test inputs for the algorithms in MeshEdit.</p> <p>The following sections contain guidelines for implementing the functionality of MeshEdit:</p> <ul> <li><a href="halfedge">Halfedge Mesh</a></li> <li><a href="local">Local Mesh Operations</a> <ul> <li><a href="local/edge_flip">Tutorial: Edge Flip</a></li> <li><a href="local/bevel">Beveling</a></li> </ul> </li> <li><a href="global">Global Mesh Operations</a> <ul> <li><a href="global/triangulate">Triangulation</a></li> <li><a href="global/linear">Linear Subdivision</a></li> <li><a href="global/catmull">Catmull-Clark Subdivision</a></li> <li><a href="global/loop">Loop Subdivision</a></li> <li><a href="global/remesh">Isotropic Remeshing</a></li> <li><a href="global/simplify">Simplification</a></li> </ul> </li> </ul> <p>As always, be mindful of the <a href="..">project philosophy</a>.</p> </div> </div> <div class="search-overlay"></div> </div> </body> </html>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment