Home Technical Talk

tutorial: fixing mirrored normal map seams

1
polycounter lvl 18
Offline / Send Message
warby polycounter lvl 18
i made this tutorial for a co worker but decided to share it with the world smile.gif

7nyItyl.jpg

3d app and engine used maya 7 and ogre

Replies

  • warby
    Offline / Send Message
    warby polycounter lvl 18
    also for the none believers i made it work in unreal engine 3 so you cant just blame it on ogre3d and maya smile.gif

    tutorial_normal_map_seams_unreal_demo.jpg
  • Neox
    Offline / Send Message
    Neox veteran polycounter
    U3 can't handle mirrored uvs properly without having a seam? Cause i never had that problem like this with max' dx9 shaders, so am I getting into trouble with mirrored uvs in the U3 engine?
    Or did you just bake out one half and mirrored it then? because i always bake both halves at one moment.
  • aesir
    Offline / Send Message
    aesir polycounter lvl 18
    dude, warby!! Thanks so much. I always have so much trouble with seams... Even at one of my internships I couldnt get rid of them and my AD wasnt all that helpful in figuring out how to get em off.
  • bounchfx
    thanks! this is a keeper.
  • warby
    Offline / Send Message
    warby polycounter lvl 18
    yes neox ue3 and just about any other engine i know has these problems.

    i think the rule of thumb is if your left half and right half of the model are identical and they have a geometry seam in the middle and the uvs end at that seam AND you are using a normal map / specular shader you will be in for trouble smile.gif
  • Neox
    Offline / Send Message
    Neox veteran polycounter
    But do you bake only one half or both at once?
  • warby
    Offline / Send Message
    warby polycounter lvl 18
    one half ! if id bake both at once they would override each other since they share the same uv space ! ... the result would be the same really unless the high poly model is asymmetric ... than there would be all sorts of artifacts
  • JordanW
    Offline / Send Message
    JordanW polycounter lvl 19
    When you're baking do you delete your geometry or just move the unused UVs off? doing the latter helps keep your low poly normals intact while baking.
  • warby
    Offline / Send Message
    warby polycounter lvl 18
    i delete it but maya keeps the normals intact anyway ! because i use 2 separated instances and i average the vertex normals all along the seam .

    it looks like its perfectly smooth shaded even though its 2 objects !
  • Neox
    Offline / Send Message
    Neox veteran polycounter
    First of all thank you for the tutorial! Never thought of that because last time i had that issue is years back since then none of my clients complained about it. But as i'm doing more U3 work in the future, i'll have to know the problems.

    I tested it and the result is not totally the same, so it makes a difference if you bake out one half or both halves at once, but the uvs of the mirrored half somewhere outside the uvs space. This is just a quick test, but it shows the issue quite good.

    normals.jpg

    So i really have to test your solution on this little fellah before getting him into the U3 engine. thankfullyI only have mirrored UVs on the neck and minor parts of him, but then again, it's good to know how to get away without a seam.#

    But then again, i don't understand why a so sophisticated engine like the U3 has such problems. looking at gears of war screenshots i see quite a lot mirrored stuff but no seams, so how do they achieve it if the engine has problems with it?

    Oh and how would i fix that problem on a character with that seam not being either vertical or horizontal but bent?
  • Eric Chadwick
    Thanks for the tut warby, looks good.

    A couple things I noticed...

    The gradient can be thinner, and don't think you need the magic wand if you make the grad half as wide. Kills less of your detail that way.

    Middle-gray is really 127, because Photoshop uses 0-255.

    Re-normalizing won't break the map, try it with Nvidia's filter and you'll see. Re-normalizing only kills normals that are pointing backwards (like if you want the surface to be lit from behind), or normals that are really short (like if you want to bake AO into the normalmap by darkening the crevices). Those seam pixels won't be changed at all.

    You'll still get some seams though unless your exporter & engine use the tangents + bitangents. This trick doesn't fix all problems. But it is a good one! Thanks for the sharing the step-by-step.
  • warby
    Offline / Send Message
    warby polycounter lvl 18
    [ QUOTE ]
    Thanks for the tut warby, looks good.

    Middle-gray is really 127, because Photoshop uses 0-255.


    [/ QUOTE ]

    i also used to be a subscriber to 127 is perfect grey theory for a LONG LONG TIME but at my last job i got into a fight with the lead coder and an art intern and we tested it by i think layering 1000 planes with a multiplyX2 blending material on top of each other ( you know where dark gets darker and bright gets brighter )and it turned out that 128 achieved perfect transparency. since that day of shameful defeat i don't claim 127 to be perfect grey anymore ... however this might be a ogre3d engine specific thing ... but i believe it comes form the conversion of the 0-255 to the 0-1 scale thats 128 becomes perfect grey even though it shouldn't.
  • Rob Galanakis
    Perfect grey would be .5/1 = x/255
    x = 255 * .5
    x = 127.5

    So both of you are right and wrong. I don't think it really matters but I will take warby's word for it.

    Anyway, this is a good fix but ideally your engine shouldn't have these lighting issues. They should really be fixed on the pipeline side, because it is not very efficient for content to have to compensate for technical deficiency (as opposed to restrictions). That said, game development is not a perfect process, so I'm sure many will find use for this tutorial.
  • warby
    Offline / Send Message
    warby polycounter lvl 18
    [ QUOTE ]

    Anyway, this is a good fix but ideally your engine shouldn't have these lighting issues. They should really be fixed on the pipeline side, because it is not very efficient for content to have to compensate for technical deficiency

    [/ QUOTE ]

    QUOTED FOR TRUTH !
  • Eric Chadwick
    I thought it was 256 grays not 255, so the art app can use a range of either 0-255 or 1-256, but it's still the same 256 colors.
  • achmedthesnake
    Offline / Send Message
    achmedthesnake polycounter lvl 17
    SEKNeox - i noticed when using cloward's shader i didn't have any porblems with any seams - except when i zoomed out 'alot' in the max veiwport and then i oculd see a slight blackish line at the seams....
  • Neox
    Offline / Send Message
    Neox veteran polycounter
    That is because of max' mipmapping if you give enough flesh around your texture (16 pixels i.e.) it won't happen.
  • arshlevon
    Offline / Send Message
    arshlevon polycounter lvl 18
    [ QUOTE ]
    I thought it was 256 grays not 255, so the art app can use a range of either 0-255 or 1-256, but it's still the same 256 colors.

    [/ QUOTE ]

    you are correct sir, so many people forget 0 is in fact a value, even if its the absence of a value its still by contrast a different value than 1, or 127, so you have to count it, and that would make 127 right in the middle.

    and great tutorial!
  • Jeremy Lindstrom
    Offline / Send Message
    Jeremy Lindstrom polycounter lvl 18
    Heck anyone know of a tutorial for Maya showing how to use mirrored normals? laugh.gif I know they say to move them in the -1, but not sure what that means laugh.gif
  • Eric Chadwick
    Hi Dekard. I added something about this to the CGTalk wiki, might help you...

    If you want to mirror the UVs, or you want to reuse parts of the normal map by overlaying multiple UV shells in the same UV space, then simply move all those overlapped/mirrored shells one unit over on the U or V axis before you bake the normal map. Only one non-overlapping set of forward-facing UV shells should remain in the 0-1 UV box at baking time.

    Normal map baking tools will only capture normals within the 0-1 UV box, any UV bits outside this area are ignored. If you move all the overlaps exactly 1 UV unit away (to the side or up or down doesn't matter) then they'll be ignored by the baker. You can also leave them there after the bake and they will be mapped correctly. Or you can move them back if you want. Doesn't matter to the game engine.
  • Eric Chadwick
    OK warby I found something similar to what you're saying. I think you're using unsigned normal maps, which for your engine means a 128 color is considered a non-bent normal (pointing straight up on X/red). Here's a quote from one of our graphics programmers:

    [ QUOTE ]

    Signed normal maps are useful for helping to hide tangent space seams that exist because of mirroring. Such a seam can only be hidden if the normals on either side of the seam are not bent along the mirrored axis.



    With an unsigned normal map it is impossible to represent a normal that isn’t bent. This is because the unsigned data is loaded into the pixel shader by the hardware so that [0, 255]->[0, 1]. The shader then transforms the data so that [0, 1]->[-1, 1].



    Ultimately, this means that 0 must be represented in the unsigned normal map as 127.5, but unfortunately the normal map can only store integers. Because of this, 0 is stored as 128, and so it maps to slightly more than 0 when it is loaded into the shader, giving the normal a very slight bend.



    With signed normal maps it is possible to represent a normal that isn’t bent. Signed data is loaded so that [-127, 127]->[-1, 1] and so 0 is simply represented as 0. The range has been diminished by one: -128 is clamped to -127.



    Signed normal maps do not magically cause all tangent seams to vanish, but they do make it possible that some mirror seams may be hidden.



    For example consider a plane with a flat normal map and a mirror seam down the middle, created by setting its left- and right-most vertices’ x-axis texture coordinates to 0 and creating vertices down its middle with x-axis texture coordinates equal to 1.



    With an unsigned normal map the seam is visible despite the fact that the normal map is flat. With a signed normal map the seam is hidden.



    The 8-bits-per-component signed normal maps we use store numbers in the range [-128, 127] whereas the equivalent unsigned normal map stores numbers in the range [0, 255]. The advantage of the signed normal map becomes apparent if we consider how the normal maps are sampled in the pixel shader.



    Values from a signed texture are mapped so that [-127, 127]->[-1, 1] when sampled in the pixel shader. Notice that -128 is not included in the source range. It appears that it is clamped to -127. Values from an unsigned texture are mapped so that [0, 255]->[0, 1]. The unsigned values must be scaled by 2 and biased by -1 in the pixel shader to move them into [-1, 1].



    The problem is that there is no way to represent 0 in the [-1, 1] range in an unsigned texture. If we try to transform 0 back from [-1, 1] into [0, 255] we get ( 0 + 1 ) / 2 * 255 = 127.5, which is not an integer. Therefore when it is stored in the texture it is rounded to 128, and when we map that back to [-1, 1] we get 128 / 255 * 2 – 1 = 0.003921568627450980392156862745098.



    With the signed texture, on the other hand, 0 represents 0 in both ranges. That means only a signed texture can represent a normal with no bend in the pixel shader, and that’s why we use it. We convert unsigned textures to signed by subtracting 128 from all the components, which maps 1 to -127, 128 to 0 and 255 to 127.


    [/ QUOTE ]

    I know, it's a lot to digest, but hopefully this can help people get better results. It is possible to hide normalmapping seams, with the proper tech.
  • warby
    Offline / Send Message
    warby polycounter lvl 18
    after a lengthier conversation with neox and carny (crytek) yesterday afternoon i was compelled to put my method to the test and used that joined double half bake trick (that i must shamefully admit i wasn't aware of )and compared the normal map result with my photoshop trick and the double half bake diffidently is substantially cleaner than a single half bake it is still marginally inferior to my method it seams ... at least in ue3

    tutorial_normal_map_seams_vs.jpg
  • Eric Chadwick
    "joined double-half bake" = ?

    What tool are you using the bake the normalmap with, and how are you getting the model into UE3? I'm wondering if UE3 is using the vertex tangent/bitangent data from the normalmap baker. If you're using UE3's own baker tool, then I'd guess that it's using the tangents. I've never used it though.
  • warby
    Offline / Send Message
    warby polycounter lvl 18
    unreal engine 3 comes with a normal map generator smile.gif ?

    i use xnormal
  • Jeremy Lindstrom
    Offline / Send Message
    Jeremy Lindstrom polycounter lvl 18
    [ QUOTE ]
    Hi Dekard. I added something about this to the CGTalk wiki, might help you...

    [/ QUOTE ]

    Thanks, I guess thats the issue, but I'm not sure how to move it over exactly one unit in Maya is what I guess my problem is laugh.gif I can move it over to the outer square or off the uv square all together but not sure how to move into the -1
  • EarthQuake
    You can just save a copy, move it off the uv sqaure somewhere, and then revert back to your other copy when you go to export or whatever.
  • Neox
    Offline / Send Message
    Neox veteran polycounter
    [ QUOTE ]
    "joined double-half bake" = ?

    What tool are you using the bake the normalmap with, and how are you getting the model into UE3? I'm wondering if UE3 is using the vertex tangent/bitangent data from the normalmap baker. If you're using UE3's own baker tool, then I'd guess that it's using the tangents. I've never used it though.

    [/ QUOTE ]

    before warby baked only the half that is going to be mirrored later, joined double half bake just means, that you can bake both halves at once, as stated severeal times in here smile.gif

    however, i took a look at the UT3 Models, if they bake it with their own baker it doesn't change a thing, the problem is still there, in all models with mirrored UVs, they just designed the Units with a visible seam in the middle so it won't hurt. Heads are not mirrored. Parts with no forced Seam in the Design, seam to work quite good without specular. You can only see the seam when you are zoomed in quite close.

    Unbelievable that the U3 really has this problem, i worked with many smaller engines and never heard about any problems with my mirrored models.
  • Ryno
    Offline / Send Message
    Ryno polycounter lvl 18
    This is looking great in UEd with just specularity, but will a reflection look correct if it were applied? This was a big issue with some vehicle models that we were working on, and couldn't correct it in the shader without using a lot of extra instructions. Proper reflections were a big sticking point.
  • Eric Chadwick
    Ah OK I get it now. Deleting the mirrored geom vs. moving the mirrored UV away. Thanks man.
  • Sage
    Offline / Send Message
    Sage polycounter lvl 19
    Ryno I'm curious, why did the reflections come out wrong? Are you using an image like a cube map to create the illusion of reflections or are they calculated in real time? Can't the reflections use their own uv coord channel or is that too expensive? Thanks or sharing this Warby.


    Alex
  • Eric Chadwick
    Well I was totally wrong about 127 gray. Doing some more tests. Turns out that (128,128,255) gives me a straight up normal once it's converted into a signed normalmap, but (127,127,255) gives me a slightly bent normal. Here's a shot.

    http://www.ericchadwick.com/examples/images/2008.01.09_normalmap_seams.jpg

    Reflection made it much more obvious for me than spec or diffuse. Ryan you should try 128 and see what you get. Warby, thanks a lot for the idea, I totally owe you a beer.

    Hi Sage. Reflection doesn't use UVs, at least not in the regular colormap sense. In most engines UVs are actually used to calculate the tangent space for a model, which then affects reflection, but that affects all lighting not just reflection. You can't really UV a reflection, it's based on the normals, whether per-pixel (normalmap) or per-vertex or per-whatever. You can however rotate a cubemap, but the model still uses its normals to look into the cubemap. "Live" reflection is usually just a set of bitmaps rendered on the fly, whether cubemap or spheremap or paraboloid, etc. So same mechanism at work. Hope that makes sense, hard to describe.
  • Ryno
    Offline / Send Message
    Ryno polycounter lvl 18
    Yep, cube maps usually rendered from the environment as Eric mentions. Both on the fly cube renders, or generic one-off renders of the scene.
  • rybeck
    Warby,

    Thanks for great information. As matter of fact, I was looking all over the place to find how to do it via "Zbrush & 3dsMax pipeline" (which I am still working on) This would be definitely giving me some break. smile.gif



    Dekard,
    [ QUOTE ]
    You can just save a copy, move it off the uv sqaure somewhere, and then revert back to your other copy when you go to export or whatever.

    [/ QUOTE ]
    Here is the link from ZB wiki that explain MEL that allow you to move UV shell.
    http://www.zbrush.info/docs/index.php/ZB...Regions_in_Maya


    Rybeck
  • Sage
    Offline / Send Message
    Sage polycounter lvl 19
    Thanks for the information Eric, I see.

    Now I'm wondering if you can get normal maps to work mirrored uvs why wouldn't with code the engine be able to figure out which section of the cube map is supposed to be rendered on the model? What I'm getting at here is if the engine is using the normal map to light the model so it looks smooth, can't the engine be told that the mirrored sections are supposed to be pointing in the opposite direction that they are pointing now and also to check to where each part of the model is actually pointing to. For some reason I thought things like cube maps at least in pre rendered animation got composited onto the model to save on render time. I'm thinking about how the reflect refract material works, well how I thought it does, where you can have it calculate the reflection stuff first then it looks at these images to save on render time.

    Meh I was going to edit my post after I saw your example. I kind of see the problem with reflections. I decided to leave the questions as is just to get more feedback. Thanks.

    Alex
  • Eric Chadwick
    Like I said it's hard to describe this. I'll try though. smile.gif

    Reflection makes any small normalmap seam look more obvious than it does with specular or diffuse lighting, because a cubemap has more color variation than a light.

    A light is a single color coming from a single direction, so two neighboring texels that have slightly different normals will get nearly the same light color on them. Maybe just a change in intensity.

    But with reflection those same neighboring texels probably get different colors out of the cubemap. More obvious.

    Also a reflection map slides across the surface as the camera moves, while diffuse lighting disregards camera angle, stays same angle to the surface. Specular uses same "sliding" as reflection, but again it's just a single color.

    Bah. Play with it in-game, best way to see.
  • Sage
    Offline / Send Message
    Sage polycounter lvl 19
    Actually what I noticed the most was how the reflection would bend where it wasn't supposed to. At least in your example. I'll have to go play with it. Thanks.

    Alex
  • Ryno
    Offline / Send Message
    Ryno polycounter lvl 18
    Yeah, weird distortion on the seam is the biggest problem. Apparently there is a way to fix it within UnrealEd if you add a bunch of instructions to the shader and another UV non-mirrored UV set from what I've heard. But we couldn't afford all of the extra instructions.
  • siegel
  • ivan0v
  • Autocon
    Offline / Send Message
    Autocon polycounter lvl 15
    warby is it possible to reupload your pic?
  • cman2k
    Offline / Send Message
    cman2k polycounter lvl 17
    here you go dude.
    tutorialnormalmapseams.jpg
  • praxedes
    how would one use that method seigel linked to in a mirrored model? Is it possible to "offset" the mirriring somehow to avoid the mirror point being a tangent edge? If so it'd be the awesome :)

    ~P~
  • Autocon
    Offline / Send Message
    Autocon polycounter lvl 15
  • MoP
    Offline / Send Message
    MoP polycounter lvl 18
    Since this thread got bumped, I'd just like to point out that you should never have to do this technique.
    This tutorial shows how to "fix" a bake from highpoly geometry, and if you're baking it correctly then you should never run into this issue. This issue will only show up if you delete your mirrored geometry before baking. The issue does not show up if you correctly bake your whole model with the duplicate UVs offset by a unit.
  • EarthQuake
    MoP wrote: »
    Since this thread got bumped, I'd just like to point out that you should never have to do this technique.
    This tutorial shows how to "fix" a bake from highpoly geometry, and if you're baking it correctly then you should never run into this issue. This issue will only show up if you delete your mirrored geometry before baking. The issue does not show up if you correctly bake your whole model with the duplicate UVs offset by a unit.

    indeed.
  • Jesse Moody
    Offline / Send Message
    Jesse Moody polycounter lvl 17
    MoP wrote: »
    Since this thread got bumped, I'd just like to point out that you should never have to do this technique.
    This tutorial shows how to "fix" a bake from highpoly geometry, and if you're baking it correctly then you should never run into this issue. This issue will only show up if you delete your mirrored geometry before baking. The issue does not show up if you correctly bake your whole model with the duplicate UVs offset by a unit.

    Typed it up before I could. Good man.
  • Autocon
    Offline / Send Message
    Autocon polycounter lvl 15
    yeah I had a big old seam in marmoset and I had no clue why since I always offset bake. This was the only thing I could think to try and right as I was about to start this I was like OHHHHH I didnt flip my green channel.
  • poostayn
    I did a offset bake but still got a slight seam at the mirror point. Will this technique fix that as well or does anyone have any other ideas?

    Normal_issue1.jpg
  • EarthQuake
    Make sure your UVs are welded(just do a weld with a tolerance of like 0.0001 on your uvs). If you somehow have unwelded uvs that can cause seams.

    Baking in one app and then viewing in another may cause seams too if the baker/previewer handle normals significantly different as well.

    Also check obvious stuff like making sure the verts along the seam are welded, and that you dont have a hard edge there in the lowpoly mesh that could be causing missed detail in the projection.
  • poostayn
    Thanks for the tip earthquake!
1
Sign In or Register to comment.