Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

12046 Posts in 1593 Topics- by 597 Members - Latest Member: Pymntizwb

20. May 2013, 01:45:26 pm
Xith3D CommunityGeneral CategorySupport (Moderator: Marvin Fröhlich)Rendering to texture and reading it back
Pages: [1]
Print
Author Topic: Rendering to texture and reading it back  (Read 586 times)
pboechat
Just dropped in

Offline Offline

Posts: 15


View Profile
« on: 14. September 2011, 05:54:02 am »

Hi

During the initialization of my code I'm setting a texture as a render target.

Code:
colorAndAlphaTexture = TextureCreator.createTexture(TextureFormat.RGBA, DEFAULT_WIDTH, DEFAULT_HEIGHT);

renderer = getXith3DEnvironment().getRenderer();

renderer.addRenderTarget(new TextureRenderTarget(root, colorAndAlphaTexture, backgroundColor, true), new BaseRenderPassConfig());

After rendering a frame I try to access its data:

Code:
byte[] buffer;
buffer = new byte[texture.getTextureCanvas().getImage().getDataSize()];
texture.getTextureCanvas().getImage().getData(0, 0, buffer);

But unfortunately the resulting byte array above doesn't seem to represent the actual scene pixels. All array is all set like the following: (0,0,0,-27,0,0,0,-27,0,0,0,-27,0,0,0,-27,...)

Do you know what I'm doing wrong?
Logged
Marvin Fröhlich
Xith Lord
Administrator
Guru
*****
Offline Offline

Posts: 4403


May the 4th, be with you...


View Profile
« Reply #1 on: 14. September 2011, 08:26:14 am »

IIRC you have to add the render target to the render pass, but not the renderer, which is for internal use.
Logged
pboechat
Just dropped in

Offline Offline

Posts: 15


View Profile
« Reply #2 on: 14. September 2011, 12:58:34 pm »

My code is based on the code of some of the tests.

Here's an excerpt from the "RenderToTextureTest" code:

Code:
sceneGraph.getRenderer().addRenderTarget( renderTarget, rp.getConfig() );

Where the "sceneGraph" reference is:

Code:
Xith3DEnvironment env = new Xith3DEnvironment( 0f, 0f, 5f,
                                                       0f, 0f, 0f,
                                                       0f, 1f, 0f,
                                                       this
                                              );


BTW, I'm doing:

Code:
renderer.addRenderTarget(new TextureRenderTarget(root, colorAndAlphaTexture, backgroundColor, true), [b]renderPass.getConfig()[/b]);

And I took the care of registering the render target, canvas, etc. in the same order the examples do.

IMHO, the only thing I'm doing really differently is that I'm adding the scene elements at runtime. I have the following methods

Code:
public void updateScene(View view, List<Light> lightSources, BranchGroup newRoot) {
        for (Light lightSource : lightSources) {
newRoot.addChild(lightSource);
}

// TODO: Check this!
ViewHelper.copy(view, getXith3DEnvironment().getView());

[b]setRoot(newRoot);[/b]
}

private void setRoot(BranchGroup newRoot) {
org.xith3d.render.Renderer renderer;
Colorf backgroundColor;
RenderPass renderPass;

if (root != null) {
getXith3DEnvironment().removeBranchGraph(root);
}

root = newRoot;

renderPass = getXith3DEnvironment().addPerspectiveBranch(root);

backgroundColor = new Colorf(0f, 0f, 0f, 0.1f);

colorAndAlphaTexture = TextureCreator.createTexture(TextureFormat.RGBA, screenWidth, screenHeight, backgroundColor);
depthTexture = TextureCreator.createTexture(TextureFormat.DEPTH, screenWidth, screenHeight);

renderer = getXith3DEnvironment().getRenderer();

renderer.addRenderTarget(new TextureRenderTarget(root, colorAndAlphaTexture, backgroundColor, true), renderPass.getConfig());
renderer.addRenderTarget(new TextureRenderTarget(root, depthTexture), renderPass.getConfig());
}

And he may be called concurrently with the "loopIteration". I created a simple mutex to guard the scene:

Code:

private void rebuildScene(View view, List<Light> lightSources, BranchGroup geometries) {
synchronized (renderer.getSceneLock()) {
renderer.updateScene(view, lightSources, geometries);
}
}

(...)

@Override
protected void loopIteration(long gameTime, long frameTime, TimingMode timingMode) {
super.prepareNextFrame(gameTime, frameTime, timingMode);

if (networkManager.startFrame()) {
synchronized (sceneLock) {
super.renderNextFrame(gameTime, frameTime, timingMode);
                    networkManager.sendColorAlphaAndDepthBuffers(readBytesFromTexture(colorAndAlphaTexture), readBytesFromTexture(depthTexture));
}
}
}
[code]
[/code]
« Last Edit: 14. September 2011, 02:46:17 pm by pboechat » Logged
Marvin Fröhlich
Xith Lord
Administrator
Guru
*****
Offline Offline

Posts: 4403


May the 4th, be with you...


View Profile
« Reply #3 on: 14. September 2011, 04:43:45 pm »

My code is based on the code of some of the tests.

Then I wasn't recalling correctly Wink.


Don't use synchronization. There's a reason, why xith doesn't do that: performance. User a ScheduledOperation to do this job.
Logged
pboechat
Just dropped in

Offline Offline

Posts: 15


View Profile
« Reply #4 on: 14. September 2011, 06:12:08 pm »

No problem, my friend Smiley

Thanks for the suggestion. I'll implement it and see if it works! Anyway I'll post my results here soon.

[]'s
Logged
pboechat
Just dropped in

Offline Offline

Posts: 15


View Profile
« Reply #5 on: 15. September 2011, 08:24:42 pm »

Marvin,

  Indeed I was getting the color + alpha buffer correctly from the texture. I was confused by a little mistake I made with the Java2D ColorModel when tried to copy it to a BufferedImage...
 
  I'm getting another error now: when I try to set the pixelReadbackEnabled to a render target which texture is in the DEPTH format.
ie.:

Code:
depthTexture = TextureCreator.createTexture(TextureFormat.DEPTH, screenWidth, screenHeight);

(...)

renderer.addRenderTarget(new TextureRenderTarget(root, depthTexture, true), renderPass.getConfig());


The first time I render it I get the following error:

Code:
org.lwjgl.opengl.OpenGLException: Invalid operation (1282)
at org.lwjgl.opengl.Util.checkGLError(Util.java:56)
at org.lwjgl.opengl.GL11.glReadPixels(GL11.java:2611)
at org.xith3d.render.lwjgl.RenderTargetPeer.finishRenderTarget(RenderTargetPeer.java:236)
at org.xith3d.render.lwjgl.RenderTargetPeer.finishRenderTarget(RenderTargetPeer.java:281)
at org.xith3d.render.lwjgl.RenderPeerImpl.renderRenderPass(RenderPeerImpl.java:760)
at org.xith3d.render.lwjgl.RenderPeerImpl.render(RenderPeerImpl.java:843)
at org.xith3d.render.lwjgl.CanvasPeerImplBase.doRender(CanvasPeerImplBase.java:331)
at org.xith3d.render.lwjgl.CanvasPeerImplNative.initRenderingImpl(CanvasPeerImplNative.java:628)
at org.xith3d.render.DefaultRenderer.doRender(DefaultRenderer.java:524)
at org.xith3d.render.DefaultRenderer.renderOnceInternal(DefaultRenderer.java:686)
at org.xith3d.render.DefaultRenderer.renderOnce(DefaultRenderer.java:819)
at org.xith3d.base.Xith3DEnvironment.render(Xith3DEnvironment.java:501)
at org.xith3d.loop.RenderLoop.renderNextFrame(RenderLoop.java:619)
at br.edu.univercidade.cc.xithcluster.Renderer.loopIteration(Renderer.java:135)
at org.xith3d.loop.RenderLoop.update(RenderLoop.java:698)
at org.xith3d.loop.UpdatingThread.nextIteration(UpdatingThread.java:487)
at org.xith3d.loop.RenderLoop.nextIteration(RenderLoop.java:709)
at org.xith3d.loop.RenderLoop.loop(RenderLoop.java:762)
at org.xith3d.loop.UpdatingThread.run(UpdatingThread.java:540)
at org.xith3d.loop.RenderLoop.run(RenderLoop.java:785)
at org.xith3d.loop.RenderLoop.begin(RenderLoop.java:841)
at br.edu.univercidade.cc.xithcluster.Renderer.begin(Renderer.java:87)
at org.xith3d.loop.RenderLoop.begin(RenderLoop.java:871)
at br.edu.univercidade.cc.xithcluster.Renderer.main(Renderer.java:181)
org.lwjgl.opengl.OpenGLException: Invalid operation (1282)
at org.lwjgl.opengl.Util.checkGLError(Util.java:56)
at org.lwjgl.opengl.GL11.glReadPixels(GL11.java:2611)
at org.xith3d.render.lwjgl.RenderTargetPeer.finishRenderTarget(RenderTargetPeer.java:236)
at org.xith3d.render.lwjgl.RenderTargetPeer.finishRenderTarget(RenderTargetPeer.java:281)
at org.xith3d.render.lwjgl.RenderPeerImpl.renderRenderPass(RenderPeerImpl.java:760)
at org.xith3d.render.lwjgl.RenderPeerImpl.render(RenderPeerImpl.java:843)
at org.xith3d.render.lwjgl.CanvasPeerImplBase.doRender(CanvasPeerImplBase.java:331)
at org.xith3d.render.lwjgl.CanvasPeerImplNative.initRenderingImpl(CanvasPeerImplNative.java:628)
at org.xith3d.render.DefaultRenderer.doRender(DefaultRenderer.java:524)
at org.xith3d.render.DefaultRenderer.renderOnceInternal(DefaultRenderer.java:686)
at org.xith3d.render.DefaultRenderer.renderOnce(DefaultRenderer.java:819)
at org.xith3d.base.Xith3DEnvironment.render(Xith3DEnvironment.java:501)
at org.xith3d.loop.RenderLoop.renderNextFrame(RenderLoop.java:619)
at br.edu.univercidade.cc.xithcluster.Renderer.loopIteration(Renderer.java:135)
at org.xith3d.loop.RenderLoop.update(RenderLoop.java:698)
at org.xith3d.loop.UpdatingThread.nextIteration(UpdatingThread.java:487)
at org.xith3d.loop.RenderLoop.nextIteration(RenderLoop.java:709)
at org.xith3d.loop.RenderLoop.loop(RenderLoop.java:762)
at org.xith3d.loop.UpdatingThread.run(UpdatingThread.java:540)
at org.xith3d.loop.RenderLoop.run(RenderLoop.java:785)
at org.xith3d.loop.RenderLoop.begin(RenderLoop.java:841)
at br.edu.univercidade.cc.xithcluster.Renderer.begin(Renderer.java:87)
at org.xith3d.loop.RenderLoop.begin(RenderLoop.java:871)
at br.edu.univercidade.cc.xithcluster.Renderer.main(Renderer.java:181)
« Last Edit: 15. September 2011, 08:33:15 pm by pboechat » Logged
pboechat
Just dropped in

Offline Offline

Posts: 15


View Profile
« Reply #6 on: 26. September 2011, 03:05:03 pm »

I opened the class RenderTargetPeer and changed from:

Code:
    private final void finishRenderTarget( TextureRenderTarget renderTarget )
    {
        if ( renderTarget.isPixelReadbackEnabled() )
        {
            Texture2D texture = (Texture2D)renderTarget.getTexture();
           
            ByteBuffer bb = texture.getImage0().getDataBuffer();
            if ( bb != null )
            {
      GL11.glReadPixels( 0, 0, texture.getWidth(), texture.getHeight(), texture.getFormat().hasAlpha() ? GL11.GL_RGBA : GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, bb );
            }
        }
       
        GL11.glPopAttrib();
        // TODO: (cylab 07-11-18) should only be called to return to the normal rendering, not between framebuffers
        EXTFramebufferObject.glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0 );
    }

to:
Code:
private final void finishRenderTarget( TextureRenderTarget renderTarget )
    {
        if ( renderTarget.isPixelReadbackEnabled() )
        {
            Texture2D texture = (Texture2D)renderTarget.getTexture();
           
            ByteBuffer bb = texture.getImage0().getDataBuffer();
            if ( bb != null )
            {
                // checking if it's a depth texture
            if (texture.getFormat() == TextureFormat.DEPTH) {
            GL11.glReadPixels( 0, 0, texture.getWidth(), texture.getHeight(), GL11.GL_DEPTH_COMPONENT, GL11.GL_UNSIGNED_BYTE, bb );
            } else {
            GL11.glReadPixels( 0, 0, texture.getWidth(), texture.getHeight(), texture.getFormat().hasAlpha() ? GL11.GL_RGBA : GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, bb );
            }
            }
        }
       
        GL11.glPopAttrib();
        // TODO: (cylab 07-11-18) should only be called to return to the normal rendering, not between framebuffers
        EXTFramebufferObject.glBindFramebufferEXT( EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0 );
    }

And It seems my problem reading the the DEPTH BUFFER from a texture is solved.


PS = I'm using LWJGL
Logged
Marvin Fröhlich
Xith Lord
Administrator
Guru
*****
Offline Offline

Posts: 4403


May the 4th, be with you...


View Profile
« Reply #7 on: 26. September 2011, 10:41:53 pm »

Good job. I have ported your patch to the JOGL layer, too.
Logged
pboechat
Just dropped in

Offline Offline

Posts: 15


View Profile
« Reply #8 on: 26. September 2011, 10:54:18 pm »

Thanks! Smiley
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic