Shadow maybe failed in GLES2 and AppSetting failed to choose GL version

First thing first, to save your time:

  1. There may be a bug in Lighting-Shadow with GLES2.
  2. AppSetting.setRenderer() failed to work.
  3. Android Studio Emulator should treated carefully in setting—>advanced—>ES api level

After resolved this problem, I experienced several new weirder issues.

With Unshaded.j3md it is ok, when changed to use Light with ShadowRenderer it failed on api 21 and passed on api 31.

INFO OpenGL Renderer Information
 * Vendor: Google (ATI Technologies Inc.)
 * Renderer: Android Emulator OpenGL ES Translator (AMD Radeon(TM) Vega 8 Graphics )
 * OpenGL Version: OpenGL ES 2.0 (4.5.0 Core Profile Context 22.20.27.07.221020)
 * GLSL Version: OpenGL ES GLSL ES 1.0.17
 * Profile: Compatibility
WARNING Cannot find loader com.jme3.cursors.plugins.CursorLoader    <------?
WARNING Cannot find loader com.jme3.audio.plugins.OGGLoader         <------?

SEVERE Exception thrown in Thread[GLThread 157,5,main]
java.lang.IllegalStateException: Framebuffer has erroneous attachment.
	at com.jme3.renderer.opengl.GLRenderer.checkFrameBufferError(GLRenderer.java:1823)
	at com.jme3.renderer.opengl.GLRenderer.updateFrameBuffer(GLRenderer.java:1996)
	at com.jme3.renderer.opengl.GLRenderer.setFrameBuffer(GLRenderer.java:2127)
	at com.jme3.shadow.AbstractShadowRenderer.renderShadowMap(AbstractShadowRenderer.java:444)
	at com.jme3.shadow.AbstractShadowRenderer.postQueue(AbstractShadowRenderer.java:422)
	at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:1216)
	at com.jme3.renderer.RenderManager.render(RenderManager.java:1287)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:278)
	at com.jme3.app.AndroidHarness.update(AndroidHarness.java:505)
	at com.jme3.system.android.OGLESContext.onDrawFrame(OGLESContext.java:365)
	at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1522)
	at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1239)
eglMakeCurrent: 0x7f4a9ec3e200: ver 2 0 (tinfo 0x7f4a9ec2c180)

api 31 succesfully init, but looks darker and there is no shadow at all!

Then, I tried to change Android Studio Emulator settings, setting—>advanced—>ES api level from ‘autoselect’ to ‘renderer maximum’. Now, everything is fine.
So,
There may be a bug in Lighting-Shadow with GL2.
Android Studio Emulator should treated carefully.

=====parting line====

But
As a monkey of monkeys I am always want to know …WHY!? :thinking:
So, another 3 hour spend. :rofl:
Program never changed, so it may be GL related. To figure out the exact GL version our shader is running on, I decided to use a custom material.
.j3me

