|
This article deals with the process of unwrapping polymeshes and mapping textures on the resulting flat mesh pieces.
How does it work
The purpose of the process is to map a texture onto a polymesh surface. This process is called 'UV' mapping, because every coordinate of the mesh surface corresponds to a (U,V) coordinate on the texture (for simplification purposes we will consider the texture is an image). There are two ways UV mapping can be achieved. The first way is to have each mesh vertex correspond to a location on the texture. This is simple, yet it does not work as intended. If you wrap an image around a mesh, at some locations the edges of the picture will meet. Or, said differently, if you wrap an image around a closed volume you have to "sew" the edges of the image so it can effectively wrap around the volume. This means that a vertex that lies on a a seam may have different (U,V) values depending on the side of the seam. So the most general way of UV mapping a mesh is to consider a UV mapping of vertices on a per face basis. A vertex can have different UV coordinates depending on the face being considered: there are as many as UV coordinates as the number of faces the vertex share.
Seams
Seams are not only a way to have the texture wrap around the mesh, it is also a necessary step in obtaining a flattened mesh (at least for closed meshes). Think of a sphere, for example the earth. To obtain a map of the earth, one has to cut the surface, unwrap the surface and then flatten it. There are different projection methods for obtaining the flat earth map. However, there are also different cutting schemes. The more you cut the surface, the easier it is to flatten. Here, easier means with less distortion. Since most of the time it's not possible to flatten a mesh surface, flattened meshes only approximate the original mesh. An extreme statement is that if you cut a triangle mesh down to every single triangle, then the resulting mesh pieces are distortion free because a triangle is flat. On the other hand, the set of scattered single triangles will be difficult and tedious to map. So the name of the game is to place seams so that you end up with a minimal number of separate mesh pieces, yet with as low a distortion as possible.
Seams are necessarily placed along mesh edges. To specify seams, select the edges you want to specify as seams and select the menu command: Texture ->Mark as Seams. You can also use all the seams editing commands to add or remove seams to the current seams list. Once the seams are marked and you think the seaml design is ok, then you can proceed to mesh unfolding. Do not open seams: the unfold command will take care of that. Open Seams command is here just to give you the possibility to manually open the mesh if need be.
On to unfolding and mapping
The
first step towards successful mesh unfolding is to decide if you need
seams and where to place them. Seams are special edges along which
the mesh will be opened prior to unfolding (or flattening). Unfolding
a mesh which has been opened using seams can result in several
separate mesh pieces. Ultimately, if every edge is designated as a
seam, then the mesh is unfolded as a collection of individual faces.
Where as this situtation is very accurate (no mesh distortion
occurs), it is very impractical to paint a texture for such a set of
scattered mesh pieces. Indeed, each time you set a seam, you'll most
likely create a texture discontinuity along the seam because the
faces will be set aside in the mesh pieces layout. In few situations,
you'll be able to match the texture on each side of the seam, but
generally the seam will be visible. It is thus a good practice to
place seams where they won't be visible or at least noticeable.
Luckily, these places generally coincide with high mesh curvature
-places where the mesh folding is high, like sharp corners-. Placing
seams over such edges also relieve the strain on the unfolding
process and minimize mesh distortion upon unfolding. How many pieces
you want to consider to unfold a mesh is up to you (and the texturing
you want to set). However, obviously closed meshes can't be unfolded
without seams and the editor won't let you unfold a closed mesh
without seams.
Be
aware that any editing operation that changes the mesh topology
-adding or deleting vertices, edges, or faces- will send seams
assignment to oblivion. This will change in the future, but for now
seams and mesh unfolding are operations that areintended on a
finalized mesh. Otherwise, prepare to start over again after the mesh
has been edited.
Assigning
seams is carried out through edge selection and then using the Mark
Selection as Seams command. The process can be tedious, although some
commands are here to help (Add Selection to Seams, etc.). In the
future, helper commands will make it possible to make semi automatic
seams assignment. However, you'll to set every seam by hand for now.
Let's
practise a bit and set seams necessary to unfold a cube. 7 seams are
need to unfold the cube to a cross shape as shown below. Create a
cube and select the seven seams shown in the image. Select the Mesh
-> Mark Selection as Seams from the « Edge »
menu and have a look at the selected edges: they're now colored in
blue. Selected seams show up in light blue whereas they're colored
plain blue when they're unselected.
Before
we unfold the mesh, we will setup a UV mapped texture. Create a
procedural 2D texture and plug a chessboard module into a default
custom color map. Add a linear transformation to the chessboard
module for a reasonable scale over UV space. Here are the settings
used for this quick example.
Next,
texture the polymesh cube using this texture. Specify a UV mapping
and edit the mapping. In the editor window, check the « Map
Each Face Independantly » option (see below). This is a
very important step. Default UV mapping let's you place vertices over
a 2D texture. Such a mapping is limited to meshes akin to a sheet of
paper or, said differently, meshes which don't need seams to be
unfold. For other meshes, opening a seam means that vertices places
the seam will be duplicated in the resulting unfolded mesh. They will
appear twice on the mesh, or even more, depending on the number of
seams they happen to be on. So since a vertex of the original mesh
has several positions on the UV layout, it must be referred by the
face which bears the vertex. There is only one position for a given
vertex of a given face. This is why this mapping is called « per
face per vertex ». This mode is activated when selected
the « Map each face independantly » option. The
PolyMesh editor only works with this type of mapping, although it is
not technically necesssary for « sheet-like »
meshes.
It's
now time to unfold the mesh. Select the Texture->Unfold Mesh
commadnd. A dialog will appear, waiting for you to click on the
« Proceed » button. The fact that the unfolding
process doesn't start at once gives you the opportunity to change
parameters like the unfolding residual to satisfy. This is a rather
advanced setting, this is why it is hidden unless you click the
'Advanced' button. For now, just click on the « Proceed »
button. Text fills up the text area, saying:
« Initial
residual: 0.0
Target
residual: 0.001 »
In
fact, since unfolding the mesh yields an exact result, the unfolding
process doesn't even have to minimize mesh distortion and stretch.
Validate and the window below appears.
The
left part of the window contains some information and settings. The
UV range displayed is specified at the top. Pressing the Auto button will reset the view so that mesh pieces fit the available space. It is handy when you've been scaling up or down a lot and the meshes are out of range. Next, the current mapping
shown is displayed in a drop down list. Its name is « Mapping
#1 », but you can change that easily using Mapping ->
Rename Mapping. You can define as many mappings as you want for a
mesh. Each mapping will have its own set of vertices positions.
Beware: this means that each mapping uses as much memory as is needed
to store these positions. If the mesh is really big, this can be
something to keep in mind. Of course, only one mapping can be applied
to a texture at a time. However, such an option can be handy if you
want to setup a new mapping but also keep the old one in case the new
one doesn't turn up as good.
The Texture drop down list allows to select the current texture. This
doesn't make much sense for a single texture as is the case here, but
if you specify a layered texture with several UV mapped textures
they'll be listed here. In this case, each single texture can be
assigned a mapping, hence the reason for being able to have different
mappings.
Finally,
the Component drop-down list allows to select the component of the
texture currently displayed. All components of the same texture must
share the same mapping.
If
no UV mapped texture with per face per vertex setting is used for
texturing the unfolded mesh, then these drop-down list will be
disabled and a white background is shown. This is intended for
setting up a mesh pieces layout and export it as a BMP image. We'll
discuss that later on.
At the bottom left part of the window, mesh tension settings can be used to apply a mesh tension while editing a mesh piece. These settings are identical to their 3D counterparts, so we won't discuss that here.
The
middle of the window shows the currently selected texture with the
unfolded mesh pieces on top of it. In this example, the cube mesh is
still in one piece. The right of the window displays a list listing
all pieces of the unfolded mesh. The currently selected piece is said
to be the active piece. Only the active piece is affected by editing
operations, the other ones are greyed out. There can only be one
active piece at a given time. Pieces can be renamed using the
Edit->Rename Selected Piece command. Below the pieces list, a
preview of the texture mapping on the mesh is shown. Furthermore,
selected vertices on the unfolded mesh show up a red spheres on the
preview (provided you enabled the Preferences -> Show Vertex
Selection on Preview option). If the mesh is smoothed, then original
positions show up: this explains why they are displayed off the mesh
surface. For a better preview response, use the raster renderer for
texture previews (set this option in AoI main preferences).
For
the moment, we need to arrange the mapping so that the chessboard
texture fits on the cube, which is not quite the case with the
default layout. Select all mesh vertices (or use the Select All
command) and move the mesh so that a vertex (you may choose any one)
fits on the chessboard texture. Then, move the manipulator position
to this vertex using Ctrl-click-drag on manipulator center. The
manipulator will now be anchored on this vertex until the selection
is discarded clicking anywhere in the mapping edition area. You can
then make the mesh fit on the texture by scaling the mesh using the
scale handles.
Tips
:
-The
edges are displayed using a bold stroke so that they can be easily
distinguished from the background. You can disable this option using
Preferences->Bold Edges. You can also change the color of edges so
they do not mix with the background texture. Use the Mapping ->
Change Edge Color command. Edge color settings are persistent and
each mapping can be assigned its own color.
-The
UV map can be scaled and panned around using the same mouse shortcuts
as AoI 3D views. If you scale up/down, make sure to have a correct
sampling setting so that texture map refreshment is fast enough.
-If you use shift-right click and ctrl-shift right click, you'll moe/rescale the whole set of pieces at once rather than moving/scaling the view. This feature is specific to the UV manipulator.
You should move and scale the mesh so that the following layout is achieved (edges are printed in red so they stand out against the chessboard background). If edges are laid out carefully, then a seamless texturing is achieved. This is almost the case for the picture shown on the right (the cube has been set to approximate smoothing), although a tiny discrepancy can be seen.
Giving Lisko the lizzard a skin...
Thanks to this simple model provided by Peteihis, we can work on a more realistic case. Here is our friend Lisko the lizzard, who, as you can see, is in great need of a skin.
Here you can have a glimpse of the seams use for mapping Lisko. We assume its belly is of a different type than the rest of his body, so we place seams at the boundary.
As before we select the unfold command and come up with the following layout :
The first thing to do is to fit the texture to an image mapped texture size. The default range, which spans over 9 U and V unit is far too large (image mapped textures span over ranges [0..1] both for U and V). To do so, use the Mapping->Fit Mapping to Image Texture Size command. Next, organize the mesh pieces so that they look like the screenshot below.
Next select the Edit->Export Image command and export this mapping (choose any size you like, but I recommend you export a square image). Use your creative skills to paint a nice skin for Lisko. Quit the polymesh editor (click OK to save your work) and create an Image mapped texture using the image you painted over the unfolded mesh. As before, make sure to check the "Map each face independantly" option. Now, edit the mesh again and choose the Texture -> Edit mapping command. You can tweak the mesh vertices positions so it best fits the image. Here is how it looks like with our image mapped texture (quickly pulled together by Peteihis) :
But let's have a look at the preview... Hey, it looks like Lisko now has a skin! That's certainly very good news for him. But we certainly haven't finished with him. It happens that Lisko belongs to a special specie akin to the chameleons. As such, his skin takes the color of its environment, except his belly which is rarely in sight. And it recently happened that Lisko wandered on a picnic area where a a table cloth had been laid on the ground. Now we have to give Lisko's body the texture of the table cloth whereas his belly keeps the image mapped texture...
Lisko on a table cloth
Let's get back to our chessboard texture and modify it so the black squares are red. We'll densify the motif by using a scale of 10.0 instead of two in the linear transform. The trick will be to have the texture overlayed on top of the image mapped texture and transparent parts will let the image mapped texture show through. Let's have the U negative, V negative domain show and everything else transparent using the logic as shown in the screenshot below.
Ooops, sorry it's in french. But I guess it's pretty easy to understand. Now, let's compose a layered texture using these two textures. Put the chessboard texture on top of the image mapped texture. Use Overlay to compose the two textures, not the default blending. Make sure to select UV mapping as mapping mathod for each texture. Edit mappings to check the "Map each face independantly" option. The layered texture setup should look like the figure below.
Edit the PolyMesh again. This time, two textures show in the textures dropdown list. The chessboard texture being transparent in the [0..1,0..1] region, you can't see it unless you zoom out. What we could do is keep a single mapping and translate the body mesh piece (piece 1) to the chessboard area, leaving piece 2 (the belly) on the image mapped texture. That would work. But we're going to play smart. Create another mapping, a simple way being the duplication of the current mapping (Mapping -> Duplicate Mapping). Then come back to Mapping #1 (the first mapping) and select the chessboard texture. Assign this texture to the second mapping using the Mapping -> Mapping to Use for Texture menu (select Mapping #2 submenu menu item). Now we have a mapping per texture rather than have the two textures share the same mapping. For each mapping, the view should like like the images below.

