JME3.1 - Rendering failure specifically for android 7 (Nougat)

Hi,

I created a simpler model and repeated the tests.

The results were the same. Both for emulator and physical device.

Follow the screens. I’m also making the program available to anyone who wants to test.

Screen 1

Screen 2

Program
https://drive.google.com/open?id=0B6PayivIlyTVc1h3NDZJcjRIMmM

1 Like

Screen capture is from a physical device. But it was also tested with emulator

1 Like

Tricky.

From wikipedia:

" Additionally, the platform switched to an OpenJDK-based Java environment"

“It was reported that the Google Compatibility Test Suite (whose tests must be passed in order to receive official certification) specified that all devices running Nougat must support either Vulkan or OpenGL ES 3.1 graphics APIs”

Unfortunately I haven’t worked with Nougat myself so I can’t help much. But it could be worth investigating if the switch to OpenJDK or OpenGL 3.1 could be the cause.

1 Like

Hi guys,

I have identified the source of the rendering problem.

For this I created a more simplified model with two geometries of only three vertices each.

Then I printed the values of the vertices obtained from the merging of triangles in GeometryBatchFactory.optimize. The results follow below, and shows the values obtained in android 6 and android 7.

The values should be the same. But in android 7 we have strange values.

ANDROID 6

07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: Position Buffer
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 1.0, 0.0, 1.0
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 1.0, 0.0, -1.0
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: -1.0, 0.0, -1.0
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 0.8, 0.0, 1.2
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: -1.2, 0.0, -0.8
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: -1.2, 0.0, 1.2
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: TexCoord Buffer
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 1.0, 1.0
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 1.0, 0.0
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 0.0, 0.0
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 1.0, 1.0
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 0.0, 0.0
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 0.0, 1.0
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: Indexes Buffer
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 0, 1, 2
07-30 19:52:28.535 3899-3974/com.mycompany.mygame I/System.out: 3, 4, 5

ANDROID 7

07-30 19:48:39.832 9615-9644/com.mycompany.mygame I/System.out: Position Buffer
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 4.6006E-41, 0.0, 4.6006E-41
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 4.6006E-41, 0.0, 4.6185E-41
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 4.6185E-41, 0.0, 4.6185E-41
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: -4.28443616E8, 0.0, -6.35269E-23
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: -6.352771E-23, 0.0, -4.28447712E8
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: -6.352771E-23, 0.0, -6.35269E-23
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: TexCoord Buffer
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 4.6006E-41, 4.6006E-41
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 4.6006E-41, 0.0
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 0.0, 0.0
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 4.6006E-41, 4.6006E-41
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 0.0, 0.0
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 0.0, 4.6006E-41
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: Indexes Buffer
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 0, 1, 2
07-30 19:48:39.833 9615-9644/com.mycompany.mygame I/System.out: 3, 4, 5

Inquiring where these values were calculated I came to the source of the problem.

This is where you make use of the conversion of buffers to FloatBuffer.asReadOnlyBuffer.

The data indicates that it is a bug with the java.nio lib for android 7.

It makes sense because as already mentioned by rickard from the Android 7 the adopted Java implementation changed to OpendJDK.

In my case this bug caused the following problems:

1 - Rendering error for models obtained from the merging of two or more geometries in GeometryBatchFactory.optimize;

2 - Error of rendering of the material applied to these same models;

3 - Error in generating collision shapes in KinematicRagdollControl.

Sources Affected:

com.jme3.scene.VertexBuffer;
jme3tools.optimize.GeometryBatchFactory.

After eliminating the use of this type of conversion everything has normalized. I was able to do this simplification because my game has no thread safe question at this point.

5 Likes

This one is tough… Nice dig.
Do you really need to do the batching at runtime ?
Can’t you batch them with the sdk or whatever and save as a j3o file ?

1 Like

Hello nehon,

That is a good question.

The explanation is how my production line is structured.

I create the model of the scenario with the geometries separated because there are two automatisms:

1 - The position in the starting grid is determined by the position geometries in the grid. After obtaining this information the program merge these geometries. Thus the program automatically discovers where to position the bottle caps in the different circuits;

2 - Running a race for the first time, there is an algorithm that takes circuit geometry and automatically mounts the track control. That is, this control identifies the limits of the lane and allows to obtain various information about the position of the caps throughout the race.
This limit control I save as a j3o because generating it is time consuming.
After that the circuit is merged with the terrain geometry.

GeometryBatchFactory.optimize done in this way has not impacted the load time of a circuit.

What’s more, today’s devices are getting faster and faster. I have seen the load occur in the blink of an eye for some devices.

2 Likes

Ok, makes sense. I’m a bit reluctant to patch the engine to work around a bug in another software… Idk how we should do.

3 Likes

