Glsl: is it possible to pass an array of floats to each shader?


#1

Hi guys,

I basically need to know the value of vFragColor
from posUpdate.frag

is that possible? any pointers?

kind regards,
thank you in advance of your help

#version 150

uniform sampler2DRect prevPosData; // previous position texture
uniform sampler2DRect velData; // velocity texture

uniform float timestep;

in vec2 vTexCoord;

out vec4 vFragColor;

void main(void){
// Get the position and velocity from the pixel color.
vec2 pos = texture( prevPosData, vTexCoord ).xy;
vec2 vel = texture( velData, vTexCoord ).xy;

// Update the position.
pos += vel * timestep; 

// And finally store it on the position FBO.
vFragColor = vec4(pos.x,pos.y,1.0,1.0);  

}


#2

This is the tricky part when working with shaders, you can not put a debugger wherever you want. What you can do, is to draw to the screen the current fbo that it is outputting as color vFragColor. For example, if you have a red screen, most probably your vFragColor variable is vec4(1.0, 0.0, 0.0 ,1.0);. From the color output you can infer the pixel values.

To debug single values for example, one by one, it is a common practice to use step() and color the screen of black just if the value of a variable is upon a certain limit. For example, your screen (or, more precisely, the part of your screen where this shader end up to be used,) will be white if vel is bigger than 0.5

vFragColor = vec4(vec3(step(0.5,vel)),1.0);

This is a great resource to get started with shaders https://thebookofshaders.com/05/


#3

it’s ok, I understand that, I just want to create a bunch of particles once, solve their equations once and I am interested in only one value output an integer to be returned I don’t even want to draw them

I will interpret that value etc.

by the way, can I create an array of integers inside a .frag or a .vert?

like before hand not dynamically
each particle instead of a pos vec2 to have a int [10]???

What are the syntax possibilities to do stuff over there ?

Can I create classes?

is it clear C?

maybe I can do something like:

        for (unsigned i = 0; i < dst->getNumTextures(); ++i){
           ofFloatPixels pixels;
             dst->getTexture(i).readToPixels(pixels);
            for (unsigned j = 0; j < pixels.size(); ++j)
            {
              ???
             }}

Thanks for the link by the way, it seems useful.


#4

I think you did not get the point. To draw on the screen is the only way to debug the sketch, even if the goal of your shader code is not to draw particles but to calculate the position of the particles in the GPU.

You can not create classes in shaders, but you can create struct and functions. I would really suggest you to go over the book of shaders, or at least read the first chapters. Also in the ofBook there is a good tutorial about shaders https://openframeworks.cc/ofBook/chapters/shaders.html

And yes, you can pass an array of integer as far as I know, but you have to define the size.
See https://openframeworks.cc/documentation/gl/ofShader/#show_setUniform1iv
And a similar answer given some month ago by @arturo Passing ofVec2 array to fragment Shader


#5

that’s fantastic, thank you I will do some studying:thinking: and come back if need be,

thank you


#6

ok I think I am on the right track

Few questions.

(I’ve prepared a minimum example so we can be both on the same page)

declare somewhere in .cpp this func

void dividefunc(float num){
ofFbo renderFBO;
ofShader shader;
string Frag ="#version 150\n";
Frag += R"(
out vec4 outputColor;
uniform float r=0;
uniform float g=0;
uniform float b=0;
uniform float a=0;
void main()
{
    float   _r = r/2;
    float   _g = g/3;
    float   _b = b/4;
    float   _a = a/5;
    outputColor = vec4(_r,_g, _b, _a);
}
)";
string Vert = "#version 150\n";
Vert += R"(
uniform mat4 modelViewProjectionMatrix;
in vec4 position;
void main(){
    gl_Position = modelViewProjectionMatrix * position;
}
)";
shader.setupShaderFromSource(GL_VERTEX_SHADER,Vert);
shader.setupShaderFromSource(GL_FRAGMENT_SHADER,Frag);
shader.linkProgram();
renderFBO.allocate(ofGetWidth(), ofGetHeight());

    renderFBO.begin();
    ofSetColor(255);
    shader.begin();
    shader.setUniform1f("r",num);
    shader.setUniform1f("g",num);
    shader.setUniform1f("b",num);
    shader.setUniform1f("a",num);
    ofDrawRectangle(0, 0, ofGetWidth(), ofGetHeight());
    shader.end();
    renderFBO.end();
    renderFBO.draw(0,0);

for (unsigned i = 0; i < renderFBO.getNumTextures(); ++i){
    ofFloatPixels pixels;
    renderFBO.getTexture(i).readToPixels(pixels);
    for (unsigned j = 0; j < 4; ++j)
    {
        cout<<pixels[j]<<",";
        if(j%4==3)cout<<endl;
    }
 }
}

and then in draw :

if(ofGetKeyPressed())dividefunc(1.0);

(or put it in ::keyReleased directly and skip draw func)

Thank you all for your help.


#8

any ideas how to pass a different set of values in each shader?

in a similar fassion as the particle system passes the pos values

I have an array of floats in my frag :

uniform float colors[6]

I want to pass 6 different (random) floats in each shader per pixel

like a custom uniform?

my shader will only have one uniform (that float array)

everything else will be the same

but with different random variables in it for each pixel

is it possible ?

for each pixel:
float cols[] = { 1,1,1,1,1,2 };//rand()

shader.setUniform1fv("colors", cols,6);

is it with setUniform2fv. ??

I found this forum post: same shader for all objects but with different values

but it doesn’t provide a solution really…

sorry for overposting


#9

ok, after further reading, I understand now that I should use

setUniformTexture( ). ???


#10

here is my code: ( I am now able to get results ) but I can’t figure how to pass a different value for each tasks[] array

main.cpp (360 Bytes)
ofApp.cpp (4.1 KB)
ofApp.h (485 Bytes)

I currently just do some basic math and return a result (7) when key is pressed

the idea is to have something like “particles” that will solve at the same time the same equation but with one variable being different (something like the pos in the particle example)

so,

let’s say I have 10 particles,

each particle will run the same shader, but will have one value that will be different

the idea is to transfer the variables in the same manner as the particle example works,

any ideas?

I am currently thinking of creating an array of ofFbo and “unpack it” in .frag

for example let’s say I want to pass an array of 50 floats to each shader I will do

ofFbo data[ max_int(50/4)];

pass them with setUniformTexture

and then unpack them:

vec4 pack1 = texture(pack1t, texCoordVarying.st);
vec4 pack2 = texture(pack2t, texCoordVarying.st);
vec4 pack3 = texture(pack3t, texCoordVarying.st);

solve equations with it

and then do my thing.

is there a better way?

I don’t want code just to know if it’s feasible

also, how many textures can I pass to a shader? is there a limit?