Hi @pierre_tardif00,
The whole point of the pingpong fbo is swaping it. If you dont swap it you will not get proper feedback.
Also, the implementation of it is wrong ( I am guilty for it).
So I was testing last night, and the only thing that seemed to fix the problem was to use GL_RGBA
as the fbo’s format.
I’ve modified slightly the FboPingPong class so I’ve added it again here.
So this is working for me
ofApp.h
#pragma once
#include "ofMain.h"
#include "FboPingPong.h"
#include "ofxGui.h"
class ofApp : public ofBaseApp{
public:
void setup();
// void update();
void draw();
void keyReleased(int key);
//void windowResized(int w, int h);
FboPingPong pingpong;
ofShader shader;
string frag, vert, fragTest, fragFeedback;
ofFbo fbo;
ofxPanel gui;
ofParameter<float> feedback;
};
ofApp.cpp
#include "ofApp.h"
void ofApp::setup(){
ofSetLogLevel(OF_LOG_VERBOSE);
gui.setup();
gui.add(feedback.set("feedback", 0.9, 0, 1));
vert = "passV.glsl";
fragTest = "test.frag";
fragFeedback = "feedbackLoop.glsl";
frag = fragFeedback;
shader.load(vert, frag);
pingpong.allocate(500,500, GL_RGBA);
fbo.allocate(500,500, GL_RGBA);
}
void ofApp::draw(){
fbo.begin();
ofClear(0, 0);
ofSetColor(255,0,0);
ofDrawSphere(ofGetMouseX(), ofGetMouseY(), 0,sin(ofGetElapsedTimef())*50);
fbo.end();
pingpong.dest().begin();
ofClear(0,0);
shader.begin();
shader.setUniformTexture("tex0", fbo.getTexture(), 0);
shader.setUniformTexture("feedback", pingpong.source().getTexture(), 1);
shader.setUniform1f("feedbackAmt",feedback.get());
shader.setUniform1f("u_time", ofGetElapsedTimef());
ofSetColor(255);
fbo.draw(0,0);
shader.end();
pingpong.dest().end();
ofSetColor(255);
pingpong.dest().draw(0, 0);
ofDrawBitmapStringHighlight("pingpong dest", 20, 20);
pingpong.source().draw(500, 0);
ofDrawBitmapStringHighlight("pingpong source", 520, 20);
fbo.draw(0,500);
ofDrawBitmapStringHighlight("fbo", 20, 520);
ofBitmapFont bf;
string msg = "Using frag shader: " + frag;
auto r = bf.getBoundingBox(msg, 0, 0);
ofDrawBitmapStringHighlight(msg, ofGetWidth() - r.width - 10, ofGetHeight() - 10);
//this line is super important as it will swap the buffers so what was the source now will be the destination and vice versa.
pingpong.swap();
gui.draw();
}
void ofApp::keyReleased(int key){
if(key == '1'){
frag = fragTest;
shader.load(vert, frag);
}else if(key == '2'){
frag = fragFeedback;
shader.load(vert, frag);
}else if(key == ' '){
shader.load(vert, frag);
}
}
FboPingPong.h
//
// FboPingPong.h
// emptyExample
//
// Created by Andreas MĂĽller on 12/08/2013.
//
//
#pragma once
#include "ofMain.h"
class FboPingPong
{
public:
void allocate( int _w, int _h, int internalformat = GL_RGB, ofColor _clearColor = ofColor(255,255,255) );
void allocate( ofFbo::Settings _settings, ofColor _clearColor = ofColor(255,255,255) );
ofFbo& source() { return fbos[sourceIndex]; }
ofFbo& dest() { return fbos[destIndex]; }
void draw( const glm::vec2& _pos, float _width, bool _drawBack = false );
void clearBoth();
void clearBoth( ofColor _clearColor );
void clearSource();
void clearDest();
void clearSource( ofColor _clearColor );
void clearDest( ofColor _clearColor );
void setClearColor( ofColor _color );
void swap();
private:
// ofFbo* sourceBuffer;
// ofFbo* destBuffer;
ofFbo fbos [2];
// ofFbo fbo2;
ofColor clearColor;
int sourceIndex = 0;
int destIndex = 1;
};
FboPingPong.cpp
//
// FboPingPong.cpp
// emptyExample
//
// Created by Andreas MĂĽller on 12/08/2013.
//
//
#include "FboPingPong.h"
// ------------------------------------------------------------------------------------
//
void FboPingPong::allocate( int _w, int _h, int _internalformat, ofColor _clearColor )
{
ofFbo::Settings settings = ofFbo::Settings();
settings.width = _w;
settings.height = _h;
settings.useDepth = true;
settings.internalformat = _internalformat;
allocate( settings, _clearColor );
}
// ------------------------------------------------------------------------------------
//
void FboPingPong::allocate( ofFbo::Settings _settings, ofColor _clearColor )
{
clearColor = _clearColor;
fbos[0].allocate( _settings);
fbos[1].allocate( _settings );
clearSource();
clearDest();
}
// ------------------------------------------------------------------------------------
//
void FboPingPong::draw( const glm::vec2& _pos, float _width, bool _drawBack )
{
float desWidth = _width;
float desHeight = (source().getWidth() / source().getHeight()) * desWidth;
source().draw( _pos.x, _pos.y, desWidth, desHeight );
if( _drawBack ){
dest().draw( _pos.x + desWidth, _pos.y, desWidth, desHeight );
}
}
// ------------------------------------------------------------------------------------
//
void FboPingPong::clearBoth()
{
clearSource();
clearDest();
}
// ------------------------------------------------------------------------------------
//
void FboPingPong::clearBoth( ofColor _clearColor )
{
clearSource( _clearColor );
clearDest( _clearColor );
}
// ------------------------------------------------------------------------------------
//
void FboPingPong::clearSource()
{
clearSource( clearColor );
}
// ------------------------------------------------------------------------------------
//
void FboPingPong::clearDest()
{
clearDest( clearColor );
}
// ------------------------------------------------------------------------------------
//
void FboPingPong::clearSource( ofColor _clearColor )
{
source().begin();
ofClear( _clearColor );
source().end();
}
// ------------------------------------------------------------------------------------
//
void FboPingPong::clearDest( ofColor _clearColor )
{
dest().begin();
ofClear( _clearColor );
dest().end();
}
// ------------------------------------------------------------------------------------
//
void FboPingPong::setClearColor( ofColor _color )
{
clearColor = _color;
}
// ------------------------------------------------------------------------------------
//
void FboPingPong::swap()
{
(++sourceIndex)%=2;
destIndex = (sourceIndex + 1)%2;
// std::swap(sourceBuffer, destBuffer);
}
and the shaders
test.frag
#version 150
uniform sampler2DRect tex0;
uniform sampler2DRect feedback;
uniform float feedbackAmt;
out vec4 outColor;
void main(){
vec2 tc = gl_FragCoord.xy;
vec4 tx = texture(tex0, tc) ;
vec4 fc = texture(feedback, tc);
fc.a *= feedbackAmt;
outColor = fc + tx;
}
feedbackLoop.glsl
#version 150
uniform sampler2DRect tex0;
uniform sampler2DRect feedback;
uniform float u_time;
out vec4 fragColor;
uniform float feedbackAmt;
float hash( float n )
{
return fract(sin(n)*43758.5453123);
}
float noise( in vec2 x )
{
vec2 p = floor(x);
vec2 f = fract(x);
f = f*f*(3.0-2.0*f);
float n = p.x + p.y*157.0;
return mix(mix( hash(n+ 0.0), hash(n+ 1.0),f.x),
mix( hash(n+157.0), hash(n+158.0),f.x),f.y);
}
// hue by netgrind(?)
vec3 hue(vec3 color, float shift) {
const vec3 kRGBToYPrime = vec3 (0.299, 0.587, 0.114);
const vec3 kRGBToI = vec3 (0.596, -0.275, -0.321);
const vec3 kRGBToQ = vec3 (0.212, -0.523, 0.311);
const vec3 kYIQToR = vec3 (1.0, 0.956, 0.621);
const vec3 kYIQToG = vec3 (1.0, -0.272, -0.647);
const vec3 kYIQToB = vec3 (1.0, -1.107, 1.704);
// Convert to YIQ
float YPrime = dot (color, kRGBToYPrime);
float I = dot (color, kRGBToI);
float Q = dot (color, kRGBToQ);
// Calculate the hue and chroma
float hue = atan (Q, I);
float chroma = sqrt (I * I + Q * Q);
// Make the user's adjustments
hue += shift;
// Convert back to YIQ
Q = chroma * sin (hue);
I = chroma * cos (hue);
// Convert back to RGB
vec3 yIQ = vec3 (YPrime, I, Q);
color.r = dot (yIQ, kYIQToR);
color.g = dot (yIQ, kYIQToG);
color.b = dot (yIQ, kYIQToB);
return color;
}
float fractalNoise(vec2 pos) {
float n = 0.;
float scale = 1. / 1.5;
for (int i = 0; i < 5; i += 1) {
n += noise(pos) * scale;
scale *= 0.5;
pos *= 2.;
}
return n;
}
void main(){
vec2 uv = gl_FragCoord.xy;
vec2 polarUv = (uv * 2.0 - 1.0);
float angle = atan(polarUv.y, polarUv.x);
// // Scale up the length of the vector by a noise function feeded by the angle and length of the vector
float ll = length(polarUv)*0.5 - fractalNoise(vec2(sin(angle*4. + u_time*2.) + length(uv)*10., length(uv)*20. + sin(angle*4.)))*0.005 ;
vec3 base = texture(tex0, uv).rgb;
// // Convert the scaled coordinates back to cartesian
vec2 offs = vec2(cos(angle)*ll + 0.5, sin(angle)*ll + 0.5);
// // sample the last texture with uv's slightly scaled up
vec3 overlay = texture(feedback, offs).rgb;
// // Since the colors of the iChannel0 are monochrome, set a color channel to zero to do a hue shift
base.b = 0.;
// // Apply a hue shift to the overlaid image so it cascades in the feedback loop
overlay = hue(overlay, .3);
// // Additively blend the colors together
vec4 col = vec4(clamp(base + overlay*feedbackAmt, vec3(0.),vec3(1.)), 1.0);
// vec4 col = vec4(base + overlay*feedbackAmt, 1.0);
fragColor = col;
// fragColor = texture(tex0, uv);
}