ofImage --> ofFbo is (so far) blank

I’m working on some extensions for OF bindings for Lua scripts in the Pure Data graphical patching programming environment. (That project is Ofelia.)

I’m quite new to all this – good with audio programming but I’m not at all expert with graphics. (Also not especially interested in C, FWIW.)

Ofelia doesn’t ship with any image filters. So after some digging around, it looked like it should be feasible to do ofImage --> draw to ofFbo --> pass fbo to shader --> get back to ofImage (and this could be passed to another fbo/shader).

Why fbo? Why not just bind the image and run the shader? The end goal is to modularize, so that the Pd user can create objects like [of.image] --> [of.brightness] --> [of.plane] and it would do texture mapping internally. (Another user has created a framework, but without shaders.) The brightness shader should be independent of any rotation/translation – so it seems necessary to me to run the shader to a non-displayed frame buffer, and then texture map the resulting frame buffer with rotation/translation.

I’ve been able to write a script that loads an image and draws it through a shader.

Now I’m trying to extend that with the fbo first (not even using the shader yet), but:

-- during setup:
fbo:allocate(image:getWidth(), image:getHeight(), GL_RGBA);

-- during drawing:
fbo:beginFbo();
image:draw(0, 0);
fbo:endFbo();

… and after this, the fbo is blank.

There’s no point in adding the shader until I’m sure the fbo has the data.

Any ideas? I’ll paste the Lua script below (and the entire Pd patch is shown in the screenshot).

hjh

if type(window) ~= "userdata" then;
window = ofWindow();
end;
;
local canvas = ofCanvas(this);
local dir = canvas:getDir() .. "/";
local image = ofImage();
local fbo = ofFbo();
local useFbo = 0;
;
function M.new();
ofWindow.addListener("setup", this);
ofWindow.addListener("draw", this);
ofWindow.addListener("exit", this);
window:setPosition(0, 0);
window:setSize(500, 500);
if ofWindow.exists then;
clock:delay(0);
else;
window:create();
end;
end;
;
function M.free();
window:destroy();
ofWindow.removeListener("setup", this);
ofWindow.removeListener("draw", this);
ofWindow.removeListener("exit", this);
end;
;
function M.setup();
ofSetWindowTitle("fbo1");
ofBackground(255, 255, 255, 255);
image:load(dir .. "../oil.jpg");
fbo:allocate(image:getWidth(), image:getHeight(), GL_RGBA);
M.pln = ofPlanePrimitive();
M.pln:setRows(4);
M.pln:setColumns(4);
M.pln:setWidth(500);
M.pln:setHeight(500);
M.pln:setPosition(ofVec3f(250.0, 250.0, 0.0):vec3());
end;
;
function M.useFbo(f) useFbo = f end;
;
function M.draw();
ofSetColor(255);
fbo:beginFbo();
image:draw(0, 0);
fbo:endFbo();
if(useFbo == 0) then image:bind() else fbo:bind() end;
M.pln:draw();
if(useFbo == 0) then image:unbind() else fbo:unbind() end;
end;
;
function M.exit();
image:clear();
end

is it an alpha channel thing? try like

fbo.begin();
ofClear(255, 255);
fbo.end();

and or ofEnableAlphaBlending()/ofDisableAlphaBlending()

Changed the draw function to:

function M.draw();
ofSetColor(255);
fbo:beginFbo();
ofClear(25, M.alpha);
fbo:endFbo();
if(useFbo == 0) then image:bind() else fbo:bind() end;
M.pln:draw();
if(useFbo == 0) then image:unbind() else fbo:unbind() end;
end;

… and added an alpha slider:

of-clear-alpha

But, when I switch the fbo on, the window is still all white instead of the 10% gray I expected.

hjh

Ah, got it – it turns out the missing piece was ofDisableArbTex();. When I added this to the setup function, then suddenly it started working. (I don’t know if any developers or maintainers are reading, but this novice’s perspective is that it’s exceptionally difficult to find all the fine print.)

So then I dropped in my test “gain” shader and, after making sure I set all the shader uniform parameters, it’s… working :grin: This, I think, is the hard part. Once the plumbing is working, it should be relatively easy to write a few other simple shaders.

hjh

Finished script:

if type(window) ~= "userdata" then;
window = ofWindow();
end;
;
local canvas = ofCanvas(this);
local dir = canvas:getDir() .. "/";
local image = ofImage();
local fbo = ofFbo();
local useFbo = 0;
M.alpha = 255;
local shader = ofShader();
;
function M.new();
ofWindow.addListener("setup", this);
ofWindow.addListener("draw", this);
ofWindow.addListener("exit", this);
window:setPosition(300, 200);
window:setSize(500, 500);
if ofWindow.exists then;
clock:delay(0);
else;
window:create();
end;
end;
;
function M.free();
window:destroy();
ofWindow.removeListener("setup", this);
ofWindow.removeListener("draw", this);
ofWindow.removeListener("exit", this);
end;
;
function M.setup();
ofSetWindowTitle("fbo1");
ofEnableAlphaBlending();
ofDisableArbTex();
ofBackground(255, 255, 255, 255);
image:load(dir .. "../oil.jpg");
fbo:allocate(image:getWidth(), image:getHeight(), GL_RGBA);
M.dimen = ofVec2f(image:getWidth(), image:getHeight()):vec2();
print(M.dimen);
M.pln = ofPlanePrimitive();
M.pln:setRows(4);
M.pln:setColumns(4);
M.pln:setWidth(500);
M.pln:setHeight(500);
M.pln:setPosition(ofVec3f(250.0, 250.0, 0.0):vec3());
shader:load(dir .. "gain");
end;
;
function M.useFbo(f) useFbo = f end;
function M.gain(f) gainC = ofFloatColor(f, f, f, 1) end;
;
M.gain(1.0);
;
function M.draw();
ofSetColor(255);
fbo:beginFbo();
shader:beginShader();
shader:setUniform4f("gain", gainC);
shader:setUniform2f("dimen", M.dimen);
image:draw(0, 0);
shader:endShader();
fbo:endFbo();
if(useFbo == 0) then image:bind() else fbo:getTexture():bind() end;
M.pln:draw();
if(useFbo == 0) then image:unbind() else fbo:getTexture():unbind() end;
end;
;
function M.exit();
image:clear();
shader:unload();
end
1 Like