Passing struct to shader

edited April 2017 in GLSL / Shaders

Hi,

Currently I'm passing an array of floats to my shader, but I'd like to pass in more complex items. From my research it seems like I'd use structs here but Java does not support them.

My object is something like this:

struct boid { vec2 position; vec2 velocity; int flock; }

Any advice on how to build an equivalent object in my Processing code to pass in?

Tagged:

Answers

  • edited April 2017 Answer ✓

    @crummy -- disclaimer -- I am not a shader pro. However:

    I think the issue is not Java support. You could create a struct-like class with public instance variables -- as per the Sun Java Coding Guidelines -- http://stackoverflow.com/a/8565711 .

    The issue seems to be that PShader.set() only accepts arrays -- not arbitrary objects.

    If your goal is concision and coding convenience, you could consider a class like this:

    class ShaderSettings {
        PVector position;
        PVector velocity;
        int flock;
        ShaderSettings(PVector p; PVector v; int f){
          position = p;
          velocity = v;
          flock = f;
        }
        void set(PShader ps){
          ps.set("position", position);
          ps.set("velocity", velocity);
          ps.set("flock", flock);
        }
     }
    

    (untested)

    Now:

    PShader sh = loadShader("shader.glsl")
    ShaderSettings ss = new ShaderSettings(myPos, myVel, myFlock):
    ss.set(sh);
    

    If you wanted to make it even more concise you could add another class constructor which takes the PShader and calls set immediately. Creating your "struct"(-like-object) and configuring your shader are one action.

    Now:

    PShader sh = loadShader("shader.glsl")
    ShaderSettings ss = new ShaderSettings(myPos, myVel, myFlock, sh);
    
  • That would work fine, but in this case (a flocking simulation) I want to push an array of about a hundred of these things. I could have "uniform vec2[100] positions", etc but with position, velocity, and more I'll run up against max uniforms sooner or later.

    Perhaps "encoding" a struct into a texture2d and passing it into the shader would allow greater flexibility?

  • edited April 2017

    How to stay under max_uniforms with a large array seems like it is a very different question from how to pass in mixed data types -- or I'm really not understanding your question, and will have to defer to a shaders expert.

    Shouldn't MAX_*_UNIFORM_COMPONENTS (or whatever) be a property of your graphics setup?

    My understanding was that it doesn't matter how you pass them in -- as PVectors, or parallel float arrays, etc. -- you are either under the memory limit or you aren't. But perhaps there is shader lore or dark magic to work around that.

    Instead of passing in 3*100 vec2 and ints (one set of three settings per boid) I would assume that you would Have a single flock object passing in 3 large parallel arrays with three set calls: -- float[100], float[100], int[100]. But memory is memory.

  • Thanks for the clarification - I read the docs and realized I misunderstood the uniform limitations. I'll pass in arrays of position, velocity etc separately.

  • Good luck! Interested to hear how it works out.

    Forum shader-experts -- do you have any follow-up confirmation or advice for crummy?

  • edited May 2017

    https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.3.30.pdf

    varying vec2 vDATA;
    vec2 emptyv2 = vec2(0);
    #define MAX_SPHERE 3
    
    //definition initialisation definition 
    struct Sphere {
        vec2 position;
    }S_[MAX_SPHERE] = Sphere[MAX_SPHERE](
        Sphere(
            vDATA
        ),
        Sphere(
            vec2(0.0, 1.)
        ),
        Sphere(
            emptyv2
        )
        );
    struct Plane { vec2 position; }P_[200];
    
    //struct in struct            
    struct POSITION { vec2 position; };
    struct Cone { POSITION POS; }C_;
    
    void main() {
        int i = 0;
        //new value/overwrite prev. initialisation 
        for (;i < MAX_SPHERE;i++) S_[i].position = vDATA;
    
        //initialisation 
        for (;i < 200;i++) if (i % 10 != 0)P_[i].position = vDATA;
    
        //initialisation
        C_ = Cone(POSITION(vec2(0, 1.)));
        //assign a value
        S_[2].position = C_POS.y;
    
        //white
        gl_FragColor++;
    }
    /*easy go*/
    
  • edited May 2017

    @nabr -- Thanks! How does your response relate to the question of how to pass large amounts of structured data to a shader from Processing?

  • Yes i just read the question without the following conversation

    struct boid { vec2 position; vec2 velocity; int flock; }B_[200]; will create 200x vec2 positions, 200x vec2 velocity, 200x int flock;

    Man sorry, i just type something, maybe its related, when somebody google how to use structs :)

  • edited May 2017

    As i know @crummy your question is related to lights in native OpenGL mostly this kind of data is passed as array into the shader. Take a look here. http://www.tomdalling.com/blog/modern-opengl/08-even-more-lighting-directional-lights-spotlights-multiple-lights/

        shaders->setUniform("numLights", (int)gLights.size());
        for(size_t i = 0; i < gLights.size(); ++i){
        SetLightUniform(shaders, "position", i, gLights[i].position); 
        SetLightUniform(shaders, "intensities", i, gLights[i].intensities);
    
        /ect.
        }
    

    Also make an internet research maybe you find better examples that fits your needs.

    Basicly the same as jeremydouglass already suggested.

Sign In or Register to comment.