Technique {
        VertexShader  GLSL430 GLSL420 GLSL410 GLSL400 GLSL330 GLSL320 GLSL310 GLSL300 GLSL100 GLSL150:   MatDefs/custom.vert
        FragmentShader  GLSL430 GLSL420 GLSL410 GLSL400 GLSL330 GLSL320 GLSL310 GLSL300 GLSL100 GLSL150: MatDefs/custom.frag

.frag


...
#import "Common/ShaderLib/GLSLCompat.glsllib"           <-----------------------THIS IS IMPORTANT !!!
//cw_colorName use same  value in JME3: const vec4 cw_Red = vec4(1.0, 0.0, 0.0, 1.0) etc.
void main(){
    vec4 color = vec4(0.5);
// ES 100=2.0 300=3.0 310=3.1 320 =3.2
    #if __VERSION__ == 100
    gl_FragColor = cw_Red;
    #else
            #if __VERSION__ == 300
            gl_FragColor = cw_Blue;
            #else
                        #if __VERSION__ == 310
                        gl_FragColor = cw_Green;
                        #else
                                    #if __VERSION__ == 320
                                    gl_FragColor = cw_Yellow;
                                    #else
//GL 110=2.0 120=2.1 130=3.0 140=3.1 150=3.2 330=3.3 400=4.0 410=4.1 420=4.2 430=4.3
  #if __VERSION__ == 110
  gl_FragColor = cw_Red;
  #else
  #if __VERSION__ == 120
  gl_FragColor = cw_Orange;
  #else
  #if __VERSION__ == 130
  gl_FragColor = cw_Blue;
  #else
  #if __VERSION__ == 140
  gl_FragColor = cw_Green;
  #else
  #if __VERSION__ == 150
  gl_FragColor = cw_Yellow;
  #else
  #if __VERSION__ == 330
  gl_FragColor = cw_Brown;
  #else
  #if __VERSION__ == 400
  gl_FragColor = cw_Magenta;
  #else
  #if __VERSION__ == 410
  gl_FragColor = cw_Pink;
  #else
  #if __VERSION__ == 420
  gl_FragColor = cw_Cyan;
  #else
  #if __VERSION__ == 430
  gl_FragColor = cw_White;
  #else
  gl_FragColor = color;
...                                                           

Scene and material:

Material mat1 = new Material(app.getAssetManager(), "MatDefs/custom.j3md");

Material mat2 = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat2.setBoolean("UseMaterialColors",true);
mat2.setColor("Diffuse", ColorRGBA.Cyan ); // with Lighting.j3md
mat2.setColor("Ambient", ColorRGBA.Pink );

geomBox.setMaterial(mat2);
surface.setMaterial(mat2);
geomSphere.setMaterial(mat1);
surface.move(1,1,5);
geomSphere.move(3,3,7);
geomBox.move(7f,7f,9f);

sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
((DirectionalLight)sun).setDirection(new Vector3f(0f,0f,-5f).normalizeLocal());
app.getRootNode().addLight(sun);
int shadlesize = 2048;
DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(app.getAssetManager(), shadlesize,3);
dlsr.setLight((DirectionalLight)sun);
app.getViewPort().addProcessor(dlsr);
app.getRootNode().setShadowMode(RenderQueue.ShadowMode.CastAndReceive);

For comparison purpose, a desktop application is designed with the same core module (SimpleApplication.class ) that android app used:

AppSettings set = new AppSettings(false);
set.setFullscreen(false);
set.setRenderer(AppSettings.LWJGL_OPENGL33);   <------- remember this
app.setSettings(set);

ok, here comes the debug sheet:
Setting: Emulator GLES3.1, desktop GL3.3.
API 21:


API 31:

Desktop:
2023-05-07_05-30-06
Physical device API 29:

Physical device API 23:

The color of the Sphere:
Green = GLES 3.1 Blue = GLES 3.0
(Since there is no Yellow, so these are the system GL version)
White = GL 4.3
(This is the GL version system can support)

Now, set Emulator back to Compatibility or autoselect.
API 31:


API 21:
failed to init.

Untill now, I’m pretty much sure there is an issue in shadow system on GL2. Curiosity fulfilled.

Wait a minute!

Didn’t I set AppSetting.setRenderer(AppSettings.LWJGL_OPENGL33) ???
Shouldn’t a Brown sphere appeared instead of a White one ?
White means the shader is running on GLSL430 and GL version is at least 4.3.

OK, let’s test all combinations:
AppSettings.LWJGL_OPENGL2 : passed. white sphere.
AppSettings.LWJGL_OPENGL30: failed.
AppSettings.LWJGL_OPENGL31: failed.
AppSettings.LWJGL_OPENGL32: passed. white sphere.
AppSettings.LWJGL_OPENGL33: passed. white sphere.
AppSettings.LWJGL_OPENGL40-45: passed. white sphere.
Error message:

com.jme3.system.JmeDesktopSystem initialize
: Running on jMonkeyEngine 3.6.0-stable
 * Branch: HEAD
 * Git Hash: 53f2a49
 * Build Date: 2023-03-20
 com.jme3.app.LegacyApplication handleError
: Context profiles are only defined for OpenGL version 3.2 and above
java.lang.Exception: Context profiles are only defined for OpenGL version 3.2 and above
	at com.jme3.system.lwjgl.LwjglWindow$1.invoke(LwjglWindow.java:229)
	at org.lwjgl.glfw.GLFWErrorCallbackI.callback(GLFWErrorCallbackI.java:43)
	at org.lwjgl.system.JNI.invokePPPP(Native Method)
	at org.lwjgl.glfw.GLFW.nglfwCreateWindow(GLFW.java:2024)
	at org.lwjgl.glfw.GLFW.glfwCreateWindow(GLFW.java:2197)
	at com.jme3.system.lwjgl.LwjglWindow.createContext(LwjglWindow.java:294)
	at com.jme3.system.lwjgl.LwjglWindow.initInThread(LwjglWindow.java:582)
	at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:704)
	at java.base/java.lang.Thread.run(Thread.java:833)

 com.jme3.system.JmeSystemDelegate lambda$new$0
: JmeDialogsFactory implementation not found.
Context profiles are only defined for OpenGL version 3.2 and above
Exception: Context profiles are only defined for OpenGL version 3.2 and above
com.jme3.app.LegacyApplication handleError
: Failed to create display
java.lang.RuntimeException: Failed to create the GLFW window
	at com.jme3.system.lwjgl.LwjglWindow.createContext(LwjglWindow.java:296)
	at com.jme3.system.lwjgl.LwjglWindow.initInThread(LwjglWindow.java:582)
	at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:704)
	at java.base/java.lang.Thread.run(Thread.java:833)

 com.jme3.system.JmeSystemDelegate lambda$new$0
