jmonkeyengine icon indicating copy to clipboard operation
jmonkeyengine copied to clipboard

3.2 Core profile renders some PBR materials darker than Compatibility profile

Open stephengold opened this issue 2 years ago • 24 comments

I recently discovered this issue recently in JME 3.6.0-alpha1 and created a test case. Here's how it renders with the 3.2 Core profile: Core

Here's how it renders with Compatibility profile: Compatibility

Here's the test-case java:

/**
 * Reproduces an issue where PBR materials render much darker with the Core 3.2
 * profile than with the Compatibility profile.
 *
 * <p>
 * This test also uses 4 textures (AO, Diffuse, GL Normal, and Rough), all at 2K
 * resolution in PNG format, which can be downloaded from
 * https://polyhaven.com/a/marble_01 and unpacked to the
 * src/main/resources/marble_01/textures directory.
 *
 * <p>
 * This test also uses a precomputed light probe which can be obtained from
 * https://github.com/stephengold/jme-vehicles/blob/master/MavCommon/src/main/resources/Textures/skies/moon/probe-day.j3o
 * and saved to the src/main/resources directory.
 */
public class TestIssue extends SimpleApplication {

    public static void main(String[] args) {
        boolean loadDefaults = true;
        AppSettings appSettings = new AppSettings(loadDefaults);
        appSettings.setGammaCorrection(true);
//        appSettings.setRenderer(AppSettings.LWJGL_OPENGL2); // to test Compatibility profile
        appSettings.setRenderer(AppSettings.LWJGL_OPENGL32); // to test Core 3.2 profile

        TestIssue application = new TestIssue();
        application.setSettings(appSettings);
        application.start();
    }

    @Override
    public void simpleInitApp() {
        flyCam.setDragToRotate(true);

        // Attach a 9x9 quad at the origin.
        Mesh mesh = new CenterQuad(9f, 9f);
        Geometry quad = new Geometry("quad", mesh);
        rootNode.attachChild(quad);

        // Apply a PBR material to the quad.
        String materialAssetPath = "marble_01.j3m";
        Material material = assetManager.loadMaterial(materialAssetPath);
        quad.setMaterial(material);

        // Add a LightProbe.
        String probeAssetPath = "probe-day.j3o";
        LightProbe probe = (LightProbe) assetManager.loadAsset(probeAssetPath);
        rootNode.addLight(probe);
    }
}

Here's the "marble_01.j3m" material for the test case:

Material marble_01: /Common/MatDefs/Light/PBRLighting.j3md {
    MaterialParameters {
        BaseColor: 1.4 1.4 1.4 1
        BaseColorMap: Repeat marble_01/textures/marble_01_diff_2k.png
        LightMap: Repeat marble_01/textures/marble_01_ao_2k.png
        LightMapAsAOMap: true
        Metallic: 0.01
        NormalMap: Repeat marble_01/textures/marble_01_nor_gl_2k.png
        NormalType: 1
        RoughnessMap: Repeat marble_01/textures/marble_01_rough_2k.png
    }
    AdditionalRenderState {
        FaceCull Off
    }
}

My configuration: x86_64 Mint Linux 21.1 (Ubuntu 5.15.0-57-generic) single monitor

Jan 10, 2023 11:18:25 AM com.jme3.system.JmeDesktopSystem initialize
INFO: Running on jMonkeyEngine 3.6.0-SNAPSHOT
 * Branch: master
 * Git Hash: b0bd1a5
 * Build Date: 2023-01-10
Jan 10, 2023 11:18:26 AM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFO: LWJGL 2.9.3 context running on thread jME3 Main
 * Graphics Adapter: null
 * Driver Version: null
 * Scaling Factor: 1
Jan 10, 2023 11:18:26 AM com.jme3.renderer.opengl.GLRenderer loadCapabilitiesCommon
INFO: OpenGL Renderer Information
 * Vendor: NVIDIA Corporation
 * Renderer: GeForce GT 545/PCIe/SSE2
 * OpenGL Version: 3.2.0 NVIDIA 390.157
 * GLSL Version: 1.50 NVIDIA via Cg compiler

stephengold avatar Jan 10 '23 19:01 stephengold

I reproduced this issue using JME v3.5.2-stable, so I don't consider it a regression. However, due to PR #1752, we'll soon have a lot more developers using the OpenGL 3.2 Core profile.

