Dev:2.4/Source/Modeling/Multires
目次
Overview
First, what multires is. Basically, multires allows you to go back to a previous level of subdivision. When you go back to the previous level, it's almost like a regular mesh (though with a few restrictions.) You can edit it in sculptmode or editmode, and when you switch back to the higher level of subdivision, your changes are copied and smoothed onto the high-res level. How is this different from regular Subsurf? Subsurf simply subdivides and smooths the mesh. Multires does this as well, but new details can be added to higher levels of subdivision.
If you've used ZBrush and know the multiresolution modeling tools, then you'll be right at home with multires.
Example
At the right is a very crude example of multires in action. Here's what each step is actually showing:
- A simple cube.
- The cube is subdivided by turning on multires and clicking Add Level. (Note that right now it looks just like the results of the Subsurf modifier.)
- The cube is subdivided four more times with Add Level.
- At the highest subdivision level (there are six of them at this point) sculptmode is activated and a hole is scooped out of the front of the mesh.
- Now we switch down to level five, and we can see the hole has been copied down to this level
- And now we switch down to level four, which has even fewer polygons, and the hole has been copied to this level as well.
- Now we go all the way back to level one, which is the base mesh. It was originally a cube and still looks more or less like a cube. So we go into editmode and pull the right side of it way over to stretch it out.
- Back at the highest level of subdivision (six) we can see the changes have been propagated all the way up, and the top level copies the new stretched form of the lowest level.
Structs
typedef struct MultiresFace {
unsigned int v[4];
unsigned int mid;
} MultiresFace;
typedef struct MultiresEdge {
unsigned int v[2];
unsigned int mid;
} MultiresEdge;
typedef struct MultiresLevel {
struct MultiresLevel *next, *prev;
MVert *verts;
MultiresFace *faces;
MultiresEdge *edges;
unsigned totvert, totface, totedge;
} MultiresLevel;
typedef struct Multires {
ListBase levels;
short level_count, current, newlvl, pad;
} Multires;
The struct Multires
data is stored per-mesh by adding a pointer named mr
to struct Mesh
. When NULL, multires is 'off' for that mesh.
Functions
multires_make()
void multires_make(void *ob, void *me);
Called when the user clicks the Make button next to the Multires label in the Mesh panel. This function initializes the Multires *mr
pointer in the Mesh struct. One level is created, containing an unmodified (though stored slightly differently) copy of the original mesh.
multires_delete()
void multires_delete(void *ob, void *me);
Called when the user clicks the Delete button next to the Multires label in the Mesh panel. Basically just a wrapper for multires_free().
multires_free()
void multires_free(Mesh *me);
Uses multires_free_level() to free all the levels, then frees me->mr itself, and sets it to NULL, which turns off multires.
multires_free_level()
void multires_free_level(MultiresLevel *lvl);
Frees all the data (verts, faces, etc.) in lvl, but doesn't actually free lvl itself.
multires_del_lower()
void multires_del_lower(void *ob, void *me);
Frees all the levels below the current level.
multires_del_higher()
void multires_del_higher(void *ob, void *me);
Frees all the levels above the current level.
multires_add_level()
void multires_add_level(void *ob, void *me);
Adds a new level to the levels list (regardless of what the current level is, the new one goes at the end.) The new level copies the entire previous level, and subdivides it using the Catmull-Clark algorithm. The results are almost exactly the same as the Subsurf modifier, except that my implementation has trouble at the edges of a mesh. multires_level_to_mesh() is called to make the new level visible to the user and to other Mesh tools.
multires_set_level()
void multires_set_level(void *ob, void *me);
Used to switch to a different (but already existing) level of subdivision. First, multires_update_levels() is called to propagate any changes that have been made on this level of subdivision to all the others, both higher and lower in the chain. multires_level_to_mesh() can then be called to actually make the level change visible to the user, and to the other Mesh tools.
multires_update_levels()
void multires_update_levels(Mesh *me);
This is the complicated heart of the Multires tool. It works by calculating deltas for each point, creating a displacement vector from the original location of each vertex to the final location of the vertex at the time the level is switched. Three things then occur:
- The vertices of the current level are updated to reflect the changes in the Mesh. This is a direct copy; though deltas are stored for this level's changes, they aren't used here.
- The vertices of all the higher levels are updated. This is done by applying the Catmull-Clark algorithm to the deltas of the surrounding vertices/face points/edge points.
- The vertices of all the lower levels are updated. This is a simple copy operation: starting from the second to last level, all of the vertices that will fit from the next level are copied down. (This works because each level stores vertices in the same order.)
multires_level_to_mesh()
void multires_level_to_mesh(Object *ob, Mesh *me);
Copies data from the current level of subdivision back into the rest of the Mesh struct. (MultiresLevel.verts into Mesh.mvert, etc.)