How to capture an image with background refresh (false) to an FBO

Hi folks :slight_smile:

I have made a simple trailing circle design. It looks cool, and I want to print it. Normally to print things, I save the image to a larger FBO offscreen and then save the .png files from there to get a good resolution.

This is all well and good, but in this instance will not work. The FBO only sees a few of the circles because it does not see the whole “drawing”, only the circles being drawn at the time I asked for a .png.

Here are some screenshots

Screenshot 2022-12-28 at 14.55.42

The first shows what is on the screen. The second is what is drawn to the FBO.

The last screenshot is what I am doing saving to a larger than screen size FBO.

The question is- what are some ways I can solve this- Do I need to use multiple FBOs somehow drawing to them or can I do a simpler way?

I would remove the no background refresh window settings all together.
Then after you allocate the _fbo do:

_fbo.begin();
ofClear(0, 0, 0, 255);//clear the fbo contents
_fbo.end();

Then make sure you don’t have ofClear in your draw function.

Also do _fbo.begin() and end() regardless of _saveToFbo
And then draw your fbo to the screen at the very end of your draw loop ( after the saving code block )

That way you see what is being drawn to your fbo and hitting save just copies the pixels to disk.

If you want to post your whole draw function I can post the changes

Theo

@theo Thank you!

I will post the code-The thing that is confusing me is that I need the circles to layer up…which is why I made sure the no back ground refresh was on

Yes! And that will happen with the fbo too.

  • As long as you don’t use ofClear inside the fbo::begin
  • and if you do fbo::begin and fbo::end every frame regardless of saving.

I think I understand- once I see the code I think the penny will drop



Uploading: Screenshot 2022-12-28 at 19.47.48.png…

Uploading: Screenshot 2022-12-28 at 19.48.41.png…

So I am drawing as normal, but then shifting to the FBO off screen just to capture the image for print

Can you share the whole of ofApp.cpp as code not screenshot?

You can paste in the code to the forum reply box and then use the </> button in the post message box to format it as code.

Thanks!


//-----------------------------------------------------
void ofApp::setup(){
    ofBackground(0);
    //set up the FBO for the picture
    //first of all, allocate a large bit of space for the FBO.  We are trying to get plenty of space for the drawing so we can print high resolution
    _fbo.allocate(4000,4000, GL_RGB);
    //Clear any junk from the FBO
    _fbo.begin();
    ofClear(0);
    _fbo.end();

    //Set up the Gui
    myGui.setup();
    myGuiHide=false;
    
    myGui.add(color1HueMultiply.set("HueOne*",0.01, 1.0, 0));
    myGui.add(color2HueMultiply.set("HueTwo*",0.01, 1.0, 0));
    myGui.add(paramSettingsFileName.set("Settings file", "settings.json"));
    myGui.add(buttonSaveSettings.setup("Save settings"));
    myGui.add(buttonLoadSettings.setup("Load settings"));
    // Setup listeners for parameters
  
    buttonSaveSettings.addListener(this, &ofApp::saveSettingsButtonPressed);
    buttonLoadSettings.addListener(this, &ofApp::loadSettingsButtonPressed);
}
//-----------------------------------------------------
void ofApp::update(){

}

//----------------------------------------------------
void ofApp::draw(){
    ofSetBackgroundAuto(false);
  
    //draw the cirle pattern
  pattern();
    
    if( !myGuiHide ){
       myGui.draw();
    }
    if (_saveToFbo) {
     _fbo.begin();
   }
    //add the code for saving to the FBO
    if (_saveToFbo) {
      _fbo.end();
      _saveToFbo = false;
      
      ofPixels pixels;
      _fbo.readToPixels(pixels);
      ofImage image;
      image.allocate(_fbo.getWidth(), _fbo.getHeight(), OF_IMAGE_COLOR);
      image.setFromPixels(pixels);
      
      string filename = "circles_" + timeStamp() + "_" + ofToString(saveCount,3,'0') + ".png";
      
      image.save(filename);
}
    
      
    }
      

