www.jpct.net

jPCT-AE - a 3d engine for Android => Support => Topic started by: MrAdam on May 02, 2012, 05:04:46 pm

Title: Viable engine?
Post by: MrAdam on May 02, 2012, 05:04:46 pm
Hey there. I'm an Android developer working at a social media company in Denmark.
We recently started a project for a big customer, which requires us to show a high-poly model to the users.
So far we've tried using JMonkeyEngine, but it's performance is not nearly good enough.

We have a very detailed 3D model of a car, consisting of over 100k vertices.
Its using shaders for coloring and for the windows.

Our main problem is the memory limitations of Android devices, with most of them running out of memory trying to load the model.
I had a go at your engine, and noticed improved loading times compared to JME, but some old (and new) devices would still run out of memory during the loading.

One of your demo apps in the play store (terrain benchmark) had a vertex count of over 100k, and loaded in no time at all.
I presume its using your DeSerializer, which I've tried using, but saving the serialized object using the desktop library is using a newer version of the format, which makes it impossible to load it with the Android library.

So, my question is. Do you think your engine will be usable in regards to loading/showing a high-poly model with shaders?

Best regards, Adam Honoré
Title: Re: Viable engine?
Post by: EgonOlsen on May 02, 2012, 10:11:19 pm
There shouldn't be any version mismatch between serialized files...try the jars mentioned in this post: http://www.jpct.net/forum2/index.php/topic,2708.msg20009.html#msg20009 (http://www.jpct.net/forum2/index.php/topic,2708.msg20009.html#msg20009)

They both work with version 4 of the serialized file format, so it should be fine.

If it's usable or not depends on your requirements. The serialized format is the fastest and most memory saving format you'll get from this engine.
Title: Re: Viable engine?
Post by: MrAdam on May 03, 2012, 11:20:51 am
Thanks. I got the loading to work with the beta, file format version matches desktop version.

Although, Ive run into a new problem with memory limits. The original 3DS file is 1.7 mb. and the serialized model is 6.4 mb.
Our old test phones die with out of memory when loading the serialized model, almost right away. (They have 24 mb heap).
But on newer phones with 32 mb heap it loads all the way, right until around the first render, then it spits out this:
Code: [Select]
05-03 11:10:09.798: E/dalvikvm-heap(21685): 287964-byte external allocation too large for this process.
What confuses me is that in your AN3DBenchXL "terrain" bench even the 24 mb heap phones is able to load the scene, but they won't load my 80k vertices model.

Ive uploaded the 3DS model to dropbox so you can see what we are dealing with:
http://dl.dropbox.com/u/63940770/basic_final80k.3DS

EDIT: It seems to me like some part of the engine might not be buffered
Title: Re: Viable engine?
Post by: EgonOlsen on May 03, 2012, 09:02:07 pm
I'm not sure what you mean with your EDIT...???

Anyway, i serialized the model using this code:

Code: [Select]
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

import com.threed.jpct.Config;
import com.threed.jpct.DeSerializer;
import com.threed.jpct.Loader;
import com.threed.jpct.Object3D;

public class Serrer {

public static void main(String[] args) throws FileNotFoundException {
Config.oldStyle3DSLoader=true;
Object3D[] objs = Loader.load3DS("basic_final80k.3DS", 1);
for (Object3D obj : objs) {
obj.build();
}

new DeSerializer().serializeArray(objs, new FileOutputStream("car.ser"), true);
}
}

As you can see, i preserved the single objects (i.e. i didn't merge them). You'll need this for transparency anyway and the resulting file is smaller, because it contains less empty space).

I then loaded it using this hacky code:

Code: [Select]
package com.threed.jpct.test.car;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.zip.ZipInputStream;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Light;
import com.threed.jpct.Loader;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;
import com.threed.jpct.util.MemoryHelper;

public class CarTestActivity extends Activity {

private static CarTestActivity master = null;

private GLSurfaceView mGLView;
private MyRenderer renderer = null;
private FrameBuffer fb = null;
private World world = null;
private RGBColor back = new RGBColor(50, 50, 100);

private float touchTurn = 0;
private float touchTurnUp = 0;

private float xpos = -1;
private float ypos = -1;

private Object3D[] parts = null;
private int fps = 0;

private Light sun = null;

protected void onCreate(Bundle savedInstanceState) {

Logger.log("onCreate");

if (master != null) {
copy(master);
}

super.onCreate(savedInstanceState);
mGLView = new GLSurfaceView(getApplication());

mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
EGLConfig[] configs = new EGLConfig[1];
int[] result = new int[1];
egl.eglChooseConfig(display, attributes, configs, 1, result);
return configs[0];
}
});

renderer = new MyRenderer();
mGLView.setRenderer(renderer);
setContentView(mGLView);
}

@Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}

@Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}

@Override
protected void onStop() {
super.onStop();
}

