www.jpct.net

jPCT-AE - a 3d engine for Android => Support => Topic started by: guillaume on September 16, 2012, 07:02:25 am

Title: jPCT and real 3D
Post by: guillaume on September 16, 2012, 07:02:25 am
Dear Egon,
     some android based smart TV sets support output two different
3d images  (one for left eye and one for right eye ) to support real 3D.
I wonder how to do this with jPCT-AE ?
does jPCT support two cameras  in a World ?
so with these two cameras (one for left eye, one for right eye), I can
render scene for different eyes ?
can I instantiate two FrameBuffers in a same GLSurfaceView (each one occupies half of the surface view)?
and render the World (with different camera) to each of them ?
Title: Re: jPCT and real 3D
Post by: EgonOlsen on September 16, 2012, 08:48:58 am
I was under the impression that some magic in the 3d drivers does this without any need to change the application somehow... ???
Title: Re: jPCT and real 3D
Post by: kiffa on September 17, 2012, 05:57:10 am
This question is also what i am interested in!

And this may depend on the way how the hardware implement real-3D.
Title: Re: jPCT and real 3D
Post by: guillaume on September 20, 2012, 01:35:54 pm
I was under the impression that some magic in the 3d drivers does this without any need to change the application somehow... ???
yes. there it is.  but is it possible for us to do it in app level ?
Title: Re: jPCT and real 3D
Post by: EgonOlsen on September 21, 2012, 05:05:12 pm
You can render the scene multiple times with different cameras...if that does any good.
Title: Re: jPCT and real 3D
Post by: guillaume on September 26, 2012, 10:54:45 am
You can render the scene multiple times with different cameras...if that does any good.
actually, after setup the world, I want to clone the world's camera
to two new cameras,  but there is no clone method for camera ,
how should I do it ?thanks
Title: Re: jPCT and real 3D
Post by: EgonOlsen on September 26, 2012, 02:48:59 pm
Like so:

Code: [Select]
Camera cam2=new Camera();
cam2.setFOV(cam.getFOV());
cam2.setPosition(cam.getPosition());
cam2.setBack(cam.getBack().cloneMatrix());
Title: Re: jPCT and real 3D
Post by: guillaume on October 09, 2012, 05:07:55 am
finally, I got my real 3D render.
the base idea is :
1.  create 1 offscreen framebuffer for each eye
2.  set the  framebuffer to render to a Texture
3.  render one eye's view to the texture
4.  blit the texture to screen with down scale to  1/2  original size.

then problem comes:
1. after several frames, OOM exception thrown.
many logs like:
I/jPCT-AE (  574): OpenGL context has changed...trying to recover!
I/jPCT-AE (  574): OpenGL context has changed...trying to recover!
I/jPCT-AE (  574): OpenGL context has changed...trying to recover!
I/jPCT-AE (  574): Additional visibility list (380) created with size: 512
I/jPCT-AE (  574): OpenGL context has changed...trying to recover!
I/jPCT-AE (  574): OpenGL context has changed...trying to recover!
I/jPCT-AE (  574): OpenGL context has changed...trying to recover!
I/jPCT-AE (  574): Additional visibility list (390) created with size: 512

2. the blit down-scaled image is upside-down.

dear Egon, can you give some advices ? thanks.

Code: [Select]
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Logger;
import com.threed.jpct.RGBColor;
import com.threed.jpct.Texture;
import com.tpv.ui.trid.AndroidFrameBlitter;
import com.tpv.ui.trid.TriDScene;
import com.tpv.ui.trid.real3d.Real3DRenderer.Position;

import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;

