-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Fix for Inverted Y Component on Gltf Normal Map Loading #2120
base: master
Are you sure you want to change the base?
Conversation
I guess the documentation in Changing the semantics of the "NormalType" material parameter would've been easy in 2014. Changing it now would be painful. I propose changing the PBRLighting documentation instead. The change could even be included in this PR, since there's a clear connection between the jme3-plugins defect and the documentation error. |
The problem is in MikktspaceTangentGenerator, test this package jme3test.model;
import com.jme3.app.*;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.*;
import com.jme3.scene.plugins.gltf.GltfModelKey;
import com.jme3.system.AppSettings;
import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
public class TestGltfNormal extends SimpleApplication {
Node probeNode;
public static void main(String[] args) {
AppSettings sett = new AppSettings(true);
sett.setWidth(1024);
sett.setHeight(768);
TestGltfNormal app = new TestGltfNormal();
app.setSettings(sett);
app.start();
}
@Override
public void simpleInitApp() {
rootNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
probeNode = (Node) assetManager.loadModel("Scenes/defaultProbe.j3o");
rootNode.attachChild(probeNode);
setPauseOnLostFocus(false);
flyCam.setEnabled(false);
viewPort.setBackgroundColor(new ColorRGBA().setAsSrgb(0.2f, 0.2f, 0.2f, 1.0f));
loadModel("jme3test/gltf/NormalTangentMirrorTest.glb", new Vector3f(0, 0, 0), 3);
}
private void loadModel(String path, Vector3f offset, float scale) {
GltfModelKey k = new GltfModelKey(path);
Spatial s = assetManager.loadModel(k);
s.scale(scale);
s.move(offset);
// MikktspaceTangentGenerator.generate(s);
probeNode.attachChild(s);
}
} GLB file: https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/NormalTangentMirrorTest/glTF-Binary/NormalTangentMirrorTest.glb This is caused by the sign of the bitangent (line 282 in MikktspaceTangentGenerator)
replacing it with
Solves the issue. I suspect this is affecting a lot more than the PBR shader, for example if we look into SPLighting that doesn't have the normal type parameter, it says
but blender uses OpenGL Y+ format, see: I suspect there was a misunderstanding, because the original jme tangent generator also had mismatched handedness, so in this case flipping the flipped sign results in correct representation of OpenGL Y+ normals and this ported to the mikkstspace generator that suffers the same issue, however what happens to imported models with Y+ normals and pregenerated tangents that use SP lighting? I supposed they will have flipped normals like in the gltf test. So, maybe we should attempt an engine wide fix for all the shaders and tangents generators and restandardize the default format to be Y+ for all the engine code. |
If someone has the time to convert the GLTF test into different formats, including both pregenerated and non-pregenerated tangents, and SP lighting, we could determine the extent of this bug. |
Ok, I'll take a crack at it. |
Finally got around to it... sorry for the delay! I've tested GLTF, J3O, and OBJ formats, with both pregenerated and non-pregenerated tangents, with each material configuration (packed pbr, runtime pbr, runtime sp), with runtime tangent generators on and off. J3O was tested when converted from both GLTF and OBJ. Results are not shown, because J3O mimicked its source format on all tests. GLTFPacked PBRLighting MaterialNo Pre-Generated Tangents
With Pre-Generated Tangents
PBRLighting Material Created at RuntimeNo Pre-Generated Tangents
With Pre-Generated Tangents
Lighting MultiPass Material Created at RuntimeNo Pre-Generated Tangents
With Pre-Generated tangents
Lighting SinglePass Material Created at RuntimeNo Pre-Generated Tangents
With Pre-Generated tangents
OBJ (no pre-generated tangents available)PBRLighting Material Created at Runtime
Lighting MultiPass Material Created at Runtime
Lighting SinglePass Material Created at Runtime
|
When you create the PBR material at runtime, do you set opengl format?
I think this shows that SP Lighting requires directx normals, what do you think? |
smh, I've made a mistake. That SPLighting data is actually for Lighting.j3md multipass. I've updated the above post to include single pass data (coincidentally, it matches the multipass data).
I did minimal setup for materials created at runtime, so no. I've pushed the test class, so you can see how I set it up.
Hmm, that seems likely. |
Thank you, i've looked into your examples, and made some considerations and some tests of my own. My current understanding of the situation:
This issue shows different symptoms depending on the mix of normal types, textures, and bitangents. It can be tricky to spot because some combinations actually work correctly, which is likely why it went unnoticed. Anyway, here's a summary:
*Actual type of the input NormalMap required to have correct results Please, anyone interested, take a look at my findings and let me know if I've missed anything. Here's my plan for the patch:
This change might create a minor backward incompatibility. SP and MP lighting shaders have an implicit normal type, which might have misled developers using these shaders along with the JME tangent generator: they might have thought the shader required an OpenGL-type normal map because a (correct) DirectX normal map would appear flipped due to the bug mentioned earlier. However, this change addresses a more significant issue: developers using the PBR shader and relying on the specified normal type would have encountered incorrect normal maps if they were using one of the JME tangent generators and this is likely to go mostly unnoticed, especially with complex textures. |
Patch here: #2140 It is left to check if the tangents imported from other formats (eg. ogre) have the correct sign or if they need to be flipped by the loader. |
I don't have a deep understanding of tangent conventions, but everything I've seen so far is consistent with |
This PR fixes #2098 by setting the normal type to -1 instead of 1 during gltf import. Since gltf goes by OpenGL's normal map convention, and PBRLighting.j3md defines 1=OpenGL and -1=DirectX, something is clearly wrong here.
See this forum post for more info.