Offering money for help with GLSL fragment shader

edited March 2017 in GLSL / Shaders

EDIT: Right now I don't have a specific problem as Lord_of_the_Galaxy gave me a solution that seems to be working (for free)
I'm sure I'll run into more problems though, so if you're competent in glsl and have time for short "freelance" kinds of projects let me know your $ rate .
Would be nice to have someone to contact next time(might be soon) I have a problem/question.
I have not set an amount, but if you can offer help relevant to my problem I'm sure we can negotiate it.


I'm not good at explaining problems, and maybe what I'm saying doesn't make sense, but I'll try my best.
I have a problem trying to make a 2D fragment shader using GLSL
Anyways, I want template for doing one pass per frame, do the next pass on the previous output and so on.

It doesn't need to do anything graphically fancy, it's having this "persistent" canvas that's important.
An analogous thing is not using the background() function,
and thus not having to redraw things every frame for them not to disappear.
It seems in GLSL some things are read-only and some things reset after it's done it work, kind of like local variables in a function.
This could possibly be done with frame buffer object, or pgraphics but I'm not familiar with these.

So you give the shader a "texture" input once, and it works on that input.
And the next frame it works on the output it generated, rather than passing it to glfragcolor and flushing it.
If your pass is rotating a small amount you get a rotating image.
You could get a similar result by rotating by an increasing angle but that's not the point. If it's a post-processing anti-aliasing, you'd get an image that get's blurrier and blurrier.
I hope you understand that it's not doing rotation or anti-aliasing I'm asking for, they're jst dumb examples.. What I wan't help with is this persistent/gradual thing, not doing multiple passes per frame, just once per frame.

But is it possible?
Could you help me with this?
How much do expect in return for your help?