//-----------------------------------------------------
void ofApp::pattern(){
    if (_saveToFbo) {
      _fbo.begin();
    }
    //declare local color var
    float C1 = mouseX;
    float C2 = mouseY;
    ofColor color1;
    color1.setHue(mouseX * color1HueMultiply);
    color1.setBrightness(ofMap(mouseX,110, ofGetWidth(), 0, 100));
    color1.setSaturation(ofMap(mouseX, 100, ofGetWidth(), 0, 255));
    
    ofColor color2;
    color2.setHue(mouseY*color2HueMultiply);
    color2.setSaturation(ofMap(mouseY, 0,ofGetHeight(), 0, 30));
    color2.setBrightness(ofMap(mouseY, 0, ofGetHeight(), 0, 155));
    
    ofColor color3;
    color3.setHue(mouseX/2);
    color3.setSaturation(ofMap(C1/C2, 0,ofGetWidth(), 0, 100));
    color3.setBrightness(ofMap(mouseY, 0, ofGetHeight(), 0, 255));
    
    
    float nPosX = posX + ofRandom(3,5);
    float nPosY = posY + ofRandom(3,15);
    float wander = ofRandom(5);
  
 
    ofSetCircleResolution(200);
    ofSetLineWidth(ofRandom(0.1,2));
    ofSetColor(color3);
    ofNoFill();
    ofDrawEllipse(posX, posY, nPosX/2+wander, nPosY/2+wander);
    ofSetLineWidth(ofRandom(0.1,3));
    ofDrawEllipse(posX, posY, nPosX/2, nPosY/2);
    ofSetLineWidth(ofRandom(0.4,2.5));
    ofDrawEllipse(posX, posY, nPosX/4, nPosY/4);
    //update values for posX, posY
    posX = nPosX;
    posY = nPosY;
    
    //note- the gui will keep being drawn.  It is essential to clear the screen to hide the gui.  So, what to do?  Set up your settings in the Gui.  Save the settings.  Load the settings. Clear. Draw. Photo taken
    if( !myGuiHide ){
       myGui.draw();
    }
    //add the code for saving to the FBO
    if (_saveToFbo) {
      _fbo.end();
      _saveToFbo = false;
      
      ofPixels pixels;
      _fbo.readToPixels(pixels);
      ofImage image;
      image.allocate(_fbo.getWidth(), _fbo.getHeight(), OF_IMAGE_COLOR);
      image.setFromPixels(pixels);
      
      string filename = "circles_" + timeStamp() + "_" + ofToString(saveCount,3,'0') + ".png";
      
      image.save(filename);
}
}
//-----------------------------------------------------
void ofApp::keyPressed(int key){
    if( key == 'h' ){
        myGuiHide = !myGuiHide;
    }
    if (key == 'c') {
         ofClear(0, 255);
     }
    if (key == ' ') {
      _saveToFbo = true;
    }
}
//-----------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
    posX = mouseX;
    posY = mouseY;

}
//-----------------------------------------------------
void ofApp::saveSettingsButtonPressed() {
    // Get the fileName from the GUI parameter
    string fileName = paramSettingsFileName.toString();
    myGui.saveToFile(fileName);
}
//-----------------------------------------------------
void ofApp::loadSettingsButtonPressed() {
    // Get the fileName from the GUI parameter
    string fileName = paramSettingsFileName.toString();
    myGui.loadFromFile(fileName);
}

Cool, it worked. I thought it did not but when I refreshed the browser it had. It was my first go at formatting like this so thanks for the patience. I can do format like this from now on :slight_smile:

1 Like

I edited it for you :wink:

but the easiest way is actually to just first put three backticks ``` on a new line in the editor.

then paste your code below it and then end the code with another ``` on a new line.

Anyway. Here is my suggestions for your code. :slight_smile:

note: your mouse might not line up with what you are seeing as the drawing is happening at a larger scale. you would need to do some mapping of the mouse to have it draw right under your cursor, but maybe it is fine without?

//-----------------------------------------------------
void ofApp::setup(){
    ofBackground(0);
    //set up the FBO for the picture
    //first of all, allocate a large bit of space for the FBO.  We are trying to get plenty of space for the drawing so we can print high resolution
    _fbo.allocate(4000,4000, GL_RGB);
    //Clear any junk from the FBO
    _fbo.begin();
    ofClear(0);
    _fbo.end();

    //Set up the Gui
    myGui.setup();
    myGuiHide=false;
    
    myGui.add(color1HueMultiply.set("HueOne*",0.01, 1.0, 0));
    myGui.add(color2HueMultiply.set("HueTwo*",0.01, 1.0, 0));
    myGui.add(paramSettingsFileName.set("Settings file", "settings.json"));
    myGui.add(buttonSaveSettings.setup("Save settings"));
    myGui.add(buttonLoadSettings.setup("Load settings"));
    // Setup listeners for parameters
  
    buttonSaveSettings.addListener(this, &ofApp::saveSettingsButtonPressed);
    buttonLoadSettings.addListener(this, &ofApp::loadSettingsButtonPressed);
}
//-----------------------------------------------------
void ofApp::update(){

}