Further effort to characterize the issue:

  • I failed to reproduce the issue using a textureless PBR material ("jme3test/light/pbr/pbrMat.j3m")
  • I reproduced the issue without "BaseColor: 1.4 1.4 1.4 1" (deleted the line from "marble_01.j3m")
  • I reproduced the issue without "BaseColorMap"
  • I reproduced the issue without "LightMap"
  • Without "LightMapAsAOMap" the differences between profiles are more subtle: Compatibility profile renders some areas with a slight greenish cast, while 3.2 Core renders similar brightness but without the greenish cast.

stephengold avatar Jan 10 '23 20:01 stephengold

Are you using assets from test data? I can not find probe-day.j3o and textures used in marble_01.j3m.

Ali-RS avatar Jan 10 '23 20:01 Ali-RS

/**
 * This test also uses 4 textures (AO, Diffuse, GL Normal, and Rough), all at 2K
 * resolution in PNG format, which can be downloaded from
 * https://polyhaven.com/a/marble_01 and unpacked to the
 * src/main/resources/marble_01/textures directory.
 *
 * <p>
 * This test also uses a precomputed light probe which can be obtained from
 * https://github.com/stephengold/jme-vehicles/blob/master/MavCommon/src/main/resources/Textures/skies/moon/probe-day.j3o
 * and saved to the src/main/resources directory.
 */

stephengold avatar Jan 10 '23 20:01 stephengold

As far i remember i stumbled also on this when switching to core profile. Not sure and not at the pc to test but i think adding a a post processor fixed it. Without tracking the issue further down and without checking the specs i kind of assumed additive blending is not allowed in core profile on the 0 framebuffer. imho not an issue since most games beside test projects use a postprocessor and in a hdr pipeline it is kind of required.

As a note. All scenes with multiple lights render also wrong without fpp (core profile only)

zzuegg avatar Jan 10 '23 20:01 zzuegg

Downloaded texture from the said URL but there were no marble_01_ao_2k.png in there so I removed LightMap param from the material file also except marble_01_disp_2k.png the others were not in png format so I converted them to png using gimp.

In my case, the output is the same in both LWJGL_OPENGL2 and LWJGL_OPENGL32.

Screenshot_2023-01-11_00-41-26

Ali-RS avatar Jan 10 '23 21:01 Ali-RS

Can you please also try TestPBRLighting with both core and compatibility profiles?

Ali-RS avatar Jan 10 '23 21:01 Ali-RS

Downloaded texture from the said URL but there were no marble_01_ao_2k.png

Sorry! Poly Haven uses a fancy download interface which requires you to specify the textures/formats you want. In the right sidebar, specify 2K resolution and ZIP archive, then open the hamburger menu button and tick the checkboxes for the 4 textures in PNG format.

stephengold avatar Jan 10 '23 22:01 stephengold

Can you please also try TestPBRLighting with both core and compatibility profiles?

I tried this and didn't see any difference between the 2 profiles.

stephengold avatar Jan 10 '23 22:01 stephengold

Sorry! Poly Haven uses a fancy download interface which requires you to specify the textures/formats you want. In the right sidebar, specify 2K resolution and ZIP archive, then open the hamburger menu button and tick the checkboxes for the 4 textures in PNG format.

Ok, grabbed the textures as you explained above.

In my case, the output is still the same in both profiles. They both look dark.

Ali-RS avatar Jan 11 '23 07:01 Ali-RS

In my case, the output is still the same in both profiles. They both look dark. Not what I expected!

I continue to investigate...

  • I reproduced the issue without "Metallic"
  • I failed to reproduce the issue without "NormalMap"
  • I reproduced the issue without "NormalType"
  • Without "RoughnessMap", the differences between profiles are increased: 3.2 Core renders even darker than with the original material parameters.
  • I reproduced the issue without "AdditionalRenderState"

On my system, the following J3M file is sufficient to reproduce the issue:

Material TestIssue1903: Common/MatDefs/Light/PBRLighting.j3md {
    MaterialParameters {
        Metallic: 0.01
        NormalMap: Repeat marble_01/textures/marble_01_nor_gl_2k.png
    }
}

1903sidebyside

Increasing "Metallic" reduces the difference between the render output of the 2 profiles. I therefore suspect that the issue is connected with how PBR uses normals in non-metallic materials.

stephengold avatar Jan 11 '23 20:01 stephengold

I cant reproduce this. Could you test if this happens with other light types then a light probe too?

Actually since you mentioned it. If increasing metallic reduces the issue it might be a mipmap issue.

zzuegg avatar Jan 11 '23 21:01 zzuegg

Random thought... this reminds me of the cases where things that the material requires are left unset. Then it becomes up to the specific graphics card + driver to decide what values to stick there (or leave garbage or whatever). Like leaving a tangent buffer out when using normal maps will look odd but work on some cards and be totally black on others.