Answers

  • Answer ✓

    sounds like you need render to texture.

    this has a blur example in step 7 (it's not processing but the glsl is familiar looking)

    http://in2gpu.com/2014/09/24/render-to-texture-in-opengl/

  • @koogs you might be on the right track

  • @prince_polka If you find a solution to your problem, please tell me also. I've been trying to find someone who knows this and have failed so far. Should I find a solution, I'll post it here.

  • edited March 2017

    @Lord_of_the_Galaxy, this isn't much but I just managed to create a circle that leaves a trail in glsl sandbox

    glslsandbox.com/e#39122.9

  • @Lord_of_the_Galaxy made a dot that leaves a smooth trail also.. I don't know how to load a texture so that's why I made it flush the screen white at an interval.
    Also I can not get it to work in processing, just getting errors. glslsandbox.com/e#39122.17

  • How did you figure out how to send a texture to the GLSL shader using Processing? Pls help.

  • @ Lord_of_the_Galaxy, by drawing a PImage before applying shader, I can access the pixels in the PImage in the shader once. how to do it "the right way" I have no idea

  • I see. If we can figure out the "right way" it may be possible to do what you want.

  • edited March 2017

    @Lord_of_the_Galaxy
    I rewrote the thing I tried before...

    PShader my_shader;
    PImage my_texture; 
    void setup() {
      size(256, 256, P2D);
      my_shader = loadShader("my_shader.frag");  
      my_texture = loadImage("my_texture.jpg"); 
      image(my_texture,0,0);
    }
    void draw(){
      if(millis()>4000 && millis()<4500){
      image(my_texture,0,0);
      }
      my_shader.set("u_resolution", float(width), float(height));
      shader(my_shader);
    }
    

    my_texture.jpg

    my_shader.frag

    #ifdef GL_ES
    precision mediump float;
    #endif
    uniform sampler2D texture;
    uniform vec2 u_resolution;
    void main () {
    float x = gl_FragCoord.x/u_resolution.x;
    float y = 1.0-gl_FragCoord.y/u_resolution.y  ;
    if(x<0.5){y=1.0-y;}
    gl_FragColor = texture2D(texture ,vec2(x,y));
    }  
    

    Never mind I have a plan an something to work with in glsl-sandbox.. Came up with a better idea than split-screen but it's explainable so just ignore my ramble for now I think givven enough time I'll be able to do a compromise in glsl-sandbox since it seems to have a persistent canvas.
    So rather than reading and writing to textures, I can get something multi pass like going, by read-and-write to different part of the canvas.
    The compromise being I can't do fullscreen/"full-window" then, because the screen is split to accommodate for all the passes. (and having to draw rather than load a picture)
    ( For actual multi pass this might not work if the different passes has to be done in a certain sequence, but in my case that's not an issue. )
    If i can make that work in sandbox, and also work as a PShader (which might be impossible?) I should be able to shade on a PGraphics larger than the actual window, that's translated so that you only see the part of it where the final pass is.

  • edited March 2017 Answer ✓

    I have reason to believe that GLSL support is incomplete/not documented in Processing.

    Update - We can input a sampler2D to the shader using PShader.set(String name, PImage img).

    Update 2 - try using it and tell me what you get. Post the code if it doesn't work. I can't test right now, sorry.

  • edited March 2017

    @Lord_of_the_Galaxy that worked, but not the way I want it.

    my_shader.set("texture", my_texture ); 
    rect(0,0,width,height);  // if i don't draw something the shader doesn't do anything
    

    gives the same result as...

    image(my_texture,0,0);  
    

    EDIT:
    I tried if you could load two textures into the shader using PShader.set, and you could.

    It's not useful for me but maybe for you.

    The neat thing about glsl-sandbox is when you output to glfragcolor, it seems to have updated to the sampler2D texture the next frame automatically.

    This may not be possible, atleast not easily or efficently in Processing?

  • Try this. Based on my crude (and probably incorrect) understanding of how Processing uses shaders, it may work.

    PShader my_shader;
    PImage my_texture; 
    PImage buffer;
    void setup() {
      size(256, 256, P2D);
      my_shader = loadShader("my_shader.frag");  
      my_texture = loadImage("my_texture.jpg"); 
      image(my_texture,0,0);
      buffer = get();
    }
    void draw(){
      background(0);
      my_shader.set("u_resolution", float(width), float(height));
      my_shader.set("texture", buffer);
      shader(my_shader);
      buffer = get();
    }
    
  • edited March 2017

    Don't. That won't work. Try this instead.

    PShader my_shader;
    PImage my_texture; 
    PImage buffer;
    void setup() {
      size(256, 256, P2D);
      my_shader = loadShader("my_shader.frag");  
      my_texture = loadImage("my_texture.jpg"); 
      image(my_texture,0,0);
      buffer = get();
    }
    void draw(){
      background(0);
      my_shader.set("u_resolution", float(width), float(height));
      my_shader.set("texture", buffer);
      shader(my_shader);
      updatePixels();
      buffer = get();
    }
    
  • @Lord_of_the_Galaxy With image(my_texture,0,0); on line 12 , instead of background(0);

    I get it flipping up and down rapidly, also added in my_shader.frag

    color = texture2D(tex1 ,vec2(x,y));
    gl_FragColor = vec4( color.r+0.01,color.g+0.01,color.b+0.01,1.0);
    

    And with that added the image gets gradually brighter until it's white.

    Thank you!

  • Can you pls post your complete GLSL code too? Thanks!

  • @Lord_of_the_Galaxy
    Too be honest I don't have any complete glsl code and just these snippets Iwe posted and linked. I only know very basic things about fragment shaders. And then when it comes to vertex shaders I have 0% knowledge

    Just things I'we read in this unfinnished e-book
    https://thebookofshaders.com/

    So I'll show what I think is relevant ...

    Running your shader, explaining how to set up a shader,
    scroll down to In Processing
    https://thebookofshaders.com/04/

    Some of the links are greyed out but accessible by number, like the chapter on textures , .
    https://thebookofshaders.com/15/

    So you load a PImage and set it as a sampler2D in the shader like...
    PShader.set(String name, PImage img) as you said And once you loaded a texture into a **uniform sampler2D ** data type ...

    You can then access pixel data using the function texture2D,
    which takes a sampler2D, and a vec2 x/y coordinate and returns the color as an rgba vec4.
    texture2D(sampler2D,vec2);

    Those pixel coordinates are mapped in a range from 0-1 So for a 1:1 mapping without applying any transformation, you take vec2 FragCoord, which is the coordinate of the current fragment and divide it by the resolution.
    You can do this in a vector operation as such... gl_FragCoord/u_resolution but as the y-coordinate is flipped relative to the processing canvas you may want to separate it into x/y components.

    And this is what this code is doing, just flipping a sampler2D upside down

    #ifdef GL_ES
    precision mediump float;
    #endif
    uniform sampler2D texture;
    uniform vec2 u_resolution;
    void main () {
    float x = gl_FragCoord.x/u_resolution.x;
    float y = 1.0-gl_FragCoord.y/u_resolution.y  ;
    gl_FragColor = texture2D(texture ,vec2(x,y));
    }  
    
  • So my guess was right. My own knowledge is also similar.

  • edited March 2017

    Can you do one more test for me? Using this very shader -

    #ifdef GL_ES
    precision mediump float;
    #endif
    uniform sampler2D texture;
    uniform vec2 u_resolution;
    void main () {
    float x = gl_FragCoord.x/u_resolution.x;
    float y = 1.0-gl_FragCoord.y/u_resolution.y  ;
    gl_FragColor = texture2D(texture ,vec2(x,y));
    }  
    

    and this code -

    PShader my_shader;
    PImage my_texture; 
    PImage buffer;
    void setup() {
      size(256, 256, P2D);
      my_shader = loadShader("my_shader.frag");  
      my_texture = loadImage("my_texture.jpg"); 
      image(my_texture,0,0);
      buffer = get();
    }
    void draw(){
      //background(0);
      rect(0, 0, width, height);
      my_shader.set("u_resolution", float(width), float(height));
      my_shader.set("texture", buffer);
      shader(my_shader);
      updatePixels();
      buffer = get();
    }  
    

    Please report the results. Thanks!

    It will tell me quite a bit of exactly what is going on behind the scenes in Processing when using shaders.

  • @Lord_of_the_Galaxy
    Something very strange happened, got an error saying there's no uniform called texture, changed the name to u_texture and then it worked, before it worked with arbitrary names so idk what's up with that.
    Anyways, changed the name and left everything else copy-pasted, shows the .jpg the right way statically. It seems like it's not applying the shader. Might be a problem on my end though. I'm awaiting a new graphics card next week though and I'll redo the test then.

  • @Lord_of_the_Galaxy It does not work for me with updatePixels(); but that's fine This is the only way I get something going

        PShader my_shader;
        PImage my_texture; 
        PImage buffer;
        void setup() {
          size(256, 256, P2D);
          my_shader = loadShader("my_shader.frag");  
          my_texture = loadImage("my_texture.jpg"); 
          image(my_texture,0,0);
          buffer = get();
        }
        void draw(){
          image(my_texture,0,0);
          my_shader.set("u_resolution", float(width), float(height));
          my_shader.set("u_texture", buffer);
          shader(my_shader);
          //updatePixels();
          buffer = get();
        }
    
        #ifdef GL_ES
        precision mediump float;
        #endif
        uniform sampler2D u_texture;
        uniform vec2 u_resolution;
        vec4 color;
        void main () {
        float x = gl_FragCoord.x/u_resolution.x;
        float y = 1.0-gl_FragCoord.y/u_resolution.y;
        if(x<0.5){y=1.0-y;}
        color = texture2D(u_texture ,vec2(x,y));
        gl_FragColor = vec4( color.r+0.01,color.g+0.01,color.b+0.01,1.0);
        }
    
  • no uniform called texture

    processing registers a few glsl variables of its own automatically. i think texture is one of these, set when you call texture() in your .pde. it's mentioned in passing in the shader tutorial but i can't find a list.

  • So it won't work without the image() on line 12? That's important - it means that Processing isn't doing what I expected.

  • Now does anyone have any idea why that image() on line 12 is so important???

  • According to The Book of Shaders, this should work. Please test. Thanks!

    PShader my_shader;
    PImage my_texture; 
    PImage buffer;
    void setup() {
      size(256, 256, P2D);
      my_shader = loadShader("my_shader.frag");  
      my_texture = loadImage("my_texture.jpg"); 
      image(my_texture,0,0);
      buffer = get();
    }
    void draw(){
      // image(my_texture,0,0);
      my_shader.set("u_resolution", float(width), float(height));
      my_shader.set("u_texture", buffer);
      shader(my_shader);
      rect(0, 0, width, height);
      //updatePixels();
      buffer = get();
    }
    
  • Or at least this should -

    PShader my_shader;
    PImage my_texture; 
    PImage buffer;
    void setup() {
      size(256, 256, P2D);
      my_shader = loadShader("my_shader.frag");  
      my_texture = loadImage("my_texture.jpg"); 
      image(my_texture,0,0);
      buffer = get();
    }
    void draw(){
      // image(my_texture,0,0);
      buffer = get();
      my_shader.set("u_resolution", float(width), float(height));
      my_shader.set("u_texture", buffer);
      shader(my_shader);
      rect(0, 0, width, height);
      //updatePixels();
      //buffer = get();
    }
    
  • edited March 2017

    @Lord_of_the_Galaxy I'm working now. And I'll test your code and retest stuff like begindraw, enddraw (which always givven me errors so far) when I installed my graphics card. It should arrive any day soon. it has arrived and is installed. Both last examples works!

  • Ok, thanks! Will check on your progress constantly.

  • Finally... Thanks a lot for your help. I now understand what is nescessary- call any drawing function after using shader() in order to make it work. Why? No idea.

  • @Lord_of_the_Galaxy You have to draw after the shader() method because OpenGL is a state machine, and you first have to set the shader state :)

    @prince_polka If you still ned help, please write your current problem and I'll try to help you.

  • edited April 2017

    @cansik OpenGL is a State machine? Incredible. So it seems we have finally found a guy (your image) who knows how OpenGL works, and how to use it in Processing. BTW, we guessed and reached so much, but guessing isn't a great idea, so will you be active on this forum so that we may ask you OpenGL/GLSL related questions?

  • @Lord_of_the_Galaxy

    OpenGL is a State machine? Incredible.

    I hope that it is not sarcasm. :P

    Yeah it was also a lot of guessing for me. But I think the problem with processing is, that the g graphics object is not treated like other graphics objects. So if you would like to test something out, try always to use a separate graphics object and draw the result to the g at the end.

    And yes I will try to be a bit more around here. But I'm also not a pro, just a student with interest.

  • Student > hobbyist (I'll become student in a few years, probably).

Sign In or Register to comment.