Specular/Glossiness PBR Material Blurs When Normal Map Is Added

I’m encountering an issue with the Specular/Glossiness PBR material in JME3. When I use it without a normal map, my textures (BaseColorMap, specular, glossiness) appear as expected. However, as soon as I add a normal map texture, the other textures seem to become blurred or distorted.

This issue does not occur when I use the Metallic/Roughness PBR workflow; the normal map works correctly in that case.

Here’s a simplified example to reproduce the problem:

package gamecollectiontester;

import com.jme3.app.SimpleApplication;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.material.Materials;
import com.jme3.material.TechniqueDef.LightMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
import com.jme3.texture.Texture;

public class AnimePBRDemo extends SimpleApplication {

    public static void main(String[] args) {
        AnimePBRDemo app = new AnimePBRDemo();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        // Create box
        Box box = new Box(1, 1, 1);
        Geometry boxGeo = new Geometry("SpecGloss Box", box);
        viewPort.setBackgroundColor(ColorRGBA.Cyan);

        // Load material
        Material mat = new Material(assetManager, Materials.PBR);

        // Set required parameters
        mat.setBoolean("UseSpecGloss", true);
        mat.setTexture("BaseColorMap", assetManager.loadTexture("/Textures/cartoon_wood_base_color.png"));
        mat.setTexture("SpecularMap", assetManager.loadTexture("/Textures/cartoon_wood_specular.png"));
        mat.setTexture("GlossinessMap", assetManager.loadTexture("/Textures/cartoon_wood_gloss.png"));
        // The problem occurs when this line is uncommented:
        mat.setTexture("NormalMap", assetManager.loadTexture("/Textures/cartoon_wood_normal.png"));

        // Apply material
        boxGeo.setMaterial(mat);
        rootNode.attachChild(boxGeo);

        // Lighting
        setUpLighting();
        setUpPbrProbe();
    }

    private void setUpLighting() {
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(-0.5f, -0.5f, -0.5f).normalizeLocal());
        sun.setColor(ColorRGBA.White.mult(1.5f));
        rootNode.addLight(sun);
    }
    private void setUpPbrProbe() {

        ModelKey Key = new ModelKey("/LightProbes/Sky_Cloudy.j3o");
        Node scene = (Node) getAssetManager().loadModel(Key);
        LightProbe lightProbe = (LightProbe) scene.getLocalLightList().get(0);
        lightProbe.setName("Default LightProbe");
        lightProbe.setPosition(new Vector3f());
        lightProbe.getArea().setRadius(10000);
        getRootNode().addLight(lightProbe);
        getRenderManager().setPreferredLightMode(LightMode.SinglePassAndImageBased);
    }
}

Additional Information:

  • JME version: 3.7.0-stable
  • Operating System: Windows 10
  • Video Card: Intel(R) UHD Graphics 630
  • Driver Version: 31.0.101.2115
WARNING: JmeDialogsFactory implementation not found.
مايو ??, ???? ??:??:?? ص com.jme3.system.JmeDesktopSystem initialize
INFO: Running on jMonkeyEngine 3.7.0-stable
 * Branch: HEAD
 * Git Hash: bc6cdf5
 * Build Date: 2024-10-21
مايو ??, ???? ??:??:?? ص com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFO: LWJGL 3.3.3+5 context running on thread jME3 Main
 * Graphics Adapter: GLFW 3.4.0 Win32 WGL Null EGL OSMesa VisualC DLL
مايو ??, ???? ??:??:?? ص com.jme3.renderer.opengl.GLRenderer loadCapabilitiesCommon
INFO: OpenGL Renderer Information
 * Vendor: Intel
 * Renderer: Intel(R) UHD Graphics 630
 * OpenGL Version: 3.2.0 - Build 31.0.101.2115
 * GLSL Version: 1.50 - Build 31.0.101.2115
 * Profile: Core
مايو ??, ???? ??:??:?? ص com.jme3.renderer.opengl.GLRenderer setMainFrameBufferSrgb
WARNING: Driver claims that default framebuffer is not sRGB capable. Enabling anyway.
مايو ??, ???? ??:??:?? ص com.jme3.asset.AssetConfig loadText
WARNING: Cannot find loader com.jme3.audio.plugins.OGGLoader
مايو ??, ???? ??:??:?? ص com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFO: Audio Renderer Information
 * Device: OpenAL Soft
 * Vendor: OpenAL Community
 * Renderer: OpenAL Soft
 * Version: 1.1 ALSOFT 1.23.1
 * Supported channels: ??
 * ALC extensions: ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF ALC_SOFT_loopback ALC_SOFT_loopback_bformat ALC_SOFT_output_limiter ALC_SOFT_output_mode ALC_SOFT_pause_device ALC_SOFT_reopen_device
 * AL extensions: AL_EXT_ALAW AL_EXT_BFORMAT AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model AL_EXT_SOURCE_RADIUS AL_EXT_STATIC_BUFFER AL_EXT_STEREO_ANGLES AL_LOKI_quadriphonic AL_SOFT_bformat_ex AL_SOFTX_bformat_hoa AL_SOFT_block_alignment AL_SOFT_buffer_length_query AL_SOFT_callback_buffer AL_SOFTX_convolution_reverb AL_SOFT_deferred_updates AL_SOFT_direct_channels AL_SOFT_direct_channels_remix AL_SOFT_effect_target AL_SOFT_events AL_SOFT_gain_clamp_ex AL_SOFTX_hold_on_disconnect AL_SOFT_loop_points AL_SOFTX_map_buffer AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length AL_SOFT_source_resampler AL_SOFT_source_spatialize AL_SOFT_source_start_delay AL_SOFT_UHJ AL_SOFT_UHJ_ex
مايو ??, ???? ??:??:?? ص com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFO: Audio effect extension version: ?.?"

I have verified that the texture paths are correct and the textures themselves are valid. I’m not sure if this is a bug in the JME3 shader, an incorrect material setting on my part, or something else. Any help would be greatly appreciated!

PBR Metallic Roughness Pipeline with normal Map

PBR Specular Glossiness Pipeline with normal Map

PBR Specular Glossiness Pipeline without normal Map