//----------------------------------------------------
void ofApp::draw(){
   ofBackground(10,10,10,255); 
    //ofSetBackgroundAuto(false);  //<------ comment this out 
  
     _fbo.begin();

    //draw the cirle pattern inside the fbo every frame 
    pattern();

    _fbo.end(); 

    //add the code for saving to the FBO
    if (_saveToFbo) {
      _saveToFbo = false;
      
      ofPixels pixels;
      _fbo.readToPixels(pixels);
      ofImage image;
      image.setUseTexture(false); //no need for a texture as we are just saving 
      image.allocate(_fbo.getWidth(), _fbo.getHeight(), OF_IMAGE_COLOR);
      image.setFromPixels(pixels);
      
      string filename = "circles_" + timeStamp() + "_" + ofToString(saveCount,3,'0') + ".png";
      
      image.save(filename);
    }
    
   //now draw the fbo to screen fitting the fbo into the window viewport 
   ofRectangle fitToScreen(0, 0, _fbo.getWidth(), fbo.getHeight()); 
   fitToScreen.scaleTo(ofRectangle(0, 0, ofGetWidth(), ofGetHeight()), ofAspectRatioMode::OF_ASPECT_RATIO_KEEP, ofAlignHorz::OF_ALIGN_HORZ_CENTER, ofAlignVert::OF_ALIGN_VERT_CENTER);

   ofSetColor(255);
   _fbo.draw(fitToScreen);

   //draw the gui over everything - this won't affect the fbo contents  
    if( !myGuiHide ){
       myGui.draw();
    }
}
      

//-----------------------------------------------------
void ofApp::pattern(){
    //declare local color var
    float C1 = mouseX;
    float C2 = mouseY;
    ofColor color1;
    color1.setHue(mouseX * color1HueMultiply);
    color1.setBrightness(ofMap(mouseX,110, ofGetWidth(), 0, 100));
    color1.setSaturation(ofMap(mouseX, 100, ofGetWidth(), 0, 255));
    
    ofColor color2;
    color2.setHue(mouseY*color2HueMultiply);
    color2.setSaturation(ofMap(mouseY, 0,ofGetHeight(), 0, 30));
    color2.setBrightness(ofMap(mouseY, 0, ofGetHeight(), 0, 155));
    
    ofColor color3;
    color3.setHue(mouseX/2);
    color3.setSaturation(ofMap(C1/C2, 0,ofGetWidth(), 0, 100));
    color3.setBrightness(ofMap(mouseY, 0, ofGetHeight(), 0, 255));
    
    
    float nPosX = posX + ofRandom(3,5);
    float nPosY = posY + ofRandom(3,15);
    float wander = ofRandom(5);
  
 
    ofSetCircleResolution(200);
    ofSetLineWidth(ofRandom(0.1,2));
    ofSetColor(color3);
    ofNoFill();
    ofDrawEllipse(posX, posY, nPosX/2+wander, nPosY/2+wander);
    ofSetLineWidth(ofRandom(0.1,3));
    ofDrawEllipse(posX, posY, nPosX/2, nPosY/2);
    ofSetLineWidth(ofRandom(0.4,2.5));
    ofDrawEllipse(posX, posY, nPosX/4, nPosY/4);
    //update values for posX, posY
    posX = nPosX;
    posY = nPosY;
}

//-----------------------------------------------------
void ofApp::keyPressed(int key){
    if( key == 'h' ){
        myGuiHide = !myGuiHide;
    }
    if (key == 'c') {
        _fbo.begin();
         ofClear(0, 255);
        _fbo.end();
     }
    if (key == ' ') {
      _saveToFbo = true;
    }
}
//-----------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
    posX = mouseX;
    posY = mouseY;

}
//-----------------------------------------------------
void ofApp::saveSettingsButtonPressed() {
    // Get the fileName from the GUI parameter
    string fileName = paramSettingsFileName.toString();
    myGui.saveToFile(fileName);
}
//-----------------------------------------------------
void ofApp::loadSettingsButtonPressed() {
    // Get the fileName from the GUI parameter
    string fileName = paramSettingsFileName.toString();
    myGui.loadFromFile(fileName);
}

Thank you! I will build this now and study to see what I was not understanding! Once again, you have been a great help. Much appreciated :slight_smile: