Need help understanding image tiling

I’m trying to do image tiling so that I can do high resolution screenshots. I found this page that describes how to do it:

http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node30.html

But I can’t wrap my head around the math, esp. for calculating xoffset and yoffset (the equations look totally arbitrary to me).

Can anyone explain or point to a more detailed explanation?

Thanks :slight_smile:

I just read the text of the page you gave the link to. You can forget the top bunch of formulas and just use the bottom ones.
The formulas for x and y offset look a bit complicated, but a one sentence explanation is given.
Basically if you have let’s say 3x3 tiles then with xoffset and yoffset you compute a transformation that transforms the center of each tile to the right position.

If we’re computing where tiles should be, why aren’t we just working with the lower left hand corner? I don’t see why xoffset and yoffset aren’t just:

xoffset = i * tileWidth;
yoffset = j * tileHeight;

If for some reason we wanted to place the centers, I don’t see why it wouldn’t be:

xoffset = i * tileWidth + tileWidth / 2.0;
yoffset = j * tileHeight + tileHeight / 2.0;

But their’s is more complicated :stuck_out_tongue:

In the case where you have only a single tile you will be using the nornaml NDC space where (-1, -1) is in the lower left (0,0) is in the center and (1,1) is in the upper right. For this xoffset and yoffset will become 0.
If you have say 3x3 tiles xoffset and yoffset need to be 0 for the middle tile with i=1 and j=1 (no offset just scaling which is not the case for your formula), while for the other tiles you need to move the center of the tile to the correct location.

You can’t work with the lower left hand corner as you need to line up the centers!

Edit: Try if you can get the formulas to work. I myself are not exactly sure why does formulas are supposed to work. If they don’t you have to come up with something yourself.

Ok maybe this works and is easier:
xScale = tile_count_x;
xOffset = -2*i + tile_count_x - 1;

Same for y. Maybe xOffset needs to be negated (don’t know). Thats just of the top of my head.

You can also use gluPickMatrix for this task.
Use the size of the high-resolution image for the “viewport” parameter. “x” and “y” represent the position of the curret tile inside the screenshot and “width/height” are set to the size of the tile. Set the viewport size of your actual render target to the tile size. The setup then looks like this:

glMatrixMode(GL_PROJECTION)
glLoadIdentity()
GLint screenshotviewport[4]={0,0,screenshot_width, screenshot_height};
gluPickMatrix(tile_x, tile_y, tile_width, tile_height, screenshotviewport)
glFrustum() (or whatever you use to setup your projection)
glMatrixMode(GL_MODELVIEW)
glViewport(0,0, tile_width, tile_height);

...render your image

Special attention is needed, when the screenshot width or height is not an exact multiple of the tile size. In this case you get border-tiles that are smaller than normal tiles.

You might want to check out my old tile rendering utility library:

http://www.mesa3d.org/brianp/TR.html

gluPickMatrix looks like it would be a lot simpler and easier. The only issue is that if I use it, and it restricts drawing to an area of a huge fake viewport, that area maybe outside the real viewport. Say the real viewport is 1280x800, and the high resolution image is 9000x9000, then there will be tiles totally off the screen (which then can’t be copied with glTexImage2D or glReadPixels, etc.). I could try giving negative x/y coords in the viewport to try and have the tile rest inside the window area, but I don’t know if OpenGL will accept negative values there.

Time to experiment…

@skynet: Sorry in my previous post I misunderstood you. I was thinking gluPickMatrix acted just like the scissor test, I didn’t realize it “zoomed in” too.

However, I can’t get this method to work. I just get a blank white area. Does any of this look incorrect?

	// Don't pick a tile size bigger than the framebuffer because we need to use glReadPixels
	// to get our screenshot
	int tileWidth, tileHeight;
	for(int i = 1; i < 1000; ++i) {
		tileWidth = std::ceil(double(sceneWidth) / double(i));
		tileHeight = std::ceil(double(sceneHeight) / double(i));
		if(	tileWidth < framebufferWidth &&
			tileHeight < framebufferHeight)
			break;
	}

	int nTilesX = std::ceil(double(sceneWidth) / double(tileWidth));
	int nTilesY = std::ceil(double(sceneHeight) / double(tileHeight));

    	for(int y = 0; y < nTilesY; ++y) {
		for(int x = 0; x < nTilesX; ++x) {
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

			GLint fake_viewport[4] = { 0, 0, sceneWidth, sceneHeight };

			glMatrixMode(GL_PROJECTION);
			glPushMatrix();
			gluPickMatrix(x * tileWidth, y * tileHeight, tileWidth, tileHeight, fake_viewport);

			glPushAttrib(GL_VIEWPORT_BIT);
			glViewport(0, 0, tileWidth, tileHeight);

			// This calls gluOrtho2D using the given width/size, then renders the scene
			m_primarySelection->ContentsRender(sceneWidth, sceneHeight);

			glPopAttrib();

			glMatrixMode(GL_PROJECTION);
			glPopMatrix();
			glMatrixMode(GL_MODELVIEW);

			// This takes a screenshot of the given window area using glReadPixels, then copies it onto a large final bitmap named
			// composite_shot
			compositor.DrawBitmap(*Screenshot(0, 0, tileWidth, tileHeight), x * tileWidth, sceneHeight - (y+1) * tileHeight);
		}
    	}

	composite_shot.SaveFile(fileDlg.GetFilename(), wxBITMAP_TYPE_PNG);

I figured it out. In case anyone has the same problem, the code above is correct except for 2 changes – glLoadIdentity() needs to be called after glPushMatrix(), and gluPickMatrix expects the given x/y to be the center of the tile, so you have to add tileWidth / 2.0 and tileHeight / 2.0.

Thanks for all the help people :slight_smile: