**Examples for Assignment 2** Transformations ======================================================================== Rotation ------------------------------------------------------------------------ `rotate( mesh, rotate )` Rotates a mesh ( or a selected part ) around an axis by number specified in the sliders. The unit used for rotation is radians. ![cube.obj rotateX 0.8](./example-images/rotate_1.png border="1") ![cube.obj (selection) rotateX 0.8 ](./example-images/rotate_2.png border="1") Warps ======================================================================== Twist ------------------------------------------------------------------------ `twist( mesh, factor )` Rotates all vertices `v` along the `Y` axis by `v.position.y * factor`. The units are again radians. ![large_cube.obj twist 1](./example-images/twist_1.png border="1") ![large_cube.obj twist 2](./example-images/twist_2.png border="1") Inflate ------------------------------------------------------------------------ `inflate( mesh, factor )` Moves all vertices in the direction of their respective vertex normals, proportional to a `factor`. For the cube, this operation will give a scaling effect. ![cube.obj inflate -1](./example-images/inflate_1.png border="1") ![cube.obj inflate 1](./example-images/inflate_2.png border="1") ![hand.obj inflate -0.1](./example-images/inflate_4.png border="1") ![hand.obj inflate 0.1](./example-images/inflate_3.png border="1") It is possible to augment this operation by `averageEdgeLength`. This will give nicer results for the inflated hand - the creases are better preserved, and the inflate operation is now aware of the mesh scale. ![cube.obj inflate -1](./example-images/inflate_factor_1.png border="1") ![cube.obj inflate 1](./example-images/inflate_factor_2.png border="1") ![hand.obj inflate -1](./example-images/inflate_factor_4.png border="1") ![hand.obj inflate 1](./example-images/inflate_factor_3.png border="1") Filters ======================================================================== Noise ------------------------------------------------------------------------ `Noise( mesh, factor )` Moves all vertices in the direction of their respective vertex normals, proportional to `mesh.averageEdgeLength(v) * factor * randomIn( -1, 1 )`. ![large_cube.obj noise 0.5](./example-images/noise_2.png border="1") ![large_cube.obj noise 1](./example-images/noise_1.png border="1") Uniform Laplacian Smoothing ------------------------------------------------------------------------ `smooth( mesh, iter, delta, curvFlow, scaleDep, implicit )` This operation needs to be applied `iter` number of times. For each iteration, each vertex should be moved towards the average of itself and its neighbors. In other words, for a vertex `V` with `N` neighbors, its updated position (`V_new`) should be `V_new = V + (sum(n_i)-N*V)*delta`, where `n_i` are the neighboring vertices. Be careful when updating the position. During a single iteration you want to use original positions throughout the entire computation. Update the actual positions of the vertices only after all new locations have been calculated. This uniform weighting scheme should be active if `curvFlow` is false. In this example, the weights are not normalized to sum to `1`, hence small deltas should be used, as can be seen in the images below. ![cheetah.obj i=1 d=1](./example-images/cheeta_1_1_fff.png border="1") ![cheetah.obj i=36 d=0.15](./example-images/cheeta_36_015_fff.png border="1") ![cheetah.obj i=3000 d=0.01](./example-images/cheeta_3000_001_fff.png border="1") ![sphere2res.obj (with halfedges visualized) i=35 d=0.15](./example-images/sphere2res_36_015_fff.png border="1") Curvature-flow Laplacian Smoothing ------------------------------------------------------------------------ `smooth( mesh, iter, delta, curvFlow, scaleDep, implicit )` The same as uniform sampling, but with a different weighting scheme, which can be applied only to triangles. In this case, the update rule is `V_new = V + (sum(w_i * n_i) - sum(w_i)*V)*delta`, where the weights `w_i` are the cotangent weights explained in the slides. Use when `curvFlow` is true. As can be seen (especially in the cut between the two resolutions of the sphere example), this scheme preserves triangle shapes well, and thus preserves features better, but it is still sensitive to triangle sizes. Note that this scheme is even more sesitive to `delta` values then the uniform one. Also note that this scheme is sensitive to long and thin triangles. To overcome this problem on bad meshes, either add checks in the code, or run a few uniform iterations before using this scheme, as was used in the hand example. ![cheetah.obj i=30 d=0.4](./example-images/cheeta_30_02_tff.png border="1") ![cheetah.obj i=3000 d=0.02](./example-images/cheeta_3000_001_tff.png border="1") ![hand.obj i=10 d=0.02 (uniform) i=100 d=0.04 (cotan)](./example-images/hand_10_002_fff_100_002_tff.png border="1") ![sphere2res.obj (with halfedges visualized) i=35 d=0.3](./example-images/sphere2res_36_015_tff.png border="1") Scale-Dependent Smoothing ------------------------------------------------------------------------ `smooth( mesh, iter, delta, curvFlow, scaleDep, implicit )` No matter the weighting scheme, when `scaleDep` is true you should multiply the vertex offset (or matrix row) by the *scale dependent* term. That is,the update rule is `V_new = V + M*(sum(w_i * n_i) - sum(w_i)*V)*delta`, where M is `average(A_v)/A_v' (average of the 1ring area of all vertices over the 1ring of `V`: the sum of areas of the faces adjacent to it). For convenience, you may want to scale the mesh to its original size after each iteration (could be done by keepying the bounding box diagonal to be the same length). ![cheetah.obj i=300 d=0.01 (uniform)](./example-images/cheeta_300_001_ftf.png border="1") ![cheetah.obj i=300 d=0.02 (cotan)](./example-images/cheeta_300_001_ttf.png border="1") ![sphere2res.obj (with halfedges visualized)i=1000 d=0.01 (uniform)](./example-images/sphere2res_1000_001_ftf.png border="1") ![sphere2res.obj (with halfedges visualized) i=1000 d=0.02 (cotan)](./example-images/sphere2res_1000_001_ttf.png border="1") Implicit Smoothing ------------------------------------------------------------------------ `smooth( mesh, iter, delta, curvFlow, scaleDep, implicit )` Regardless of the choice of the actual Laplacian, if `implicit` is true, you should formulate the previous computations in a matricial form and solve the linear system 'V = V_new - M*L*delta*V_new'. For further reading refer to [this paper](http://w.multires.caltech.edu/pubs/ImplicitFairing.pdf). An implicit solution is completely robust to `delta` sizes, so you typically don't need more than one iteration. Use the `.lup()` method of 'math.js' to decompose the matrix, and reuse the decomposition 3 times, to solve for the `x`, `y` and `z` axes. Note that the decomposition is slow, so you may want to stick to low vertex-count meshes such as `hand-simple`, `teapot` and `cheetah'. Using better optimized packages (or languages) would render this operation immediate. ![cheetah.obj i=1 d=30 (uniform, scale-dependent)](./example-images/chheta_1_30_ftt.png border="1") ![cheetah.obj i=1 d=30 (cotan, scale-dependent)](./example-images/cheeta_1_30_ttt.png border="1") ![hand-simple.obj i=1 d=30 (uniform, scale-dependent)](./example-images/handSimple_1_30_ftt.png border="1") ![hand-simple.obj i=1 d=30 (cotan, not scale-dependent)](./example-images/handSimple_1_30_tft.png border="1") Sharpen ------------------------------------------------------------------------ `sharpen( mesh, iter, delta )` This operation needs to be applied `iter` number of times, similarly to Uniform Laplacian Smoothing. It is the exact same behavior, only in the opposite direction. Note that this operation is very sesitive to `delta` values. ![cheetah.obj i=5 d=0.04](./example-images/cheeta_5_-004.png border="1") ![cheetah.obj i=5 d=0.02](./example-images/cheeta_5_-002.png border="1") ![cheetah.obj i=12 d=0.02](./example-images/cheeta_12_-002.png border="1") Curvature ------------------------------------------------------------------------ `curvature( mesh )` Depending on your choice of visualization, your results might vary greatly from this. However for the cheetah, what you should be seeing is high curvature values (bright yellow in our visualization) in places like the claws, nostrils or ears, and low curvature values (blue in our visualization) around the claws. This is due to the fact that Gaussian curvature is defined as product of principal curvatures. Your final colors will vary depending on what method you use to map the curvature to a suitable range for the colors. Notice that for the cube, all the vertices have the same value so they are all mapped to mid gray. ![cube.obj curvature](./example-images/curvature_1.png border="1") ![cheetah.obj curvature](./example-images/curvature_2.png border="1") ![cow.obj curvature](./example-images/curvature_3.png border="1") Topology ======================================================================== Truncate ------------------------------------------------------------------------ `truncate( mesh, factor )` Creates an effect where each vertex is "cut off". It is possible to accomplish this using the `splitEdge()` and `splitFace()` functions. Topologically we are only adding vertices, so there is no need to remove any vertices. Think about the necessary topological and geometrical changes. ![cube.obj truncate 0.2](./example-images/truncate_1.png border="1") ![cube.obj truncate 0.4](./example-images/truncate_2.png border="1") ![cube.obj (selected) truncate 0.4](./example-images/truncate_3.png border="1") Extrude ------------------------------------------------------------------------ `extrude( mesh, factor )` The vertices of each face should be duplicated and moved along the normal of the face. The original face should be attached to the duplicated vertices. The set of original vertices and duplicated vertices should be connected together by new faces. This feature requires you to modify the half edge data structure by using the `splitFaceMakeEdge(...)`, `joinEdgeKillVertex( v1, v2, v3 )`, and `splitEdgeMakeVertex( v1, v2, f )` functions. Make sure you familiarize yourself with these functions before starting to code this one! ![cube.obj extrude 1](./example-images/extrude_1.png border="1") ![cube.obj (selected) extrude 1](./example-images/extrude_2.png border="1") Split Long Edges ------------------------------------------------------------------------ `splitLong( mesh, factor )` Splits the longest edge in the mesh. Depending on the choice of which vertices you selected to connect to a newly created one, you can obtain different results. Notice that as you go through the iterations one of the newly added edges might be the longest one. ![cube.obj splitLong 0.1](./example-images/split_long_1 border="1") ![cube.obj splitLong 0.5](./example-images/split_long_2 border="1") ![cube.obj splitLong 1.0](./example-images/split_long_3 border="1") Triangle Topology ------------------------------------------------------------------------ `triSubdiv( mesh, levels )` Splits each face into triangles. This effect is applied `levels` number of times. The mesh should be triangulated before using this function. ![tetrahedron.obj triSubdiv 1](./example-images/triangle_1 border="1") ![tetrahedron.obj triSubdiv 3](./example-images/triangle_2 border="1") Subdivision ======================================================================== Loop Subdivision ------------------------------------------------------------------------ `loop( mesh, levels )` Splits each face into triangles. This effect is applied `levels` number of times. The mesh should be triangulated before using this function. In the example images, we have used Warren weights. ![tetrahedron.obj triSubdiv 1](./example-images/loop_2 border="1") ![tetrahedron.obj triSubdiv 3](./example-images/loop_3 border="1") ![cheetah.obj triSubdiv 1](./example-images/loop_7 border="1") ![cheetah.obj triSubdiv 3](./example-images/loop_8 border="1") ![tetrahedron.obj triSubdiv 1](./example-images/loop_1 border="1") ![tetrahedron.obj triSubdiv 3](./example-images/loop_4 border="1") ![cheetah.obj triSubdiv 1](./example-images/loop_5 border="1") ![cheetah.obj triSubdiv 3](./example-images/loop_6 border="1") Quad Topology ------------------------------------------------------------------------ `quadSubdiv( mesh, levels )` Splits each face into quads. This effect is applied `levels` number of times. ![cube.obj quadSubdiv 1](./example-images/quad_subdivide_1.png border="1") ![cube.obj quadSubdiv 2](./example-images/quad_subdivide_2.png border="1") ![cube.obj quadSubdiv 3](./example-images/quad_subdivide_3.png border="1") ![cube.obj (selected) quadSubdiv 1](./example-images/quad_subdivide_4.png border="1") ![cube.obj (selected) quadSubdiv 2](./example-images/quad_subdivide_5.png border="1") ![cube.obj (selected) quadSubdiv 3](./example-images/quad_subdivide_6.png border="1") Catmull-Clark Subdivision ------------------------------------------------------------------------ `catmullClark( mesh, levels )` Splits each face into quads. This effect is applied `levels` number of times. Users update the rules as described in the lecture and precept slides. The order in which you should apply the geometrical changes is: modify the positions of the new edge midpoints, modify the positions of the newly created face centroids, modify the positions of the old vertices. *Tip*: When calculating the locations for the edge midpoints, take the average of the vertices' positions of that edge, and the average of centroids of adjacent faces. ![cube.obj catmullClark 1](./example-images/cc_1.png border="1") ![cube.obj catmullClark 2](./example-images/cc_3.png border="1") ![cube.obj catmullClark 3](./example-images/cc_5.png border="1") ![dodacahedron.obj catmullClark 1](./example-images/cc_7.png border="1") ![dodacahedron.obj catmullClark 2](./example-images/cc_9.png border="1") ![dodacahedron.obj catmullClark 3](./example-images/cc_11.png border="1") ![cube.obj catmullClark 1](./example-images/cc_2.png border="1") ![cube.obj catmullClark 2](./example-images/cc_4.png border="1") ![cube.obj catmullClark 3](./example-images/cc_6.png border="1") ![dodacahedron.obj catmullClark 1](./example-images/cc_8.png border="1") ![dodacahedron.obj catmullClark 2](./example-images/cc_10.png border="1") ![dodacahedron.obj catmullClark 3](./example-images/cc_12.png border="1")