glsl + hue change + blend mode
in
Contributed Library Questions
•
5 months ago
Hi everyone,
I am developing a software were PImages have to be displayed depending on MIDI messages. At runtime, when entering into draw(), some pictures are not displayed and some pictures are displayed after an operation on their hue: depending of the MIDI messages the hue changes. All displayed pictures are blended together in ADD mode (I want black to become transparent) and displayed in a "canvas", a PGrahics object which is sent to a Syphon server.
I first tried to apply the hue change using the loadPixels() and pixels[] of the PImage but it was to much work for the CPU. I also tried to use LUTs as suggested in this
post but it wasn't enough (the CPU exploses and each time I have pictures to display the framerate slow down around 20 fps). So I decided that the most powerful way to do the work was to go into glsl shaders... It is the first time I use it so I still miss a lot of experience !
After playing around with examples, tutorials and forum topics, I finally got a shader which does the hue operation very well (and it is very fast! I keep a good fps and it demands only 35% of CPU VS 70% before). The problem is that my blend mode is not working... the behaviour of my canvas is weird, with the same MIDI messages sometimes the pictures are blending, sometimes not, some pictures are not displayed...
I think that the blend shaders proposed
here are not what I need as they need two pictures (textures) as parameters but what I want is to blend the canvas into itself every time I draw a picture in it between beginDraw() and endDraw(). I read on the internet about openGL and the concept of buffering for blend modes but I am still confused with all of this. I also think that asking Processing to do the blend mode as there are operations on the PImages in the shader is not a good way to go (I tried this and it doesn't work), but I don't really know about blending in openGL, still learning!
Processing 2.0b8
Here is the Processing code:
- import java.awt.event.ActionEvent;
- import java.util.Observable;
- import java.util.Observer;
- import controlP5.*;
- import java.io.*;
- import java.util.*;
- import themidibus.*;
- import codeanticode.syphon.*;
- Model model;
- ControlP5 cp5;
- MidiBus bus;
- SyphonServer server;
- PGraphics canvas;
- Group[] controlChannel;
- XML config;
- String busMIDI;
- File[][] mediaFiles;
- int lengthLibrary = 0;
- PShader hueShader;
- public static final int nbreChannels = 16;
- void setup() {
- // SETUP FRAME AND SYPHON
- size(1280, 720, P2D);
- canvas = createGraphics(1280, 720, P2D);
- server = new SyphonServer(this, "Piano Syphon");
- hueShader = loadShader("hueChange2.glsl");
- hueShader.set("resolution", float(width), float(height));
- hueShader.set("hue", 0.0);
- loadConfig();
- // SETUP THE MIDI BUS
- MidiBus.list();
- bus = new MidiBus(this, 0, 0, "bus");
- // SETUP MVC
- createGUI();
- noLoop();
- }
- void draw(){
- if (frameCount==1){
- try{
- mediaFiles = createMediasFiles();
- }
- catch(Exception e){
- }
- for (int i=0;i<mediaFiles.length;i++){
- for (int j=0;j<12;j++){
- println(mediaFiles[i][j].getAbsolutePath());
- }
- }
- model = new Model(this, mediaFiles);
- loop();
- }
- if (frame!=null){
- frame.setTitle(int(frameRate) + " fps");
- }
- int startTime = millis();
- background(0);
- // here I tried to use canvas.blendMode(ADD); and/or blendMode(ADD); , none of them work
- canvas.beginDraw();
- canvas.background(0);
- colorMode(HSB,1,1,1);
- /*
- ColoredObject updates their colors depending of the MIDI messages, then the hue operation is applied depending of these colors
- */
- for (ColoredObject co: model.observers){
- //this if() sentence is for GUI, checking if a MIDI channel is active or not
- if (co.isSwitchedON()&&(co.getMedia()!=-1)){
- // get a color to apply
- color[] mco = co.getMixedColors();
- for (int i=0;i<mco.length;i++){
- //checks if the color is black or not, if black don't display the picture
- if (saturation(mco[i]) !=0){
- PImage img = model.images[co.getMedia()-1][i];
- float h = hue(mco[i]);
- hueShader.set("iChannel0", img);
- hueShader.set("hue", h);
- canvas.shader(hueShader);
- canvas.rect(0, 0, 1280, 720);
- /*
- here I tried blend(canvas, 0, 0, 1280, 720, 0, 0, 1280, 720, ADD); but does not work properly and get the CPU crazy again so the shader is useless
- */
- }
- }
- }
- }
- canvas.endDraw();
- image(canvas,0,0);
- server.sendImage(canvas);
- colorMode(RGB,255);
- println("draw: " + (millis() - startTime) + " milliseconds");
- }
- void loadConfig(){
- //load some specific constants
- }
- File[][] createMediasFiles(){
- //create an array of Files, which will be used to load the pictures when the sketch begins (just after setup() )
- }
- void createGUI(){
- cp5 = new ControlP5(this);
- cp5.setColorActive(color(255,107,107));
- cp5.setColorBackground(color(21,24,51,100));
- cp5.setColorForeground(color(111,160,206));
- initDashboard();
- initControlChannel();
- cp5.hide();
- }
- void initDashboard(){
- // create a GUI element
- }
- void initControlChannel(){
- // create a GUI element
- }
- void initLibrary(){
- // create a GUI element
- cp5.show();
- }
- void noteOn(int channel, int pitch, int velocity) {
- try{
- // update ColorObject's colors
- model.observers[channel].update(pitch, velocity);
- }
- catch(Exception e){
- println("erreur noteOn");
- }
- println("noteOn:" + pitch +"vélocité note" + "," + "channel" + (channel+1) + ":" + velocity);
- }
- void noteOff(int channel, int pitch, int velocity) {
- try{
- // update ColorObject's colors
- model.observers[channel].update(pitch, 0);
- }
- catch(Exception e){
- println("erreur noteOn");
- }
- println("noteOff");
- }
- // ACTIONS : VUE > MODELE
- void controlEvent(ControlEvent theEvent) {
- //actions on GUI
- }
- void keyPressed() {
- if (key == ESC) {
- key = 0;
- }
- }
- // IMAGE LOADING LISTENER
- class Model implements DataLoadCallback {
- //basically the Model loads and store the PImages to be manipulated and displayed
- }
- // HUE CHANGE
- #ifdef GL_ES
- precision highp float;
- #endif
- #define PROCESSING_COLOR_SHADER
- uniform float time;
- uniform vec2 resolution;
- uniform vec2 mouse;
- vec3 iResolution = vec3(resolution,0.0);
- float iGlobalTime = time;
- vec4 iMouse = vec4(mouse,0.0,0.0); // zw would normally be the click status
- uniform sampler2D iChannel0;
- uniform float hue;
- // works well
- vec3 HUEtoRGB(in float H){
- float R = abs(H * 6.0 - 3.0) - 1.0;
- float G = 2.0 - abs(H * 6.0 - 2.0);
- float B = 2.0 - abs(H * 6.0 - 4.0);
- return clamp(vec3(R,G,B),0.0,1.0);
- }
- //works well
- vec3 HSVtoRGB(in vec3 HSV){
- vec3 RGB = HUEtoRGB(HSV.x);
- return ((RGB - 1.0) * HSV.y + 1.0) * HSV.z;
- }
- //works well
- vec3 RGBtoHSV(vec3 rgb) {
- vec3 hsv;
- float rgb_min, rgb_max;
- float r = rgb.x;
- float g = rgb.y;
- float b = rgb.z;
- rgb_min = min(r, min(g,b));
- rgb_max = max(r, max(g, b));
- hsv.z = rgb_max;
- if (hsv.z == 0.0){
- hsv.x = hsv.y = 0.0;
- return hsv;
- }
- r /= hsv.z;
- g/= hsv.z;
- b /= hsv.z;
- rgb_min = min(r, min(g,b));
- rgb_max = max(r, max(g, b));
- hsv.y = rgb_max - rgb_min;
- if (hsv.y == 0.0){
- hsv.x = 0.0;
- return hsv;
- }
- r = (r - rgb_min) / (rgb_max - rgb_min);
- g = (g- rgb_min) / (rgb_max - rgb_min);
- b = (b- rgb_min) / (rgb_max - rgb_min);
- rgb_min = min(r, min(g,b));
- rgb_max = max(r, max(g, b));
- if (rgb_max == r){
- hsv.x = 0.0 + 60.0*(g-b);
- if (hsv.x < 0.0){
- hsv.x += 1.0;
- }
- }
- else if (rgb_max == g){
- hsv.x = 0.5 + 0.16*(b - r);
- }
- else {
- hsv.x = 0.6 + 0.16*(r- g);
- }
- return hsv;
- }
- void main(void){
- vec2 position = gl_FragCoord.xy / iResolution.xy;
- position.y = 1.0-position.y;
- vec4 color = texture2D(iChannel0, position);
- /*
- get the RGB info, then turn the RGB image info into a HSV image info then go back to RGB but impose the hue. This part works very well !
- */
- vec3 rgbImage = vec3(color.r, color.g, color.b);
- vec3 hsvImage = RGBtoHSV(rgbImage);
- vec3 rgbApplied = HSVtoRGB(vec3(hue, hsvImage.y, hsvImage.z));
- /*
- the alpha is set to the V value of HSV, just a try with the blend() and blendMode() functions of Processing to get the dark/black parts transparents
- */
- gl_FragColor = vec4(rgbApplied.x, rgbApplied.y, rgbApplied.z, hsvImage.z);
- }
Does anyone have some clues / suggestions / tracks for me ? It would be great.
Thanks all
1