-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support stored vertex 'tangent' attribute #15749
Conversation
@mrdoob This is excellent, and it can be merged, IMO. |
To be addressed in a later PR: I don't like this terminology, though: vertexTangents = THREE.AutoTangents;
// or
vertexTangents = THREE.VertexTangents; I have not heard of the term "auto tangents" used in this regard. I never liked this, either, for that matter: vertexColors = THREE.VertexColors; // ugh If it wasn't for Legacy vertexTangents = true; // default false
vertexColors = true; // default false Or, an alternate property name: attributeTangents = true; // default false That being said, we could take another approach and use vertex tangents automatically if they are present as a buffer geometry attribute. Likewise for vertex colors.
|
The downside here is that a single material can be reused where the renderer will have to compile two materials. There is a nice simplicity in the explicit 1:1 mapping. If we’re planning to drop support for rendering Geometry (#15514) then we may as well remove the Material property for FaceColors, and just have:
|
@stephenhurleyjpl do you have other examples that we should test here, or would you be able to test them? :) |
Just for clarity: The change only affects |
Agreed. Lets set |
e30bbad
to
0b3150d
Compare
Updated so that
That's correct. MeshLambertMaterial isn't supported because it computes lighting per-vertex. MeshPhongMaterial could be supported, but (unless we still have code somewhere to compute tangents on the CPU?) I'm not sure how it much would be used, since GLTFLoader does not create Phong materials. I'm also not sure whether we want more advanced options like this on the Phong model. Any preference? |
Is that statement true? Phong is sharing the same shader chunks...
We should not be computing tangents for the user, I would think. Are you saying we have no way of loading tangents with any loader other than glTF?
I don't think it is necessary. // What about three.js tangent support for grayscale bump maps? Or is there such a thing? glTF does not support bump maps, of course. |
Maybe the |
Thanks! |
There are more places I'd need to patch the Phong shader, but it would be a small addition if we decide we want it.
An FBX file can contain tangents, but FBXLoader doesn't use them. Note that FBXLoader always creates Phong or Lambert materials. I don't know how many other formats support tangents, but would be surprised if our other loaders were doing anything with them.
I don't think there is such a thing... a 'tangent space bump map' wouldn't make sense to me, but I'm open to suggestions. 😅 |
In practice it always creates Phong materials. Lambert should be supported by FBX but I haven't found or been able to create any models with Lambert materials. At least the Maya and 3DS Max exporters support computing tangents and binormals at export time. However, Maya and Max use different bases for the tangent space and apparently export their own basis directly to FBX so supporting that would add an extra layer of complexity. |
So previously, three.js did not honor attribute tangents at all. Now it does in some cases. @donmccurdy and @looeee If you could provide a clear statement as to when and where attribute tangents are now supported, I think that would be beneficial. I think it would also be useful to state where they are not supported. Obviously, if loaders do not support tangents, that makes their use difficult.
BTW, we used to have |
glTF advises that MikkTSpace should be used to compute tangents when they are not provided in the model. I don’t think there is any requirement that stored tangents be calculated that way. The problem would be if the model did not have tangents, and we didn’t know how the normal map was created. If it doesn’t already, one option would be to ensure BufferGeometryUtils.computeTangents uses MikkTSpace — That is the standard these days. |
Also - the bitangent is always the cross product of the normal and tangent. Whatever Maya and Max are doing, that should remain true. At most the loader might have to flip the .w component? |
Right. And for that reason, I do not think three.js should be in the tangent-creation business. I would prefer to remove
I don't think a loader should do that -- an exporter, may have to, though. |
OK. Regarding the FBXLoader, tangents are currently ignored, but it should be possible to add support. However, given the complexity, unless we have a clear use case I'm not sure how useful it is to do so.
Yes. I mentioned binormals/bitangents just because it seems that there's no way to export tangents without bitangents being exported too. Converting between bases should be trivial, it's knowing when to do the conversion that may be problematic. Also, from this article on the Blender wiki it seems like it might not be as simple as that, as tangent space normal maps are tied into the basis being used, so converting the basis will result in the tangent space normal map being read incorrectly. From the article:
That might make it simpler though, as we would not have to do any conversion of basis and just load the tangents as is from the file. @donmccurdy are tangents in glTF models always in MikkTSpace? Or are you just assuming that the tangents loaded match the tangent space normal map that comes with the file? |
glTF specification states that if the tangents are not defined but needed, then they should be generated using the MikkTSpace algorithm. That is, as long as the gltf primitive contains tangents, the tangents can be generated with an arbitrary algorithm, but if the tangents are not explicitly defined but they are needed (e.g. because of an existing normal-map) than they need to be generated by the MikkTSpace algorithm. I would argue that the loader should do that. |
@donmccurdy I have tested today the
|
The loader should load the model, not modify it. I disagree with the glTF spec if it implies otherwise. |
@donmccurdy More test ideas... Did you test both |
@Mugen87 that example contains tangents but no normal map. That seems pretty pointless, but I suppose the loader should leave the tangents intact, e.g. in case the user adds normals later. We'll want another
A normal map is meaningless without a tangent space, and it has to be created – that we can do so in the fragment shader is just a nice convenience. The glTF spec must give some recommendation for the sake of consistency, and recommends that if the model is missing tangents, MikkTSpace is the preferred way to generate them. MikkTSpace is supported by UE4, Unity, Substance Painter, Xnormal, Blender, Toolbag, Modo, etc. — it's a robust choice, and since some of those tools do not write tangents, using MikkTSpace (or having a method for users to generate MikkTSpace tangents themselves) is necessary for correct results. However, for now it's a moot point. I'm not aware that any JS implementation of MikkTSpace exists, and I don't think it can be done in the shader. If someone wanted to try a JS or WASM port of the native code, there would be uses for that. But even then, the amount of added code is significant (~2000 LOC)... it is probably better left to the user to do this. Also, according to this thread I think Maya's FBX tangents should be supported by this change. 3DS Max maybe not, and I don't know how we tell the difference from a given FBX file. You can see why glTF wanted to recommend MikkTSpace. 😅
Hm, yeah that's no good. My changes to |
@donmccurdy The shader must use the same tangent space that was used to generate the normal map. If tangents are missing in the model, then the model is incomplete. It is not the job of the loader to fix it. That's my opinion, anyway. That being said, I know I am fighting a losing battle here. Sooo, I'll drop it... :-) |
Sidenote: The mentioned warning also pops up in one of the examples: https://raw.githack.com/mrdoob/three.js/dev/examples/webgl_postprocessing_unreal_bloom.html |
Quote @WestLangley :
I think rendering Points and Lines or Points and Meshes from the same geometry is a nice feature. Or Meshes with vertex colors and Meshes with other shading. How about (Ideally, geometries should in my opinion have independent properties for each supported type of index. Not something which would be used often, perhaps, but it could for instance be a way to render a line-based wireframe and a shaded mesh from the same geometry.) |
@EliasHasle I don't think I understand how |
@donmccurdy I just thought the presence of attributes would by default enable the usage of them in the material, but that the |
There's a conflict between automatically enabling features that affect shader compilation, and not automatically creating more shader programs than the user expects. Currently there's a 1:1 relationship here – 1 Material compiles to 1 shader program — and this makes performance optimization easier. Supporting |
Fixes #15692, fixes #15428.
Changes:
Here's the effect on some example glTF files we've had normal-related issues with in the past:
Row 2 (flat normal map) looks a bit less "flat shaded" than I'd like. I'm not sure why, but it's certainly closer to the goal.
Row 3 (normalTangentTest) shows a regression because the model doesn't have tangents. By removing
normalScale.y *= -1
from GLTFLoader, I've broken that case. But row 4 (similar model, with tangents) appears correctly, and keepingnormalScale.y *= -1
would break it. I've never understood thaty *= -1
hack, and so I'm inclined to remove it, but we could also apply it only to models that don't have tangents.