EDIT: This was originally split off from the Handplane3D thread requesting a UE4 preset for Handplane. It's now discussing some apparent faults in the way UE4 calculates tangents on imported FBX files.
I think that's probably because UE3 is (still?) unknown in terms of tangent basis so Handplane was close but not quite. UE4 has a clearly defined tangent basis.
Personally I'd prefer to use Handplane over xNormal's obj-to-tangent converter tool as Handplane's much faster and easier.
Replies
It's Quack's file with baked with Xnormal 3.19.8
If you want to bake your own: https://copy.com/TO16UFcRkhU1KTXk
Interestingly enough, if you export the .fbx from Blender (which uses mikktspace natively) and include tangents and bitangents, and then import those tangents and bitangents into UE4, it just happens that the normal map we baked against the .fbx with no exported tangents works perfectly!
(mesh from Blender on the right, mesh from Quack on the left)
Which seems to indicate that there's a problem with the mikktspace calculator within UE4's importer, since the tangents seem to work OK when they come from Blender's native MikkTSpace.
Oh bother, look at those gratuitously split tangent vectors. This does seem to be a bug after all! In the meantime, you can just export everything from Blender with tangents and import those tangents and bitangents into UE4, then when they come out with the fix for this you can go back to your regularly scheduled pipeline.
I thought it was an issue with Modo's FBX exporter... looks like it might be UE4's FBX importer.
Same to Farfarer, we need to get fresh eyes on this and bump that thread.
+1 Agreed, can a mod move our post to the Unreal subforum? Or how should we do this? And thank you guys for posting on AnswerHub!
Jed: I've not seen issues directly related to sharp angles. Quote of my reply on the UE4 Answers;
I'm not sure. I've tried some tests based on that and I can't seem to get 90 degree angles to do anything strange. I get tons of tangent splits where I have UV splits, though. Give this mesh a look over, should show what I mean.
Bottom row is just a bunch of planes that meet at different angles. Next row up is those joined up to triangles at the side. Next row up is the same, but unwrapped with UV splits and BAM tons of tangent splits. Top one is them as closed surfaces and there's tangent splits with those too because of the UV splits.
Angle Test Mesh
I've been doing additional testing of my own, comparing Mikktspace tangents exported from Blender to tangent space vectors calculated by Unreal. You can see that there's quite a bit of splitting going on all over the place in the mesh that UE4 is calculating tangents for, and not necessarily on the UV borders.
UE4 calculated:
Imported MikkTSpace from Blender:
I don't think there's actually a single tangent vector in the UE4-calculated version of this monkey that's properly merged. Will investigate further when I get home and see if I can figure out what the real solution to all this is.
But yeah, the tangent should be summed (and orthonormalised) for each vertex that shares the same properties (position, normal, UV). Looks like it's not.
I'll have a peruse through that and see if anything strange is happening.
Usually if there are that many braces in a row, there's a good chance that someone has made a mistake somewhere.
Is the FBX importer on the 4.5 release bugged? Or is this more specific to Blender and Handplane?
While we're working on a fix, if you notice shading errors in your mesh and you've baked the normal maps in Xnormal, just use the old-school synced workflow of exporting tangents from your DCC app, baking in Xnormal with those exported tangents (which Xnormal does automatically if you've exported tangents), and importing your mesh into UE4 with the "Import Normals and Tangents" option.
Unfortunately, I can't use the "fix" because MODO doesn't export tangents and binormals
I know everyone is doing their best here but if a standard cannot be reached then we seem to be pissing into the wind.
See:
All you have to do is import it as a skeletal mesh and everything works fine. Well, except for stationary and static lights and distance fields. This leads me to believe that the issue probably isn't within the ComputeTangents method itself, but perhaps somewhere a little further up the call stack. I'm going to compare the way that static and skeletal meshes are built and see if I can learn anything.
Is there a way to save smoothing group(or Maya style edge/soft edge) along with tangents in blender?
Let's say I've modeled a beveled box in Modo and I want to take it through to Unreal Engine 4, with hard edges where I have UV splits. If I import it into Blender from the File menu, I get a fully smoothed box with UVs. If I right-click the cube to make it my active object, then press Tab to enter edit mode, I'll be able to set specific edges as 'sharp.'
The fastest way to get this done after you've gone into Edit Mode with Tab is to select everything (A key), press Space to bring up the text search, type part of "Seams from Islands", and click the Seams from Islands button that comes up.
Then, deselect everything with A, press Ctrl+Tab to bring up subobject modes and click Edge (or press E).
Right-click to select an edge that was marked as a UV split (they're red), then press Shift+G to bring up a Select Similar menu. Pick Seam from that menu to select all your edges that have UV splits.
Then hit space and type "Mark Sharp" (or find the buttons for it on the toolbar to the left as I've indicated.) You'll see all your UV splits become bright green, which means that they'll be exported as hard edges.
If you're wondering why the sharp edges don't show up in the viewport, you have to go to a particular tab and check the Auto Smooth box for them to show up. But they'll be exported, and that's what matters most. Here's the box you have to check. Also make sure that smoothing angle is set to 180 degrees, so you have full control over sharp edges.
At this point you can select any edges that the previous process made sharp that you actually want to be smooth, and click the Smooth button under Edges. You can speed up the selection process by using loop select (Alt+Right Click), select shortest path (Ctrl+Right Click), box select (B, then LMB-drag to select more things, MMB-drag to select fewer things, or RMB to cancel), and circle select (C, then LMB-drag, MMB-drag, and RMB do the same things, as well as the scroll wheel which increases and decreases the size of the brush.) If you want to be able to select through your model, press Z, which toggles between wireframe and shaded modes and also has the side-effect of toggling raycast selection.
Once you've got everything smoothed the way you want it, toss a Triangulate modifier at the end of the stack and exit Edit mode if you want. This ensures that the tangent space is correctly exported and that all the bakes are correct.
Finally, export a .fbx from the file menu. Make sure that selected objects is checked, apply modifiers is checked, and tangent space is checked. Everything else should be OK out of the box (although you may want to increase the scale to 100 as well, depending on how the mesh imported from Modo. You can change the import scale in UE4 as well and it works well.)
When you take the model to UE4, make sure that you've set the importer to import normals and tangents. Otherwise, you'll get split tangents as usual.
thanks for the run down! I'm a modo user so I don't know my way around blender.
I just got a reply
"Sorry for the delay in response, I was away on vacation. I have Eric looking into this now. He will be able to help you resolve the problem.
Let me know if you need any help again.
-Alexander"
I forwarded this thread to Alexander to give to Eric, since there isn't a answerHUB thread for it other than Quack's thread.
if ((NextFaceIndex != OtherFaceIdx)
&& (RawMesh.FaceSmoothingMasks[NextFace.FaceIndex] & RawMesh.FaceSmoothingMasks[OtherFace.FaceIndex]))
So, that's that. If I export the monkey mesh with smoothing set to Edge I can still spot some tangent space splits, but everything that's off a UV split is A-OK. The exported tangent basis works OK, though, and it's a good reference for what mikktspace tangents look like. As far as I'm concerned this is probably something that I'll want to discuss with mont29, since he knows a lot more about Blender's FBX export than I do.
I've created a more minimal 2-manifold mesh that reproduces the problem. Quack's is kind of a pain to step all the way through. This one is six triangles, which is still a bear but is a bit more doable. Here's the mesh with the tangent space imported from Blender (no smoothing group data included.) This is the tangent space that a correct MikkTSpace implementation would calculate.
This is what UE4 calculates. ("Smoothing groups" in this file, and no tangent space.)
You can see that there are splits in the one where there aren't splits in the other. I'm pretty sure at this point that you were right about the split tangents having to do with UV splits not being handled correctly, so all we have to do now is step through the code with this more minimal mesh and see if we can figure out where it goes wrong.
You can download the test meshes here:
Face smoothed (import normals and no tangents to reproduce problem)
https://mega.co.nz/#!xE12iCAR!sw3tsl6HWjdLMe5-wwulCHV_DT5fzJDHuXAn3vDXzZs
Smoothing off and tangent space exported (import normals and tangents to have a reference of the correct tangent space)
https://mega.co.nz/#!FJcAnRbJ!e_A4nH1QhwcVq_wCEZxD5eQIXwTcC2s2rzLlu0UODtg
Cheers,
Jed
I think the issue probably lies in that code somewhere, though. I had a look at optimising the mesh further up the chain, but that'd only work if all of the UV maps shared the same boundaries, so I can see why it needs doing this way.
Still need to get a chance to go through the code thoroughly. Kind of annoying that a lot of the array contents aren't viewable in debug.
There are definitely still problems if you save the smoothing data, I never denied that. Should probably clarify: It's just that there are some vertices that are altogether far from a seam, and have their tangents correctly merged if the mesh has smoothing group data saved. With smoothing set to 'off' in Blender, RawMesh.FaceSmoothingMasks is set to zero throughout the mesh, which means that none of the faces get marked for tangent smoothing at all, so every vertex has split tangents. Setting smoothing to 'edge' or 'face' means that RawMesh.FaceSmoothingMasks is generally set to 1, which means that UE4 can at least think about merging the tangents (and it does, in a lot of cases, but not everywhere that it matters.)
As far as seeing array contents, I haven't really had any problems. You can see the contents of the array that has the tangents, but the problem is that the section of the code that isn't doing its job right doesn't actually touch the arrays. We need more faces that are marked with bBlendTangents = true than we have right now, and that happens in that section of code that has the ridiculous number of terminating braces that I was making fun of before.
So this is the simplest mesh I can think of that clearly shows the issue.
Going to start debugging the import process of this and see if I can figure out what's up... (once the damn thing's finished building).
Although I'm not certain about their correctness - I'm getting slightly hard seams around the UV edges and I'm not sure why yet. Even if I make those edges hard and re-bake.
Bit of a hack, I'll need to go through it a bit more carefully to see if it's actually correct.
Does anybody know if they address this issue with the update?
Yup, it's disappointing. Thanks for fixing it and submitting a pull request! hopefully the PR will work on most mesh cases.
After a couple of days working on this, I'm coming to the conclusion that it could be beneficial to integrate Mr. Mikkelsen's code that calculates MikkTSpace tangents. The methods used in ComputeTangents seem mostly OK to me, but if we do fix this particular bug with the tangent space computation on static meshes, who knows what other subtle problems will be there that are insidious and difficult to detect? It's better to use the reference implementation, in my opinion, and be sure that, if there are any defects in the tangent space computation, that at least they will be consistent with the defects that are in all the other implementations.
It's free for commercial and non-commercial use, an extremely permissive license. The only real stipulation is that if you redistribute an altered version, you mustn't solely attribute the code to Mr. Mikkelsen.
See: https://svn.blender.org/svnroot/bf-blender/trunk/blender/intern/mikktspace/mikktspace.c
https://svn.blender.org/svnroot/bf-blender/trunk/blender/intern/mikktspace/mikktspace.h
For instructions on the integration process itself, this post is helpful as a starting point:
http://coremega.tumblr.com/post/5707679685/mikktspace-for-normal-mapping
I've been working on my own integration of this for the past day or so in my free time, but I'm running into a rough patch with UnrealBuildTool and precompiled headers. Pretty sure I'm on the verge of figuring it out, though. It's really a better solution, in the long term, to integrate this rather than whatever band-aid patches Farfarer or I might come up with, for both static and skeletal meshes, although I can appreciate that you guys are constantly on a tight release schedule and don't necessarily have the time to do everything right.
Mostly trying to wrap it around the general framework that's there as I'm not really au fait with the full mesh import pipeline.
No point submitting a fix that doesn't fix everything.
See:
I want to test this further, including with some more complex and non-manifold meshes to make sure that everything works correctly with .fbx files from programs that aren't Blender and I haven't broken any other part of the pipeline. One other nice thing about my implementation is that it doesn't fail if the smoothing groups are all set to zero :> But for that testing to happen, I have to work on my desktop, and for that to happen this World Series game has to end.
https://github.com/EpicGames/UnrealEngine/pull/561
I look forward to getting this fixed as soon as possible.
I was just trying to make sure the tangents blended, bit implementing MikkTSpace itself is probably the way to go :P
Haha. Awesome job!
However, the Y/green channel used to have to be flipped and now it doesn't.
That's technically good because now it matches the +X+Y+Z output from xNormal (as it should) but skinned meshes are not using this proper MikkTSpace implementation.
So I skinned the cube I tested on to a bone and imported it as a skeletal mesh. But now it's normal map is incorrect and needs it's green channel flipping (I'm using the same material and normal map from the original cube I tested).
Might need to have either skeletal meshes use this same thing, or have the static mesh implementation work with X+Y-Z+ maps as default.
I'm not sure which is preferable for Epic. Really, they should fix all their normal maps and adopt this new version - have it done correctly - but that might piss off a lot of people :P