We are about to switch to a new forum software. Until then we have removed the registration on this forum.
there's stuff in java/ch/bildspur/postfx/pass/BasePass.java which handles filenames. there is windows-specific code in there so you'd think it would work.
AdvancedEffect, CustomShaderEffect, OffScreenEffect, ReadMeRendering, and SimpleEffect are not running. These examples contains "Pass" that are showing error message:
C:\Documents\Processing\libraries\PostFX\src\main\java\ch\bildspur\postfx\pass
go to above path on your computer, you will find different "pass", all "pass" are showing error in above mentioned examples.
All examples are not running, BrightPass, sobelPass, BloomPass, BlurPass, and other are showing error.
does not compute.
i've just installed it (1.1) and i only get these examples:
https://github.com/cansik/processing-postfx/tree/master/examples
There is an error in running the example codes of PostFX library, the error is: InvalidPathException: Illegal char <:> Please help me how to resolve this???????
PImage img;
void setup() {
size(480,640,P3D);
hint(DISABLE_DEPTH_TEST);
blendMode(ADD);
//image credit: pixabay.com/de/startrails-felsen-nacht-918551/ CC0
img=loadImage("https://"+"cdn.pixabay.com/photo/2015/09/02/12/36/startrails-918551_640.jpg?attachment");
}
int y=0;
void draw() {
background(0);
image(img,0,0);
translate(width/2,(y>640)?y-=y:y++);
fill(204,102,0,125);
sphere(90);
}
@trailbalzer47 can't help you any further. Blend Modes is something on my to do list. I just try things out.
Here is a nice PostFx Lib
github.com/cansik/processing-postfx
Good Luck.
@nabr I'm hoping to have some PostFX render pass classes to share.
a|x
@toneburst Yes the OpenGL error is a bit annoying. It happens only with some shaders, but I did not have time to investigate it. But as far as I know it's more a warning then a real error. I have it on track here (it was the first issue I added ;) ):
https://github.com/cansik/processing-postfx/issues/1
Copying pixels around (loadpixels
/ updatepixels
) is very slow. Try to avoid it. It simpler to draw the texture on to the other with the image(img, x, y)
method:
pass.beginDraw();
// also apply shader if you want to process the drawn texture
// pass.shader(myShader);
pass.image(previewsTexture, 0, 0);
pass.endDraw();
I hope that helps :) This does the same as the filter()
method with a shader.
@cansik incidentally, I get an error
OpenGL error 1282 at top endDraw(): invalid operation
every time I run my sketch, when using PostFX passes.
a|x
@cansik Hi, hope you don't mind me cross-posting, but is this the best (fastest) way to implement texture feedback in a custom PostFX pass definition?
pass.loadPixels();
previousTexture.loadPixels();
arrayCopy(pass.pixels, previousTexture.pixels);
pass.updatePixels();
previousTexture.updatePixels();
a|x
@nabr thanks re. the feedback! I got a bit sidetracked into messing around with that for a while. Still have a little idea I'd like to integrate into it.
Am I right in thinking that copying the pixels in the custom PostFX pass definition is a performance bottleneck, do you think? I can't imagine it's done on the GPU.
a|x
Yes, their a bug in your code. @cansik know's a quick fix i think
It was not working, on my PC i changed few lines to make it work
https://processing.org:8443/tutorials/video/
You have different declarations like P2D and then P3D. I found it's best, while debuging your stetch, when you use nummers in the size(nummer, nummer, P3D)
- and then createGraphic(nummer,nummer) >instead of width, height. Thouse values can evaluate druing the "startup" and "miss" the setup. default is 100x100 px so you would run a createGraphic, or a box(size) Object at a lower res ...etc.
//
////////////////////////////////////////////////////
////////////////////////////////////////////////////
//A-Life
//Alex Drinkwater 2017
////////////////////////////////////////////////////
////////////////////////////////////////////////////
//
// Video library
import processing.video.*;
// PostFX shader-chaining library
// https://github.com/cansik/processing-postfx
import ch.bildspur.postfx.builder.*;
import ch.bildspur.postfx.pass.*;
import ch.bildspur.postfx.*;
// ControlP5 GUI library
// https://github.com/sojamo/controlp5
import controlP5.*;
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// GLOBAL VARIABLES //////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
Capture cam;
PGraphics camFrame;
// Custom shader pass class (requires PostFX)
PostFX fx;
FeedbackPass feedbackPass;
ConwayPass conwayPass;
PGraphics canvas;
// GUI library
ControlP5 cp5;
color guiColor = color(200, 200, 200);
float brushSize;
float feedback;
float channelSpread;
boolean runFX;
//changed
void captureEvent(Capture video) {
video.read();
}
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// SETUP /////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
void setup() {
//changed
size(640, 480, P3D);
//////////////////
// Init Capture //
//////////////////
//changed
camFrame = createGraphics(640, 480, P3D);
///////////////////////
// PostFX pass stuff //
///////////////////////
fx = new PostFX(this);
feedbackPass = new FeedbackPass();
conwayPass = new ConwayPass();
//////////////////
// Add controls //
//////////////////
cp5 = new ControlP5(this);
cp5.addSlider("brushSize")
.setPosition(40, 40)
.setSize(100, 20)
.setRange(0.01, 0.05)
.setValue(0.025)
.setColorCaptionLabel(guiColor);
cp5.addSlider("feedback")
.setPosition(40, 70)
.setSize(100, 20)
.setRange(0.0, 0.90)
.setValue(0.80)
.setColorCaptionLabel(guiColor);
cp5.addSlider("channelSpread")
.setPosition(40, 100)
.setSize(100, 20)
.setRange(0.00, 0.07)
.setValue(0.0)
.setColorCaptionLabel(guiColor);
cp5.addToggle("runFX")
.setPosition(40, 130)
.setSize(20, 20)
.setColorCaptionLabel(guiColor)
.setValue(false);
//changed
cam = new Capture(this, 640, 480);
cam.start();
}
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// DRAW //////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
void draw() {
// Set feedback level for feedback pass shader
feedbackPass.setFeedback(feedback);
feedbackPass.setChannelSpread(channelSpread);
conwayPass.setStartFX(runFX);
conwayPass.setMouse(map(mouseX, 0, width, 0, 1), map(mouseY, 0, height, 1, 0));
conwayPass.setBrushSize(brushSize);
// Copy capture pixels to PGraphics instance
cam.loadPixels();
camFrame.loadPixels();
arrayCopy(cam.pixels, camFrame.pixels);
cam.updatePixels();
camFrame.updatePixels();
image(camFrame, 0, 0);
//OpenGL error 1282 at top endDraw(): invalid operation
//Apply passes
blendMode(BLEND);
fx.render()
.custom(conwayPass)
.custom(feedbackPass)
//.bloom(0.5, 20, 40)
.compose();
//enable for debug
//image(cam, 0, 0);
}
Hi @cansik is this the right place to post about issues using PostFX?
I'm having some problems implementing texture feedback in a custom pass (more details in this thread https://forum.processing.org/two/discussion/22508/chaining-shaders-and-feedback#latest ).
a|x
Got image capture working :)
/*
////////////////////////////////////////////////////
////////////////////////////////////////////////////
A-Life
Alex Drinkwater 2017
////////////////////////////////////////////////////
////////////////////////////////////////////////////
*/
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// LIBRARIES /////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// Video library
import processing.video.*;
// PostFX shader-chaining library
// https://github.com/cansik/processing-postfx
import ch.bildspur.postfx.builder.*;
import ch.bildspur.postfx.pass.*;
import ch.bildspur.postfx.*;
// ControlP5 GUI library
// https://github.com/sojamo/controlp5
import controlP5.*;
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// GLOBAL VARIABLES //////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
Capture cam;
PGraphics camFrame;
// Custom shader pass class (requires PostFX)
PostFX fx;
FeedbackPass feedbackPass;
ConwayPass conwayPass;
PGraphics canvas;
// GUI library
ControlP5 cp5;
color guiColor = color(200,200,200);
float brushSize;
float feedback;
boolean runFX;
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// SETUP /////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
void setup() {
size(1280, 720, P2D);
//////////////////
// Init Capture //
//////////////////
String[] cameras = Capture.list();
if (cameras.length == 0) {
println("There are no cameras available for capture.");
exit();
} else {
println("Available cameras:");
for (int i = 0; i < cameras.length; i++) {
println(cameras[i]);
}
// The camera can be initialized directly using an
// element from the array returned by list():
cam = new Capture(this, cameras[0]);
cam.start();
}
camFrame = createGraphics(width, height, P2D);
///////////////////////
// PostFX pass stuff //
///////////////////////
fx = new PostFX(this);
feedbackPass = new FeedbackPass();
conwayPass = new ConwayPass();
//////////////////
// Add controls //
//////////////////
cp5 = new ControlP5(this);
cp5.addSlider("brushSize")
.setPosition(40, 40)
.setSize(100, 20)
.setRange(0.01, 0.05)
.setValue(0.025)
.setColorCaptionLabel(guiColor);
cp5.addSlider("feedback")
.setPosition(40, 70)
.setSize(100, 20)
.setRange(0., 0.95)
.setValue(0.80)
.setColorCaptionLabel(guiColor);
cp5.addToggle("runFX")
.setPosition(40, 100)
.setSize(20, 20)
.setColorCaptionLabel(guiColor)
.setValue(false);
}
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
// DRAW //////////////////////////////////////////////
//////////////////////////////////////////////////////
//////////////////////////////////////////////////////
void draw() {
// Set feedback level for feedback pass shader
feedbackPass.setfeedback(feedback);
conwayPass.setStartFX(runFX);
conwayPass.setMouse(map(mouseX, 0, width, 0, 1), map(mouseY, 0, height, 1, 0));
conwayPass.setBrushSize(brushSize);
if (cam.available() == true) {
cam.read();
}
cam.loadPixels();
camFrame.loadPixels();
arrayCopy(cam.pixels, camFrame.pixels);
cam.updatePixels();
camFrame.updatePixels();
image(camFrame, 0, 0);
// Apply passes
blendMode(BLEND);
fx.render()
//.custom(conwayPass)
.custom(feedbackPass)
//.bloom(0.5, 20, 40)
.compose();
}
a|x
Too easy...
This seems to work :)
/*
////////////////////////////////////////
PostFX custom pass class definition
Dependencies:
PostFX library
////////////////////////////////////////
*/
class FeedbackPass implements Pass
{
private PShader shader;
private float feedbackLevel;
private PGraphics previousTex;
/////////////////
// Constructor //
/////////////////
public FeedbackPass()
{
shader = loadShader("feedback.glsl");
previousTex = createGraphics(width, height, P3D);
}
@Override
public void prepare(Supervisor supervisor) {
shader.set("oldTexture", previousTex);
}
@Override
public void apply(Supervisor supervisor) {
PGraphics pass = supervisor.getNextPass();
//supervisor.clearPass(pass);
shader.set("feedback", feedbackLevel);
pass.beginDraw();
pass.shader(shader);
pass.image(supervisor.getCurrentPass(), 0, 0);
pass.endDraw();
// Update previous texture
previousTex = pass;
}
/////////////////////
// Mutator methods //
/////////////////////
public void setfeedback(float feedback)
{
this.feedbackLevel = feedback;
}
}
I have a feeling that setting 'oldTex' to 'pass' like this (line 45) may not be the fastest way to do it.
I tried arrayCopy, but got a nullPointer exception.
a|x
Aha.. if I comment out the line
supervisor.clearPass(pass);
in my feedbackPass class declaration, it works...
I've added a function to my feedbackPass class to allow me to change one of the shader uniforms from the draw loop in the main sketch. No idea if this is the correct way to do this, as I'm unfamiliar with Java (and OOP in general, to my shame).
FeedbackPass.pde:
class FeedbackPass implements Pass
{
PShader shader;
float feedbackLevel;
public FeedbackPass()
{
shader = loadShader("feedback.glsl");
}
@Override
public void prepare(Supervisor supervisor) {
shader.set("feedback", 0.75);
}
@Override
public void apply(Supervisor supervisor) {
PGraphics pass = supervisor.getNextPass();
//supervisor.clearPass(pass);
shader.set("feedback", feedbackLevel);
pass.beginDraw();
pass.shader(shader);
pass.image(supervisor.getCurrentPass(), 0, 0);
pass.endDraw();
}
public void setfeedback(float feedback)
{
feedbackLevel = feedback;
}
}
And the main sketch .pde:
// PostFX shader-chaining library
import ch.bildspur.postfx.builder.*;
import ch.bildspur.postfx.pass.*;
import ch.bildspur.postfx.*;
// GLSL version of Conway's game of life
PShader conway;
PGraphics canvas;
// Custom shader pass class
PostFX fx;
FeedbackPass feedbackPass;
// GUI library
import controlP5.*;
ControlP5 cp5;
float brushSize;
float feedback;
///////////////////////////
// SETUP //////////////////
///////////////////////////
void setup() {
size(640, 480, P2D);
// Add controls
cp5 = new ControlP5(this);
cp5.addSlider("brushSize")
.setPosition(40, 40)
.setSize(100, 20)
.setRange(0.01, 0.05)
.setValue(0.025)
.setColorCaptionLabel(color(200,200,200));
cp5.addSlider("feedback")
.setPosition(40, 70)
.setSize(100, 20)
.setRange(0., 0.95)
.setValue(0.5)
.setColorCaptionLabel(color(200,200,200));
// Init shader stuff
canvas = createGraphics(width, height, P3D);
canvas.noSmooth();
conway = loadShader("conway.glsl");
conway.set("resolution", float(canvas.width), float(canvas.height));
// PostFX pass stuff
//supervisor = new PostFXSupervisor(this);
fx = new PostFX(this);
feedbackPass = new FeedbackPass();
}
///////////////////////////
// DRAW ///////////////////
///////////////////////////
void draw() {
// Shader uniforms
conway.set("time", millis()/1000.0);
float x = map(mouseX, 0, width, 0, 1);
float y = map(mouseY, 0, height, 1, 0);
conway.set("brushsize", brushSize);
conway.set("mouse", x, y);
// Draw shader
canvas.beginDraw();
canvas.background(0);
canvas.pushMatrix();
canvas.shader(conway);
canvas.rect(0, 0, canvas.width, canvas.height);
canvas.popMatrix();
canvas.endDraw();
image(canvas, 0, 0);
// Set feedback level for feedback pass shader
feedbackPass.setfeedback(feedback);
// Apply passes
blendMode(BLEND);
fx.render()
//.bloom(0.5, 20, 40)
.custom(feedbackPass)
.compose();
}
a|x
So, now I have:
// PostFX shader-chaining library
import ch.bildspur.postfx.builder.*;
import ch.bildspur.postfx.pass.*;
import ch.bildspur.postfx.*;
// GLSL version of Conway's game of life
PShader conway;
PGraphics canvas;
// Custom shader pass class
PostFX fx;
//PostFXSupervisor supervisor;
FeedbackPass feedbackPass;
NegatePass negatePass;
// GUI library
import controlP5.*;
ControlP5 cp5;
float brushSize;
///////////////////////////
// SETUP //////////////////
///////////////////////////
void setup() {
size(640, 480, P2D);
// Add controls
cp5 = new ControlP5(this);
cp5.addSlider("brushSize")
.setPosition(40, 40)
.setSize(100, 20)
.setRange(0.01, 0.05)
.setValue(0.025)
.setColorCaptionLabel(color(200,200,200));
// Init shader stuff
canvas = createGraphics(width, height, P3D);
canvas.noSmooth();
conway = loadShader("conway.glsl");
conway.set("resolution", float(canvas.width), float(canvas.height));
// PostFX pass stuff
//supervisor = new PostFXSupervisor(this);
fx = new PostFX(this);
feedbackPass = new FeedbackPass();
negatePass = new NegatePass();
}
///////////////////////////
// DRAW ///////////////////
///////////////////////////
void draw() {
// Shader uniforms
conway.set("time", millis()/1000.0);
float x = map(mouseX, 0, width, 0, 1);
float y = map(mouseY, 0, height, 1, 0);
conway.set("brushsize", brushSize);
conway.set("mouse", x, y);
// Draw shader
canvas.beginDraw();
canvas.background(0);
canvas.pushMatrix();
canvas.shader(conway);
canvas.rect(0, 0, canvas.width, canvas.height);
canvas.popMatrix();
canvas.endDraw();
//
blendMode(BLEND);
fx.render(canvas)
.bloom(0.5, 20, 40)
.custom(feedbackPass)
.compose();
}
And my shader:
// Mix between input texture and previous frame pixels
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
uniform sampler2D texture;
uniform sampler2D ppixels;
uniform float feedback;
varying vec4 vertTexCoord;
void main( void ) {
vec2 position = vertTexCoord.st;
gl_FragColor = mix(texture2D(texture, position), texture2D(ppixels, position), feedback);
}
Which doesn't work. The ppixel texture in the feedback shader seems to contain nothing, so changing the feedback amount just has the effect of mixing between the output of the first pass and black, and making the image darker. I'd intended to create a kind of 'trails' effect.
Does this mean I have to manage my own FBOs manually, in order to get feedback working?
I'm able to use ppixels for feedback, while I do the initial drawing of the Conway shader, before I apply the PostFX passes.
a|x
I've made some progress.
// PostFX shader-chaining library
import ch.bildspur.postfx.builder.*;
import ch.bildspur.postfx.pass.*;
import ch.bildspur.postfx.*;
// GLSL version of Conway's game of life
PShader conway;
PGraphics canvas;
// Custom shader pass class
PostFX fx;
//PostFXSupervisor supervisor;
//FeedbackPass feedbackPass;
NegatePass negatePass;
// GUI library
import controlP5.*;
ControlP5 cp5;
float brushSize;
///////////////////////////
// SETUP //////////////////
///////////////////////////
void setup() {
size(640, 480, P2D);
// Add controls
cp5 = new ControlP5(this);
cp5.addSlider("brushSize")
.setPosition(40, 40)
.setSize(100, 20)
.setRange(0.01, 0.05)
.setValue(0.025)
.setColorCaptionLabel(color(200,200,200));
// Init shader stuff
canvas = createGraphics(width, height, P3D);
canvas.noSmooth();
conway = loadShader("conway.glsl");
conway.set("resolution", float(canvas.width), float(canvas.height));
// PostFX pass stuff
//supervisor = new PostFXSupervisor(this);
fx = new PostFX(this);
//feedbackPass = new FeedbackPass();
negatePass = new NegatePass();
}
///////////////////////////
// DRAW ///////////////////
///////////////////////////
void draw() {
// Shader uniforms
conway.set("time", millis()/1000.0);
float x = map(mouseX, 0, width, 0, 1);
float y = map(mouseY, 0, height, 1, 0);
conway.set("brushsize", brushSize);
conway.set("mouse", x, y);
// Draw shader
canvas.beginDraw();
canvas.background(0);
canvas.pushMatrix();
canvas.shader(conway);
canvas.rect(0, 0, canvas.width, canvas.height);
canvas.popMatrix();
canvas.endDraw();
//
blendMode(BLEND);
fx.render(canvas)
.bloom(0.5, 20, 40)
//.custom(negatePass)
.compose();
}
This nicely applies a bloom effect to the output of the conway shader.
My hope is to replace the negate shader, from the PostFX CustomShaderEffect example with my own, but for the moment, I'm just using the negate shader from the example.
Unfortunately, if I uncomment the line
.custom(negatePass)
I get an OpenGL error
ERROR: 0:12: Regular non-array variable 'vertColor' may not be redeclared
Is there a way to fix this, @cansik?
a|x
Hi,
got sidetracked and ended up trying to do this in Quartz Composer, failed, so I'm now back in Processing...
@cansik, can I access the previous frame's texture using ppixels when using postFX?
a|x
Congrats on this work. A major contribution! And just a reminder to all, PostFX is on the libraries page under utilities:
...and can be found in the PDE Contributions Manager (although that version number isn't always up-to-the-minute -- and you may need to restart PDE).
I am happy to announce that I released version 1.1 today!
Version 1.1 brings a lot of new features to post processing library. First of all a bunch of new shaders have been added to the library, which are useful for 3D and 2D scenes. Here is a list of the new shaders:
The second new thing is, that the library now works on the default graphics object (onscreen buffer g
with P2D
and P3D
). So now it is not needed to draw your scene onto a canvas anymore. Just run following code:
// in setup
PostFX fx = new PostFX(this);
// in draw
fx.render()
.invert()
.compose();
It is also possible now to preload shaders, to run initialisation in the setup method:
fx.preload(InvertPass.class);
And I also implemented a way to simply run your own custom passes:
// in draw
fx.render()
.custom(myCustomPass)
.compose();
I hope the library works as expected! If you have any suggestion just write me here or leave a new issue in github!