Beruflich Dokumente
Kultur Dokumente
Toddler Pregnancy Acne Aerobics & Cardio Alternative Medicine Beauty Tips Depression Diabetes Exercise & Fitness Hair Loss Medicine Meditation Muscle Building & Bodybuilding Nutrition Nutritional Supplements Weight Loss Yoga Martial Arts Finding Happiness Inspirational Breast Cancer Mesothelioma & Cancer Fitness Equipment Nutritional Supplements Weight Loss
Affiliate Revenue Blogging, RSS & Feeds Domain Name E-Book E-commerce Email Marketing Ezine Marketing Ezine Publishing Forums & Boards Internet Marketing Online Auction Search Engine Optimization Spam Blocking Streaming Audio & Online Music Traffic Building Video Streaming Web Design Web Development Web Hosting Web Site Promotion Broadband Internet VOIP Computer Hardware Data Recovery & Backup Internet Security Software
Advertising Branding Business Management Business Ethics Careers, Jobs & Employment Customer Service Marketing Networking Network Marketing Pay-Per-Click Advertising Presentation Public Relations Sales Sales Management Sales Telemarketing Sales Training Small Business Strategic Planning Entrepreneur Negotiation Tips Team Building Top Quick Tips Book Marketing Leadership Positive Attitude Tips Goal Setting Innovation Success Time Management Public Speaking Get Organized - Organization
Credit Currency Trading Debt Consolidation Debt Relief Loan Insurance Investing Mortgage Refinance Personal Finance Real Estate Taxes Stocks & Mutual Fund Structured Settlements Leases & Leasing Wealth Building Home Security
Mobile & Cell Phone Video Conferencing Satellite TV Dating Relationships Game Casino & Gambling Humor & Entertainment Music & MP3 Photography Golf Attraction Motorcycle Fashion & Style Crafts & Hobbies Home Improvement Interior Design & Decorating Landscaping & Gardening Pets Marriage & Wedding Holiday Fishing Aviation & Flying Cruising & Sailing Outdoors Vacation Rental
Book Reviews College & University Psychology Science Articles Religion Personal Technology Humanities Language Philosophy Poetry Book Reviews Medicine Coaching Creativity Dealing with Grief & Loss Motivation Spirituality Stress Management Article Writing Writing Political Copywriting Parenting Divorce
The Human Head site celebrated its first anniversary (last month) languishing, unused and aging, on my hard drive. My personal thanks to Wade Acuff and Patrick Miller for making it possible to be bring it back online after its five month hiatus. Unfortunately, I haven't had time to update the site beyond the mini-bio on the overview page and the temporary alternate navigation at the bottom of this page to support linux/mozilla users. The Human Head is now hosted by the Department of Art at Mississippi State University.
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies copyright Andrew Camenisch | 2001
The Human Head site celebrated its first anniversary (last month) languishing, unused and aging, on my hard drive. My personal thanks to Wade Acuff and Patrick Miller for making it possible to be bring it back online after its five month hiatus. Unfortunately, I haven't had time to update the site beyond the mini-bio on the overview page and the temporary alternate navigation at the bottom of this page to support linux/mozilla users. The Human Head is now hosted by the Department of Art at Mississippi State University.
A word about myself: I built this site while pursuing a Master of Fine Arts at Mississippi State University. The site represented a culmination (of sorts) of my personal research in organic modeling undertaken to support my thesis in portraiture and characterization. I graduated in December 2001 and currently live and work in New Zealand under contract with Weta Digital.
000000000000000000000000000
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
The parameterization therefore should follow the direction of this topography emanating from the center of the mouth as concentric circles.
Furthermore, from kissing to shouting to smiling, the direction of the motion of the mouth radiates from the center of the mouth, mandating a topology that flows out and away from the center of the mouth.
Let's compare this to an improper topology that ignores the direction of surface shapes and the direction of motion.
Note that though this surface has a higher resolution than the first surface it inadequately and awkwardly represents the mouth shape primarily in its dealing with the corners of the mouth.
You'll notice that the flow of their fibers corresponds roughly to the flow of the parameterization in the mouth region. This is an important observation. As you attempt to build more and more subtlety of expression and shape into your character's model you will want to conform your parameterization more and more to the underlying muscles of the face.
1|2|3
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Wrinkles
Wrinkles on skin are essentially the same as wrinkles on cloth: a bunching of fabric. The fabric draping the head, however, is typically firm and elastic, conforming tightly to the underlying fat, muscle and bone. Nevertheless, a large part of the expression and personality a particular head communicates is dependent on a network of temporary and permanent wrinkles.
Temporary wrinkles are those that that come and go with particular
facial movement. Some of these wrinkles are key to identifying facial expressions. The parameterization of a head model should plan for wrinkles that will be modeled into the blend (morph) shapes when setting up the head for animation.
For Example
The most prominent of wrinkles, the smile/shout wrinkle around the mouth, is commonly overlooked in the modeling of youthful heads, because the crease is typically not visible in the expressionless base shape and the artist simply overlooks the fact that it will be needed later in modeling the target shapes (check out most head modeling tutorials on the web). Thoughtlessly extending the concentric circle parameterization of the mouth region, also contributes to improper structure for defining the mouth wrinkle. (I've been there and done that...)
rollover
Permanent wrinkles represent the history of a head's facial action, forming on the human face after a lifetime of facial movement (and time in the sun). As age increases, the elasticity of skin decreases. The skin becomes less and less able to spring back to its original position, increasing the surface area of the skin and eventually sagging and bunching on the face (more info). The lines formed by these wrinkles illustrate a nearly ideal topology for a CG head model.
I'm not sure who owns the copyright on this picture. If anyone happens to know, please email me.
Van Gogh's intuitive understanding of the natural flow of lines on the face, possibly developed from observing the face's wrinkles of expression and age. The compatibility of Van Gogh's brushwork with Langer's Lines also leads one to wonder if he had been influenced by illustrations of these so-called lines of tension.
Langer's Lines
A stab wound inflicted with an ice pick or a similar weapon with a conical blade will leave a slit in the skin, not a round puncture as might be expected (a bit more info on stab wounds and Langer's Lines). The direction of a slit varies between different areas of the body but remains fairly consistent from person to person. Langer's lines map the direction of slits across the body and are used in surgery to guide incisions: cuts along Langer's Lines heal better leaving less scarring. Named after Austrian anatomist, Carl Ritter von E. Langer (1819-1887), Langer's Lines represent lines of tension within the skin. These lines tend to be oriented parallel to the direction the skin is pulled and are dependent on the direction of collagenous bundles (elastic connective tissue) in the reticular layer of the skin.
Though certainly not the final word on topology, Langer's lines provide
several interesting ideas for the head and rest of the body, as well as offer insights regarding the tension placed on skin in different regions.
Illustrations taken from Henry Gray's Anatomy of the Human Body. In public domain.
1|2|3
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation
Since the factors (the shape and motion of the surface) that
influence topology are independent of each other, there are certain regions on the human head where they demand conflicting structures. One example region is the promontory of the cheekbone.
However, the motion of the skin in this region, is manipulated directly and indirectly by several different muscles which push and pull the skin in a variety of directions -- directions that don't necessarily flow along the topographical (again, don't confuse with topology) lines. Smiling pushes the skin up and back; kissing pulls it down toward the mouth; while squinting pulls it up and in toward the eye. In the illustration, you can see that the movements just described run along lines that are diagonal to the cheekbone.
In summary, the surface's shape requires a horizontal/vertical grid, while the surface's motion demands a diagonal configuration. When you place a diagonal grid over a horizontal grid you end up with something that is incompatible with NURBS and undesirable for Maya subd surfaces: 3 and 5 sided faces. Resolving conflicting parameterization usually entails beginning with the structure demanded by the motion and adjusting it as much as possible to conform with topographical concerns.
Suggested workflow:
Make several copies of a drawing/photograph of your character. On one picture, draw lines indicating the direction of major shapes of the surface. On another picture, draw lines indicating the direction of the movement of the surface using the facial muscles as reference. Copy the lines from both pictures onto a third picture and begin connecting the lines that seem to flow into each other to form what Bay Raitt refers to as Edge Loops. All lines must end up roughly parallel or perpendicular to the lines closest to it so that a grid of sorts can be constructed. When surface lines and motion lines don't overlap, aren't parallel and aren't perpendicular -- you've officially found
a problem spot.
Decide what is most important and resolve it the best you
can (remember, with Maya subds, avoid creating faces with more or fewer sides than 4; but if necessary, almost always give preference to a five-side over a three-side. Refer to the Subdivision Modeling Resource Page maintained by Tams Varga, for dealing with odd numbered faces).
1|2|3
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
There a several different common approaches to modeling the human head. Following is a list of these methods with a short description: NURBS single mesh: The head being
spherical in shape, the NURBS sphere is a popular place to start. The sphere can be oriented along any axis: x) poles are located in the ears; I've only seen one head built this way and I'm not sure where... y) poles are placed on the top of the skull and around the neck, see Jeremy Birn's tutorial for example, or z) poles are in the the mouth and on the back of the skull or in the mouth and opening at neck. [see example note that the eyes are separate geometry] One big disadvantage to the single mesh NURBS is that the entire head has to share the same resolution; meaning the model might have a zillion isoparms running around it just to be able to define a decent nose or eye. It is a fast and easy way to model a head, however, and works fairly well for low detail, highly abstracted characters.
NURBS patch model: Modeling the head by stitching together a number of NURBS patches allows for both more complexity in the shape and more regularity and efficiency in the parameterization. This system is fairly complex however and involves a lot of tedious tweaking at the seams of each patch to ensure smooth continuity with adjacent patches. The NURBS patched head is discussed in more detail in the process>NURBS chapter of this website.
multiple NURBS patches
1|2|3
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Each modeling paradigm has its pros and cons, and the smart modeler will know when to use each one. Following is a chart comparing some of the pros and cons of each paradigm. Though to my knowledge the chart is fairly software independent, I did include factors specific to Maya.
NURBS:
Polygons:
pros:
automatic organization: all vertices are kept in consistent, quadrilateral relationships allowing for built-in UVs which makes applying a texture faster. scalable resolution: surface is defined by mathematical equations and therefore is infinitely smooth, allowing for infinite scaling small file size curves on surface: allowing for Paint Effects (Maya) fur support (Maya)
pros:
single mesh: most models can be constructed as one solid mesh local detail: resolution can be added locally arbitrary topology: how the vertices are connected can easily be rearranged and edited import/export between other packages: poly file formats like .dxf and .obj are supported by practically every commercial 3D software texture control; power to manipulate placement of each individual UV
cons:
limited complexity in the shape of the surface without resorting to multiple patches, in which case the following point applies... can be complicated and tedious seams very little control over texture stretching and placement
cons:
large file size fixed resolution texture control: the control polys offer in terms of setting up UVs comes at the expense of ease; applying a texture can be a fairly involved process no curves on surface: and hence no Paint Effects support (Maya)
cons:
no fur or PE support (Maya) no soft body dynamics (Maya)
1|2|3
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
"The convenience and global power of NURBS modeling tools and the organization inherent to NURBS topology suggest that NURBS are the ideal modeling paradigm for setting up the initial structure of the head model."
However, there are several compelling reasons for starting with NURBS:
1) NURBS automatically maintain a quadrilateral relationship between surface points ensuring proper structure for later conversion to subdivision surfaces (quad faces are preferred by Maya's subds and are more easily organized); 2) NURBS allow for hull selection and pick walking (using the arrow keys to move to adjacent CVs; very useful when the serial relationship between two points is not clear); 3) NURBS can be quickly rebuilt in U and V directions separately (offering versatility while allowing for a quick roughing out of the shape and the progressive refinement of that shape). In summary, the convenience and global power of NURBS modeling tools and the organization inherent to NURBS topology suggest that NURBS are the ideal modeling paradigm for setting up the initial structure of the head model.
1|2|3
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Preparing to Model
Downloading reference material or creating your own
Stand as far away from the subject as your lens will allow. This will flatten the head, eliminating much of the perspective in the photo, preparing it for its destination: the orthographic view. A lot of distortion in a model can result from using a perspective-filled photo as reference in an orthographic view! Use lighting that is clear but also accentuates the forms of the face. Make sure your light setup works for both the front and profile view of the head (see next point). Don't use a flash! Don't rotate the subject in front of the camera, but instead orbit the camera around the subject. The subject should remain stationary; this will ensure that shadows on the face are consistent between the front and profile views, which makes identifying and aligning features between the two views much easier. Be aware of the colors in your photo. Remember you will be modeling on top of these photos in wireframe view. What color is the wireframe? When selected? It may be helpful to process the color in Photoshop (decrease saturation/value, colorize, etc.) if the modeling components are getting lost in the photo. Make sure you get a TRUE profile. A slight turn of the head can throw off your proportions. Make sure the up and down tilt of the head is consistent between front and profile views. (The forward tilt of the head in the Natalie Portman "front view" below required her profile to be rotated slightly.) You may find it helpful to draw points or a grid on the subject's face to streamline the surface construction process later on the computer. This may be obvious, but I find it easier to align the two photos in Photoshop and cropping them to identical sizes before importing them into the 3d package, instead of aligning them in the 3d package.
For your convenience, here are photos to be used as onscreen reference that I either took myself or found on the web.
Notice in the front view that half the face was mirrored in Photoshop. One reason for doing this is to make sure the face is oriented at a 90 degree angle and not leaning over slightly. The lighting is identical in both shots so shadows and highlights are found at the exact same spots on both faces.
Notice the profile view is NOT a true profile. The head is slightly angled away. Students who have used these images struggled against placing the eyes on their models too far forward. Also, since these photos were taken under different lighting conditions, locating the same point on her face in both photos can be difficult. Images from a Natalie Portman fan site. Copyright owner unknown to author -will remove images if requested.
These images are from the research being done in face cloning at MIRALab. Though I am not yet permitted to display the hi-res versions of the photos, they remain an example of good reference. If you look at the vegetation in the background and the lighting on the man's face, you'll notice the subject stood still as the camera moved around him.
The Anatomy Resource References for 3D artists has a few more profile/frontal photos
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Patchwork Strategies
Comparing NURBS patch designs 1|2
For a brief history and slightly technical overview of NURBS surfaces click here.
The Bingo Setup. Developed by AliasWavefront for the short film Bingo and featured in AW's training videos, this model uses 10 patches to define the face (9 depending on the eye setup). The two most significant problems with this setup in my opinion are:
1) The isoparms flowing from the top of the wing of the nose flow back and around the cheek terminating in the jaw. Consequently, the crease in the cheek that occurs when sneering or smiling can only be faked. Instead, the isoparms should flow along the surface detail whose shape actualy flows from the top of the nose lobe, down around the corner of the mouth and into the chin. 2) The juncture point just to the right of the eye is placed at a point on the face that receives alot of deformation which can cause some tangency problems. <<<model available for free download at AliasWavefront.
My Setup. After experimenting with the Bingo setup and applying what I'd learned about stitching and patchwork strategies, I designed a setup that I believe to be the best for a medium resolution human head. The face is composed of 6 patches whose topologies flow in the direction of the major muscles of the face. The topology is far from perfect, obviously, since NURBS technology is limited. However, the model is built to naturally receive (without forcing and faking) the major deformations of facial action.
Except for the juncture on the eyebrow, all seams and junctures have been placed in areas that receive either very little deformation or else very broad deformation. Click here for another view of this model showing the strategy for the entire head.
A Setup to Avoid.This final head is a design used by a company to demonstrate software that creates NURBS surfaces from polygonal meshes. I found it curious due to the number of patches used to construct the face (around 30) and think it's a good example of how patchwork design can get out of hand if the three principles aforementioned are not kept in mind. :)
1|2
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Patchwork Strategies
The NURBS ear and the rules of stitching
1|2
The ear is like a face within a face. The complexity, variation and
uniqueness of each ear is nothing short of amazing. Unfortunately many CG heads fail at depicting a believable, realistic ear. I think the main reason for this is simply a lack of good reference (it's very difficult to examine one's own ears in a mirror) and lack of priority (rarely do we notice ears; is it worth the time to do it right?). The ear modeled in NURBS is further complicated by the limitation inherent to that paradigm in depicting complex shapes. Stitching multiple patches, however, offers a solid way of depicting human ears. Before discussing patchwork strategies for the ear, we need to go over a few guidelines for stitching. According to the recommended workflow of this site, there is no point in creating a refined seamless NURBS head since all seams will be dealt with after the patches are converted to polygons. However, stitching can be helpful in general NURBS modeling and is still considered a commercially valuable skill. Following is a list of rules governing master and slave stitching.
Never use the 2nd to last or first CVs to define detail on a patch as these CVs are used to achieve tangency between patches
Place breaks betweeen patches at areas that recive the least deformation. ie. DO NOT design patches to break at natural creases in the face [placing seams at flat areas if possible]
Work out which edges will be masters or slaves before beginning modeling. To determine which is the slave and which the master use the following rules/guidelines: 1) any edge that is to be stitched to two edges must be a master, or 2) if rule #1 doesn't apply, choose as master the patch that represents the point(s) of insertion of muscles whose effect is shared by adjacent patches. In other words, enslave the patches that move very little to the ones that move a lot. The insertion of a muscle is where the muscle connects to the skin. The origin of a muscle is where the muscle is grounded, usually connected to bone. When the muscle contracts it pulls the insertion toward the origin. For example, the muscle that pulls the brow up in surprise is grounded in the upper forehead but is inserted at the brow. The brow consequently receives the primary deformation in the contracting of that muscle. Therefore the forehead should be enslaved to the brow.
The order of stitching is very important and should be worked out on paper before proceeding: 1) always stitch patches first which are masters at every edge 2) for all other patches, observe this principle: always stitch all the enslaved edges of a patch before stitching the master edge(s) of that patch. This will ensure that all corners meet at the proper place without overlapping or dragging.
Align isoparms of patches to achieve a more predictable and secure stitch and to aid congruency in texture maps.
When fixing problem areas (tangled CVs, etc.) adjust the border and tangent CVs on the master surface first. The tangent CVs kind of see-saw around the border CVs.
Whenever the topography of a surface flows in multiple directions, multiple patches are required to adequately define the shape. Assigning one surface to each line is the first step to designing a patchwork for the ear.
Since there is no way to stitch the bottom part of these two patches with the current setup, the middle patch will be broken into two.
Now each edge at the circled juncture has a corresponding edge to which it can be stitched. However, the resolution that the inner hook of the outer surface requires (both to define the shape of that area and to stitch with the two inner patches) is too high to be spread across the entire surface. Therefore the outer surface will also be split allowing for a concentration of resolution where it is needed.
Finally a master/slave system is worked out based on the above rules and guidelines. Notice that one edge of the inner patch is not stitched at all but instead is hidden under the cleft of the outer patch.
Notice that this ear setup can be either blended or stitched to a NURBS head.
Below are several MEL scripts passed along to me by Jeffrey Wilson that are useful for NURBS stitching in Maya. tangentCVWin.mel by JS hullTangencyWin.mel by Jeffrey Wilson mAlignCvs.mel by Matthew Gidney mMidPointCvs.mel by Matthew Gidney mPlanar Cvs.mel by Matthew Gidney pickVertexC.mel by Matthew Gidney pickvertex.mel by Becky Chow
1|2
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
The Relationship
How Polgons and Subdivision Surfaces "Get Along" Polygonal modeling is pretty straightforward though it
requires a lot of discipline to keep organized and efficient. How polygons work in conjunction with subdivision surfaces, however, is a bit more involved. Most significantly, there are three things to be aware of in the way a subdivision surface works with its polygonal control mesh--the poly proxy.
1.
The topology of a poly proxy influences the final shape of the subdivision surface. Placing your mouse over the illustration above will reveal that all three blobs have identical geometry (same number of vertices with exactly the same placement) but unique topologies (vertices are connected in different ways). For the most part, predictable smoothing during animation will require maintaining quad faces on the poly proxy. This thread from the Digital Sculpting Forum ponders the potential of five-sided faces.
2.
Subdivision surfaces expect regular spacing between edges. For example, the shape of the two objects above appear identical. However, placing your mouse over the image reveals that the extra edge around the middle of the second shape creates a bump on the subdivision surface. John Feather explains why, as well as elaborating on problem #1, in this thread from the Mirai Bulletin Board. The practical implication of this problem is that fine wrinkles on the face that appear and disappear cannot be built into the model unless the surrounding resolution is equally high.
3.
This final point is specific to the hierarchical system of Maya's subdivision surfaces. Maya allows for manipulation of subdivision surfaces at various levels of detail enabling general and local control over the geometry of the model. I personally have not found a use for this technology in modeling the human head. The main reason being that modeling done at different levels of detail can react unpredictably if the topology is later altered in poly proxy mode. I prefer modeling detail directly into the polygon mesh and then using clusters and other deformers when general control is need.
Maya Tip: Because subdivision surfaces can slow down interactivity while modeling, I setup my workspace with two perspective modeling views one showing only the poly proxy and the other displaying only the subd surfaces (use the Show menu of each view panel). To view the poly control mesh in shaded view, apply a material to it, but be sure to turn off its "Primary Visibility", etc. attributes in the Render Stats section of its Attribute Editor so that it won't render. Most modeling is then accomplished while the poly view is maximized; a quick tap of the space bar allows me to check progress on the subd surface.
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Attacking Stretching
Mapping UVs 1|2|3
Stretching is a common problem in texturing complex 3D models and can be particularly frustrating on the human head. There are essentially two fronts where stretching can be attacked: 1) setting up UVs and 2) painting the texture. Part 1 of "Attacking Stretching" looks at mapping UVs; Part 2 at tweaking UVs; and Part 3 at painting textures with corrective distortion. Below is a close-up by Michael Koch depicting very nice texture mapping around a potentially tricky area of the face.
part 1
Michael Koch
A UV is a mapping coordinate that determines the relationship between the pixel of a texture and its relative
position on a surface. Unlike NURBS, which have "built-in", uneditable UVs, polygonal surfaces offer the modeler control over the UV setup.
Methods
Spherical, cylindrical, cubic, and planar mapping are different approaches to the same goal: generating mapping coordinates for a surface. Determining which to use in a given situation depends on which will generate a map that is closest to the final goal, requiring the least amount of tweaking. Spherical mapping, in my opinion, doesn't deal with the caverns and mountains of the head as predictably as cylindrical mapping does and therefore requires more adjustment to approximate a modified Mercator projection. Cylindrical mapping, though, doesn't generate proportional UVs in some areas; for instance, compressing the top of the skull.
spherical
cylindrical
Simply mapping the model, however, generates a UV map with many overlapping UVs in the mouth, ears, and nose regions. As a solution, the Maya Rendering Courseware suggests generating UVs for a human head model using the following process: 1) duplicate the head 2) average vertices on duplicate model 3) spherical wrap 4) transfer UV set from duplicate to original Averaging vertices is a way of "smoothing out" the model, flattening raised areas and raising sunken areas by averaging the distance between vertices. This, of course, makes the head much more ball-like and reduces the amount of overlapping in the critical regions.
spherical
cylindrical
There are a few problems, however, with this general "smoothing out." Averaging vertices modifies the relative placement of vertices, distributing them more evenly across the model. It is important, as we'll see later, that the relative size and shape of each face of the poly mesh remain consistent between the UV set and the actual model--as much as possible. A solution, therefore, is to use averaging vertices selectively and locally on the ear, nose, mouth, brow, and chin/neck regions.
spherical
cylindrical
Maya offers an iterative action called "relax UVs" that performs the same smoothing effect as "average vertices", but on UVs. Mapping the original head model and then applying "relax UVs" on the mouth, nose, ears, etc. can result in a UV map identical to one generated by the "duplicate/average/transfer" method. In conclusion, whether you map the raw model and relax UVs, or you duplicate the model, average vertices, map it and then transfer the UVs--it's completely up to you. : )
1|2|3
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Attacking Stretching
Tweaking UVs
1|2|3
part 2
2) all mapped checkers/squares are, for the most part, still squarish on the model (no rectangles or diamonds).
rollover
2) the basic shape of each polygonal face must be maintained. If the vertices on the model define a face that is square, the UVs at those vertices should also define a square. Notice below that the texture straightens out when the shapes the UVs define mimic those defined by the model's vertices.
rollover
Maya offers a fairly powerful toolset for editing UVs. The following tutorials show these tools in action: Baskin's Subd, Padron's Ugly, UnderTow's Lowpoly, and Kapp's Chicken.
1|2|3
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Attacking Stretching
Painting textures with corrective distortion
1|2|3
part 3
Left head is textured procedurally. Right head is textured with an image map based on the procedural texture to the left.
Converting to file texture generated the following 2D image. Notice the stretching of the texture near the
poles to accommodate the pinching of the UVs in those areas. This is corrective distortion. rollover to view UV map of sphere
Mapping this 2D texture back onto the sphere (and turning off texture filtering) resulted in an image identical to the one above featuring the procedural granite texture.
The Process
Set up 3D procedural textures that fairly convincingly depict different aspects of the skin surface: pimples, moles, glyphics, discolorations, stubble, freckles, dry skin, etc. Convert each of these to an image file. Notice the corrective distortion in the examples below (based on this imperfect UV map). freckles pimples
glyphics
light stubble
Photoshop and proceed to mask out each layer where needed (for instance, mask out most of the "freckles" layer around the neck, forehead, and chin regions, localizing freckles to the nose and cheeks). After color correction and additional painting a decent texture map with built-in corrective distortion is created.
This process is a relatively easy way of creating good skin textures that deal with stretching on the model. However, for high-end close-up work there is no avoiding significant hand painting and possibly the limited use of photography. Nevertheless, 2D images converted from 3D procedural textures can serve, if nothing else, as reference by identifying stretching and proposing corrective distortion.
Achieving the material qualities of skin is one of the most difficult aspects of human head texturing. The translucency , and subsurface light scattering properties, and the softening effect of the carpet of "peachfuzz" covering the skin are difficult qualities to achieve using conventional shaders. Tweaking the shader for the unique lighting conditions of different shots may be the most practical solution to achieving a consistent fleshy look. One of the most useful tools available for an artist to study the properties of skin (by viewing it under various lighting conditions) is the Facial Reflectance Field Demo. Excellent reference for lighting setup, too.
Be sure to read Steven Stahlberg's comments on human skin and shaders in chapters 17 - 19 of his head/face tutorial (info also found on his site). Alias|Wavefront's skin shader plugin for Maya offers further information. Peter Levius is doing some promising work using this plugin. Seryong Kim has done some interesting stuff with Mark Davies' raydiffuse plugin for Maya.
1|2|3
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links
Modeling Blendshapes
A few things to consider 1|2
Mark Piretti
David Maas
Though comics artists are masters of abstracting facial poses to a few expressive lines, their drawings focus on the major shapes created in a pose while often consciously editing out what is going on around them. While a 3D modeler must also prioritize the depiction of the major shapes, he must convincingly deal with the stretching, creasing, bulging, etc. that the rest of the face undergoes to accommodate these shapes. That is where the average artist's knowledge breaks down and is often found relying on cliche and imagination.
(Read Scott McCloud's Understanding Comics for a compelling argument for the power of "cartoony" characters; ie. it's not just kid's stuff.)
Examples:
The eyebrows should glide over the eyebone as muscles pull them up in surprise. Notice the downward pull on the hairline and compare this to Square's demonstration of the forehead wrinkle setup in Final Fantasy (Production>CG Animation>8).
click for QTVR Sometimes, however, it's the other way around. Notice in this QTVR how the skin does not cling to the jaw as the mouth opens but instead the jaw passes through the skin. A commonly overlooked action. Also notice the reach of this motion, affecting skin as high as the cheekbones and as low as the Adam's apple. click for QTVR
Guidelines for modeling blendshapes: 1) Analyze facial expressions in motion; look for a general line in motion--it is not sufficient to use static images for reference when modeling blendshapes. Every point on the skin of a real head follows a certain path and covers a definite distance between the neutral pose and an expressive one. Each vertex of your head model should seek to correlate as closely as possible to the movement of the point on the head that it represents. You'll find, after staring at a point on your own face as you make an expression over and over again, that the movement of that point can be abstracted into a line. What is the angle of the line? Does it curve in or out? how much? Also, be sure to watch the movement of your face in the mirror from different angles to determine the line of movement in each axis (this is why even video reference is inadequate). I guarantee your face will get a work out if you don't cut corners on analytical observation.
Tip: when looking in the mirror, make use of pimples, moles and pockmarks to analyze motion of skin. The messier the face, the better. :) Case study: Smiling, one of the broadest movements of the face, pulls the muzzle out, up, and back, tucking it up under the cheeks which rise slightly in the y axis but also push out in the z and x. Abstracted, the line of motion is like a sweep that pivots around the middle of the nose (notice how the movement of the skin fades out as it approaches the
6) Be aware of points on the face where the skin appears anchored or resists movement. Expressive wrinkles form when moving skin meets skin that doesn't want to move. (corner of the eyes, upper nose).
7) Model and place the teeth in the skull before attempting to model
blendshapes for mouth movement (obviously, the same thing goes for the eyes). The teeth, as part of the skull, serve to push the mouth out. Smiling pulls the lips back around the teeth tightening the skin in that region. A toothless smile is still obviously toothless even if the mouth is kept closed because of the missing support of the substructure!
1|2
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Paul Ekman has developed a system of codifying facial expressions based on the muscles used in their execution. FACS (Facial Action Coding System) assigns numbers to the muscles relevant to facial action creating an objective way of recording and analyzing facial expressions independent of individual subjective perception. The artist, actually, is more interested in the subjective perception of facial information but still has much to gain from the work of Ekman and others who are building on research by Duchene and Darwin in the 19th century. FACS identifies 46 Action Units, sometimes combining more than one muscle per unit. In deciding which blendshapes and controls to set up, I narrowed down the action of facial muscles to the following list:
Major Blendshapes
feature muscle
[total: 29]
description left right top bottom surprise worry anger close/ open side squeeze and squint sneer x x x x x x x x
eyebrow frontalis eyebrow frontalis eyebrow corrugator eye levator palpebrae orbicularis oculi elevator labii superioris zygomatic major
eye
smile
x x
x x
triangularis frown
risorius/ platysma orbicularis oris orbicularis oris orbicularis oris depressor labii inferioris
x x
x x x x x x
Major Wrinkles
feature forehead eyebrow eye eye nose chin mouth description surprise furrowed crow's feet smile under eye sneer cry/frown pucker
Misc
feature description
[total: 5] setup cluster with membership on jaw, chin and bottom lip (top lip receives some deformation at corners of mouth and from friction with bottom lip); remember to parent bottom teeth to cluster cluster cluster
jaw
slide
jaw nose
tense flare
cluster with membership that fades out at corners of eye and with pivot point located in eyelids sheath for eyeball center of eyeball; rotation of eyeball drives rotation of cluster throat cheek swallowing puffing/sucking sculpt deformers clusters
Much more can be said about setting up the human head for animation; the eye for instance should be a chapter in itself. I do plan on adding to this website as time permits. There is, however, a limit to what can be done with off the shelf software that hasn't been customized for subtle aspects of character animation. Animation Artist has an article mentioning some of the software that has been written to handle the subtleties of facial action in recent CG films.
1|2
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Just Pictures
A small image and QTVR library of the facial features. Sorry for bad lighting and blur on some of these; I hope to redo them when I have more time. If anyone has quality photos and QTVR/movies they would like to share, please post them somewhere and I will link to them.
The Head
The Eye
The Mouth/Nose
The Ear
books
Gray's Anatomy: The Classic Collector's Edition by Henry Gray o The Making of Final Fantasy: The Spirits Within by Steven Kent The Expression of the Emotions in Man and Animals by Charles Darwin
dvds
Final Fantasy The Spirits Within Square Pictures o
Foooooo
downloads
3Q scanned head -- .dxf of myself [294 KB] 3 Maya NURBS bodies -early models by Jeffrey Ian Wilson Lightwave body parts -by Pierre-Marie Albert Maya NURBS patched head -- by Petre Gheorghian Poly body -- by Richard Suchy
visual reference
The AR Face Database Hair Boutique -- with gallery Wig Styles HiRes pictures of public officials -- great skin ref. The Figure on CD -- very few heads; Jeremy Birn's review of the CD Facial Expressions -scroll down for pictures head and skull -- the Visible Woman Project
Teeth
people
Andrew Camenisch Alceu Baptisto John Feather Seryong Kim Dylan Gottlieb Michel Roger Pierre-Marie Albert Miles Estes Hikaru K. Hyung jun Julien Leveugle Olli Sorjonen Ken Brilliant Malcolm Thain Igor Posavec Nakajima Michael Koch Marco Patrito Amaan Akram Stuart Aitken Tibor Madjar Frank Silas Ulf Lungdren Jean Marc ARIU Andrey Purtov Albert Susantio Dana H. Dorian Michael Sormann Hou Soon Ming Matthew Clark Jeremy A. Engleman Pascal Blanche Francois Rimasson David Lightbown Daniele Duri Sam Gebhardt Taron Bill Fleming Bay Raitt Arild Wiro Anfinnsen Tom Capizzi Nicolas DuThatCo Ren Morel Mauro Baldissera Caleb "Cro" Owens Jeremy Birn e-frontier (commercial) Steven Stahlberg Visen Brnicevic Robert Kuczera Richard Suchy Ryan Duncan Virtual Celebrity (commercial)
Eric Sanford
Giovanni Nakpil
tutorials
highend3d's maya tuts AW's tut on blendshapes Susantio's subd tut pandora Hannon's berNURBS tut virtual mime Jeremy Birns' NURBS tut Steven Stahlberg's NURBS tut (free download) Ron Lemen's Constructing the Head on Paper Minako's paintfx hair David K.'s poly tut Nakajima's MetaNURBS tut for body Carsten Lind's NURBS tut Eric Sanford's Frankenstein Richard Natzke's ear
information
Digital Sculpting Forum Lavater's Essays on Physiognomy Understanding Facial Expressions Subdivision Modeling Resource Gamasutra article on facial animation BBC's The Human Face Facial Animation / CRL research Facial Action Coding System The Art of Poly Panther Calzone's resource Digital Sculpture Techniques Surface Anatomy of Head and Neck Gray's Anatomy Online
broken links
The Virtual Character Project Peter Ratner's subd tut Dirk Bialluch's subd tut Veli-Antti Rautiola's subd tut Mark Strohbehn complete skull QTVR Surfaces and Renderings Bill Stahl's NURBS tut Facial Perception Basic Portrait Lighting
Maxunderground
ROM3D
theory overview modeling theory approaches process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
Showcase
Human Heads of the Web (and one monkey)
This is a small gallery of work being done around the world.
Andrew Camenisch
Alceu Baptisto
John Feather
Pasha Ivanov
Michael Koch
. . . [models] . . . [textures]
Ulf Lundgren
Ren Morel
Marco Patrito
Francois Rimasson
Michel Roger
Steven Stahlberg
If you know someone who should be in this gallery feel free to let me know.
process setup NURBS polys/subds texturing animation resources features close-up reference/links gallery pics and movies
// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
Alias|Wavefront Script File MODIFY THIS AT YOUR OWN RISK Creation Date: Jan 9, 1998 Author: js Description: Type: tangentCVWin <-- creates a window to use this script interactively. Basically it's a way of moving surface cv's to help create tangency. Notes: it's really helpful for corners where 3 or more surfaces come together and you need to keep tangency between those surfaces. Example: For a corner where 4 surfaces come together: while in CV component selection mode select the 4 cv's which are on the corners of each surface and press the "cv's that move" button (you should have done the "tangentCVWin" command before this). Then select the surrounding cvs and press the "cv's that don't" button. Then press the "Make cv's tangent" button at the bottom of the window - this will move those first cv's so their xyz position is an average of all the other cv's you select. Input Arguments: None. Return Value: None.
global proc string[] cvSel () { // This procedure reads in a selection of cv's & outputs their // names string $objs[1]; $objs = `ls -sl`; string $result[1]; int $counter = 0; for ($z = 0; $z < size($objs); $z++) { string $tmp = $objs[$z]; string $tmp2[1]; string $object;
// replace ".cv" with "." for ease of tokenizing string $tmp3 = `substitute ".cv" $tmp "."`; tokenize($tmp3, ".", $tmp2); $object = $tmp2[0]; string $sets[1]; tokenize ($tmp2[1], "][", $sets); // separate them into min & max string $u[1]; string $v[1]; tokenize ($sets[0], ":", $u); tokenize ($sets[1], ":", $v); clear ($tmp2); clear ($sets); int $umin; int $umax; int $vmin; int $vmax; $umin = $u[0]; if (size($u[1]) != 0 ) { $umax = $u[1]; } else { $umax = $umin; } int $vmin = $v[0]; if (size($v[1]) != 0) { $vmax = $v[1]; } else { $vmax = $vmin; } for ($x = $umin; $x <= $umax; $x++) { for ($y = $vmin; $y <= $vmax; $y++) { $result[$counter] = ($object + ".cv["+$x +"]["+$y+"]"); $counter = $counter+1; } } } clear ($objs); return ($result);
} global proc makeTangent (string $moveCvs[], string $tangentCvs[]) { float $xAverage=0.0; float $yAverage=0.0; float $zAverage=0.0; for ($cv in $tangentCvs) { $currentPos = `xform -q -ws -t $cv`; $xAverage = $xAverage + $currentPos[0]; $yAverage = $yAverage + $currentPos[1]; $zAverage = $zAverage + $currentPos[2]; } $xAverage = $xAverage/size ($tangentCvs); $yAverage = $yAverage/size ($tangentCvs); $zAverage = $zAverage/size ($tangentCvs); for ($cv in $moveCvs) { move $xAverage $yAverage $zAverage $cv; } } global proc makeCVsTangent () { $moveCvs = `textScrollList -q -ai cvMoveCVTextScrollList`; $tangentCvs = `textScrollList -q -ai cvTangentCVTextScrollList`; makeTangent $moveCvs $tangentCvs; } global proc buildTangentCVWindow ( string $win ) { window -title "Make cv's tangent" $win; columnLayout topCVWindowLayout; rowColumnLayout -nc 2 -cw 1 200 -cw 2 200 cvRowColumnLayout; button -w 200 -l "cv's that move" cvReloadLeftButton; button -w 200 -l "cv's that don't" cvReloadRightButton; textScrollList -w 200
-h 300 -nr 12 cvMoveCVTextScrollList; textScrollList -w 200 -h 300 -nr 12 cvTangentCVTextScrollList; setParent topCVWindowLayout; button -w 400 -l "Make cv's tangent!!" makeTangentButton; } global proc loadCVs ( string $scrollList) { $selectedCvs = `cvSel`; textScrollList -e -ra $scrollList; for ($item in $selectedCvs) { textScrollList -e -a $item -w 200 -h 300 $scrollList; } textScrollList -e -w 200 -h 300 $scrollList; } global proc createCallBacksCVWindow () { button -e -c "loadCVs \"cvMoveCVTextScrollList\"" cvReloadLeftButton; button -e -c "loadCVs \"cvTangentCVTextScrollList\"" cvReloadRightButton; button -e -c makeCVsTangent makeTangentButton; } global proc tangentCVWin () { $win = "tangentCVWin"; if (!`window -exists $win`) { buildTangentCVWindow $win; createCallBacksCVWindow; } showWindow $win; }
//hullTangencyWin.mel: created by Jeffrey Wilson, 09.26.00 //This script is based off of tangentCVWin script created //by js @ A|W 01.09.98 // //edited by Jeffrey Wilson 09.26.00 // fix conflicts with tangencyCvWin.mel // // //This script will allow you generate tangency at a surface //seam or multiknot through the selection of the seam hulls //and the hulls adjacent to the seam. // //usage: hullTangency // (This will bring up the Surface Seam Continuity // window) // Load the cv hulls into the window: // select a single hull at the seam // press Seam Hull 1 Button // select the corresponding seam // (if multiknot, no need to select another hull) // press Seam Hull 2 Button // select adjacent hull to Seam Hull 1 // press Tangency Hull 1 // select adjacent hull to Seam Hull 2 // press Tangency Hull 2 // Execute "Create Tangency Along Seam" // (If the seam twists, execute the Untwist Seam button) //
global proc string[] hullSel (){ // This procedure reads in a selection of cv's & outputs their // names string $objs[1]; $objs = `ls -sl`; string $result[1]; int $counter = 0; for ($z = 0; $z < size($objs); $z++){ string $tmp = $objs[$z]; string $tmp2[1]; string $object; // replace ".cv" with "." for ease of tokenizing string $tmp3 = `substitute ".cv" $tmp "."`; tokenize($tmp3, ".", $tmp2);
$object = $tmp2[0]; string $sets[1]; tokenize ($tmp2[1], "][", $sets); // separate them into min & max string $u[1]; string $v[1]; tokenize ($sets[0], ":", $u); tokenize ($sets[1], ":", $v); clear ($tmp2); clear ($sets); int $umin; int $umax; int $vmin; int $vmax; $umin = $u[0]; if (size($u[1]) != 0 ){ $umax = $u[1]; } else{ $umax = $umin; } int $vmin = $v[0]; if (size($v[1]) != 0){ $vmax = $v[1]; } else{ $vmax = $vmin; } for ($x = $umin; $x <= $umax; $x++){ for ($y = $vmin; $y <= $vmax; $y++){ $result[$counter] = ($object + ".cv["+$x+"]["+$y+"]"); $counter = $counter+1; } } } clear ($objs); return ($result); } global proc makeHullTangents (){ $tangentCVs1 = `textScrollList -q -ai cvTangentCVTextScrollList1`; $tangentCVs2 = `textScrollList -q -ai cvTangentCVTextScrollList2`; $seamCVs1 = `textScrollList -q -ai cvSeamCVTextScrollList1`; $seamCVs2 = `textScrollList -q -ai cvSeamCVTextScrollList2`; for ($i = 0; $i < size($tangentCVs1); $i++){ $cvPos1 = `xform -q -ws -t $tangentCVs1[$i]`;
$cvPos2 = `xform -q -ws -t $tangentCVs2[$i]`; $avgX = ($cvPos1[0] + $cvPos2[0])/2; $avgY = ($cvPos1[1] + $cvPos2[1])/2; $avgZ = ($cvPos1[2] + $cvPos2[2])/2; //print ("position of tangency1 " + $cvPos1[0] + " " + $cvPos1[1] + " " + $cvPos1[2] + "\n"); //print ("position of tangency2 " + $cvPos2[0] + " " + $cvPos2[1] + " " + $cvPos2[2] + "\n"); //print ("avg position of seams " + $avgX + " " + $avgY + " " + $avgZ + "\n"); //print ("diff between points " + ($cvPos1[0] - $cvPos2[0]) + " " + ($cvPos1[1] + $cvPos2 [1]) + " " + ($cvPos1[2] + $cvPos2[2]) + "\n"); if (size($seamCVs1) > 0){ move $avgX $avgY $avgZ $seamCVs1[$i]; } if (size($seamCVs2) > 0){ move $avgX $avgY $avgZ $seamCVs2[$i]; } } } global proc unTwistHulls (){ $tangentCVs1 = `textScrollList -q -ai cvTangentCVTextScrollList1`; $tangentCVs2 = `textScrollList -q -ai cvTangentCVTextScrollList2`; $seamCVs1 = `textScrollList -q -ai cvSeamCVTextScrollList1`; $seamCVs2 = `textScrollList -q -ai cvSeamCVTextScrollList2`; undo makeHullTangents; $in = size($tangentCVs1); for ($i = 0; $i < size($tangentCVs1); $i++){ $in--; $cvPos1 = `xform -q -ws -t $tangentCVs1[$i]`; $cvPos2 = `xform -q -ws -t $tangentCVs2[$in]`; $avgX = ($cvPos1[0] + $cvPos2[0])/2; $avgY = ($cvPos1[1] + $cvPos2[1])/2; $avgZ = ($cvPos1[2] + $cvPos2[2])/2; //print ("position of tangency1 " + $cvPos1[0] + " " + $cvPos1[1] + " " + $cvPos1[2] + "\n"); //print ("position of tangency2 " + $cvPos2[0] + " " + $cvPos2[1] + " " + $cvPos2[2] + "\n"); //print ("avg position of seams " + $avgX + " " + $avgY + " " + $avgZ + "\n"); //print ("diff between points " + ($cvPos1[0] - $cvPos2[0]) + " " + ($cvPos1[1] + $cvPos2 [1]) + " " + ($cvPos1[2] + $cvPos2[2]) + "\n"); if (size($seamCVs1) > 0){ move $avgX $avgY $avgZ $seamCVs1[$i]; } if (size($seamCVs2) > 0){ move $avgX $avgY $avgZ $seamCVs2[$in]; } } } global proc buildHullTangencyWindow (string $win){ window -title "Surface Seam Continuity" $win; columnLayout topHULLWindowLayout;
rowColumnLayout -nc 4 -cw 1 200 -cw 2 200 -cw 3 200 -cw 4 200 cvRowColumnLayout; button -w 200 -l "Seam Hull 1" hullReloadButton1; button -w 200 -l "Seam Hull 2" hullReloadButton2; button -w 200 -l "Tangency Hull 1" hullReloadButton3; button -w 200 -l "Tangency Hull 2" hullReloadButton4; textScrollList -w 200 -h 150 -nr 12 cvSeamCVTextScrollList1; textScrollList -w 200 -h 150 -nr 12 cvSeamCVTextScrollList2; textScrollList -w 200 -h 150 -nr 12 cvTangentCVTextScrollList1; textScrollList -w 200 -h 150 -nr 12 cvTangentCVTextScrollList2; setParent topHULLWindowLayout; button -w 800 -l "Create Tangency Along Seam" makeHullTangentButton; button -w 800 -l "Untwist Seam" unTwistHullsButton; } global proc loadHulls (string $scrollList){ $selectedCvs = `hullSel`; textScrollList -e -ra $scrollList; for ($item in $selectedCvs){ textScrollList -e -a $item -w 200 -h 150 $scrollList; } textScrollList -e -w 200 -h 150 $scrollList; } global proc createCallBacksHullWindow (){ button -e -c "loadHulls \"cvSeamCVTextScrollList1\"" hullReloadButton1; button -e -c "loadHulls \"cvTangentCVTextScrollList1\"" hullReloadButton3; button -e -c "loadHulls \"cvSeamCVTextScrollList2\"" hullReloadButton2; button -e -c "loadHulls \"cvTangentCVTextScrollList2\"" hullReloadButton4;
button -e -c makeHullTangents makeHullTangentButton; button -e -c unTwistHulls unTwistHullsButton; } global proc hullTangencyWin (){ $win = "hullTangencyWin"; if (!`window -exists $win`) { buildHullTangencyWindow $win; createCallBacksHullWindow; } showWindow $win; }
// Select two CVs first as pins // any other cvs selected after the first two will be moved // onto the vector defined by the pins // useful for stitching surfaces together // the selection order is maintained so that the pick walker can be used after joining // by Matthew Gidney 1999 ( second real mel script!) // global proc mAlignCvs() { string $parents[] = `filterExpand -ex true -sm 28 `; int $numberOfCvs = `size $parents`; if ( $numberOfCvs < 3) { print("mAlign(): You must pick at least 3 Cv's to align \n"); return; } float $CVPin1[3] = `xform -q -worldSpace -t $parents[0]`; float $CVPin2[3] = `xform -q -worldSpace -t $parents[1]`; vector $origin = <<($CVPin1[0]),($CVPin1[1]),($CVPin1[2])>>; vector $rawVector = <<($CVPin2[0]-$CVPin1[0]),($CVPin2[1]-$CVPin1[1]),($CVPin2[2]$CVPin1[2])>>; vector $unitRawVector = unit ($rawVector); float $magRawVector = mag ($rawVector); for ($cnt = 2; $cnt < ($numberOfCvs); $cnt++) { float $CVPin3[3] = `xform -q -worldSpace -t $parents[$cnt]`; vector $testVector = <<($CVPin3[0]-$CVPin1[0]),($CVPin3[1]-$CVPin1[1]),($CVPin3[2]$CVPin1[2])>>; float $dotProduct = dot ( $rawVector, $testVector ); vector $moveVectorRel = $unitRawVector * ($dotProduct / $magRawVector); vector $moveVector = $moveVectorRel + $origin; xform -worldSpace -t ($moveVector.x) ($moveVector.y) ($moveVector.z) $parents[$cnt]; } }
// Select two CVs first as pins // any other cvs selected after the first two will be moved to the vector // defined by the first 2 pins // useful for stitching surfaces together // the selection order is maintained so that the pick walker can be used after joining // by Matthew Gidney 1999 ( first real mel script!) // global proc mMidPointCvs() { string $parents[] = `filterExpand -ex true -sm 28 `; int $numberOfCvs = `size $parents`; if ( $numberOfCvs < 3) { print("mMidPointCvs(): You must pick at least 3 Cv's to align \n"); return; } float $CVPin1[3] = `xform -q -worldSpace -t $parents[0]`; float $CVPin2[3] = `xform -q -worldSpace -t $parents[1]`; float $midPoint[3] = {(($CVPin1[0]+$CVPin2[0])/2),(($CVPin1[1]+$CVPin2[1])/2),(($CVPin1[2]+ $CVPin2[2])/2)}; for ($cnt = 2; $cnt < ($numberOfCvs); $cnt++) { xform -worldSpace -t $midPoint[0] $midPoint[1] $midPoint[2] $parents[$cnt]; } }
// Select three CVs first as pins // any other cvs selected after the first two will be moved // onto the plane defined by the pins // useful for smoothing corners where patches meet // by Matthew Gidney 2000 // global proc mPlanarCvs() { string $parents[] = `filterExpand -ex true -sm 28 `; int $numberOfCvs = `size $parents`; if ( $numberOfCvs < 4) { print("mPlanarCvs(): You must pick at least 4 Cv's to align \n"); return; } float $CVPin1[3] = `xform -q -worldSpace -t $parents[0]`; float $CVPin2[3] = `xform -q -worldSpace -t $parents[1]`; float $CVPin3[3] = `xform -q -worldSpace -t $parents[2]`; // first define the plane by its normal vector $pin1To2 = <<($CVPin1[0]-$CVPin2[0]),($CVPin1[1]-$CVPin2[1]),($CVPin1[2]-$CVPin2 [2])>>; vector $pin1To3 = <<($CVPin1[0]-$CVPin3[0]),($CVPin1[1]-$CVPin3[1]),($CVPin1[2]-$CVPin3 [2])>>; vector $normal = cross ($pin1To2,$pin1To3); float $magNormal = mag ($normal); vector $unitNormal = unit ($normal);
// next resolve the points onto the plane via the normal
for ($cnt = 3; $cnt < ($numberOfCvs); $cnt++) { float $point[3] = `xform -q -worldSpace -t $parents[$cnt]`; vector $pointToPin1 = <<($point[0]-$CVPin1[0]),($point[1]-$CVPin1[1]),($point[2]-$CVPin1 [2])>>; float $magPointToPin1 = mag ($pointToPin1); float $dotProduct = dot ( $normal,$pointToPin1); vector $moveVectorRel = -1.0 * $unitNormal * ($dotProduct / $magNormal); xform -worldSpace -r -t ($moveVectorRel.x) ($moveVectorRel.y) ($moveVectorRel.z) $parents[$cnt]; } }
// written by Becky Chow // work phone 650 628 7755 // home phone 650 743 6066 // robybeck@geeksville.com // becky.chow@ea.com // this script allows users to pick out all the vertex based // on vertex color range, from a complex polyset. // for instance, to pick out all the dark colored vertex, // just put dark gray in color box, and give it a 10% percentage range. // the script will automatically pick the darkest shaded vertex. //to install: //Copy "pickVertexC.mel" into your /maya/x.x/scripts folder. //Copy "pickVertexCIcon.bmp" to your /maya/x.x/prefs/icons folder. //open the "pickVertexC.mel" in script editor, //and execute it. then type "pickVertexCSetup"; global proc pc( ) { float $rgbup[2]; // upper end value of rgb float $rgbdn[2]; // lower end value of rgb float $rgb[2]; string $vtc[]; // temp list of vertex color within boundry int $polyn[]; // number of vertex in polyset int $i; // counter int $jv = 0; //counter for vertex number float $rgb[] ; //rgb value of vertex being evaluated float $tmpf; float $pcnt = `floatSliderGrp -q -value slider2`; $poly = `textFieldGrp -q - text textMeshName`; $polyn = `polyEvaluate -v $poly` ; $rgb0 = `colorSliderGrp -q -rgb slider1`; // seed color $pcnt = $pcnt / 100; $rgbup[0] = (($rgb0[0]+$pcnt) >= 1) ? 1: ($rgb0[0]+$pcnt); //red $rgbdn[0] = (($rgb0[0]-$pcnt) <= 0) ? 0: ($rgb0[0]-$pcnt); $rgbup[1] = (($rgb0[1]+$pcnt) >= 1) ? 1: ($rgb0[1]+$pcnt); //green $rgbdn[1] = (($rgb0[1]-$pcnt) <= 0) ? 0: ($rgb0[1]-$pcnt); $rgbup[2] = (($rgb0[2]+$pcnt) >= 1) ? 1: ($rgb0[2]+$pcnt); //blue $rgbdn[2] = (($rgb0[2]-$pcnt) <= 0) ? 0: ($rgb0[2]-$pcnt);
{ select -r ($poly + ".vtx[" + $i + "]"); $rgb = `polyColorPerVertex -q -rgb`; if (($rgb[0]>=$rgbdn[0]) && ($rgb[0]<=$rgbup[0]) && ($rgb[1]>=$rgbdn[1]) && ($rgb[1]<= $rgbup[1]) && ($rgb[2]>=$rgbdn[2]) && ($rgb[2]<=$rgbup[2])) { $vtc[$jv] = ($poly + ".vtx[" + $i + "]"); //making list $jv++ ; } } select -cl; for ($i = 0; $i < $jv; $i++ ) { select -add ($vtc[$i]); } print ("vertex selected: \n" ); print ($vtc ); } global proc mkwin () { window -widthHeight 800 300 -sizeable true -title "pickcolr" pickcolr; columnLayout; separator -w 210 -height 5 -style "none"; textFieldGrp -label "name of the Poly mesh :" - text "polyName" -columnWidth 1 125 -columnWidth 2 110 textMeshName; text -label " double click on color box to change seed color. "; text -label " it will pick all the vertex within the seed color range. "; text -label " 100% will let you select all the vertex with every color."; rowColumnLayout -numberOfColumns 2 -columnWidth 1 10 -columnWidth 2 240; text - label " "; colorSliderGrp -enable 1 -cw 1 80 -cw 2 30 -cw 3 100 -label "starting color" -rgb 0.5 0.5 0.5 slider1; setParent ..; rowColumnLayout -numberOfColumns 1 -columnWidth 1 400; floatSliderGrp -enable 1 -field 1
-value 0 -cw 1 180 -cw 2 40 -cw 3 100 -label "% range from the seed vertex color " -min 0 -max 100 -precision 1 slider2; setParent ..;
rowColumnLayout -numberOfColumns 2 -cw 1 120 -cw 2 60; text -label "press here to select "; button -label "select" -height 30 -command "pc" button1; setParent ..; rowColumnLayout -numberOfColumns 2 -cw 1 120 -cw 2 120; text -label " "; button -label "close window" -height 30 -align "center" -command ("deleteUI pickcolr "); showWindow; }
global proc pickVertexC () { global string $poly; global float $rgb0[]; if (`window -exists pickcolr`) deleteUI pickcolr; mkwin; }
//main
global proc pickVertexCSetup() { global string $gShelfTopLevel; if (`tabLayout -exists $gShelfTopLevel`) shelfButton -parent ($gShelfTopLevel + "|" + `tabLayout -q -st $gShelfTopLevel`) -command "source pickVertexC.mel; pickVertexC" -image1 "pickVertexCIcon.bmp"
-annotation "pick Vertex by vertex color Tool"; else error "You need a shelf for this Tool to work!"; }
/* This file downloaded from Highend3d.com '' '' Highend3d.com File Information: '' '' Script Name: PickVertex v0.0 '' Author: becky chow '' Last Updated: February 12, 2001 '' Update/Change this file at: '' http://www.highend3d.com/maya/mel/?section=polygon#831 '' '' Please do not alter any information above this line '' it is generated dynamically by Highend3d.com and will '' be changed automatically on any updates. */ // written by Becky Chow // work phone 650 628 7755 // home phone 650 743 6066 // robybeck@geeksville.com // becky.chow@ea.com // to use it, load the program into Mel script editor. // type "pickvertex" at the command prompt at the lower left // hand of the Maya screen. // this script allows users to pick out all the vertex based // on vertex color range, from a complex polyset. // for instance, to pick out all the dark colored vertex, // just put dark gray in color box, and give it a 10% percentage range. // the script will automatically pick the darkest shaded vertex. proc pc( ) { float $rgbup[2]; // upper end value of rgb float $rgbdn[2]; // lower end value of rgb float $rgb[2]; string $vtc[]; // temp list of vertex color within boundry int $polyn[]; // number of vertex in polyset int $i; // counter int $jv = 0; //counter for vertex number float $rgb[] ; //rgb value of vertex being evaluated float $tmpf; float $pcnt = `floatSliderGrp -q -value slider2`; $poly = `textFieldGrp -q - text textMeshName`; $polyn = `polyEvaluate -v $poly` ; $rgb0 = `colorSliderGrp -q -rgb slider1`; // seed color $pcnt = $pcnt / 100;
$rgbup[0] = (($rgb0[0]+$pcnt) >= 1) ? 1: ($rgb0[0]+$pcnt); //red $rgbdn[0] = (($rgb0[0]-$pcnt) <= 0) ? 0: ($rgb0[0]-$pcnt); $rgbup[1] = (($rgb0[1]+$pcnt) >= 1) ? 1: ($rgb0[1]+$pcnt); //green $rgbdn[1] = (($rgb0[1]-$pcnt) <= 0) ? 0: ($rgb0[1]-$pcnt); $rgbup[2] = (($rgb0[2]+$pcnt) >= 1) ? 1: ($rgb0[2]+$pcnt); //blue $rgbdn[2] = (($rgb0[2]-$pcnt) <= 0) ? 0: ($rgb0[2]-$pcnt);
for ($i = 0; $i < $polyn[0] ; $i++ ) { select -r ($poly + ".vtx[" + $i + "]"); $rgb = `polyColorPerVertex -q -rgb`; if (($rgb[0]>=$rgbdn[0]) && ($rgb[0]<=$rgbup[0]) && ($rgb[1]>=$rgbdn[1]) && ($rgb[1]<= $rgbup[1]) && ($rgb[2]>=$rgbdn[2]) && ($rgb[2]<=$rgbup[2])) { $vtc[$jv] = ($poly + ".vtx[" + $i + "]"); //making list $jv++ ; } } select -cl; for ($i = 0; $i < $jv; $i++ ) { select -add ($vtc[$i]); } print ("vertex selected: \n" ); print ($vtc ); } proc mkwin () { window -widthHeight 800 300 -sizeable true -title "pickcolr" pickcolr; columnLayout; separator -w 210 -height 5 -style "none"; textFieldGrp -label "name of the Poly mesh :" - text "polyName" -columnWidth 1 125 -columnWidth 2 110 textMeshName; text -label " double click on color box to change seed color. "; text -label " it will pick all the vertex within the seed color range. "; text -label " 100% will let you select all the vertex with every color."; rowColumnLayout -numberOfColumns 2 -columnWidth 1 10 -columnWidth 2 240; text - label " ";
colorSliderGrp -enable 1 -cw 1 80 -cw 2 30 -cw 3 100 -label "starting color" -rgb 0.5 0.5 0.5 slider1; setParent ..; rowColumnLayout -numberOfColumns 1 -columnWidth 1 400; floatSliderGrp -enable 1 -field 1 -value 0 -cw 1 180 -cw 2 40 -cw 3 100 -label "% range from the seed vertex color " -min 0 -max 100 -precision 1 slider2; setParent ..;
rowColumnLayout -numberOfColumns 2 -cw 1 120 -cw 2 60; text -label "press here to select "; button -label "select" -height 30 -command "pc" button1; setParent ..; rowColumnLayout -numberOfColumns 2 -cw 1 120 -cw 2 120; text -label " "; button -label "close window" -height 30 -align "center" -command ("deleteUI pickcolr "); showWindow; }
global proc pickvertex () { global string $poly; global float $rgb0[]; if (`window -exists pickcolr`) deleteUI pickcolr; mkwin;