private void copy(Object src) {
try {
Logger.log("Copying data from master Activity!");
Field[] fs = src.getClass().getDeclaredFields();
for (Field f : fs) {
f.setAccessible(true);
f.set(this, f.get(src));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public boolean onTouchEvent(MotionEvent me) {

if (me.getAction() == MotionEvent.ACTION_DOWN) {
xpos = me.getX();
ypos = me.getY();
return true;
}

if (me.getAction() == MotionEvent.ACTION_UP) {
xpos = -1;
ypos = -1;
touchTurn = 0;
touchTurnUp = 0;
return true;
}

if (me.getAction() == MotionEvent.ACTION_MOVE) {
float xd = me.getX() - xpos;
float yd = me.getY() - ypos;

xpos = me.getX();
ypos = me.getY();

touchTurn = xd / -100f;
touchTurnUp = yd / -100f;
return true;
}

try {
Thread.sleep(15);
} catch (Exception e) {
// No need for this...
}

return super.onTouchEvent(me);
}

protected boolean isFullscreenOpaque() {
return true;
}

class MyRenderer implements GLSurfaceView.Renderer {

private long time = System.currentTimeMillis();

public MyRenderer() {
}

public void onSurfaceChanged(GL10 gl, int w, int h) {
if (fb != null) {
fb.dispose();
}
fb = new FrameBuffer(gl, w, h);

if (master == null) {

world = new World();
world.setAmbientLight(20, 20, 20);

sun = new Light(world);
sun.setIntensity(250, 250, 250);

ZipInputStream zis;
try {
zis = new ZipInputStream(getResources().getAssets().open("car.zip"));
zis.getNextEntry();
} catch (IOException e) {
throw new RuntimeException(e);
}

parts = Loader.loadSerializedObjectArray(zis);
world.addObjects(parts);
world.buildAllObjects();

for (Object3D obj : parts) {

if (obj.getName().indexOf("windshield") != -1 || obj.getName().indexOf("glas") != -1 || obj.getName().indexOf("lights_fro") != -1) {
obj.setTransparency(3);
}

obj.strip();
if (obj != parts[0]) {
obj.addParent(parts[0]);
}
}

Camera cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 250);
cam.lookAt(parts[0].getTransformedCenter());

SimpleVector sv = new SimpleVector();
sv.set(parts[0].getTransformedCenter());
sv.y -= 500;
sun.setPosition(sv);
sun.setDiscardDistance(-1);
MemoryHelper.compact();

if (master == null) {
Logger.log("Saving master Activity!");
master = CarTestActivity.this;
}
}
}

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}

public void onDrawFrame(GL10 gl) {
if (touchTurn != 0) {
parts[0].rotateY(touchTurn);
touchTurn = 0;
}

if (touchTurnUp != 0) {
parts[0].rotateX(touchTurnUp);
touchTurnUp = 0;
}

fb.clear(back);
world.renderScene(fb);
world.draw(fb);
fb.display();

if (System.currentTimeMillis() - time >= 1000) {
Logger.log(fps + "fps");
fps = 0;
time = System.currentTimeMillis();
}
fps++;
}
}
}

While running, it uses around 10mb and renders @ 20fps on a Galaxy S class device. It looks like this:

(http://jpct.de/pix/cartest.png)
Title: Re: Viable engine?
Post by: MrAdam on May 08, 2012, 10:52:31 am
Thanks a lot. It works perfectly when keeping the model split up :-)
It even runs on old phones like the HTC Wildfire now.

Anyways, I got one more question. As the loader takes the materials from the 3DS file, is it possible to fetch the material in the code and change the ambient color?

Regards, MrAdam.

P.S. Sorry for the late response, I was in a bike accident last thursday ^^
Title: Re: Viable engine?
Post by: EgonOlsen on May 08, 2012, 08:36:50 pm
Not directly, but you could try to hack around it. The colors are represented by little colored textures. These texture have generated names that might appear in the log output when they get added to the TextureManager. If you replace them in the TextureManager after the loading has finished, the color's should change.
Title: Re: Viable engine?
Post by: MrAdam on May 10, 2012, 02:12:58 pm
Got it working with swapping the textures, thanks.

Another question: Is it possible to make the windows semi-transparent, to make it looked like toned windows?

And another question: I've noticed that the model looks a hell of a lot smoother on a Galaxy S II and a Galaxy Nexus, than it does on a Desire, Desire S or Wildfire S. Is there any way to make the edges less "crispy" on low dpi devices? Anti-aliasing maybe?

Regards, MrAdam.
Title: Re: Viable engine?
Post by: Thomas. on May 10, 2012, 03:14:56 pm
Anti-aliasing is possible to use in OGL2 only. I'm using this.

Code: [Select]
switch (GameConfig.oglVersion) {
case 1:
mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
@Override
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 24, EGL10.EGL_NONE };
EGLConfig[] configs = new EGLConfig[1];
int[] result = new int[1];
egl.eglChooseConfig(display, attributes, configs, 1, result);
return configs[0];
}
});
break;
case 2:
mGLView.setEGLContextClientVersion(2);
if (GameConfig.antiAliasing)
mGLView.setEGLConfigChooser(new AAConfigChooser(mGLView));
break;
}

edit: But with to large count of edges, it'll be probably very slow.
Title: Re: Viable engine?
Post by: MrAdam on May 10, 2012, 04:06:54 pm
Anti-aliasing is possible to use in OGL2 only. I'm using this.

Code: [Select]
switch (GameConfig.oglVersion) {
case 1:
mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
@Override
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 24, EGL10.EGL_NONE };
EGLConfig[] configs = new EGLConfig[1];
int[] result = new int[1];
egl.eglChooseConfig(display, attributes, configs, 1, result);
return configs[0];
}
});
break;
case 2:
mGLView.setEGLContextClientVersion(2);
if (GameConfig.antiAliasing)
mGLView.setEGLConfigChooser(new AAConfigChooser(mGLView));
break;
}

edit: But with to large count of edges, it'll be probably very slow.
I already tried that. Even though I got GLES2.0 enabled I get this:
Code: [Select]
05-10 16:01:19.255: E/libEGL(24536): called unimplemented OpenGL ES API
05-10 16:01:19.263: E/libEGL(24536): called unimplemented OpenGL ES API
05-10 16:01:19.263: E/libEGL(24536): called unimplemented OpenGL ES API
05-10 16:01:19.263: E/libEGL(24536): called unimplemented OpenGL ES API
05-10 16:01:19.263: E/libEGL(24536): called unimplemented OpenGL ES API
05-10 16:01:19.263: E/libEGL(24536): called unimplemented OpenGL ES API
05-10 16:01:20.419: E/libEGL(24536): called unimplemented OpenGL ES API
05-10 16:01:20.419: E/libEGL(24536): called unimplemented OpenGL ES API
05-10 16:01:20.419: E/libEGL(24536): called unimplemented OpenGL ES API
05-10 16:01:20.544: E/AndroidRuntime(24536): FATAL EXCEPTION: GLThread 873
05-10 16:01:20.544: E/AndroidRuntime(24536): java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
05-10 16:01:20.544: E/AndroidRuntime(24536): at com.threed.jpct.CompiledInstance.fill(CompiledInstance.java:1155)
05-10 16:01:20.544: E/AndroidRuntime(24536): at com.threed.jpct.Object3DCompiler.compile(Object3DCompiler.java:145)
05-10 16:01:20.544: E/AndroidRuntime(24536): at com.threed.jpct.World.compile(World.java:1914)
05-10 16:01:20.544: E/AndroidRuntime(24536): at com.threed.jpct.World.renderScene(World.java:1038)
05-10 16:01:20.544: E/AndroidRuntime(24536): at nodes.android.MainActivity$GLRenderer.onDrawFrame(MainActivity.java:202)
05-10 16:01:20.544: E/AndroidRuntime(24536): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1462)
05-10 16:01:20.544: E/AndroidRuntime(24536): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216)
Title: Re: Viable engine?
Post by: Thomas. on May 10, 2012, 04:21:41 pm
You need to enable OpenGL ES 2.0 in your app through AndroidManifest.xml.

Code: [Select]
<uses-feature android:glEsVersion="0x00020000"></uses-feature>
<uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8"></uses-sdk>
Title: Re: Viable engine?
Post by: MrAdam on May 10, 2012, 04:28:22 pm
You need to enable OpenGL ES 2.0 in your app through AndroidManifest.xml.

Code: [Select]
<uses-feature android:glEsVersion="0x00020000"></uses-feature>
<uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8"></uses-sdk>
Still getting
Code: [Select]
05-10 16:26:49.234: E/AndroidRuntime(1331): FATAL EXCEPTION: GLThread 156
05-10 16:26:49.234: E/AndroidRuntime(1331): java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
05-10 16:26:49.234: E/AndroidRuntime(1331): at com.threed.jpct.CompiledInstance.fill(CompiledInstance.java:1155)
05-10 16:26:49.234: E/AndroidRuntime(1331): at com.threed.jpct.Object3DCompiler.compile(Object3DCompiler.java:145)
05-10 16:26:49.234: E/AndroidRuntime(1331): at com.threed.jpct.World.compile(World.java:1914)
05-10 16:26:49.234: E/AndroidRuntime(1331): at com.threed.jpct.World.renderScene(World.java:1038)
05-10 16:26:49.234: E/AndroidRuntime(1331): at nodes.android.MainActivity$GLRenderer.onDrawFrame(MainActivity.java:246)
05-10 16:26:49.234: E/AndroidRuntime(1331): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1462)
05-10 16:26:49.234: E/AndroidRuntime(1331): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216)
Title: Re: Viable engine?
Post by: Thomas. on May 10, 2012, 04:31:53 pm
Have you the newest version?

http://www.jpct.net/forum2/index.php/topic,2708.msg20009.html#msg20009
Title: Re: Viable engine?
Post by: MrAdam on May 10, 2012, 04:34:10 pm
Have you the newest version?

http://www.jpct.net/forum2/index.php/topic,2708.msg20009.html#msg20009
I certainly have ;-)
Title: Re: Viable engine?
Post by: Thomas. on May 10, 2012, 04:43:25 pm
So, I have no idea, where is problem... :D
Title: Re: Viable engine?
Post by: EgonOlsen on May 10, 2012, 06:37:17 pm
To use 2.0, you have to use the other constructor for your FrameBuffer....the one without the gl instance.
Title: Re: Viable engine?
Post by: MrAdam on May 18, 2012, 09:44:53 am
Thaks a lot for the help. I got everything working great so far with a detailed model and transparency.
But I've run in to some problems with using shaders. On our old engine (jmonkeyengine) we used shaders for the model instead of textures. I can see that your engine supports shaders, but I have not been able to find a good example for a simple lighting shader. The only thing I really need is just to make the car "shine" more, like real car paint.