public class Real3DRenderer implements Renderer {


private TriDScene mScene = null;
private FrameBuffer mFb = null;
private FrameBuffer mBackFb = null;
private Texture mBackTexture = null;
public enum Position {
LEFT,
RIGHT,
};
private Position mPos = Position.LEFT;
private float mSpeed = 0.0f;
private final float SPEED_OFFSET = 0.01f;

public void incAngle() {
// TODO Auto-generated method stub
mSpeed += SPEED_OFFSET;
if(mPos == Position.LEFT)
Log.d("3DUI","left camera speed"+mSpeed);
else
Log.d("3DUI","right camera speed"+mSpeed);
}
public void decAngle() {
// TODO Auto-generated method stub
mSpeed -= SPEED_OFFSET;
if(mSpeed < 0)
mSpeed = 0.0f;
if(mPos == Position.LEFT)
Log.d("3DUI","left camera speed "+mSpeed);
else
Log.d("3DUI","right camera speed "+mSpeed);

}

public Real3DRenderer(TriDScene scene, Position pos){
mScene = scene;
mPos = pos;
}
private RGBColor black = new RGBColor(0, 0, 0, 0);
@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub

mBackFb.clear(black);
if(mPos == Position.LEFT)
mScene.renderFrame(mBackFb, -mSpeed);
else
mScene.renderFrame(mBackFb, mSpeed);
mBackFb.display();

// blit to screen
mFb.clear(black);
mFb.blit(mBackTexture, 0, 0, 0, 0,
mBackTexture.getWidth(), mBackTexture.getHeight(),
mBackTexture.getWidth()/2, mBackTexture.getHeight(),
-1,false, null);
mFb.display();


}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
if (mFb != null) {
mFb.dispose();
}
mFb = new FrameBuffer(gl, width, height);
Logger.log("==== Launcher launch: " +width+"X" +height+" OpenGL Major Version: "+mFb.getOpenGLMajorVersion());

if(mBackFb != null){
mBackFb.dispose();
}
mBackFb = new FrameBuffer(gl, width*2, height);
mBackTexture = new Texture(width*2, height);
mBackFb.setRenderTarget(mBackTexture);
}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub

}

}
Title: Re: jPCT and real 3D
Post by: EgonOlsen on October 09, 2012, 06:27:39 pm
You are not supposed to use multiple FrameBuffer instances at a time. This makes jPCT-AE think that the context has changed each time you render into it, which is why it behaves the way it does. You should be able to rewrite the code to use one buffer instead. If you assign a render target, the actual buffer size will be overriden by the size of the texture.
Title: Re: jPCT and real 3D
Post by: EgonOlsen on October 09, 2012, 06:40:56 pm
About things being upside down: That's caused by the way gls coordinate system works. You can try to blit with a negative height...you should be able to find something about this somewhere around here.

Edit: Like so:


fb.blit(renderTarget, 0, 0, 0, fb.getHeight(), fb.getWidth(), fb.getHeight(), fb.getWidth(), -fb.getHeight(), -1, false, null);
Title: Re: jPCT and real 3D
Post by: guillaume on October 10, 2012, 05:29:56 am
You are not supposed to use multiple FrameBuffer instances at a time. This makes jPCT-AE think that the context has changed each time you render into it, which is why it behaves the way it does. You should be able to rewrite the code to use one buffer instead. If you assign a render target, the actual buffer size will be overriden by the size of the texture.

currently I render left eye's and right eye's scene to screen side by side. to achieve this,
I use two GLSurfaceView on the screen with two FrameBuffer.
by using ONE  FrameBuffer, How can I render side by side scene on screen ?
and before render to the screen, I would like to down scale the rendered image to its 1/2 width.
Title: Re: jPCT and real 3D
Post by: EgonOlsen on October 10, 2012, 08:16:54 am
Does real 3d require to use two GLSurfaceView instances? Or would it work with one that contains both parts of the image?
Title: Re: jPCT and real 3D
Post by: guillaume on October 10, 2012, 08:23:53 am
Does real 3d require to use two GLSurfaceView instances? Or would it work with one that contains both parts of the image?
No it doesn't.
we just require that the image contains left,right eye's view side by side.
Title: Re: jPCT and real 3D
Post by: EgonOlsen on October 10, 2012, 08:50:09 am
Well then...create one framebuffer of the output size, create one (or two) texture(s) to render the parts into, set them as render targets one after the other, render the parts in each one, remove the render target and blit both textures into the framebuffer. You might have to enable OpenGL ES 2.0 for proper render to texture btw. (if you haven't already).
Title: Re: jPCT and real 3D
Post by: guillaume on October 11, 2012, 05:31:41 am
thanks, egon.
with FrameBuffer.blit 's argument  destWidth set to mFb.getWidth()/2 , I got the device-2012-10-11-111842-half.png
with destWidth set to  mFb.getWidth(), I got  the device-2012-10-11-111934-full.png.
my goal is to show the full content in left side of the screen.

the half width image dose not show the full content of the full width image, but lost some.
does this mean that the FrameBuffer.blit is broken in android ?

Code: [Select]
mFb.blit(mLeftTexture,
0, 0, 0, mFb.getHeight(),
mLeftTexture.getWidth(), mLeftTexture.getHeight(),
mFb.getWidth(), -mFb.getHeight(), -1, false, null);

[attachment deleted by admin]
Title: Re: jPCT and real 3D
Post by: EgonOlsen on October 11, 2012, 07:23:53 am
I'm not aware of any problem with blitting. I'll try to create a simple test case today and post the results and the code.
Title: Re: jPCT and real 3D
Post by: guillaume on October 11, 2012, 01:14:16 pm
I'm not aware of any problem with blitting. I'll try to create a simple test case today and post the results and the code.
thanks, Egon. I appreciate your help very much.
Title: Re: jPCT and real 3D
Post by: EgonOlsen on October 11, 2012, 05:28:30 pm
Here's a simple example. It contains a little quirk...it renders into the render targets and then, after removing the render target, it renders into an empty world that shares its camera with the normal world. This doesn't cost any performance at all, but it's a quick way to set the viewport to the desired size. This doesn't happen correctly otherwise, because of...engine internals...(No, it's not a hack... ;) )

Hope this helps:

Code: [Select]
package com.example.helloworldsplitted;

import java.lang.reflect.Field;

import javax.microedition.khronos.egl.EGLConfig;
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.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.World;
import com.threed.jpct.util.MemoryHelper;

/**
 *
 * @author EgonOlsen
 *
 */
public class HelloWorldSplitted extends Activity {

// Used to handle pause and resume...
private static HelloWorldSplitted master = null;

private GLSurfaceView mGLView;
private MyRenderer renderer = null;
private FrameBuffer fb = null;
private World world = null;
private World emptyWorld=null;

private Texture renderTarget = null;
private Texture renderTarget2 = null;

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

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

private Object3D cube = 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.setEGLContextClientVersion(2);

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( w, h);

if (master == null) {

emptyWorld = new World();

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

sun = new Light(world);
sun.setIntensity(250, 250, 250);
cube = Primitives.getCube(10);
cube.strip();
cube.build();

world.addObject(cube);

Camera cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
cam.lookAt(cube.getTransformedCenter());

SimpleVector sv = new SimpleVector();
sv.set(cube.getTransformedCenter());
sv.y -= 100;
sv.z -= 100;
sun.setPosition(sv);
MemoryHelper.compact();

renderTarget=new Texture(fb.getWidth(), fb.getHeight());
renderTarget2=new Texture(fb.getWidth(), fb.getHeight());

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

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

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

if (touchTurnUp != 0) {
cube.rotateX(touchTurnUp);
touchTurnUp = 0;
}

fb.setRenderTarget(renderTarget);
fb.clear(RGBColor.RED);
world.renderScene(fb);
world.draw(fb);
fb.setRenderTarget(null);

fb.setRenderTarget(renderTarget2);
fb.clear(RGBColor.GREEN);
world.renderScene(fb);
world.draw(fb);
fb.setRenderTarget(null);

fb.clear();
emptyWorld.setCameraTo(world.getCamera());
emptyWorld.renderScene(fb);
emptyWorld.draw(fb);

fb.blit(renderTarget, 0, 0, 0, 0, renderTarget.getWidth(), -renderTarget.getHeight(), fb.getWidth()/2, fb.getHeight(), -1, false, null);
fb.blit(renderTarget2, 0, 0, fb.getWidth()/2, 0, renderTarget2.getWidth(), -renderTarget2.getHeight(), fb.getWidth()/2, fb.getHeight(), -1, false, null);

fb.display();

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

Title: Re: jPCT and real 3D
Post by: guillaume on October 20, 2012, 07:07:19 am
thanks. this really helps. 8)