I`m using android studio and genymotion to test android. With android 6 all good, but with android 7.* I have this rendering failure. ( I removed the references of com.jme3.scene.VertexBuffer and jme3tools.optimize.GeometryBatchFactory from my project ) . I cant find any meaningful in logcat indicating the problem. Can you tell me what should I look for or test.

Hi kaloyan,

It’s hard to pinpoint a cause when we do not have the source.

But note that in my case the problem was in the use of the conversion function on the VertexBuffer, FloatBuffer.asReadOnlyBuffer.

This is a difficult problem to identify. What I did was create a minimal test scenario and gradually I was testing what worked and what did not.

As soon as possible I will make available the sources of classes com.jme3.scene.VertexBuffer and jme3tools.optimize.GeometryBatchFactory for you to see what I’ve changed. I have compiled these sources separately and replace the .class in the jmonkey packages.

I’ve seen this issue three times now and every time it’s a Samsung device on nougat. Just throwing that in there.

Hi Kaloyan,

Follow the link to the files:

Note that it is just a workaround.

I did very simple test with rigged model.
private AmbientLight lightSelection = new AmbientLight(new ColorRGBA(1.75f, 1.2f, -0.95f, .1f));
private Geometry someGeometry;
public void simpleInitApp() {
tmp = (Node) ((Node) assetManager.loadModel(“Models/Enemies/devil.j3o”)).getChild(0);
tmp = (Node) tmp.getChild(0);
// tmp = (Node) tmp.getChild(0);
someGeometry = (Geometry) tmp.getChild(0);
someGeometry.addLight(lightSelection);
rootNode.attachChild(tmp);
}

(I usually convert the blend file through sdk option “Convert to j3o Binary” and load Node or Spatial I need recursively).
After I removed the bones (using blender and convert it) the geometry is rendered properly then I add again just single bone (no animation) “With automatic weights” (convert it again to j3o) and again render failure.
P.S. on android 8 there is no such problem

I have good news and bad news for you.

The good news is that you have been able to identify at what point the problem occurs.

The bad news is that you will have to investigate the JME source code.

What is the relationship between bones and rendering? Answer, animation.

The animation is made with bones, and it changes the arrangement of the vertices of the 3D mesh. That is, calculations with VertexBuffer.

My guess is that at some point the vertices are being recalculated due to the presence of the bone.

Make sense. Probably I`ll make a try to dig in the sources. :neutral_face:

With getControl(SkeletonControl.class).setHardwareSkinningPreferred(false); helps for rendering issue but affects RigidBodyControl.class which is not workaround.

Animation and physics are totally separate things. So I suspect your method of detecting that it’s causing problems is in error.

Hardware skinning false should not affect bullet physics at all.

Android 7 :neutral_face:
https://imgur.com/a/CsNTi
Android 8

1 Like

I build jme3-core with your with provided link

com.jme3.scene.VertexBuffer;
jme3tools.optimize.GeometryBatchFactory.

https://drive.google.com/open?id=1b2Arj2duzhT__VcViHCmR-mNlRNJax6Z

and seem to patch the problem with rendering… (probably if you willing you can explain the problem again because I did not quit understand it) I have not done any deep testing

this is my

build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
repositories {
jcenter()
maven {
url ‘https://maven.google.com/
name ‘Google’
}
}
dependencies {
classpath ‘com.android.tools.build:gradle:3.0.1’

    // NOTE: Do not place your application dependencies here; they belong
    // in the individual module build.gradle files
    classpath 'com.google.gms:google-services:3.1.0'
}

}

allprojects {
repositories {
jcenter()
maven {
url ‘http://dl.bintray.com/jmonkeyengine/org.jmonkeyengine
}
google()
}

// TODO try upgrade java version
tasks.withType(JavaCompile) {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

}

project(":core") {
apply plugin: “java”
dependencies {
//compile ‘org.jmonkeyengine:jme3-core:3.2.+’
compile (‘org.jmonkeyengine:jme3-bullet:3.2.+’) {
exclude group: “org.jmonkeyengine”, module: “jme3-core”
}
/*
compile ‘com.googlecode.json-simple:json-simple:1.1.1’
*/
compile(‘org.jmonkeyengine:jme3-lwjgl:3.2.+’) {
exclude group: ‘org.jmonkeyengine’, module: ‘jme3-desktop’
exclude group: “org.jmonkeyengine”, module: “jme3-core”
}

    compile ('org.jmonkeyengine:jme3-effects:3.2.+'){
        exclude group: "org.jmonkeyengine", module: "jme3-core"
    }
    compile ('org.jmonkeyengine:jme3-niftygui:3.2+'){
        exclude group: "org.jmonkeyengine", module: "jme3-core"
    }
    compile ('org.jmonkeyengine:jme3-networking:3.2+'){
        exclude group: "org.jmonkeyengine", module: "jme3-core"
    }
    compile files('libs/cai-nmgen-0.1.2.jar')
    compile files('libs/jme3-core-3.2.1-stable-CUSTOM.jar')

}

}

project(":desktop") {
apply plugin: “java”
dependencies {
compile project(":core")
/*
compile ‘org.jmonkeyengine:jme3-desktop:3.2.+’
*/
}
}

project(":app") {
apply plugin: “android”
dependencies {
compile project(":core")
compile (‘org.jmonkeyengine:jme3-android:3.2.+’) {
exclude group: “org.jmonkeyengine”, module: “jme3-core”
}
compile (‘org.jmonkeyengine:jme3-android-native:3.2.+’) {
exclude group: “org.jmonkeyengine”, module: “jme3-core”
}
compile (‘org.jmonkeyengine:jme3-bullet-native-android:3.2.+’){
exclude group: “org.jmonkeyengine”, module: “jme3-core”
}
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

Hi kaloyan,

The explanation is as follows. The problem is in converting vertex buffer to a read only buffer with the FloatBuffer.asReadOnlyBuffer method.

The new buffer obtained will contain strange coordinate values for the vertices. Therefore, if the position of the vertex is incorrect, the rendering is scrambled.

The data indicates that it is a bug with the java.nio lib for android 7.

It makes sense because as already mentioned by rickard from the Android 7 the adopted Java implementation changed to OpendJDK.

In my case this bug caused the following problems:

1 - Rendering error for models obtained from the merging of two or more geometries in GeometryBatchFactory.optimize;

2 - Error of rendering of the material applied to these same models;

3 - Error in generating collision shapes in KinematicRagdollControl.