You can see below how it looks so far:
(http://i.imgur.com/dKXAO.png)
(http://i.imgur.com/WSpeY.png)
Title: Re: Viable engine?
Post by: EgonOlsen on May 18, 2012, 11:00:22 am
If you have the former shader available, you should be able to port it to be used by jPCT-AE. After all, it's all standard GLSL code. You will most likely have to make it use jPCT-AE's naming conventions for uniforms and attributes that can be found here: http://www.jpct.net/jpct-ae/doc/com/threed/jpct/GLSLShader.html (http://www.jpct.net/jpct-ae/doc/com/threed/jpct/GLSLShader.html)
Title: Re: Viable engine?
Post by: MrAdam on May 18, 2012, 11:04:27 am
If you have the former shader available, you should be able to port it to be used by jPCT-AE. After all, it's all standard GLSL code. You will most likely have to make it use jPCT-AE's naming conventions for uniforms and attributes that can be found here: http://www.jpct.net/jpct-ae/doc/com/threed/jpct/GLSLShader.html (http://www.jpct.net/jpct-ae/doc/com/threed/jpct/GLSLShader.html)
Thanks. I used a default shader in JME, which I've tried porting already using jPCT naming conventions for shaders, but there's a lot of stuff that simply won't compile in it.

I just need a simple reflection shader for this project though.
Title: Re: Viable engine?
Post by: EgonOlsen on May 18, 2012, 11:08:25 am
Why shouldn't it compile? It's all the same GLSL based stuff...maybe the types don't match or something like that. You might have to convert them. Can you post the shader code that won't compile?
Title: Re: Viable engine?
Post by: MrAdam on May 18, 2012, 11:12:47 am
Why shouldn't it compile? It's all the same GLSL based stuff...maybe the types don't match or something like that. You might have to convert them. Can you post the shader code that won't compile?
Well, right now Im trying to port this shader: http://www.davidcornette.com/glsl/glsl.html
It's simple, and should look fine. Although, I can't seem to fint the jPCT equivalent of gl_NormalMatrix
Title: Re: Viable engine?
Post by: EgonOlsen on May 18, 2012, 11:23:24 am
The equivalent of gl_NormalMatrix is modelViewMatrix...well, not really but as long as you are only using uniform scaling (which you do, because jPCT doesn't allow for aynthing else), you can simply replace something like

Code: [Select]
vec3 n = normalize(gl_NormalMatrix * gl_Normal);

by

Code: [Select]
vec3 n = normalize(modelViewMatrix * vec4(normal,0.0)).xyz;
Title: Re: Viable engine?
Post by: MrAdam on May 18, 2012, 11:33:23 am
The equivalent of gl_NormalMatrix is modelViewMatrix...well, not really but as long as you are only using uniform scaling (which you do, because jPCT doesn't allow for aynthing else), you can simply replace something like

Code: [Select]
vec3 n = normalize(gl_NormalMatrix * gl_Normal);

by

Code: [Select]
vec3 n = normalize(modelViewMatrix * vec4(normal,0.0)).xyz;

Thanks. Im 100% new to shaders. Theres a few more functions and variables It can't seem to find:

05-18 11:32:05.278: I/jPCT-AE(27583): ERROR: 0:9: 'ftransform' : no matching overloaded function found
Title: Re: Viable engine?
Post by: EgonOlsen on May 18, 2012, 12:18:17 pm
OpenGL ES misses a lot of stuff that the desktop version has. Maybe it helps to compare the glsl code of the parallax mapping shaders that are included as an example in both versions (HelloShader iirc) so see how the desktop stuff translates to mobile.
Title: Re: Viable engine?
Post by: MrAdam on May 18, 2012, 04:46:57 pm
OpenGL ES misses a lot of stuff that the desktop version has. Maybe it helps to compare the glsl code of the parallax mapping shaders that are included as an example in both versions (HelloShader iirc) so see how the desktop stuff translates to mobile.
Okay, can't get the shader to work. I've searched the web for a simple reflection shader, but no luck.
Do you have any sources for a simple reflection shader?
Title: Re: Viable engine?
Post by: EgonOlsen on May 18, 2012, 05:53:53 pm
Here's a rough port of the shader in your link:

vertex:
Code: [Select]
uniform mat4 modelViewMatrix;
uniform mat4 modelViewProjectionMatrix;

uniform vec3 lightPositions[8];
uniform vec3 diffuseColors[8];

attribute vec4 position;
attribute vec3 normal;
attribute vec2 texture0;

varying vec3 vnormal;
varying vec4 pos;
varying vec4 diffuseColor;
varying vec2 texCoord;

void main() {
  vnormal = normalize(modelViewMatrix * vec4(normal, 0.0)).xyz;
  pos = modelViewMatrix * position;
  diffuseColor = vec4(diffuseColors[0], 0.0);
  texCoord = texture0.xy;
  gl_Position = modelViewProjectionMatrix * position;
}

fragment:
Code: [Select]
precision highp float;

uniform sampler2D textureUnit0;
uniform vec3 lightPositions[8];

varying vec3 vnormal;
varying vec4 pos;
varying vec4 diffuseColor;
varying vec2 texCoord;

void main() {
  vec4 color = texture2D(textureUnit0, texCoord);
 
  // Adjust this...
  vec4 matspec = vec4(0.8, 0.8, 0.8, 0.0);
  vec4 lightspec = vec4(1.0, 1.0, 1.0, 0.0);
  float shininess = 0.45;
  // ...
 
  vec4 lpos = vec4(lightPositions[0], 0.0);
  vec4 s = -normalize(pos-lpos);

  vec3 light = s.xyz;
  vec3 n = normalize(vnormal);
  vec3 r = -reflect(light, n);
  r = normalize(r);
  vec3 v = -pos.xyz;
  v = normalize(v);
   
  vec4 diffuse  = color * max(0.0, dot(n, s.xyz)) * diffuseColor;
  vec4 specular = lightspec * matspec * pow(max(0.0, dot(r, v)), shininess);

  gl_FragColor = diffuse + specular;
}

To get different specular effects, adjust the settings inside the comments...especially the shininess value. Note that you can't use this shader on transparent objects as it is. You would have to write a version that takes alpha into account if that is needed.

Hope this helps...
Title: Re: Viable engine?
Post by: MrAdam on May 20, 2012, 10:26:05 am
Thanks! I really appreciate your help.

Although, there seems to be a problem with alpha in the shader. I've checked all the vec4's, and none of them has an alpha that would explain this :-/
(http://i.imgur.com/AQdUi.jpg)
Title: Re: Viable engine?
Post by: EgonOlsen on May 20, 2012, 11:41:40 am
Not sure where this comes from....but you can set to any value you like by adding gl_FragColor.a =<alpha>; as the last line.
Title: Re: Viable engine?
Post by: MrAdam on May 20, 2012, 12:05:48 pm
Thanks! Works perfectly now ;-)

There seems to be a problem with parts of the model looking "cracked" from some angles.
(http://i.imgur.com/d7eRz.jpg)

Ive tried changing glDither and glTrilinear as that might have been the cause, but to no help :-/
Title: Re: Viable engine?
Post by: EgonOlsen on May 20, 2012, 01:57:10 pm
I'm not sure what you mean. Maybe you can highlight it in the screen shot somehow.
Title: Re: Viable engine?
Post by: MrAdam on May 20, 2012, 01:58:09 pm
I'm not sure what you mean. Maybe you can highlight it in the screen shot somehow.
Try looking at the right side door. Its full of small white lines/cracks
Title: Re: Viable engine?
Post by: EgonOlsen on May 20, 2012, 02:11:41 pm
I just wanted to be sure that i'm not looking at some compression artifacts...really strange. Does this happen with the camera image in the background only? Can you try it on a different device that uses another gpu? I'll try to reproduce it on my device, but i don't remember seeing anything like it.
Title: Re: Viable engine?
Post by: MrAdam on May 20, 2012, 02:30:07 pm
It happens without the camera preview as well. And appears on the Galaxy SII as well as on my Galaxy Nexus.

If you want to see it in the app, I can send you the APK.
Title: Re: Viable engine?
Post by: EgonOlsen on May 20, 2012, 02:39:56 pm
That would be helpful.
Title: Re: Viable engine?
Post by: MrAdam on May 20, 2012, 04:07:51 pm
Another thing. When loading via: model = Loader.loadSerializedObjectArray(getAssets().open("model.ser"));
Is it possible to somehow check when the loading is done? I need to load the car in the background, as it takes a lot of time.
but the .loadSerializedObjectArray() function starts a new thread in the background when run, which means I can't just wait for the function to finish.

EDIT: Looks like from the logs that its not loading the model itself thats the problem. But its adding it to the scene.
If I load it before entering the activity, it still takes a while to show up, a while after the onSurfaceChanged have run.
Title: Re: Viable engine?
Post by: EgonOlsen on May 20, 2012, 05:53:30 pm
The engine doesn't spawn any additional threads. When the methods in Loader return, the loading is done. The delay that you notice is caused by the engine compiling the mesh to be processed by the gpu in the most optimal way. This happens in two steps. The second one has to happen in the render thread, you can't get around that. However, the first step can be triggered from anywhere. To do this, add the objects to the world and call World.compileAllObjects. That should remove some load from the render thread.
Title: Re: Viable engine?
Post by: MrAdam on May 20, 2012, 05:54:48 pm
The engine doesn't spawn any additional threads. When the methods in Loader return, the loading is done. The delay that you notice is caused by the engine compiling the mesh to be processed by the gpu in the most optimal way. This happens in two steps. The second one has to happen in the render thread, you can't get around that. However, the first step can be triggered from anywhere. To do this, add the objects to the world and call World.compileAllObjects. That should remove some load from the render thread.
Its not really the timing that matters. Its mostly so I can create a ProgressDialog and dismiss it when it is actually done.

EDIT: Is it possible to check when all the VBO's has been created for the object?
Title: Re: Viable engine?
Post by: MrAdam on May 21, 2012, 11:32:55 am
A totally different question: I use a rotation matrix to set the position of the car in 3D.
Is it possible to set the rotation around a specific axis to 0?
Lets say I only wanted the rotation matrix to rotate pitch and roll, not yaw, of the car.

EDIT: I was thinking it might be possible to pull just the two vectors out of three from the matrix, and applying them to the model, not completely sure how to do that though.
Title: Re: Viable engine?
Post by: EgonOlsen on May 21, 2012, 01:40:52 pm
Why don't you use the rotate?()-methods instead?
Title: Re: Viable engine?
Post by: MrAdam on May 21, 2012, 01:42:02 pm
Why don't you use the rotate?()-methods instead?
Because Im getting a rotation matrix from the phones sensors. I can only set the rotation, not get the current rotation of the car :-/
Title: Re: Viable engine?
Post by: EgonOlsen on May 21, 2012, 02:30:06 pm
I see...you can derive the euler angles from the matrix and create a new matrix with only a sub-set, but i'm not sure if the results will be satisfying. The basic problem is that an unlimited number of cascaded transformations result in the same output. The derived angles are just one way to do it...anyway, here's some code: http://www.jpct.net/forum2/index.php/topic,1191.0.html (http://www.jpct.net/forum2/index.php/topic,1191.0.html)
Title: Re: Viable engine?
Post by: MrAdam on May 22, 2012, 10:10:39 am
I see...you can derive the euler angles from the matrix and create a new matrix with only a sub-set, but i'm not sure if the results will be satisfying. The basic problem is that an unlimited number of cascaded transformations result in the same output. The derived angles are just one way to do it...anyway, here's some code: http://www.jpct.net/forum2/index.php/topic,1191.0.html (http://www.jpct.net/forum2/index.php/topic,1191.0.html)
Thanks, that helped :-)

Also, I've noticed that if there is solid objects behind transparent objects, it will render the solid objects behind as transparent as well.
We had the same issue in the iPhone version, which was solved by setting a glColorMask after drawing transparent stuff (http://stackoverflow.com/questions/10450680/isgl3d-transparency-issues)
Is it possible to somehow implement this in your engine?
Title: Re: Viable engine?
Post by: EgonOlsen on May 22, 2012, 11:20:54 am
Is it possible to somehow implement this in your engine?
Yes. You can add an implementation of the IRenderHook-interface to your transparent object(s) that does this.
Title: Re: Viable engine?
Post by: MrAdam on May 22, 2012, 11:59:50 am
Is it possible to somehow implement this in your engine?
Yes. You can add an implementation of the IRenderHook-interface to your transparent object(s) that does this.
And what is the best way to expose the GL20 object to do raw gl calls inside the IRenderHook?
Title: Re: Viable engine?
Post by: EgonOlsen on May 22, 2012, 12:07:44 pm
You don't. It's a static class. Just do GLES20.glColorMask(...);
Title: Re: Viable engine?
Post by: MrAdam on May 22, 2012, 01:27:11 pm
You don't. It's a static class. Just do GLES20.glColorMask(...);
Thanks! Worked wonders. Although, now the transparent lines appearing are even more visible ^^

EDIT: It appears that this is not a shader-problem, as its still visible without the shader enabled:
(http://i.imgur.com/bBSWe.png)
Title: Re: Viable engine?
Post by: EgonOlsen on May 22, 2012, 02:31:00 pm
This might be really far fetched, but try to call Object3D.setFixedPointMode(false); after loading the models.
Title: Re: Viable engine?
Post by: MrAdam on May 22, 2012, 02:41:18 pm
This might be really far fetched, but try to call Object3D.setFixedPointMode(false); after loading the models.
Sorry, didn't make a difference :-/
Title: Re: Viable engine?
Post by: Thomas. on May 22, 2012, 02:56:22 pm
try to disable anti-aliasing
Title: Re: Viable engine?
Post by: MrAdam on May 22, 2012, 03:08:57 pm
try to disable anti-aliasing
Sorry, didn't work :-/
Title: Re: Viable engine?
Post by: Thomas. on May 22, 2012, 03:37:28 pm
And what geometry? Is possible that some vertices are little bit shifted? If you have 3Ds max, you can try merge vertices in very small distance... editable poly -> vertex selection -> select all vertices -> weld and try some very small distance. Below you can see vertex count before and after weld...
Title: Re: Viable engine?
Post by: MrAdam on May 22, 2012, 04:05:14 pm
And what geometry? Is possible that some vertices are little bit shifted? If you have 3Ds max, you can try merge vertices in very small distance... editable poly -> vertex selection -> select all vertices -> weld and try some very small distance. Below you can see vertex count before and after weld...
Didn't solve the problem.
Title: Re: Viable engine?
Post by: EgonOlsen on May 22, 2012, 08:52:41 pm
Ok...i had a look at the app that you sent to me...it's looks really strange. The edges of some polygons are transparent in some cases. You simply see the camera image shining through. I managed to bring the door in a position where actually the whole thing was more or less transparent.

Then, i fired up my test case and tried to reproduce it...i failed...until i enabled AA more or less by accident and then, i got the same visual artifacts in my test app. So i assume, that the issue will disappear if you disable AA. If that's the case, then i've no idea what i can do against this. Most likely nothing, because the AA implementation is part of the GPU hardware. And if it thinks that this is the right way to do it, then i can't tell it otherwise. I fiddled around with the EGL-config settings for AA, but to no avail...
Title: Re: Viable engine?
Post by: EgonOlsen on May 22, 2012, 09:02:55 pm
BTW: I've noticed another visual flaw in my test app as well as in your app...on some devices (like mine), the GPU seems to have a startup problem with high polygon counts, i.e. the first rendered image after a context change misses some polygons when rendering high polygon objects. I consider this to be a driver issue (i had the same problem in my benchmark app). The best solution that could come up with was to discard the first frame after creating a new FrameBuffer, i.e. to do something like:

Code: [Select]
fb.clear(back);
world.renderScene(fb);
world.draw(fb);
fb.display();

if (!init) {
fb.clear(back);
init=true;
}

...and to set init to false each time you create a new FrameBuffer.

It's not great, but it shouldn't hurt either...
Title: Re: Viable engine?
Post by: MrAdam on May 23, 2012, 12:47:32 pm
Ok...i had a look at the app that you sent to me...it's looks really strange. The edges of some polygons are transparent in some cases. You simply see the camera image shining through. I managed to bring the door in a position where actually the whole thing was more or less transparent.

Then, i fired up my test case and tried to reproduce it...i failed...until i enabled AA more or less by accident and then, i got the same visual artifacts in my test app. So i assume, that the issue will disappear if you disable AA. If that's the case, then i've no idea what i can do against this. Most likely nothing, because the AA implementation is part of the GPU hardware. And if it thinks that this is the right way to do it, then i can't tell it otherwise. I fiddled around with the EGL-config settings for AA, but to no avail...
Well, thats bad :-/ I tried disabling AA yesterday, but couldn't see a difference, must have made a mistake.
Anyways, It works now. But won't be as sharp as before ..

But thanks a lot for the help! Almost done with the app now ;-)
Title: Re: Viable engine?
Post by: MrAdam on May 24, 2012, 10:42:24 am
I know I already asked this question, but the answer didn't resolve my issue :-/

Im trying to load the model in the background (load and compile) so that it shows up more quickly when opening one of the two 3D activities containing the model.

My problem is that the FrameBuffer is needed to compile the object, but the framebuffer isn't created yet, as the activity containing jpct haven't been launched yet. I've tried creating the FrameBuffer in another activity and resuing it, but its only giving me errors:
Code: [Select]
05-24 10:31:01.721: E/AndroidRuntime(7063): java.lang.RuntimeException: [ 1337848261728 ] - ERROR: java.lang.RuntimeException: [ 1337848261725 ] - ERROR: java.lang.RuntimeException: [ 1337848261720 ] - ERROR: java.lang.RuntimeException: [ 1337848261718 ] - ERROR: Failed to load and compile vertex shaders!
Title: Re: Viable engine?
Post by: EgonOlsen on May 24, 2012, 12:30:47 pm
You can't create a FrameBuffer outside of the thread that own the gl context. However, checking the code, the dependence of the compileAllObjects()-method on FrameBuffer doesn't seem to be needed. I'll look at this again this evening and i think i can simply remove it.
Title: Re: Viable engine?
Post by: MrAdam on May 24, 2012, 01:04:44 pm
You can't create a FrameBuffer outside of the thread that own the gl context. However, checking the code, the dependence of the compileAllObjects()-method on FrameBuffer doesn't seem to be needed. I'll look at this again this evening and i think i can simply remove it.
Thanks! Thats great to hear :-)
Title: Re: Viable engine?
Post by: EgonOlsen on May 24, 2012, 10:24:41 pm
Removed. Please use this jar: http://jpct.de/download/beta/jpct_ae.jar (http://jpct.de/download/beta/jpct_ae.jar)
Title: Re: Viable engine?
Post by: Thomas. on May 24, 2012, 10:34:57 pm
so, compilation can be serialized?
Title: Re: Viable engine?
Post by: EgonOlsen on May 24, 2012, 10:41:31 pm
No. It still has to happen on the device. You just don't have to create a FrameBuffer to trigger it.
Title: Re: Viable engine?
Post by: MrAdam on May 24, 2012, 11:58:34 pm
Removed. Please use this jar: http://jpct.de/download/beta/jpct_ae.jar (http://jpct.de/download/beta/jpct_ae.jar)
Thanks! Ill try it first thing in the morning ;-)
Title: Re: Viable engine?
Post by: MrAdam on May 25, 2012, 09:59:28 am
Okay, got the new version in. Only one slight problem:
Code: [Select]
model = Loader.loadSerializedObjectArray(getAssets().open("modern.png"));
world.addObjects(model);
world.compileAllObjects();
As Loader.loadSerializedObjectArray() is threaded, I am of course getting a null pointer exception due to the model not being loaded yet when it runs world.addObjects(). I have yet been able to find a way to check if the loading has finished.
Title: Re: Viable engine?
Post by: EgonOlsen on May 25, 2012, 10:01:56 am
Loader.loadSerializedObjectArray()  isn't threaded...nothing is threaded in the engine... ???

Title: Re: Viable engine?
Post by: MrAdam on May 25, 2012, 10:26:08 am
Loader.loadSerializedObjectArray()  isn't threaded...nothing is threaded in the engine... ???
Well, I just did a while(model == null){}
No null pointers now ^^
Title: Re: Viable engine?
Post by: EgonOlsen on May 25, 2012, 10:32:15 am
Ok, but that doesn't make any sense...there are no threads involved. And even if there were...you can't change a returned instance afterwards, i.e. if it returns null, it will stay null forever. So this loop will never be entered if the loading goes fine and it will never terminate if null will be returned.

Maybe it's something else...are you trying to render the model while still loading/adding it? Can you post the null pointer exception you are getting?
Title: Re: Viable engine?
Post by: MrAdam on May 25, 2012, 10:52:15 am
Ok, but that doesn't make any sense...there are no threads involved. And even if there were...you can't change a returned instance afterwards, i.e. if it returns null, it will stay null forever. So this loop will never be entered if the loading goes fine and it will never terminate if null will be returned.

Maybe it's something else...are you trying to render the model while still loading/adding it? Can you post the null pointer exception you are getting?
This is happening at application launch and when user changes application language, way before the activity with the 3D part.
Here's the error:
Code: [Select]
05-25 10:46:42.650: E/AndroidRuntime(4411): FATAL EXCEPTION: Thread-949
05-25 10:46:42.650: E/AndroidRuntime(4411): java.lang.NullPointerException
05-25 10:46:42.650: E/AndroidRuntime(4411): at bmw.makeityours.BMWApplication$ModelLoaderThread.run(BMWApplication.java:81)
Here's the code:
Code: [Select]
private class ModelLoaderThread extends Thread {

        String modelName = "";

        public ModelLoaderThread(String modelName) {
            this.modelName = modelName;
        }

        @Override
        public void run() {
            isModelLoading = true;
            if (world != null) {
                world.removeAll();
                world.dispose();
                world = new World();
            }
            if (model != null) {
                model = null;
            }
            try {
                model = Loader.loadSerializedObjectArray(getAssets().open(modelName + ".png"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            world.addObjects(model);
            world.buildAllObjects();
            world.compileAllObjects();
            isModelLoaded = true;
            isModelLoading = false;
        }
    }
The line causing the crash is the "world.addObjects(model);"
Title: Re: Viable engine?
Post by: EgonOlsen on May 25, 2012, 10:55:34 am
...so world is null in this case, not model. Otherwise, it would crash inside of the method and not when trying to call it.
Title: Re: Viable engine?
Post by: MrAdam on May 25, 2012, 11:02:46 am
...so world is null in this case, not model. Otherwise, it would crash inside of the method and not when trying to call it.
Well yeah, but it shouldn't reach that point without having created world. "world = new World();" doesn't fail

EDIT: Never mind, fixed it by initializing the world before starting the thread:
public World world = new World();
Title: Re: Viable engine?
Post by: zammbi on May 25, 2012, 02:44:07 pm
Quote
Removed. Please use this jar: http://jpct.de/download/beta/jpct_ae.jar
I've tested it and it works fine in my basic tests.
Title: Re: Viable engine?
Post by: MrAdam on May 25, 2012, 03:14:49 pm
Here's a rough port of the shader in your link:

vertex:
Code: [Select]
uniform mat4 modelViewMatrix;
uniform mat4 modelViewProjectionMatrix;

uniform vec3 lightPositions[8];
uniform vec3 diffuseColors[8];

attribute vec4 position;
attribute vec3 normal;
attribute vec2 texture0;

varying vec3 vnormal;
varying vec4 pos;
varying vec4 diffuseColor;
varying vec2 texCoord;

void main() {
  vnormal = normalize(modelViewMatrix * vec4(normal, 0.0)).xyz;
  pos = modelViewMatrix * position;
  diffuseColor = vec4(diffuseColors[0], 0.0);
  texCoord = texture0.xy;
  gl_Position = modelViewProjectionMatrix * position;
}

fragment:
Code: [Select]
precision highp float;

uniform sampler2D textureUnit0;
uniform vec3 lightPositions[8];

varying vec3 vnormal;
varying vec4 pos;
varying vec4 diffuseColor;
varying vec2 texCoord;

void main() {
  vec4 color = texture2D(textureUnit0, texCoord);
 
  // Adjust this...
  vec4 matspec = vec4(0.8, 0.8, 0.8, 0.0);
  vec4 lightspec = vec4(1.0, 1.0, 1.0, 0.0);
  float shininess = 0.45;
  // ...
 
  vec4 lpos = vec4(lightPositions[0], 0.0);
  vec4 s = -normalize(pos-lpos);

  vec3 light = s.xyz;
  vec3 n = normalize(vnormal);
  vec3 r = -reflect(light, n);
  r = normalize(r);
  vec3 v = -pos.xyz;
  v = normalize(v);
   
  vec4 diffuse  = color * max(0.0, dot(n, s.xyz)) * diffuseColor;
  vec4 specular = lightspec * matspec * pow(max(0.0, dot(r, v)), shininess);

  gl_FragColor = diffuse + specular;
}

To get different specular effects, adjust the settings inside the comments...especially the shininess value. Note that you can't use this shader on transparent objects as it is. You would have to write a version that takes alpha into account if that is needed.

Hope this helps...
I noticed that this shader only works with one light at a time. Is it hard to modify it to work with several lights?
Title: Re: Viable engine?
Post by: Thomas. on May 25, 2012, 03:50:43 pm
It's just wrote in reply, I didn't test it... shader ignore specular colors of lights, that you set in application... but it isn't hard to implement, look at java doc (http://www.jpct.net/jpct-ae/doc/com/threed/jpct/GLSLShader.html)...

fragment:
Code: [Select]
precision highp float;

uniform sampler2D textureUnit0;
uniform vec3 lightPositions[8];
uniform int lightCount;

varying vec3 vnormal;
varying vec4 pos;
varying vec4 diffuseColor;
varying vec2 texCoord;

void main() {
  vec4 color = texture2D(textureUnit0, texCoord);
 
  // Adjust this...
  vec4 matspec = vec4(0.8, 0.8, 0.8, 0.0);
  vec4 lightspec = vec4(1.0, 1.0, 1.0, 0.0);
  float shininess = 0.45;
  // ...
 
  vec4 lpos = vec4(lightPositions[0], 0.0);
  vec4 s = -normalize(pos-lpos);

  vec3 light = s.xyz;
  vec3 n = normalize(vnormal);
  vec3 r = -reflect(light, n);
  r = normalize(r);
  vec3 v = -pos.xyz;
  v = normalize(v);
   
  vec4 diffuse  = color * max(0.0, dot(n, light)) * diffuseColor;
  vec4 specular = lightspec * matspec * pow(max(0.0, dot(r, v)), shininess);

  gl_FragColor = diffuse + specular;

  if(lightCount >= 2){
     lpos = vec4(lightPositions[1], 0.0);
     s = -normalize(pos-lpos);

     light = s.xyz;
     n = normalize(vnormal);
     r = -reflect(light, n);
     r = normalize(r);
     v = -pos.xyz;
     v = normalize(v);
   
     diffuse  = color * max(0.0, dot(n, light)) * diffuseColor;
     specular = lightspec * matspec * pow(max(0.0, dot(r, v)), shininess);

     gl_FragColor += diffuse + specular;

   // if(lightCount >= 3){...}
   }
}
Title: Re: Viable engine?
Post by: EgonOlsen on May 25, 2012, 05:44:44 pm
Just keep in mind (as you can see when looking at the source of jPCT-AE's default shaders...) that using loops for multiple lightsources isn't a good idea. because they don't compile well on Adreno GPUs. So if you want to support even more lights, do what Thomas. did and add additional if-blocks instead.