I haven't been following closely enough to know if that's the case in these examples.

pspeed42 avatar Jan 11 '23 21:01 pspeed42

I reproduced the issue using a texture and light probe from jme3-testdata. For convenience, I've committed the simplified test to the "master" branch of the project repo.

Note that these tests rely on AppSettings configured in main(). Therefore they shouldn't be run from the jme3-examples TestChooser!

stephengold avatar Jan 11 '23 21:01 stephengold

Could you test if this happens with other light types then a light probe too?

For PBR, a light probe is required. I discovered the issue using Probe+Ambient+Direct.

stephengold avatar Jan 11 '23 21:01 stephengold

The probe is not required to render. If rendering without a probe works as expected it would rule out all framebuffer/srgb/normals/tangent related stuff. It would come down to the access/upload/format of the specularEnvMap.

I have access to other computer at the weekend, intry to reproduce then and launch the debugger

zzuegg avatar Jan 12 '23 07:01 zzuegg

For convenience, I've committed the simplified test to the "master" branch of the project repo.

My result

compatibility-vs-core-profile

As mentioned by pspeed42, might be a graphics card + driver issue.

Ali-RS avatar Jan 12 '23 12:01 Ali-RS

To test whether the issue is hardware-, system-, or driver-dependent, I ran the tests on my Windows 11 laptop with GeForce RTX 2070 and LWJGL v3. (All my previous test were with Mint Linux and a GeForce GT 545.)

I reproduced it with ease: image

@zzuegg please provide screenshots for comparison.

stephengold avatar Jan 13 '23 01:01 stephengold

The probe is not required to render. If rendering without a probe works as expected it would rule out all framebuffer/srgb/normals/tangent related stuff. It would come down to the access/upload/format of the specularEnvMap.

When I replaced the probe with an AmbientLight, both renders were solid black, as I expected.

stephengold avatar Jan 13 '23 02:01 stephengold

Yeah. AmbientLight is the only one not working. Not sure if intentional or not since that one should be replaced by the light probe. However the code is in there guarded by a define. i test and report back today evening.

Notes: (mostly to myself for the testing) a possible reason could also be the use of gl_FragColor. Following the specs it should not be availabe in a core profile Especially when reading from FragColor. I remember having the same issue when not using a floating point render targert when switching to gl4 core profile. (only wih jme shaders, my own rendered the same)

zzuegg avatar Jan 13 '23 08:01 zzuegg

It occurred to me that there's a commonality between my Windows 11 laptop and my Mint Linux desktop: both have NVDIA graphics adapters.

@zzuegg and @Ali-RS, what brand(s) of graphics adapter did you test?

stephengold avatar Jan 13 '23 09:01 stephengold

what brand(s) of graphics adapter did you test?

Advanced Micro Devices, Inc. [AMD/ATI] Robson CE [Radeon HD 6370M/7370M]

and

Intel Corporation 2nd Generation Core Processor Family Integrated Graphics

Ali-RS avatar Jan 13 '23 10:01 Ali-RS

Seems again that the issue comes down to nvidia+windows beeing the worst programming environment. The nividia driver somehow managed in compat mode to work around missing tangents.

If you add: MikktspaceTangentGenerator.generate(quad);

The results are bright as they should be.

zzuegg avatar Jan 13 '23 11:01 zzuegg

From me above: "Random thought... this reminds me of the cases where things that the material requires are left unset. Then it becomes up to the specific graphics card + driver to decide what values to stick there (or leave garbage or whatever). Like leaving a tangent buffer out when using normal maps will look odd but work on some cards and be totally black on others."

nVidia is really nice to program on in one respect because it will take anything you throw at it and "just work". Nice for prototyping and they are great performers even outside of the "one path that most games use". Great solid cards, in general.

But yeah, when you want to deploy on something else then you better not be testing in compatibility mode anymore.

re: Tangents, I think nvidia initializes missing tangent buffers to 1,0,0 or something while other cards just leave it at 0,0,0. So tangents will look like they work from certain directions. It's been a long time, though.

pspeed42 avatar Jan 13 '23 13:01 pspeed42

If you add: MikktspaceTangentGenerator.generate(quad); The results are bright as they should be.

Indeed they are. Thank you, @zzuegg and @pspeed42!

I hadn't realized tangents were required for PBR.

Is there anything more to be done here? Perhaps:

  • documentation in the Wiki that tangents are required for PBR, or
  • a diagnostic message when tangents are not provided for PBR, or
  • a better default for tangents?

stephengold avatar Jan 13 '23 18:01 stephengold