: JmeDialogsFactory implementation not found.
Failed to create display
RuntimeException: Failed to create the GLFW window
com.jme3.system.lwjgl.LwjglWindow run
: Display initialization failed. Cannot continue.
6:52:56: Execution finished ':desktop:DesktopApp.main()'.

Conclusion:
AppSetting.setRenderer has bugs.

====finish line====

thanks for your reading here, have a gooood day :smiley:

[EDIT]
Well, Filter has material internally. pls, ignore BTW part~~~
BTW:
The custom j3me do not contain any shadow Technique yet it can still cast shadow.
Is this mean shadow will use inPosition and we’d better do not reuse ‘attribute vec3 inPosition’ when we link custom objs to shadow inherence tree?

Sounds related

1 Like

For the reason AppSetting failed to choose version below 3.2:
see this in stackoverflow and GLFW guide

GLFW_OPENGL_PROFILE** specifies which OpenGL profile to create the context for. Possible values are one of GLFW_OPENGL_CORE_PROFILE or GLFW_OPENGL_COMPAT_PROFILE , or GLFW_OPENGL_ANY_PROFILE to not request a specific profile. If requesting an OpenGL version below 3.2, GLFW_OPENGL_ANY_PROFILE must be used. If OpenGL ES is requested, this hint is ignored.

so I guess we should modify jme3/system/lwjgl /LwjglWindow.java-line 242
from

        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

to sth like

    if (  (!RENDER_CONFIGS. containsKey (renderer))   ||   
          renderer.contains (LWJGL_OPENGL30) || 
          renderer.contains (LWJGL_OPENGL31)     
       ) {
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_ANY_PROFILE);
    }else {
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    }

following the last post,
when set AppSettings.LWJGL_OPENGL32 the App.getRenderer().getCaps() returns:

OpenGL20, OpenGL21, OpenGL30, OpenGL31, OpenGL32,
GLSL100, GLSL110, GLSL120, GLSL130, GLSL140, GLSL150, GLSL330, GLSL400, GLSL410, GLSL420, GLSL430, GLSL440, GLSL450,

this info indicate that the GL is runing in version 3.2 , BUT the shader support as far as GLSL450 :thinking:
GLFW doc :

GLFW_CONTEXT_VERSION_MAJOR and GLFW_CONTEXT_VERSION_MINOR specify the client API version that the created context must be compatible with. The exact behavior of these hints depend on the requested client API.
While there is no way to ask the driver for a context of the highest supported version, GLFW will attempt to provide this when you ask for a version 1.0 context, which is the default for these hints.

This could be a trouble when certain version of shader language is expected.
For example if we want to test j3md’s compatibility with an old GLSL version, we might just set AppSettings.LWJGL_OPENGL32 to see if everything is ok. But the j3md may always run on the highest GLSL version instead of the lower one wanted!

In this case, the version number in j3md must set to the exact one desirered.

from
Technique {
        VertexShader  GLSL430 GLSL420 GLSL410 GLSL400 GLSL330 GLSL320 GLSL310 GLSL300 GLSL100 GLSL150:   MatDefs/custom.vert
to
Technique {
        VertexShader  GLSL310:   MatDefs/custom.vert

Just to get sure, is the issue related to Android or Desktop? Because afaik LWJGL and GLFW have nothing to do with Android in JME!

Well I may need to explain this clearly.
GL : openGL destoop
GLES: openGL android
GLSL : shader

First issue , for android system:
Android app acts differently. As described shadow system act strangely when set Android Emulator to GLES2.0. Haven’t figure out the reason yet.
During the investigation I need to run JME3 on desktop GL2.0 (and expect GLSL200 used ) to learn how j3md behaves in GLSL200. This leads to the second issue.

Second issue , for desktop:
By investigating the First issue, I discovered a second issue : AppSetting.setRenderer has bugs. Engine failed when set to GL version below 3.2.
Luckily, I may have found a solution as posted.

Third issue , for desktop:
Even with or without issue 2 solved.
what we expect:
GL set to 3.2 , GLSL works on 320 310 … …, and j3md use GLSL320 to compile
What we actually got:
GL set to 3.2, GLSL works on 450 440 … …, and j3md use GLSL450 to compile
The actual GLSL version used is always the highest.
This maybe a feature of GLFW: see this

for reference:
OpenGL Version and associated GLSL Version
2.0 110
2.1 120
3.0 130
3.1 140
3.2 150
3.3 330
4.0 400
4.1 410
4.2 420
4.3 430

OpenGL ES Version and associated GLSL ES Version
2.0 100
3.0 300
3.1 310
3.2 320

1 Like

So happy for my first PR for the engine (of course with help from Ali-RS :+1: :+1:) :smiley:

3 Likes

Nice! thanks for your contribution :slightly_smiling_face: