-
-
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
Removal of Tangents code? #7094
Comments
Clara.io uses the tangents, although I had to modify them a bit. I use then to do anisotropic (non-circular) highlights: https://clara.io/view/4faca36d-d9aa-4b1b-b9a2-dfa8d6bc978b Details: https://en.wikipedia.org/wiki/Specular_highlight#Ward_anisotropic_distribution I did try to implement anisotropic reflection without tangents but I could never get great results. Now I am not 100% sure I can not get the same results with just UV derivatives, but I couldn't manage it and I tried a fair bit. The main issue I believe I ran into is that the UV derivatives are constant within a face and change abrutly when you switch to a difference face -- because they are derived from the UV interpolation across each face. Tangents are interpolated from the vertices, thus they vary smoothly across faces, thus you can get continuous results across faces. You do not notice the abrupt change of UV derivates with bump and normal map because you are not looking at the tangent/binormal directly as you are with an anisotropic highlight, rather just the normal. /ping @WestLangley: Your math expertise may be useful here. |
I assume you're using I'm just trying to simplify/reduce the code we have to maintain. |
I am fine removing it from core. Actually we did end up are generating tangents explicitly within Clara.io and storing them in our mesh data files, very similar to how explicit UV maps are handled. So we are already doing a fully out of ThreeJS core solution for tangents, although it is based on the tangent code in ThreeJS -- so thank you! |
Ended up moving |
Aaaand... we're back at 99kb gzipped 😁 |
Yikes! I agree that tangent computation should be at the application/modeling level. Moving It was also OK to remove from the library and examples the shaders that rely on attribute tangents. But you also removed all tangent support from the library. I would not do that. I would continue to support users who have attribute tangents in their geometry. |
Oh, I left one. |
In the IRC someone is saying that they were relying on |
As I said
I would suggest we add vertex texture and displacement map support to Do any vertex texture examples remain? |
That sounds good to me!
Hmm... |
As per things to keep... Maybe we can keep |
It would seem to me that any loader that supports tangents should continue to do so. Also, the pipeline from IMO, those two are important. You can move the |
I'd prefer to still be able to specify tangents and have them communicated to shaders. But everything but basic support can be moved to examples. Radical idea - if we want to be space efficient why don't we demo |
@bhouston that's the long term goal 😀 I suspect that someone that knows what tangents are is unlikely to be using THREE.Geometry... |
Ok, implemented displacementMap. I think this is the first time I hack the shader chunk stuff. What a mess... 😅 I'm not updating the normals though, I think that would require sampling the neighbour pixels in the texture to find the slope. And for that I would also need the dimensions of the texture... |
So did I in #7107. Hmmm... |
Is this still something we'd want in core three.js? For example: geometry.setAttribute( 'tangent', tangentAttribute );
material.vertexTangents = true;
var mesh = new THREE.Mesh( geometry, material ); |
@donmccurdy To the best of my knowledge, there has not been any demand for tangent support in three.js in years. three.js does not require them, and internal support for tangents has been removed. So, in spite of what I wrote in 2015, I would not worry about it at this point. |
With the current code, is there a way to invert Maybe something like... mapN.xy = mapN.xy * normalScale * normalize( vUV.st ); https://threejs.org/examples/webgl_loader_gltf.html Notice how the right side of the helmet has the normalMap inverted due to the texture being mirrored. |
@mrdoob This is definitely a normal map issue. I would think that Also see this comment -- and in fact, the entire thread. |
Actually, that code is stupid. Sorry about that 😅 |
Just confirmed that re-introducing tangent support fixes the DamagedHelmet model:
Longer discussion in KhronosGroup/glTF-Sample-Models#149. (also requires updating to a version of the model that uses tangents) |
@donmccurdy This is a pretty minor issue and does not require tangents to be calculated, you are going about it in the wrong way. I'll post it on the glTF issue as well. This issue can be quickly fixed in the calculation of the normal map tangent space because it is possible to detected mirrored faces by comparing the specified normal with the tangent space normal. Just update normalmap_pars_fragments.glsl with this code and it probably will be fixed:
|
Thank you @bhouston! Yes, that fixes the issue and is a much easier solution than I attempted. 😅 |
@donmccurdy The DamagedHelmet model is mirrored. This means that the winding order of the uvs are clockwise on one half and counterclockwise on the other half. This means that the problem can not be fixed be setting I'll file a PR to fix this. @bhouston Our exiting code is based on this paper, which states.
That statement is not true. If you scale a vector and then normalize it, the direction of the vector changes if the scale is negative. Consequently, our code is buggy. There are better solutions to this problem. I'll pick one and file a PR. |
Huh? Normalizing a vector does not change its direction. ? |
@WestLangley please try my solution it is actually very robust and correct. |
@WestLangley I do not have a reference for my solution, I just derived it but I am pretty confident in it. |
@bhouston These vectors are different. new THREE.Vector3( 10, 0, 0 ).multiplyScalar( - 1 ).normalize();
new THREE.Vector3( 10, 0, 0 ).normalize(); You can't drop the scale factor. A modification to our existing code that I believe works is simply honoring (at least the sign of) the scale factor: vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {
// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988
vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );
vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );
vec2 st0 = dFdx( vUv.st );
vec2 st1 = dFdy( vUv.st );
float denom = sign( st1.t * st0.s - st0.t * st1.s ); // we do not care about the magnitude
vec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) / denom );
vec3 T = normalize( ( -q0 * st1.s + q1 * st0.s ) / denom );
vec3 N = normalize( surf_norm );
vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
mapN.xy = normalScale * mapN.xy;
mat3 tsn = mat3( S, T, N );
return normalize( tsn * mapN );
} There is another approach described here. |
@WestLangley I do not understand your argument. I am pretty sure in the end if your solution works correct it is mathematically equivalent to what I am proposing. I am fine if you want to use your solution instead of mine, I'm not picky, let's just fix it. |
@WestLangley I am confused that you are not comparing the st1/st0 result in denom to the surf_norm/N. That was sort of key to my approach. I think your approach is not equivalent. |
@bhouston I do not care whose solution we use. I prefer to pick the solution that is most performant. You probably have a better feel for that than I do. I am simply implementing the code in the paper, but I am not ignoring the scale term because it is incorrect to ignore it. |
@WestLangley, in the normalmap code, which scale factor am I ignoring in my proposed changes: All I am proposing is to add this code that flips the U and V direction vectors when I detect its implied normal doesn't match up with the explicitly given normal. This situation happens in the case of mirrored faces, the UVs are backwards but someone has got the normal pointing forwards:
It is a pretty simple fix. This fix is a cross + dot + if test. It is pretty minor. |
@bhouston YOU are not ignoring a scale term. The reference from which our code is based is ignoring a scale term. All I did was reintroduce the scale term. It is very simple. I have not passed judgement on your proposal at all. I just presented the solution I discovered last week. |
Does it work equivalently? Does it fix the mirror case? I could imagine that the signs may represent whether it is facing the camera. Thus it may work. If you want it performance, just multiply the sign rather than dividing it. I think that divide is slow. |
Both proposals do fix the mirror case above. |
Let's go with @WestLangley solution but with muls instead of divides, it is mathematically equivalent. |
There is another approach that uses cotangent frames that we could try if you want. I linked to that above. There is a fourth approach used by khronos here. I was in the process of trying to determine the advantages/disadvantages of the various approaches last week, but we can just pick one. I was mostly just curious... :) |
OK. Going with one solution now, rather than pursuing this further. For the record, our approach does not guarantee an orthonormal TBN matrix. Other approaches, do. Apparently it doesn't matter that much... Thank you @bhouston for your solution, and @donmccurdy for your input. |
Guaranteeing an orthonormal matrix can introduce issues because it is basically a per pixel orthonormal matrix correction and that correction may not always be applied in a way that leads to continuity of the orthonormal matrix across adjacent pixels. |
@bhouston Interesting... thanks! |
Now that bump/normalmaps are using derivatives I wonder if we need the tangents code (
Geometry.computeTangents
andBufferGeometry.computeTangents
) any longer.These are the only examples that rely on it:
webgl_materials_normaldisplacementmap
Uses NormalDisplacementShader.js, which I don't know if we should still maintain
webgl_materials_bumpmap_skin
I think it's not needed on this one, but it's currently broken
webgl_terrain_dynamic
easy to port to derivatives I think
Does anyone rely on this code? And if so, what's the use case?
The text was updated successfully, but these errors were encountered: