FrameBuffer and Camera: Unexpected translation

I’m using a FrameBufferObject to capture some graphics drawn by openframeworks and an ofEasyCam and then piping them into an image in ImGui. In the process, I’ve discovered an interesting feature.

I have two rectangles: drawArea (green), which represents the area the frame buffer captures, and camArea (blue), which represents the area the easyCam draws to and uses as its viewport. The image below shows how this looks drawn normally to the screen (no buffers). The blue box bounds the camera output, as one would expect.

Once I wrap those drawing routines in buffer.begin() and buffer.end(), things get a little weird. I have the buffer draw itself a little ways from the top-left corner. We see that the green and blue rectangles still have the same relative positions, but the camera view is no longer contained within the blue box (see below). More specifically, the x-coordinates of the blue box still bound the camera view, but the y-coordinates do not.

Anyone have any ideas? To recreate this demo and test it yourself, create a blank project with no addons and add the following objects to ofApp.h:

ofEasyCam cam;
ofFbo buffer;
GLuint bufferID;
ofFbo::Settings settings;

In ofApp.cpp, setup():

cam.setDistance(50);
cam.setNearClip(1.f);

draw():

ofRectangle drawArea(0,0,405,405);
ofRectangle camArea(20,20,380,380);
settings.width = drawArea.width;
settings.height = drawArea.height;
settings.textureTarget = GL_TEXTURE_2D;
settings.internalformat = GL_RGBA;

buffer.allocate(settings);
bufferID = buffer.getTexture().texData.textureID;


// Comment / Uncomment lines below
buffer.begin();
ofClear(255, 255, 255, 0);
//-----------------------

cam.begin(camArea);

ofSpherePrimitive s1, s2, s3, s4;
s1.setPosition(0,0,0);
s1.setRadius(2);
s2 = s3 = s4 = s1;
s2.setPosition(6,0,0);
s3.setPosition(0,6,0);
s4.setPosition(0,0,6);

ofSetColor(ofColor::red);
s1.draw();
s2.draw();
s3.draw();
s4.draw();

cam.end();

ofSetColor(ofColor::green);
ofFill();
ofDrawRectangle(ofRectangle(drawArea.x,drawArea.y,15,15));
ofDrawRectangle(ofRectangle(drawArea.x+drawArea.width-15, drawArea.y+drawArea.height-15, 15, 15));
ofSetColor(ofColor::blue);
ofDrawRectangle(ofRectangle(camArea.x+camArea.width-15,camArea.y,15,15));
ofDrawRectangle(ofRectangle(camArea.x, camArea.y+camArea.height-15, 15, 15));

ofNoFill();
ofSetColor(ofColor::green);
ofSetLineWidth(2);
ofDrawRectangle(drawArea);
ofSetColor(ofColor::blue);
ofDrawRectangle(camArea);

// Comment / Uncomment lines below
buffer.end();
buffer.draw(100, 100);

You get the same behavior if you make the camArea rectangle shorter than the frame buffer area:

ofRectangle drawArea(0,0,405,405);
ofRectangle camArea(0,0,405,380);

Here the shift is again in the opposite direction as the translation of camArea; seems to be an inverse relationship on the y-translation somewhere…