Multiple Viewports, Multiple Textures - 3D

I would in no way consider myself an advanced openGL programmer; I believe the code I inherited from previous colleagues is and I am having a problem with some changes that were made before they left that went unseen. So I hope my posting to the advanced forum doesn’t ruffle too many feathers.

I work on visualization software for a medical company. OpenGL (jogl) is used for both 2D and 3D rendering. Until these changes mentioned above were made, when a monitor displayed multiple viewports, each viewport ‘owned’ an openGL canvas. additional requirements were added that required simultaneous scrolling of multiple viewports at a specified rate. with each viewport having it’s own canvas, the scrolling speed was limited by the screen refresh rate since each viewport required a single screen refresh to update. so, the design was changed to use one single canvas for a monitor and then create ‘virtual’ viewports on top of that canvas. There have been no problems with the 2D implementation. But recently a situation was encountered with 3D that has stumped me for several weeks now. I realize that I probably cannot describe the implementation as well as might be required and to upload the code that renders/displays the 3D images would be near impossible since it is so embedded in the entire application. I will try and explain the best I can and hope that there might be someone who can shed some light on what I clearly cannot see.

For those familiar with GPU-based volume rendering, there is a paper, “Acceleration Techniques for GPU-based Volume Rendering”, written by j. Kruger and R. Westerman that was used to implement 3D rendering (which I can make available to anyone who would like to read it). Quote from the paper which I consider to be my focus as to where the problem might lie: “Instead of using the frame buffer, the rendering can be directed to a 2D texture map that is aligned with the viewport. The texture can be accessed in the following rendering passes. consequently, this mechanism allows different passes to communicate their rendering results to consecutive passes”. This is achieved by glCopyTexSubImage2D() after each pass. What is happening in a nutshell is that the viewport at (0,0) displays correctly; any other viewport(s) display black. I have used ‘glGetTexImage()’ to determine that the texture image is black when the viewport coordinates are anything other than (0,0). I have used ‘glReadPxels()’ to determine that the image is correct in the back buffer for all viewports, regardless of the coordinates.

Instead of waxing on with additional information and details, if anyone has any expertise in this area and is able to help, let me know and I will provide whatever additional details/information you need.


glGetError is often useful in situations like this.

It sounds from your description that glCopyTexSubImage2D may have issues.

However this call is not guaranteed to work with all dimensions on some platforms I have worked with.

You may want to try to make sure that any offsets and dimensions are a multiple of 8.

Also you went from a single canvas to multiple, but presumably the texture stayed the size of the viewport.

Make sure that you are offsetting the framebuffer read point and not the texture destination point. The first x,y in the call should remain 0,0 The second x,y is the viewport origin (some multiple of 8 pixels (humor me)) and shold be relative to the window origin not the viewport, and the width and height should NOT exceed the size of the TEXTURE width and height AND not exit the overall screen.

Finally (and probably firstly) try drawing to the lower left viewport so that both values for x,y are 0,0 (surely you’ve already done this) and this will at least validate that basic operation is working for the new system.

Check window origin and y asis direction for your platform.

I advise to look around glScissor, which is often mandatory when doing multiple viewports within a single GL window :

Make sure that each subwindow get a correct scissor.

thanks for your response Dorbie. I’m amazed anyone understood what I wrote :D.

Can you explain why offsets/dimensions need to be a multiple of 8? I have an idea but I would like to know what you are thinking.

and actually, we went from multiple canvas’s to single canvas. but you are correct about the texture size staying the same.

glGetError() is sprinkled throughout the code and there are no errors on any openGL call. When calling glCopyTexSubImage2D(), I am retrieving the viewport dimension prior to the call and using those.

int[] aiViewport = new int[4];
mtGL.glGetIntegerv(GL.GL_VIEWPORT, java.nio.IntBuffer.wrap(aiViewport));

// Copy the frame buffer into a texture
mtGL.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, // target
0, // mip-map level
0, // x-offset into target
0, // y-offset into target
aiViewport[0], // screen x
aiViewport[1], // screen y
getImageWidth(), // screen width
getImageHeight()); // screen height

image Height/Width is the NPOT image size (textures are all POT size)

drawing to the lower left viewport is no problem. I assume that is because the origin is (0,0), the easy case.

I started using gDebugger yesterday (finally convinced mgmt that I couldn’t resolve this without it). when drawing to the front buffer I can see the image. that is the part I cannot figure out. I think I am still not very clear on how texture mapping works.

I’m not sure what you mean about the window origin and y-axis. if you are referring to the difference between the windows origin (top left = 0) and openGL origin (bottom left = 0), that is taken care of by using glPixelZoom(1.0, -1.0) earlier in the code.

thanks for taking time to help me.

ZbufferR - thank you for your input. the scissor test is enabled during the rendering and the parameters are the same as the viewport. see code below:

// Get the dimensions and offset of the ‘virtual’ panel
final int iWidth = tPanel.getWidth();
final int iHeight = tPanel.getHeight();
final int iX = tPanel.getX();

// OpenGL flips the y-coordinate system. The bottom left corner of the canvas is 0,0 so we need to adjust the y position
mtGLCanvas = (GLCanvas) tGLDrawable;

final int iY = mtGLCanvas.getHeight() - tPanel.getY() - iHeight;

final GL tGL = tGLDrawable.getGL();

// Enable scissor-cropping to ensure we paint only in the virtual canvavs.

tGL.glViewport(iX, iY, iWidth, iHeight);
tGL.glScissor(iX, iY, iWidth, iHeight);

thanks ZbufferR