
:: Post Date: 2007-12-09 10:58:34 [Post Comment] [Post Articles]
|
Making of Varga - Part 2 - 3D Character Model Normal Mapping in MayaSoftware: MayaAuthor: Paul ToscaContact: contact[at]paultosca[dot]comAuthor Website:http://www.paultosca.com4.4.Further Tweaking of Normal Maps in PhotoshopThis section is for those of you who want to better understand normal maps. It may seem a little technical (it requires some basic knowledge of math, vectors and stuff like that).4.4.1.Some General Info About TS (tangent space) Normal MapsFirst, I would like to talk a little about normal maps, how they are computed/displayed.I am more interested about tangent space normal maps (world or object space normal maps are not suitable for characters or for objects that will deform) so for now on when I will say normal map, you can assume I am talking about tangent space unless stated otherwise. If you are in the same situation as I was when I first started with normal maps (tangent space in particular), then probably the following info will help. At the beginning I was really frustrated by the "Seam" problem smile, where a normal map computed within a software will not display properly in another. What I'm talking about here is the seam that will appear in the geometry where you have a UV shell border. I have struggled to find out what the problem was ...thought that I was doing something wrong, read the help of each apps, then started searching on the internet and after some research, I finally got the idea about the problem -- how and why it will occur...but not how to fix it thoughsmile The main problem resides in the way each application computes/displays tangent space normal maps. Tangent space is represented by three vectors: normal (that will always be perpendicular to the surface), and two other vectors perpendicular to the normal called tangent and bi-normal (or bi-tangent: I have seen that the names are used interchangeably though some say that the correct name will be bi-tangent since we are talking about a surface ...for a curve in 3D, the tangent space will have one tangent and two normals (normal and bi-normal). For surfaces, we have one normal and two tangent vectors (tangent and bi-tangent). The naming does not matter much as long as we know what vectors we are talking about. These three vectors can be defined for each point on a surface and taken collectively, they define a coordinate frame. Usually tangent space per triangle will be computed in the following way: -The normal vector will always be perpendicular to the surface (triangle); it will be the blue one and will be stored in the blue channel of the normal map. -The tangent (the red one stored in the red channel) and binormal (the green one stored in the green channel) vectors will be oriented in accordance with the UVs -- tangent will be left to right (or right to left) in UV space, so it will be the U coordinate in the texture space; and binormal will be down to up (or up-down), so it will be the V coordinate in the texture space. Probably you have seen in many dialogs for normal maps the options to flip Red or Green channel. These options stand for the orientations of the tangent(left-right/right-left) and binormal (up-down/down-up), some apps use different orientation than others; you can flip the channels inside Photoshop, for instance to flip the Red channel press Ctrl+1 (to go to the red channel) and Ctrl+I (to invert it) then Ctrl+~ (control tilda , that will be to the left of the 1 key) to go back to full RGB image (same for green Ctrl+2,Ctrl+I,Ctrl+~). Now let's say that I'll cut the UVs along the edge and will rotate one shell 90 degrees CCW like in the image below. Because of the rotation in UV space the tangent space for the first triangle will be different than in the first situation (the RGB triad for the first triangle has rotated also 90 degrees along the blue axis). As a result of this, the orientation of the UV shells will affect the colors you see in the normal map; if you rotate the UVs of your model (or the UVs for some shells) let's say 90 degrees Clockwise and recompute the normal map, the colors in the new normal map will be completely different (not because the entire image will be rotated by 90 degrees, you can rotate it 90 CCW in Photoshop and compare it with the first version to check -- they will be different). Tangent space per vertex will then be computed and after that, you can compute the tangent space vectors for any arbitrary point on the surface by interpolating vertex tangent space vectors. Now for computing a normal map, the raytracing algorithm will cast a ray from the current point of the low poly mesh to the high poly and at the point of intersection with the highrez, it will compute the normal for the high surface in world space (WS). Then this normal is transformed in the tangent space (TS) of the low poly version and stored in the normal map. So you see that the normal computed is dependent on the tangent space used for the low poly version and the tangent space normal map must be created using the same normal/tangent/binormal as the game uses (or the application you use to display the normal maps), otherwise the normals will be misinterpreted and you will see discontinuities on border UV shells. And that is why you will have problems when trying to display a normal map computed with one app, viewed in another app. It wouldn't be a problem if different apps use different methods for tangent space vector calculations. The problem is that they are not making that info available so that someone interested could write a plug-in/tool that will remedy the problem ...the only app I know so far to make the formulae public is Mudbox, on their online help pages, you can find how they are calculating tangent space vectors. Now you know why the problem occurs but there is little that can be done about it ... at least you should know that you aren't doing anything wrong, the app is to blame smile. I will show an example and explain how the normal map will be computed and how to interpret it channel by channel -- this will help if you want to alter the normal maps in Photoshop, overlay multiple normal maps, paint on them directly in Photoshop etc... I will bake the normals from the plane and cylinder below to a single quad plane highlighted in green. As I explained earlier, the tangent space will be: normal pointing up (blue one) tangent from left to right (3-4 red one) and binormal/binormal down-up (3-1 the green one). The cylinder has all the edges hard so the normals will change in steps, it will be easier to analyze. I have numbered the faces on the cylinder from 1 to 7. Now let's suppose we are looking at the objects directly from the front view, it will look something like in the image below. At the top of the image you have a color scheme: high poly is white, the normals for high poly are cyan, low poly is magenta, the normals for low poly are yellow (since we have a quad plane the normals will have the same orientation everywhere on the surface), Below the color codes you see the TS (tangent space) triad: tangent(red left to right), normal (blue down to up) and binormal (green and perpendicular to the screen pointing from you to the screen). Notice in the figure above that all the faces from the high version are parallel with the green arrow (binormal in tangent space), excluding the triangles that will cap the cylinder and that will not be visible in the normal map anyway. Now, for every face in the high poly, I can decompose the normal vectors (cyan color-coded) in TS in their tangent(red color-coded) and normal (blue color-coded) components, the binormal component will be zero for all of them since the faces are parallel with the binormal vector = green arrow, hence the flat color in the green channel of the normal map. The green interrupted guides were drawn to help visualize better the transitions between faces and to see how they correspond with the actual geometry. The gray arrows pointing from low poly to high are the searching rays used during the computation of normal map. Now let's consider some points from the low poly (A,B,C,D,E,F,G) and see what actually happens. As a side note, usually vectors are normalized (with unit length) and if you decompose a vector into TS components (or other system coordinate) each component will have a real value between -1 and 1. However, this will be converted to positive integer and stored into RGB channels of the normal map as follows: -For tangent (in the red channel) negative values (-1,0) will be mapped linear to 0- 127, 0 will be 128 (neutral) and positive values (0,1) will be mapped linear to 129-255. -The same will apply for binormal in the green channel. -For the normal vector, the values can be only positive (0,1) so they will be mapped to 128-255; most of the time the normal of the high poly will not deviate a lot in comparison with the normal vector in TS for the low poly hence the blue look of normal maps in TS (the blue channel will be mostly white); because of this TS normal maps might be compressed since it uses fewer colors than OS (object space)/WS (world space) normal maps, also since TS vectors can't point backwards, the normal component will be always positive and when normalized it can be coded using only the tangent and binormal (the normal will be computed based on the other two). For point D, we shoot a ray and when intersecting the high version the normal will be that of face number 4 that will be parallel with the normal TS vector and following the dotted lines. You can see that the red channel will be 128 since the tangent component will be zero, and the normal component will be 1 mapped to 255 (full white) in blue channel. For point F, the searching ray will intersect face number 6 and we can see that the normal vector of this face (cyanish color-coded) will be decomposed into two components: tangent component(red) with a positive value around 0.78 mapped to 228 in the red channel and binormal component (blue) with a positive value of 0.625 mapped to 208 in the blue channel. For point B, the searching ray will intersect face number 2 and we can see that the normal vector of this face will be decomposed into tangent component(red) with a negative value around -0.78 mapped to something like 22 in the red channel and binormal component (blue) with a positive value of 0.625 mapped to 208 in the blue channel. By the way ,you can see individual channels inside Photoshop with ctrl+1 ,ctrl+2 ,ctrl+3 for red green and blue and ctrl+~ (that will be tilda ... left of 1) for full RGB. You can copy them as follows: for red -> ctrl+1(go to red channel), ctrl+a (select all), ctrl+shift+c (copy visible), ctrl+~(go to full RGB) and ctrl+v (paste), after this combination of shortcuts you will have the red channel of the current selected layer as a new layer on top. If I rotate the cylinder 90degrees like below -- the normal map will look something like this. Here it is on separate channels. ![]() ![]() This time the red channel is flat at 128 (like green channel was before) since all the faces in the high are now parallel with the red arrow (and when the normals are decomposed the tangent components will be zero mapped to 128); the green channel (binormal) will look similar to the red channel before (but rotated 90 degrees CCW) and the blue channel looks the same as before but rotated 90 deg. After knowing how each channel is rendered, we can make the following analogy: -I will assign a lambert to the high poly (cylinder and plane), set the color to neutral gray (128 128 128),set the incandescence to neutral gray also (128 128 128) and also set the diffuse to 1 -We'll look at the cylinder from top (orthographic view) in viewport: -Create a normal directional light with color full white and intensity 1 coming from right (the light will be parallel with the screen). -Create a "sucker" directional light, I do not know if you are familiar with the term smile "light suckers" ... I have seen them named like that on some forums and I will name them the same ... it's a light with a negative intensity. So when rendering, the "sucker" light will actually subtract/"suck" light, thus darkening the scene. Pretty handy when you have overbright areas in the scene, cause if you adjust the attributes for the lights already in the scene, you will mess the lighting in other areas. This way you can add a sucker light and fix the problem -- so add a sucker light with color full white and intensity -1 coming from left also parallel with the screen (so both lights will be in tangent-binormal plane). If we compare the screenshot from the Maya viewport and the red channel in the computed normal map, they will look exactly the same. Same applies for the green channel if you test it out. This time the same normal light will come from top and the sucker light from below (also same lights in tangent- binormal plane). For the blue channel you will keep only the normal light but this time lighting from straight top (light parallel with normal vector in TS). ![]() If I want to see all the channels together I will have to change the color for each light to affect only one channel. So for the setup below I will have 5 lights. With the lighting setup from above you can check real-time the normal map from the orthographic top view for any geometry. Now this info won't be too useful since you still have to handle geometry ... but check the next paragraph ... you can simulate this lighting setup within Photoshop with layer styles and all you have to do is make selections . 4.4.2. Normal Maps in PhotoshopNow I will try to simulate in Photoshop the same effect as shown above with lights within Maya, but this time using layer styles.I will set the background color to 128 128 255 I will need 5 layers, one for each light (make 5 layers and change their fill opacity to 0. Then I will make selections and fill them within each layer but only the effects will be visible) For Red normal light, apply an effect like below (bevel and emboss), uncheck use global lighting, set the angle to 0 (the light will come from the right), set altitude to 0 (light parallel with the screen), highlight mode set to overlay with color 255 128 128 (RGB) to lighten only the red channel and opacity to 100%, set opacity for shadows to 0 (don't need that). You can play however you want with the settings under structure, but you have to make sure that all the effects have the same settings. For the Red sucker light, copy and paste the last effect and change the angle to 180 deg (light coming from left) and change color to 0 128 128 so it will subtract light/darken only the red channel. For the Green normal light, paste the same effect but change the angle to 90 deg (light coming from top) and change color for the highlight to 128 255 128 to lighten only the green channel. For the Green sucker light, paste the same effect but change the angle to -90 deg (light coming from below) and change color for the highlight to 128 0 128 to darken only the green channel. And finally for the blue channel, apply an inner shadow effect, uncheck global lighting, distance 0, choke 0, set size to whatever you had for the size of the bevel and emboss and set color to 255 255 128 to darken only the blue channel, opacity to 100. The fun part is that now that you have the layer styles in place, you can just go and adjust the size in pixels for the effect and play with all the other attributes within bevel and emboss. If you want to "carve" detail you just have to change the direction in the bevel and emboss from up to down for the red and green layer styles, you can blur the selections with Gaussian blur to achieve smoother results. You can duplicate this set and alter the attributes again and do all kinds of crazy stuff. It's up to you to experiment. You can even place the layer sets on top of other normal maps and will display ok (just run NVIDIA normal map filter with the normalize option on the final texture). Below I was fooling around for a couple of minutes duplicating the layer set I had built earlier, filling the layers within the sets with some selections and altering the attributes for the effects, the normals are not 100% accurate as if it was done with real geometry (because of the rendering done by the bevel and emboss style). But if you set the attributes accordingly, you can barely notice it. Try to make a normal map like this with geometry in less than 15 minutes ... I'll bet you can't . This technique was used for Peril (the bow). Wire With Normal Map And the Full Textured Model Another thing you could do is to overlay two normal maps inside Photoshop, I have seen a lot of people actually setting the blend mode to overlay and call that final. This is not quite a good method and I will show you why in the next image. Let's say we want to overlay the normal map in the right on top of the left one; you can see how the blue channel is looking for each map and how it should look for the combined image. But when setting the mode to overlay, because the blue channel is almost white, it will completely wipe out any detail in the blue channel and the composite normal map will look wrong. Below is the final composite map when set to overlay; we're completely wiping out the information about the normal component so the overlay mode for blending is a BIG NO NO NO A better way to combine them is to set the red and green channels to overlay and the blue channel to multiply ... now how in the world I will do that?? Well, duplicate the second layer (the layer that was supposed to be set to overlay mode), one layer will be set to overlay, the other with multiply. Now, for the layer set on overlay I should neutralize the information in the blue channel by selecting a neutral gray (128 128 128) and by filling the blue channel with this color -- that will be ctrl+3 (to go to blue channel) and alt+backspace (to fill it with neutral grey, assuming the FG color will be 128 128 128), this layer should now look like this when viewed on its own. For the second layer set to multiply, I should neutralize the red and green channels in respect to multiply blending mode (that would be to fill them with white), so set white as FG color and ctrl+1 (to go to red channel) and alt+backspace to fill with white, same for green ctrl+2 and alt+backspace; the second layer should look like the image below when viewed on its own. Below is a comparison between the two methods, obviously the combination overlay/multiply is the way to go. If the vectors stored in the normal map are normalized, then the red and green channel will suffice because the normal component can be computed from the tangent, bi-tangent and the calculation should be done when displaying. If this is the case then a simple overlay will work fine because the info in the blue channel won't be used, but most apps will use the blue channel as well, so you should go for overlay/multiply combination. Of course for the example above you could just make a selection and overlay them with normal mode, but most of the time you will have details in both maps that need to be overlaid. Now that you know how to combine normal maps, you're probably asking why would you ever want to do that? Well, I will give you some examples. After you finish the diffuse textures, you can create a bump map with fine detail (pores in skin and other granularities like leather , cloth ... etc), then use NVIDIA filters to create a normal map that will be overlaid on top of the normal map computed from geometry (this way the fine detail from diffuse and normal will register correctly). It can help you in other situations as well: When I sculpted the torso for Varga I forgot to sculpt the scar of the missing breast and later on when I realized that I had some weird problems with the scenes and could not load them so I just sculpted a scar on a new plane and overlaid it on top. Also when I was sculpting Umbra, I went too far with the number of polygons and later on realized I was too timid with the musculature -- but it was too late...I had already broken the model into pieces ... To remedy the situation I started sculpting the muscles on a new plane using a temporary normal map baked from an earlier version as my guide, then I computed a normal map between this geo and a quad plane and overlaid it on top of the old normal map to reinforce the muscles. ![]() A Final Image with Umbra And below are the models with the final "super-tweaked" normal maps That pretty much covers all I wanted to say in this tutorial and if you read it so far, probably there was something that caught your attention. Thank you for reading. 5. Final modelIn conclusion of this tutorial, I would like to show you a couple of final renders with Varga (fully textured). ![]() ![]() I hope you enjoyed this tutorial and that you did find something useful by wasting your time browsing it. Good luck with normal mapping! Paul Tosca Links:Making of Varga-3D Character Model Normal Mapping in Maya-Part 1Making Low Poly Game Character Hair - Paul Tosca |
| Great to read. You explained it very well. P |
| Thanks for this amazing explanation! I'll bookmark it as my only resource for normal mapping from now on. Great job! |
| It looks really cool. Good job. |
| faggot |
| she has one titty. shes an amazonian babe |
| Ur stuff is hard to follow but looking at the pictures u make inspire me to learn 3D art. The $hit u produce is high end amazing whoah-ness |