Have a look at the preview : one mesh piece (the belly) is textured using the image mapped texture whereas th body is textured using a procedural texture. So, will you ask, what's the advantage of having to separate mappings? Well, this will become clear in the next section where our poor Lisko is ill and has fever...
Lisko has fever
...and when Lisko has fever his color skin cells don't work well. Practically, this means that he can't blend into the background : patches of its original green skin will show. To achieve this effect, we will put some transparency in the non transparent part of the chessboard texture using the Turbulence motif. This is not as trivial as it seems, so do it as a Procedural homework. Caution : when you modify a texture which belongs to a layered texture, you'll have to assign it again to the relevant mapping when opening the UV mapping editor afterwards. Here's how the procedural texture looks like (the Turbulence pattern has an amplitude of 6) :
And finally, here is our sick Lisko with patches of green skin showing through the table cloth pattern. To be totally honest, it is possible to achieve the same result using a single mapping. But it calls for a tricky overlay of the two textures which is probably very tedious, whereas using two mappings is a lot more simple...
Advanced Settings : Note for Techies
It's highly unlikely you'll need to resort to the advanced settings, i.e. manually setting a residual. However, for those of you who are interested, here's the full story.
Mesh unfolding is carried out using the ABF++ (Angle Based Fitting) algorithm as published by SHEFFER, LEVY MOGILNITSKY aand BOGOMYAKOV (you should have no difficulty googling the reference. Beware, though, the preprint available on the net misses the reconstruction part. So make sure to get the real article from ACM or manage to get this one). The principle of this algorithm is as follows:
- Compute the angles between each consecutive edge of mesh faces (triangles).
- Find the set of angles that are closest to the 3D mesh angles and represent a flat mesh. The fact that the new set of angles must describe a flat mesh generates constraints like the sum of angles over a triangular face must be equal to PI.
- Express a smart way to compute the new set of angles using the angles of the 3D mesh as starting variables. Basically you can't compute the target set of angles in one go. You compute a set of angles from the starting parameters, then refine this set of angles using them as the new starting set of parameters. The closeness to a flat mesh is expressed in the form of a residual. The lower the residual, the closest the angles are to a flat mesh while still being as cloase as possible to the original set of angles as yielded by the 3D mesh.
Since each cyle (iteration) takes time, the question is: how low the residual must be? To answer this question, we need to explain how the 2D mesh vertices are reconstructed from the angle set. Yes, unfortunately, it's not because we have the set of angles describing the 2D flat mesh that we are done. What we want are vertex locations, not angles. To this end, we can proceed as you would do if you had to tile the floor or the walls of your bathroom (or any other room, for that matter). You lay a tile, then another tile next to it, then another one, etc. Here we start from an edge and give the same length as in the 3D mesh. Then, using the angular values, we compute the faces sharing this angle. From edge to edge, we generate faces. But just as with the bathroom example, problems arise when a lot of faces or tiles have to been laid down. Any small error in tile/face placement, like tilting, can lead to considerable problems faces/tiles later. Small discrepancies add up and ruin the mesh reconstruction (or the floor tiling).
So it seems we need precise angles, especially for big meshes. So we have to specify a quite low residual, but how low? We also have to consider the precision to which each iteration is computed. This will limit how well we can satisify the flat mesh constraint. And iterations take time, even more when the mesh is big (and that's when we need to be all the more precise concerning the flat mesh constraint). Oh dear, it seems we have a problem here.
The solution is to consider the whole set of vertex locations and say they must satisfy the set of angles computed using the ABF++ algorithm. We'll find the set of vertex locations that best match the set of angular values yielded by the ABF++ procedure. Yes, we're on to another minimization of yet another residual. But for those who knows, this is a linear problem, so the solution is exactly konwn in a cycle/iteration. Indeed it's equivalent to Linear Conformant Mapping (do not mistake it for Least Square Conformant Mapping).
But, hey, if we're looking for the vertex locations that best describe the angular values of the flat mesh, do we need precise angular values? The answer is: not that much. A rough guess will do. Actually we could apply this procedure using the starting set of angular values as computed from the 3D mesh and entirely skip the ABF++ step. The unfolding would then follow Linear Conformant Mapping and the result is expected to be not as good as when using ABF++. However, you can fall back on that one if ABF++ fails (not that I know situations where ABF++ would fail) or yields results you don't like. To bypass the ABF++ step, record the initial residual reported when unfolding the mesh. Then unfold the mesh again, this time specifiying a target residual greater than the initial residual you recorded. The ABF++ procedure will be skipped and 2D mesh reconstruction will be carried out considering the angular values as computed considering the 3D mesh.
Even if we need to resort to ABF++ for getting a good set of angular values that represent a low distortion 2D mesh, we don't need as low a residual as when we were reconstructing the 2D mesh from edge to edge. In fact, whereas a residual of 0.001 yields a good quality mesh, you can go as high as 1 and still obtain a 2D mesh that's close to what you'd have with a residual of 0.001 (according to the authors). For this reason, the residual is set to 1 for meshes over 1K faces and for which iterations take time. For meshes with a number of faces below 1,000, the computation time is low enough so you can reach a residual of 0.001 without having to wait unnecessarily.
To sum up what 's been said about residuals, here are the basic facts you have to know if you want to fiddle with the residual setting:
- Decreasing the residual will push the ABF++ algorithm further and thus minimize the distortion that may be brought by the 2D mesh reconstruction.
- Increasing the residual will minimize the effect of ABF++ algorithm (even bypass it if the residual is high enough) and the flattening will be carrried out using linear conformant mapping.
So if you happen to witness a bad behavior of the unfolding process, setting a high or low residual may help you identify the problem and come up with a better unfolding. For meshes with a high number of poly, maybe decreasing the default residual (1) can yield better results at the expense of longer computation times.
Only registered users can leave comments. Please login or register. Powered by AkoComment Tweaked Special Edition v.1.4 |