<!DOCTYPE html><htmllang="en-US"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=Edge"><title>Bevelling - </title><linkrel="shortcut icon"href="/favicon.ico"type="image/x-icon"><linkrel="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><metaname="viewport"content="width=device-width, initial-scale=1"><!-- Begin Jekyll SEO tag v2.7.1 --><title>Bevelling</title><metaname="generator"content="Jekyll v4.2.0"/><metaproperty="og:title"content="Bevelling"/><metaproperty="og:locale"content="en_US"/><metaname="twitter:card"content="summary"/><metaproperty="twitter:title"content="Bevelling"/><script type="application/ld+json">{"headline":"Bevelling","@type":"WebPage","url":"/meshedit/local/bevel/","@context":"https://schema.org"}</script><!-- End Jekyll SEO tag --></head><body><svgxmlns="http://www.w3.org/2000/svg"style="display: none;"><symbolid="svg-link"viewBox="0 0 24 24"><title>Link</title><svgxmlns="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"><pathd="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><pathd="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><symbolid="svg-search"viewBox="0 0 24 24"><title>Search</title><svgxmlns="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"><circlecx="11"cy="11"r="8"></circle><linex1="21"y1="21"x2="16.65"y2="16.65"></line></svg></symbol><symbolid="svg-menu"viewBox="0 0 24 24"><title>Menu</title><svgxmlns="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"><linex1="3"y1="12"x2="21"y2="12"></line><linex1="3"y1="6"x2="21"y2="6"></line><linex1="3"y1="18"x2="21"y2="18"></line></svg></symbol><symbolid="svg-arrow-right"viewBox="0 0 24 24"><title>Expand</title><svgxmlns="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"><polylinepoints="9 18 15 12 9 6"></polyline></svg></symbol><symbolid="svg-doc"viewBox="0 0 24 24"><title>Document</title><svgxmlns="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"><pathd="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polylinepoints="13 2 13 9 20 9"></polyline></svg></symbol></svg><divclass="side-bar"><divclass="site-header"><ahref="/"class="site-title lh-tight"></a><ahref="#"id="menu-button"class="site-button"><svgviewBox="0 0 24 24"class="icon"><usexlink:href="#svg-menu"></use></svg></a></div><navrole="navigation"aria-label="Main"id="site-nav"class="site-nav"><ulclass="nav-list"><liclass="nav-list-item"><ahref="/"class="nav-list-link">Home</a></li><liclass="nav-list-item"><ahref="/git/"class="nav-list-link">GitHub Setup</a></li><liclass="nav-list-item"><ahref="/build/"class="nav-list-link">Building Scotty3D</a></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/guide/"class="nav-list-link">User Guide</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/guide/animate_mode/"class="nav-list-link">Animate</a></li><liclass="nav-list-item "><ahref="/guide/layout_mode/"class="nav-list-link">Layout</a></li><liclass="nav-list-item "><ahref="/guide/model_mode/"class="nav-list-link">Model</a></li><liclass="nav-list-item "><ahref="/guide/render_mode/"class="nav-list-link">Render</a></li><liclass="nav-list-item "><ahref="/guide/rigging_mode/"class="nav-list-link">Rig</a></li><liclass="nav-list-item "><ahref="/guide/simulate_mode/"class="nav-list-link">Simulate</a></li></ul></li><liclass="nav-list-item active"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/"class="nav-list-link">A2: MeshEdit</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/meshedit/halfedge"class="nav-list-link">Halfedge Mesh</a></li><liclass="nav-list-item active"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/local/"class="nav-list-link">Local Operations</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/meshedit/local/edge_flip"class="nav-list-link">Edge Flip Tutorial</a></li><liclass="nav-list-item active"><ahref="/meshedit/local/bevel/"class="nav-list-link active">Bevelling</a></li></ul></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/global/"class="nav-list-link">Global Operations</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/meshedit/global/catmull/"class="nav-list-link">Catmull-Clark Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/remesh/"class="nav-list-link">Isotropic Remeshing</a></li><liclass="nav-list-item "><ahref="/meshedit/global/linear/"class="nav-list-link">Linear Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/loop/"class="nav-list-link">Loop Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/simplify/"class="nav-list-link">Simplification</a></li><liclass="nav-list-item "><ahref="/meshedit/global/triangulate/"class="nav-list-link">Triangulation</a></li></ul></li></ul></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/"class="nav-list-link">A3: Pathtracer</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/pathtracer/camera_rays"class="nav-list-link">(Task 1) Camera Rays</a></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/intersecting_objects"class="nav-list-link">(Task 2) Intersections</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/ray_triangle_intersection"class="nav-list-link">Ray Triangle Intersection</a></li><liclass="nav-list-item "><ahref="/pathtracer/ray_sphere_intersection"class="nav-list-link">Ray Sphere Intersection</a></li></ul></li><liclass="nav-list-item "><ahref="/pathtracer/bounding_volume_hierarchy"class="nav-list-link">(Task 3) BVH</a></li><liclass="nav-list-item "><ahref="/pathtracer/shadow_rays"class="nav-list-link">(Task 4) Shadow Rays</a></li><liclass="nav-list-item "><ahref="/pathtracer/path_tracing"class="nav-list-link">(Task 5) Path Tracing</a></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/materials"class="nav-list-link">(Task 6) Materials</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/dielectrics_and_transmission"class="nav-list-link">Dielectrics and Transmission</a></li></ul></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/environment_lighting"class="nav-list-link">(Task 7) Environment Lighting</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/importance_sampling"class="nav-list-link">Environment Light Importance Sampling</a></li></ul></li><liclass="nav-list-item "><ahref="/pathtracer/visualization_of_normals"class="nav-list-link">Visualization of normals</a></li></ul></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/animation/"class="nav-list-link">A4: Animation</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/animation/splines"class="nav-list-link">Splines</a></li><liclass="nav-list-item "><ahref="/animation/skeleton_kinematics"class="nav-list-link">Skeleton Kinematics</a></li><liclass="nav-list-item "><ahref="/animation/skinning"class="nav-list-link">Skinning</a></li><liclass="nav-list-item "><ahref="/animation/particles"class="nav-list-link">Particles</a></li></ul></li></ul></nav><footerclass="site-footer"> This site uses <ahref="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer></div><divclass="main"id="top"><divid="main-header"class="main-header"><divclass="search"><divclass="search-input-wrap"><inputtype="text"id="search-input"class="search-input"tabindex="0"placeholder="Search "aria-label="Search "autocomplete="off"><labelfor="search-input"class="search-label"><svgviewBox="0 0 24 24"class="search-icon"><usexlink:href="#svg-search"></use></svg></label></div><divid="search-results"class="search-results"></div></div></div><divid="main-content-wrap"class="main-content-wrap"><navaria-label="Breadcrumb"class="breadcrumb-nav"><olclass="breadcrumb-nav-list"><liclass="breadcrumb-nav-list-item"><ahref="/meshedit/">A2: MeshEdit</a></li><liclass="breadcrumb-nav-list-item"><ahref="/meshedit/local/">Local Operations</a></li><liclass="breadcrumb-nav-list-item"><span>Bevelling</span></li></ol></nav><divid="main-content"class="main-content"role="main"><h1id="beveling"><ahref="#beveling"class="anchor-heading"aria-labelledby="beveling"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Beveling </h1><p>Here we provide some additional detail about the bevel operations and their implementation in Scotty3D. Each bevel operation has two components:</p><ol><li>a method that modifies the <em>connectivity</em> of the mesh, creating new beveled elements, and</li><li>a method the updates the <em>geometry</em> of the mesh, insetting and offseting the new vertices according to user input.</li></ol><p>The methods that update the connectivity are <codeclass="language-plaintext highlighter-rouge">HalfedgeMesh::bevel_vertex</code>, <codeclass="language-plaintext highlighter-rouge">halfedgeMesh::bevel_edge</code>, and <codeclass="language-plaintext highlighter-rouge">HalfedgeMesh::bevel_face</code>. The methods that update geometry are <codeclass="language-plaintext highlighter-rouge">HalfedgeMesh::bevel_vertex_positions</code>, <codeclass="language-plaintext highlighter-rouge">HalfedgeMesh::bevel_edge_positions</code>, and <codeclass="language-plaintext highlighter-rouge">HalfedgeMesh::bevel_face_positions</code>.</p><p>The methods for updating connectivity can be implemented following the general strategy outlined in <ahref="edge_flip">edge flip tutorial</a>. <strong>Note that the methods that update geometry will be called repeatedly for the same bevel, in order to adjust positions according to user mouse input. See the gif in the <ahref="../guide/model">User Guide</a>.</strong></p><p>To update the <em>geometry</em> of a beveled element, you are provided with the following data:</p><ul><li><codeclass="language-plaintext highlighter-rouge">start_positions</code> - These are the original vertex positions of the beveled mesh element, without any insetting or offsetting.</li><li><codeclass="language-plaintext highlighter-rouge">face</code> - This is a reference to the face currently being beveled. This was returned by one of the connectivity functions.</li><li><codeclass="language-plaintext highlighter-rouge">tangent_offset</code> - The amount by which the new face should be inset (i.e., “shrunk” or “expanded”)</li><li><codeclass="language-plaintext highlighter-rouge">normal_offset</code> - (faces only) The amount by which the new face should be offset in the normal direction.</li></ul><p>Also note that we provide code to gather the halfedges contained in the beveled face, creating the array <codeclass="language-plaintext highlighter-rouge">new_halfedges</code>. You should only have to update the position (<codeclass="language-plaintext highlighter-rouge">Vertex::pos</code>) of the vertices associated with this list of halfedges. The basic recipe for updating these positions is:</p><ul><li>Iterate over the list of halfedges (<codeclass="language-plaintext highlighter-rouge">new_halfedges</code>)</li><li>Grab the vertex coordinates that are needed to compute the new, updated vertex coordinates (this could be a mix of values from <codeclass="language-plaintext highlighter-rouge">start_positions</code>, or the members <codeclass="language-plaintext highlighter-rouge">Vertex::pos</code>)</li><li>Compute the updated vertex positions using the current values of <codeclass="language-plaintext highlighter-rouge">tangent_offset</code> (and possibly <codeclass="language-plaintext highlighter-rouge">normal_offset</code>)</li><li>Store the new vertex positions in <codeclass="language-plaintext highlighter-rouge">Vertex::pos</code><em>for the vertices of the new, beveled polygon only</em> (i.e., the vertices associated with each of <codeclass="language-plaintext highlighter-rouge">new_halfedges</code>).</li></ul><p>The reason for storing <codeclass="language-plaintext highlighter-rouge">new_halfedges</code> and <codeclass="language-plaintext highlighter-rouge">start_positions</code> in an array is that it makes it easy to access positions “to the left” and “to the right” of a given vertex. For instance, suppose we want to figure out the offset from the corner of a polygon. We might want to compute some geometric quantity involving the three vertex positions <codeclass="language-plaintext highlighter-rouge">start_positions[i-1]</code>, <codeclass="language-plaintext highlighter-rouge">start_positions[i]</code>, and <codeclass="language-plaintext highlighter-rouge">start_positions[i+1]</code> (as well as <codeclass="language-plaintext highlighter-rouge">inset</code>), then set the new vertex position <codeclass="language-plaintext highlighter-rouge">new_halfedges[i]->vertex()->pos</code> to this new value:</p><center><imgsrc="bevel_diagram.png"/></center><p>A useful trick here is <em>modular arithmetic</em>: since we really have a “loop” of vertices, we want to make sure that indexing the next element (+1) and the previous element (-1) properly “wraps around.” This can be achieved via code like</p><divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>// Get the number of vertices in the new polygon
int N = (int)hs.size();
// Assuming we're looking at vertex i, compute the indices
// of the next and previous elements in the list using
// modular arithmetic---note that to get the previous index,
// we can't just subtract 1 because the mod operation in C++
// doesn't behave quite how you might expect for negative
// values!
int a = (i+N-1) % N;
int b = i;
int c = (i+1) % N;
// Get the actual 3D vertex coordinates at these vertices
Vec3 pa = start_positions[a];
Vec3 pb = start_positions[b];
Vec3 pc = start_positions[c];
</code></pre></div></div><p>From here, you will need to compute new coordinates for vertex <codeclass="language-plaintext highlighter-rouge">i</code>, which can be accessed from <codeclass="language-plaintext highlighter-rouge">new_halfedges[i]->vertex()->pos</code>. As a “dummy” example (i.e., this is NOT what you should actually do!!) this code will set the position of the new vertex to the average of the vertices above:</p><divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>new_halfedges[i].vertex()->pos = ( pa + pb + pc ) / 3.; // replace with something that actually makes sense!
</code></pre></div></div><p>The only question remaining is: where <em>should</em> you put the beveled vertex? <strong>We will leave this decision up to you.</strong> This question is one where you will have to think a little bit about what a good design would be. Questions to ask yourself:</p><ul><li>How do I compute a point that is inset from the original geometry?</li><li>For faces, how do I shift the geometry in the normal direction? (You may wish to use the method <codeclass="language-plaintext highlighter-rouge">Face::normal()</code> here.)</li><li>What should I do as the offset geometry starts to look degenerate, e.g., shrinks to a point, or goes outside some reasonable bounds?</li><li>What should I do when the geometry is nonplanar?</li><li>Etc.</li></ul><p>The best way to get a feel for whether you have a good design is <em>to try it out!</em> Can you successfully and easily use this tool to edit your mesh? Or is it a total pain, producing bizarre results? You be the judge!</p></div></div><divclass="search-overlay"></div></div></body></html>
<!DOCTYPE html><htmllang="en-US"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=Edge"><title>Edge Flip Tutorial - </title><linkrel="shortcut icon"href="/favicon.ico"type="image/x-icon"><linkrel="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><metaname="viewport"content="width=device-width, initial-scale=1"><!-- Begin Jekyll SEO tag v2.7.1 --><title>Edge Flip Tutorial</title><metaname="generator"content="Jekyll v4.2.0"/><metaproperty="og:title"content="Edge Flip Tutorial"/><metaproperty="og:locale"content="en_US"/><metaname="twitter:card"content="summary"/><metaproperty="twitter:title"content="Edge Flip Tutorial"/><script type="application/ld+json">{"headline":"Edge Flip Tutorial","@type":"WebPage","url":"/meshedit/local/edge_flip","@context":"https://schema.org"}</script><!-- End Jekyll SEO tag --></head><body><svgxmlns="http://www.w3.org/2000/svg"style="display: none;"><symbolid="svg-link"viewBox="0 0 24 24"><title>Link</title><svgxmlns="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"><pathd="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><pathd="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><symbolid="svg-search"viewBox="0 0 24 24"><title>Search</title><svgxmlns="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"><circlecx="11"cy="11"r="8"></circle><linex1="21"y1="21"x2="16.65"y2="16.65"></line></svg></symbol><symbolid="svg-menu"viewBox="0 0 24 24"><title>Menu</title><svgxmlns="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"><linex1="3"y1="12"x2="21"y2="12"></line><linex1="3"y1="6"x2="21"y2="6"></line><linex1="3"y1="18"x2="21"y2="18"></line></svg></symbol><symbolid="svg-arrow-right"viewBox="0 0 24 24"><title>Expand</title><svgxmlns="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"><polylinepoints="9 18 15 12 9 6"></polyline></svg></symbol><symbolid="svg-doc"viewBox="0 0 24 24"><title>Document</title><svgxmlns="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"><pathd="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polylinepoints="13 2 13 9 20 9"></polyline></svg></symbol></svg><divclass="side-bar"><divclass="site-header"><ahref="/"class="site-title lh-tight"></a><ahref="#"id="menu-button"class="site-button"><svgviewBox="0 0 24 24"class="icon"><usexlink:href="#svg-menu"></use></svg></a></div><navrole="navigation"aria-label="Main"id="site-nav"class="site-nav"><ulclass="nav-list"><liclass="nav-list-item"><ahref="/"class="nav-list-link">Home</a></li><liclass="nav-list-item"><ahref="/git/"class="nav-list-link">GitHub Setup</a></li><liclass="nav-list-item"><ahref="/build/"class="nav-list-link">Building Scotty3D</a></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/guide/"class="nav-list-link">User Guide</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/guide/animate_mode/"class="nav-list-link">Animate</a></li><liclass="nav-list-item "><ahref="/guide/layout_mode/"class="nav-list-link">Layout</a></li><liclass="nav-list-item "><ahref="/guide/model_mode/"class="nav-list-link">Model</a></li><liclass="nav-list-item "><ahref="/guide/render_mode/"class="nav-list-link">Render</a></li><liclass="nav-list-item "><ahref="/guide/rigging_mode/"class="nav-list-link">Rig</a></li><liclass="nav-list-item "><ahref="/guide/simulate_mode/"class="nav-list-link">Simulate</a></li></ul></li><liclass="nav-list-item active"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/"class="nav-list-link">A2: MeshEdit</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/meshedit/halfedge"class="nav-list-link">Halfedge Mesh</a></li><liclass="nav-list-item active"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/local/"class="nav-list-link">Local Operations</a><ulclass="nav-list"><liclass="nav-list-item active"><ahref="/meshedit/local/edge_flip"class="nav-list-link active">Edge Flip Tutorial</a></li><liclass="nav-list-item "><ahref="/meshedit/local/bevel/"class="nav-list-link">Bevelling</a></li></ul></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/global/"class="nav-list-link">Global Operations</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/meshedit/global/catmull/"class="nav-list-link">Catmull-Clark Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/remesh/"class="nav-list-link">Isotropic Remeshing</a></li><liclass="nav-list-item "><ahref="/meshedit/global/linear/"class="nav-list-link">Linear Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/loop/"class="nav-list-link">Loop Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/simplify/"class="nav-list-link">Simplification</a></li><liclass="nav-list-item "><ahref="/meshedit/global/triangulate/"class="nav-list-link">Triangulation</a></li></ul></li></ul></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/"class="nav-list-link">A3: Pathtracer</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/pathtracer/camera_rays"class="nav-list-link">(Task 1) Camera Rays</a></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/intersecting_objects"class="nav-list-link">(Task 2) Intersections</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/ray_triangle_intersection"class="nav-list-link">Ray Triangle Intersection</a></li><liclass="nav-list-item "><ahref="/pathtracer/ray_sphere_intersection"class="nav-list-link">Ray Sphere Intersection</a></li></ul></li><liclass="nav-list-item "><ahref="/pathtracer/bounding_volume_hierarchy"class="nav-list-link">(Task 3) BVH</a></li><liclass="nav-list-item "><ahref="/pathtracer/shadow_rays"class="nav-list-link">(Task 4) Shadow Rays</a></li><liclass="nav-list-item "><ahref="/pathtracer/path_tracing"class="nav-list-link">(Task 5) Path Tracing</a></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/materials"class="nav-list-link">(Task 6) Materials</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/dielectrics_and_transmission"class="nav-list-link">Dielectrics and Transmission</a></li></ul></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/environment_lighting"class="nav-list-link">(Task 7) Environment Lighting</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/importance_sampling"class="nav-list-link">Environment Light Importance Sampling</a></li></ul></li><liclass="nav-list-item "><ahref="/pathtracer/visualization_of_normals"class="nav-list-link">Visualization of normals</a></li></ul></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/animation/"class="nav-list-link">A4: Animation</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/animation/splines"class="nav-list-link">Splines</a></li><liclass="nav-list-item "><ahref="/animation/skeleton_kinematics"class="nav-list-link">Skeleton Kinematics</a></li><liclass="nav-list-item "><ahref="/animation/skinning"class="nav-list-link">Skinning</a></li><liclass="nav-list-item "><ahref="/animation/particles"class="nav-list-link">Particles</a></li></ul></li></ul></nav><footerclass="site-footer"> This site uses <ahref="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer></div><divclass="main"id="top"><divid="main-header"class="main-header"><divclass="search"><divclass="search-input-wrap"><inputtype="text"id="search-input"class="search-input"tabindex="0"placeholder="Search "aria-label="Search "autocomplete="off"><labelfor="search-input"class="search-label"><svgviewBox="0 0 24 24"class="search-icon"><usexlink:href="#svg-search"></use></svg></label></div><divid="search-results"class="search-results"></div></div></div><divid="main-content-wrap"class="main-content-wrap"><navaria-label="Breadcrumb"class="breadcrumb-nav"><olclass="breadcrumb-nav-list"><liclass="breadcrumb-nav-list-item"><ahref="/meshedit/">A2: MeshEdit</a></li><liclass="breadcrumb-nav-list-item"><ahref="/meshedit/local/">Local Operations</a></li><liclass="breadcrumb-nav-list-item"><span>Edge Flip Tutorial</span></li></ol></nav><divid="main-content"class="main-content"role="main"><h1id="edge-flip-tutorial"><ahref="#edge-flip-tutorial"class="anchor-heading"aria-labelledby="edge-flip-tutorial"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Edge Flip Tutorial </h1><p>Here we provide a step-by-step guide to implementing a simplified version of the <em>EdgeFlip</em> operation for a pair of triangles—the final version, however, must be implemented for general polygons (i.e., any <em>n</em>-gon). The basic strategy for implementing the other local operations is quite similar to the procedure outlined below.</p><p><strong>Note:</strong> if you’re not familiar with C++, you should definitely take a moment to learn about the <ahref="http://en.cppreference.com/w/cpp/container/vector">standard library class</a><codeclass="language-plaintext highlighter-rouge">std::vector</code>, especially the method <codeclass="language-plaintext highlighter-rouge">push_back()</code>, which will make it easy to accumulate a list of pointers as you walk around a polygon, vertex, etc.</p><p>We now consider the case of a triangle-triangle edge flip.</p><h3id="phase-0-draw-a-diagram"><ahref="#phase-0-draw-a-diagram"class="anchor-heading"aria-labelledby="phase-0-draw-a-diagram"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> PHASE 0: Draw a Diagram </h3><p>Suppose we have a pair of triangles (a,b,c) and (c,b,d). After flipping the edge (b,c), we should now have triangles (a,d,c) and (a,b,d). A good first step for implementing any local mesh operation is to draw a diagram that clearly labels all elements affected by the operation:</p><center><imgsrc="edge_flip_diagram.png"/></center><p>Here we have drawn a diagram of the region around the edge both before and after the edge operation (in this case, “flip”), labeling each type of element (halfedge, vertex, edge, and face) from zero to the number of elements. It is important to include every element affected by the operation, thinking very carefully about which elements will be affected. If elements are omitted during this phase, everything will break—even if the code written in the two phases is correct! In this example, for instance, we need to remember to include the halfedges “outside” the neighborhood, since their “twin” pointers will be affected.</p><h3id="phase-i-collect-elements"><ahref="#phase-i-collect-elements"class="anchor-heading"aria-labelledby="phase-i-collect-elements"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> PHASE I: Collect elements </h3><p>Once you’ve drawn your diagram, simply collect all the elements from the “before” picture. Give them the same names as in your diagram, so that you can debug your code by comparing with the picture.</p><divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>// HALFEDGES
HalfedgeRef h0 = e0->halfedge();
HalfedgeRef h1 = h0->next();
HalfedgeRef h2 = h1->next();
HalfedgeRef h3 = h0->twin();
HalfedgeRef h4 = h3->next();
HalfedgeRef h5 = h4->next();
HalfedgeRef h6 = h1->twin();
HalfedgeRef h7 = h2->twin();
HalfedgeRef h8 = h4->twin();
HalfedgeRef h9 = h5->twin();
// VERTICES
VertexRef v0 = h0->vertex();
VertexRef v1 = h3->vertex();
// ...you fill in the rest!...
// EDGES
EdgeRef e1 = h5->edge();
EdgeRef e2 = h4->edge();
// ...you fill in the rest!...
// FACES
FaceRef f0 = h0->face();
// ...you fill in the rest!...
</code></pre></div></div><h3id="phase-ii-allocate-new-elements"><ahref="#phase-ii-allocate-new-elements"class="anchor-heading"aria-labelledby="phase-ii-allocate-new-elements"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> PHASE II: Allocate new elements </h3><p>If your edge operation requires new elements, now is the time to allocate them. For the edge flip, we don’t need any new elements; but suppose that for some reason we needed a new vertex v4. At this point we would allocate the new vertex via</p><divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>VertexRef v4 = mesh.new_vertex();
</code></pre></div></div><p>(The name used for this new vertex should correspond to the label you give it in your “after” picture.) Likewise, new edges, halfedges, and faces can be allocated via the methods <codeclass="language-plaintext highlighter-rouge">mesh.new_edge()</code>, <codeclass="language-plaintext highlighter-rouge">mesh.new_halfedge()</code>, and <codeclass="language-plaintext highlighter-rouge">mesh.new_face()</code>.</p><h3id="phase-iii-reassign-elements"><ahref="#phase-iii-reassign-elements"class="anchor-heading"aria-labelledby="phase-iii-reassign-elements"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> PHASE III: Reassign Elements </h3><p>Next, update the pointers for all the mesh elements that are affected by the edge operation. Be exhaustive! In other words, go ahead and specify every pointer for every element, even if it did not change. Once things are working correctly, you can always optimize by removing unnecessary assignments. But get it working correctly first! Correctness is more important than efficiency.</p><divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>// HALFEDGES
h0->next() = h1;
h0->twin() = h3;
h0->vertex() = v2;
h0->edge() = e0;
h0->face() = f0;
h1->next() = h2;
h1->twin() = h7;
h1->vertex() = v3;
h1->edge() = e3;
h1->face() = f0;
// ...you fill in the rest!...
// ...and don't forget about the "outside" elements!...
h9->next() = h9->next(); // didn't change, but set it anyway!
h9->twin() = h4;
h9->vertex() = v1;
h9->edge() = e1;
h9->face() = h9->face(); // didn't change, but set it anyway!
// VERTICES
v0->halfedge() = h2;
v1->halfedge() = h5;
v2->halfedge() = h4;
v3->halfedge() = h3;
// EDGES
e0->halfedge() = h0; //...you fill in the rest!...
// FACES
f0->halfedge() = h0; //...you fill in the rest!...
</code></pre></div></div><h3id="phase-iv-delete-unused-elements"><ahref="#phase-iv-delete-unused-elements"class="anchor-heading"aria-labelledby="phase-iv-delete-unused-elements"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> PHASE IV: Delete unused elements </h3><p>If your edge operation eliminates elements, now is the best time to deallocate them: at this point, you can be sure that they are no longer needed. For instance, since we do not need the vertex allocated in PHASE II, we could write</p><divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>mesh.erase(v4);
</code></pre></div></div><p>You should be careful that this mesh element is not referenced by any other element in the mesh. But if your “before” and “after” diagrams are correct, that should not be an issue!</p><h3id="design-considerations"><ahref="#design-considerations"class="anchor-heading"aria-labelledby="design-considerations"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Design considerations </h3><p>The basic algorithm outlined above will handle most edge flips, but you should also think carefully about possible corner-cases. You should also think about other design issues, like “how much should this operation cost?” For instance, for this simple triangle-triangle edge flip it might be reasonable to:</p><ul><li>Ignore requests to flip boundary edges (i.e., just return immediately if either neighboring face is a boundary loop).</li><li>Ignore requests to perform any edge flip that would make the surface non-manifold or otherwise invalidate the mesh.</li><li>Not add or delete any elements. Since there are the same number of mesh elements before and after the flip, you should only need to reassign pointers.</li><li>Perform only a constant amount of work – the cost of flipping a single edge should <strong>not</strong> be proportional to the size of the mesh!</li></ul><p>Formally proving that your code is correct in all cases is challenging, but at least try to think about what could go wrong in degenerate cases (e.g., vertices of low degree, or very small meshes like a tetrahedron). The biggest challenge in properly implementing this type of local operation is making sure that all the pointers still point to the right place in the modified mesh, and will likely be the cause of most of your crashes! To help mitigate this, Scotty3D will automatically attempt to <codeclass="language-plaintext highlighter-rouge">validate</code> your mesh after each operation, and will warn you if it detects abnormalities. Note that it will still crash if you leave references to deleted mesh elements!</p></div></div><divclass="search-overlay"></div></div></body></html>
<!DOCTYPE html><htmllang="en-US"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=Edge"><title>Local Operations - </title><linkrel="shortcut icon"href="/favicon.ico"type="image/x-icon"><linkrel="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><metaname="viewport"content="width=device-width, initial-scale=1"><!-- Begin Jekyll SEO tag v2.7.1 --><title>Local Operations</title><metaname="generator"content="Jekyll v4.2.0"/><metaproperty="og:title"content="Local Operations"/><metaproperty="og:locale"content="en_US"/><metaname="twitter:card"content="summary"/><metaproperty="twitter:title"content="Local Operations"/><script type="application/ld+json">{"headline":"Local Operations","@type":"WebPage","url":"/meshedit/local/","@context":"https://schema.org"}</script><!-- End Jekyll SEO tag --></head><body><svgxmlns="http://www.w3.org/2000/svg"style="display: none;"><symbolid="svg-link"viewBox="0 0 24 24"><title>Link</title><svgxmlns="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"><pathd="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><pathd="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><symbolid="svg-search"viewBox="0 0 24 24"><title>Search</title><svgxmlns="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"><circlecx="11"cy="11"r="8"></circle><linex1="21"y1="21"x2="16.65"y2="16.65"></line></svg></symbol><symbolid="svg-menu"viewBox="0 0 24 24"><title>Menu</title><svgxmlns="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"><linex1="3"y1="12"x2="21"y2="12"></line><linex1="3"y1="6"x2="21"y2="6"></line><linex1="3"y1="18"x2="21"y2="18"></line></svg></symbol><symbolid="svg-arrow-right"viewBox="0 0 24 24"><title>Expand</title><svgxmlns="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"><polylinepoints="9 18 15 12 9 6"></polyline></svg></symbol><symbolid="svg-doc"viewBox="0 0 24 24"><title>Document</title><svgxmlns="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"><pathd="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polylinepoints="13 2 13 9 20 9"></polyline></svg></symbol></svg><divclass="side-bar"><divclass="site-header"><ahref="/"class="site-title lh-tight"></a><ahref="#"id="menu-button"class="site-button"><svgviewBox="0 0 24 24"class="icon"><usexlink:href="#svg-menu"></use></svg></a></div><navrole="navigation"aria-label="Main"id="site-nav"class="site-nav"><ulclass="nav-list"><liclass="nav-list-item"><ahref="/"class="nav-list-link">Home</a></li><liclass="nav-list-item"><ahref="/git/"class="nav-list-link">GitHub Setup</a></li><liclass="nav-list-item"><ahref="/build/"class="nav-list-link">Building Scotty3D</a></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/guide/"class="nav-list-link">User Guide</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/guide/animate_mode/"class="nav-list-link">Animate</a></li><liclass="nav-list-item "><ahref="/guide/layout_mode/"class="nav-list-link">Layout</a></li><liclass="nav-list-item "><ahref="/guide/model_mode/"class="nav-list-link">Model</a></li><liclass="nav-list-item "><ahref="/guide/render_mode/"class="nav-list-link">Render</a></li><liclass="nav-list-item "><ahref="/guide/rigging_mode/"class="nav-list-link">Rig</a></li><liclass="nav-list-item "><ahref="/guide/simulate_mode/"class="nav-list-link">Simulate</a></li></ul></li><liclass="nav-list-item active"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/"class="nav-list-link">A2: MeshEdit</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/meshedit/halfedge"class="nav-list-link">Halfedge Mesh</a></li><liclass="nav-list-item active"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/local/"class="nav-list-link active">Local Operations</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/meshedit/local/edge_flip"class="nav-list-link">Edge Flip Tutorial</a></li><liclass="nav-list-item "><ahref="/meshedit/local/bevel/"class="nav-list-link">Bevelling</a></li></ul></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/global/"class="nav-list-link">Global Operations</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/meshedit/global/catmull/"class="nav-list-link">Catmull-Clark Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/remesh/"class="nav-list-link">Isotropic Remeshing</a></li><liclass="nav-list-item "><ahref="/meshedit/global/linear/"class="nav-list-link">Linear Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/loop/"class="nav-list-link">Loop Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/simplify/"class="nav-list-link">Simplification</a></li><liclass="nav-list-item "><ahref="/meshedit/global/triangulate/"class="nav-list-link">Triangulation</a></li></ul></li></ul></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/"class="nav-list-link">A3: Pathtracer</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/pathtracer/camera_rays"class="nav-list-link">(Task 1) Camera Rays</a></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/intersecting_objects"class="nav-list-link">(Task 2) Intersections</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/ray_triangle_intersection"class="nav-list-link">Ray Triangle Intersection</a></li><liclass="nav-list-item "><ahref="/pathtracer/ray_sphere_intersection"class="nav-list-link">Ray Sphere Intersection</a></li></ul></li><liclass="nav-list-item "><ahref="/pathtracer/bounding_volume_hierarchy"class="nav-list-link">(Task 3) BVH</a></li><liclass="nav-list-item "><ahref="/pathtracer/shadow_rays"class="nav-list-link">(Task 4) Shadow Rays</a></li><liclass="nav-list-item "><ahref="/pathtracer/path_tracing"class="nav-list-link">(Task 5) Path Tracing</a></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/materials"class="nav-list-link">(Task 6) Materials</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/dielectrics_and_transmission"class="nav-list-link">Dielectrics and Transmission</a></li></ul></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/environment_lighting"class="nav-list-link">(Task 7) Environment Lighting</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/importance_sampling"class="nav-list-link">Environment Light Importance Sampling</a></li></ul></li><liclass="nav-list-item "><ahref="/pathtracer/visualization_of_normals"class="nav-list-link">Visualization of normals</a></li></ul></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/animation/"class="nav-list-link">A4: Animation</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/animation/splines"class="nav-list-link">Splines</a></li><liclass="nav-list-item "><ahref="/animation/skeleton_kinematics"class="nav-list-link">Skeleton Kinematics</a></li><liclass="nav-list-item "><ahref="/animation/skinning"class="nav-list-link">Skinning</a></li><liclass="nav-list-item "><ahref="/animation/particles"class="nav-list-link">Particles</a></li></ul></li></ul></nav><footerclass="site-footer"> This site uses <ahref="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer></div><divclass="main"id="top"><divid="main-header"class="main-header"><divclass="search"><divclass="search-input-wrap"><inputtype="text"id="search-input"class="search-input"tabindex="0"placeholder="Search "aria-label="Search "autocomplete="off"><labelfor="search-input"class="search-label"><svgviewBox="0 0 24 24"class="search-icon"><usexlink:href="#svg-search"></use></svg></label></div><divid="search-results"class="search-results"></div></div></div><divid="main-content-wrap"class="main-content-wrap"><navaria-label="Breadcrumb"class="breadcrumb-nav"><olclass="breadcrumb-nav-list"><liclass="breadcrumb-nav-list-item"><ahref="/meshedit/">A2: MeshEdit</a></li><liclass="breadcrumb-nav-list-item"><span>Local Operations</span></li></ol></nav><divid="main-content"class="main-content"role="main"><h1id="local-mesh-operations"><ahref="#local-mesh-operations"class="anchor-heading"aria-labelledby="local-mesh-operations"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Local Mesh Operations </h1><p>Many of the actions that need to be implemented in the MeshEdit mode are local mesh operations (like edge collapse, face bevel, etc.).</p><p>A good recipe for ensuring that all pointers are still valid after a local remeshing operation is:</p><ol><li>Draw a picture of all the elements (vertices, edges, faces, halfedges) that will be needed from the original mesh, and all the elements that should appear in the modified mesh.</li><li>Allocate any new elements that are needed in the modified mesh, but do not appear in the original mesh.</li><li>For every element in the “modified” picture, set <strong>all</strong> of its pointers – even if they didn’t change. For instance, for each halfedge, make sure to set <codeclass="language-plaintext highlighter-rouge">next</code>, <codeclass="language-plaintext highlighter-rouge">twin</code>, <codeclass="language-plaintext highlighter-rouge">vertex</code>, <codeclass="language-plaintext highlighter-rouge">edge</code>, and <codeclass="language-plaintext highlighter-rouge">face</code> to the correct values in the new (modified) picture. For each vertex, make sure to set its <codeclass="language-plaintext highlighter-rouge">halfedge</code> pointer. Etc. A convenience method <codeclass="language-plaintext highlighter-rouge">Halfedge::set_neighbors()</code> has been created for this purpose.</li><li>Deallocate any elements that are no longer used in the modified mesh, which can be done by calling <codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::erase()</code>.</li></ol><p>The reason for setting all the pointers (and not just the ones that changed) is that it is very easy to miss a pointer, causing your code to crash.</p><h3id="interface-with-global-mesh-operations"><ahref="#interface-with-global-mesh-operations"class="anchor-heading"aria-labelledby="interface-with-global-mesh-operations"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Interface with global mesh operations </h3><p>To facilitate user interaction, as well as global mesh processing operations (described below), local mesh operations should return the following values when possible. However, should it happen that the specified values are not available, or that the operation should not work on the given input, we need a way to signify the failure case. To do so, each local operation actually returns a <codeclass="language-plaintext highlighter-rouge">std::optional</code> value parameterized on the type of element it returns. For example, <codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::erase_vertex</code> returns a <codeclass="language-plaintext highlighter-rouge">std::optional<Halfedge_Mesh::Face></code>. An <codeclass="language-plaintext highlighter-rouge">optional</code> can hold a value of the specified type, or, similarly to a pointer, a null value (<codeclass="language-plaintext highlighter-rouge">std::nullopt</code>). See <codeclass="language-plaintext highlighter-rouge">student/meshedit.cpp</code> for specific examples.</p><p>Also, remember that in any case, <em>the program should not crash!</em> So for instance, you should never return a pointer to an element that was deleted.</p><p>See the <ahref="/Scotty3D/guide/model">User Guide</a> for demonstrations of each local operation.</p><ul><li><codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::flip_edge</code> - should return the edge that was flipped</li></ul><p><imgsrc="flip_edge.svg"alt=""/></p><ul><li><codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::split_edge</code> - should return the inserted vertex</li></ul><p><imgsrc="split_edge.svg"alt=""/></p><ul><li><codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::collapse_edge</code> - should return the new vertex, corresponding to the collapsed edge</li></ul><p><imgsrc="collapse_edge.svg"alt=""/></p><ul><li><codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::collapse_face</code> - should return the new vertex, corresponding to the collapsed face</li></ul><p><imgsrc="collapse_face.svg"alt=""/></p><ul><li><codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::erase_vertex</code> - should return the new face, corresponding to the faces originally containing the vertex</li></ul><p><imgsrc="erase_vertex.svg"alt=""/></p><ul><li><codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::erase_edge</code> - should return the new face, corresponding to the faces originally containing the edge</li></ul><p><imgsrc="erase_edge.svg"alt=""/></p><ul><li><codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::bevel_vertex</code> - should return the new face, corresponding to the beveled vertex</li></ul><p><imgsrc="bevel_vertex.svg"alt=""/></p><ul><li><codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::bevel_edge</code> - should return the new face, corresponding to the beveled edge</li></ul><p><imgsrc="bevel_edge.svg"alt=""/></p><ul><li><codeclass="language-plaintext highlighter-rouge">Halfedge_Mesh::bevel_face</code> - should return the new, inset face</li></ul><p><imgsrc="bevel_face.svg"alt=""/></p></div></div><divclass="search-overlay"></div></div></body></html>
<!DOCTYPE html><htmllang="en-US"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=Edge"><title>(Task 3) BVH - </title><linkrel="shortcut icon"href="/favicon.ico"type="image/x-icon"><linkrel="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><metaname="viewport"content="width=device-width, initial-scale=1"><!-- Begin Jekyll SEO tag v2.7.1 --><title>(Task 3) BVH</title><metaname="generator"content="Jekyll v4.2.0"/><metaproperty="og:title"content="(Task 3) BVH"/><metaproperty="og:locale"content="en_US"/><metaname="twitter:card"content="summary"/><metaproperty="twitter:title"content="(Task 3) BVH"/><script type="application/ld+json">{"headline":"(Task 3) BVH","@type":"WebPage","url":"/pathtracer/bounding_volume_hierarchy","@context":"https://schema.org"}</script><!-- End Jekyll SEO tag --></head><body><svgxmlns="http://www.w3.org/2000/svg"style="display: none;"><symbolid="svg-link"viewBox="0 0 24 24"><title>Link</title><svgxmlns="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"><pathd="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><pathd="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><symbolid="svg-search"viewBox="0 0 24 24"><title>Search</title><svgxmlns="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"><circlecx="11"cy="11"r="8"></circle><linex1="21"y1="21"x2="16.65"y2="16.65"></line></svg></symbol><symbolid="svg-menu"viewBox="0 0 24 24"><title>Menu</title><svgxmlns="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"><linex1="3"y1="12"x2="21"y2="12"></line><linex1="3"y1="6"x2="21"y2="6"></line><linex1="3"y1="18"x2="21"y2="18"></line></svg></symbol><symbolid="svg-arrow-right"viewBox="0 0 24 24"><title>Expand</title><svgxmlns="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"><polylinepoints="9 18 15 12 9 6"></polyline></svg></symbol><symbolid="svg-doc"viewBox="0 0 24 24"><title>Document</title><svgxmlns="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"><pathd="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polylinepoints="13 2 13 9 20 9"></polyline></svg></symbol></svg><divclass="side-bar"><divclass="site-header"><ahref="/"class="site-title lh-tight"></a><ahref="#"id="menu-button"class="site-button"><svgviewBox="0 0 24 24"class="icon"><usexlink:href="#svg-menu"></use></svg></a></div><navrole="navigation"aria-label="Main"id="site-nav"class="site-nav"><ulclass="nav-list"><liclass="nav-list-item"><ahref="/"class="nav-list-link">Home</a></li><liclass="nav-list-item"><ahref="/git/"class="nav-list-link">GitHub Setup</a></li><liclass="nav-list-item"><ahref="/build/"class="nav-list-link">Building Scotty3D</a></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/guide/"class="nav-list-link">User Guide</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/guide/animate_mode/"class="nav-list-link">Animate</a></li><liclass="nav-list-item "><ahref="/guide/layout_mode/"class="nav-list-link">Layout</a></li><liclass="nav-list-item "><ahref="/guide/model_mode/"class="nav-list-link">Model</a></li><liclass="nav-list-item "><ahref="/guide/render_mode/"class="nav-list-link">Render</a></li><liclass="nav-list-item "><ahref="/guide/rigging_mode/"class="nav-list-link">Rig</a></li><liclass="nav-list-item "><ahref="/guide/simulate_mode/"class="nav-list-link">Simulate</a></li></ul></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/"class="nav-list-link">A2: MeshEdit</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/meshedit/halfedge"class="nav-list-link">Halfedge Mesh</a></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/local/"class="nav-list-link">Local Operations</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/meshedit/local/edge_flip"class="nav-list-link">Edge Flip Tutorial</a></li><liclass="nav-list-item "><ahref="/meshedit/local/bevel/"class="nav-list-link">Bevelling</a></li></ul></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/meshedit/global/"class="nav-list-link">Global Operations</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/meshedit/global/catmull/"class="nav-list-link">Catmull-Clark Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/remesh/"class="nav-list-link">Isotropic Remeshing</a></li><liclass="nav-list-item "><ahref="/meshedit/global/linear/"class="nav-list-link">Linear Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/loop/"class="nav-list-link">Loop Subdivision</a></li><liclass="nav-list-item "><ahref="/meshedit/global/simplify/"class="nav-list-link">Simplification</a></li><liclass="nav-list-item "><ahref="/meshedit/global/triangulate/"class="nav-list-link">Triangulation</a></li></ul></li></ul></li><liclass="nav-list-item active"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/"class="nav-list-link">A3: Pathtracer</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/pathtracer/camera_rays"class="nav-list-link">(Task 1) Camera Rays</a></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/intersecting_objects"class="nav-list-link">(Task 2) Intersections</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/ray_triangle_intersection"class="nav-list-link">Ray Triangle Intersection</a></li><liclass="nav-list-item "><ahref="/pathtracer/ray_sphere_intersection"class="nav-list-link">Ray Sphere Intersection</a></li></ul></li><liclass="nav-list-item active"><ahref="/pathtracer/bounding_volume_hierarchy"class="nav-list-link active">(Task 3) BVH</a></li><liclass="nav-list-item "><ahref="/pathtracer/shadow_rays"class="nav-list-link">(Task 4) Shadow Rays</a></li><liclass="nav-list-item "><ahref="/pathtracer/path_tracing"class="nav-list-link">(Task 5) Path Tracing</a></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/materials"class="nav-list-link">(Task 6) Materials</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/dielectrics_and_transmission"class="nav-list-link">Dielectrics and Transmission</a></li></ul></li><liclass="nav-list-item "><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/pathtracer/environment_lighting"class="nav-list-link">(Task 7) Environment Lighting</a><ulclass="nav-list"><liclass="nav-list-item "><ahref="/pathtracer/importance_sampling"class="nav-list-link">Environment Light Importance Sampling</a></li></ul></li><liclass="nav-list-item "><ahref="/pathtracer/visualization_of_normals"class="nav-list-link">Visualization of normals</a></li></ul></li><liclass="nav-list-item"><ahref="#"class="nav-list-expander"><svgviewBox="0 0 24 24"><usexlink:href="#svg-arrow-right"></use></svg></a><ahref="/animation/"class="nav-list-link">A4: Animation</a><ulclass="nav-list "><liclass="nav-list-item "><ahref="/animation/splines"class="nav-list-link">Splines</a></li><liclass="nav-list-item "><ahref="/animation/skeleton_kinematics"class="nav-list-link">Skeleton Kinematics</a></li><liclass="nav-list-item "><ahref="/animation/skinning"class="nav-list-link">Skinning</a></li><liclass="nav-list-item "><ahref="/animation/particles"class="nav-list-link">Particles</a></li></ul></li></ul></nav><footerclass="site-footer"> This site uses <ahref="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer></div><divclass="main"id="top"><divid="main-header"class="main-header"><divclass="search"><divclass="search-input-wrap"><inputtype="text"id="search-input"class="search-input"tabindex="0"placeholder="Search "aria-label="Search "autocomplete="off"><labelfor="search-input"class="search-label"><svgviewBox="0 0 24 24"class="search-icon"><usexlink:href="#svg-search"></use></svg></label></div><divid="search-results"class="search-results"></div></div></div><divid="main-content-wrap"class="main-content-wrap"><navaria-label="Breadcrumb"class="breadcrumb-nav"><olclass="breadcrumb-nav-list"><liclass="breadcrumb-nav-list-item"><ahref="/pathtracer/">A3: Pathtracer</a></li><liclass="breadcrumb-nav-list-item"><span>(Task 3) BVH</span></li></ol></nav><divid="main-content"class="main-content"role="main"><h1id="task-3-bounding-volume-hierarchy"><ahref="#task-3-bounding-volume-hierarchy"class="anchor-heading"aria-labelledby="task-3-bounding-volume-hierarchy"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> (Task 3) Bounding Volume Hierarchy </h1><p>In this task you will implement a bounding volume hierarchy that accelerates ray-scene intersection. Most of this work will be in <codeclass="language-plaintext highlighter-rouge">student/bvh.inl</code>. Note that this file has an unusual extension (<codeclass="language-plaintext highlighter-rouge">.inl</code> = inline) because it is an implementation file for a template class. This means <codeclass="language-plaintext highlighter-rouge">bvh.h</code> must <codeclass="language-plaintext highlighter-rouge">#include</code> it, so all code that sees <codeclass="language-plaintext highlighter-rouge">bvh.h</code> will also see <codeclass="language-plaintext highlighter-rouge">bvh.inl</code>.</p><p>First, take a look at the definition for our <codeclass="language-plaintext highlighter-rouge">BVH</code> in <codeclass="language-plaintext highlighter-rouge">rays/bvh.h</code>. We represent our BVH using a vector of <codeclass="language-plaintext highlighter-rouge">Node</code>s, <codeclass="language-plaintext highlighter-rouge">nodes</code>, as an implicit tree data structure in the same fashion as heaps that you probably have seen in some other courses. A <codeclass="language-plaintext highlighter-rouge">Node</code> has the following fields:</p><ul><li><codeclass="language-plaintext highlighter-rouge">BBox bbox</code>: the bounding box of the node (bounds all primitives in the subtree rooted by this node)</li><li><codeclass="language-plaintext highlighter-rouge">size_t start</code>: start index of primitives in the <codeclass="language-plaintext highlighter-rouge">BVH</code>’s primitive array</li><li><codeclass="language-plaintext highlighter-rouge">size_t size</code>: range of index in the primitive list (number of primitives in the subtree rooted by the node)</li><li><codeclass="language-plaintext highlighter-rouge">size_t l</code>: the index of the left child node</li><li><codeclass="language-plaintext highlighter-rouge">size_t r</code>: the index of the right child node</li></ul><p>The BVH class also maintains a vector of all primitives in the BVH. The fields start and size in the BVH <codeclass="language-plaintext highlighter-rouge">Node</code> refer the range of contained primitives in this array. The primitives in this array are not initially in any particular order, and you will need to <em>rearrange the order</em> as you build the BVH so that your BVH can accurately represent the spacial hierarchy.</p><p>The starter code constructs a valid BVH, but it is a trivial BVH with a single node containing all scene primitives. Once you are done with this task, you can check the box for BVH in the left bar under “Visualize” when you start render to visualize your BVH and see each levels.</p><p>Finally, note that the BVH visualizer will start drawing from <codeclass="language-plaintext highlighter-rouge">BVH::root_idx</code>, so be sure to set this to the proper index (probably 0 or <codeclass="language-plaintext highlighter-rouge">nodes.size() - 1</code>, depending on your implementation) when you build the BVH.</p><h2id="step-0-bounding-box-calculation"><ahref="#step-0-bounding-box-calculation"class="anchor-heading"aria-labelledby="step-0-bounding-box-calculation"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Step 0: Bounding Box Calculation </h2><p>Implement <codeclass="language-plaintext highlighter-rouge">BBox::hit</code> in <codeclass="language-plaintext highlighter-rouge">student/bbox.cpp</code>. Also if you haven’t already, implement <codeclass="language-plaintext highlighter-rouge">Triangle::bbox</code> in <codeclass="language-plaintext highlighter-rouge">student/tri_mesh.cpp</code> (<codeclass="language-plaintext highlighter-rouge">Triangle::bbox</code> should be fairly straightforward). We recommend checking out this <ahref="https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection">Scratchapixel article</a>.</p><h2id="step-1-bvh-construction"><ahref="#step-1-bvh-construction"class="anchor-heading"aria-labelledby="step-1-bvh-construction"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Step 1: BVH Construction </h2><p>Your job is to construct a <codeclass="language-plaintext highlighter-rouge">BVH</code> using the <ahref="http://15462.courses.cs.cmu.edu/fall2017/lecture/acceleratingqueries/slide_025">Surface Area Heuristic</a> discussed in class. Tree construction would occur when the BVH object is constructed. Below is the pseudocode by which your BVH construction procedure should generally follow (copied from lecture slides).</p><center><imgsrc="BVH_construction_pseudocode.png"/></center><h2id="step-2-ray-bvh-intersection"><ahref="#step-2-ray-bvh-intersection"class="anchor-heading"aria-labelledby="step-2-ray-bvh-intersection"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Step 2: Ray-BVH Intersection </h2><p>Implement the ray-BVH intersection routine <codeclass="language-plaintext highlighter-rouge">Trace BVH<Primitive>::hit(const Ray& ray)</code>. You may wish to consider the node visit order optimizations we discussed in class. Once complete, your renderer should be able to render all of the test scenes in a reasonable amount of time. <ahref="visualization_of_normals.md">Visualization of normals</a> may help with debugging.</p><center><imgsrc="ray_bvh_pseudocode.png"/></center><h2id="visualization"><ahref="#visualization"class="anchor-heading"aria-labelledby="visualization"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Visualization </h2><p>In Render mode, simply check the box for “BVH”, and you would be able to see the BVH you generated in task 3 when you <strong>start rendering</strong>. You can click on the horizontal bar to see each level of your BVH.</p><center><imgsrc="new_results/bvh_button.png"style="height:120px"/></center><h2id="sample-bvhs"><ahref="#sample-bvhs"class="anchor-heading"aria-labelledby="sample-bvhs"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Sample BVHs </h2><p>The BVH constructed for Spot the Cow on the 10th level.</p><center><imgsrc="new_results/bvh.png"style="height:320px"/></center><p>The BVH constructed for a scene composed of several cubes and spheres on the 0th and 1st levels.</p><center><imgsrc="new_results/l0.png"style="height:220px"/><imgsrc="new_results/l2.png"style="height:220px"/></center><p>The BVH constructed for the Stanford Bunny on the 10th level.</p><center><imgsrc="new_results/bvh_bunny_10.png"style="height:320px"/></center></div></div><divclass="search-overlay"></div></div></body></html>