GLSL Image Generator

How does one receive the current time, width and height values into a composition when one has selected “new shader”, then “image generator”?

When I write:

uniform float width, height;
void main()
{
vec2 uv=gl_FragCoord.xy/vec2(width,height);
gl_FragColor = vec4(uv.x,uv.y,.5,1);
}

…then run the composition, it appears that the shader does not receive the current window width and height values from the VUO editor app.

Running your code I get “VuoGlProgram_use():1531 : WARNING: Output of vertex shader ‘isf_FragNormCoord’ not read by fragment shader” in the console. By using

vec2 uv= isf_FragNormCoord;

instead you get the expected behaviour.  

1 Like

What do you do to run the code?

It is just a fragment shader, there is no vertex shader, so I am very confused by that error.

It seems like you must have done something to link it to a vertex shader to get that warning. That said, I think gl_FragCoord doesn’t have to be defined within the vertex shader because it is part of the GLSL language.

I really appreciate you looking at this, I am still unsure why it doesn’t work.

Why is all of this ISF stuff part of the shader? Is it not possible to use regular GLSL version code?

Also, I do not understand how to receive width, height, and time values, while writing the shader in VUO. Does the VUO Editor not send these values when writing a protocol, the way (sorry) QC did sent audio data for music visualizers, x/y for image filters, and other things like that? I see these ports, but the shader does not seem to receive the values from the composition runner.  

I think @jstrecker have to answer the more technical questions as to why this is so, but I’m just running the shader either as a node or in the shader editor. Note that this is shown in the MacOS console not the Vuo console (that I forgot about). You can just filter the MacOS console in the top right corner with “Vuo” to get rid of most of the irrelevant OS stuff and get any code-related warnings there.

There is also a quick GLSL/ISF reference in the view menu where the input uniforms are listed. Might be worth a read-through if you haven’t looked at it yet :)

1 Like

Thanks Martinus!

What do I do to run it as a node? Guessing the file has to go somewhere?

I did notice the ISF methods listed in the panel to the right of the editor, but it hadn’t occurred to me that the shader might not be able to use typical GLSL functions such as gl_FragCoord…but it may be that the problem there is just that width and height isn’t being received by the shader when running the shader editor.

1 Like

Just put it in the user modules folder (tools → open user modules folder, or something like that), and then it should be available as a node in the library.

I struggled a bit with getting inputs to work, but I was in a bit of a rush. Might be able to look more into it tomorrow. The cool thing about it being ISF compatible is that it should be relatively easy to port or tweak MadMapper materials over to Vuo, or vice versa.

some libraries/porting info (for MadMapper but might be relevant?):
https://editor.isf.video/shaders?q=&category=&sort=Date+Created+↓&page=0
https://projectileobjects.com/2020/10/22/isf-shaders-and-madmapper-materials/

1 Like

Ok, so it is pretty easy, a published port is automagically declared as a uniform when you add it. The resolution is RENDERSIZE.xy, and the time input is TIME (both capitalized).

This will make a color based on time and render size along with a published Real port named blue:

void main()
{
	float red = mod(TIME, 1.0);
	float green =  RENDERSIZE.y / RENDERSIZE.x;
	gl_FragColor = vec4(red,green,blue,1);
}
3 Likes

Interesting.

So this is after loading into the modules folder that you can see something working?

When you open a new shader composition from the editor, and there are the input ports there already in the protocol comp, are you seeing the shader able to get receive the time value, or the other values?  

Oh, I see it working by running it in the shader editor (like a composition). Time and resolution are supported without declaring any uniforms. If you use the Image filter protocol/editor there is also provided an image of a bird when you run it standalone.

The code above is the only thing you need to input for a simple shader utilizing time, resolution and inputs. It will modulate the red channel by time, the green channel by the rendered window size, and the blue channel by a published port/slider.

I have to admit, I am completely confused at this point.

Do the capitalized TIME and RENDERSIZE you refer to in your shader code directly correspond to the pre-existing time, width, and height ports that are at the right hand side of a shader protocol? And the data is coming through the ports? Or are these uniform values somehow supplied by an unseen vertex shader that exists somewhere and is linked to the fragment?

Very cool.

Super basic – next I tried changing red to:

float red = (sin(hz * TIME * 2PI) + 1.0) / 2.0;

But using #define 2PI 6.2831853076; at the top generates an error.  

Yes - to both the questions I think actually. If I have understood it correctly, a fragment shader always needs a vertex shader to display anything (at least in Vuo). My guess is that the vertex shader is just a very basic quad and some default uniforms that sets up a framework for less boilerplate coding.

At the risk of confusing you further, if you look at the code for a custom GLSL image filter node in the Vuo source (that is the C source, has nothing to do with the shader editor), you can find the following line setting up the shader:

VuoShader_addSource(instance->shader, VuoMesh_IndividualTriangles, NULL, NULL, fragmentShaderSource);

Looking at VuoShader_addSource in the API, it lists the inputs to the function as follows:

void VuoShader_addSource	(	VuoShader 	shader,
    const VuoMesh_ElementAssemblyMethod 	inputPrimitiveMode,
    const char * 	vertexShaderSource,
    const char * 	geometryShaderSource,
    const char * 	fragmentShaderSource 
    )

With this in mind, it can seem like there are no vertex shader for the fragment shader that does the filters, but in the notes of the function we can also read:

GLSL vertex shader source code. If NULL, a default vertex shader is used (it passes texture coordinates through, and projects the vertex).

Vuo Shader example: vuo/example/node/imageFilterGLSL/example.imageFilter.brightness.c at main · vuo/vuo · GitHub

VuoShader_addSource in the API: Vuo: VuoShader

This works (with ports added for blue and hz):

const float TWOPI = 6.2831853076;

void main()
{
    float red = (sin(TIME * TWOPI * hz)) + 1.0 / 2.0;
    float green =  RENDERSIZE.y / RENDERSIZE.x;
    gl_FragColor = vec4(red,green,blue,1);
}

Vuo is a little slow to update glsl error reporting at the bottom of the shader comp, need to close the comp, maybe save/close/reopen, etc.  

@jersmi you can’t start a variable name with a number. If you use #define twoPI 6.2831… it should work.

I’m not sure if the implementation of inputs are totally there yet. It seems you can’t add variables before declaring them in code either (they disappear for me at least).

Oh, alright. Yeah, I saw your bug post. Thank you! Above code worked for me with hz (after declaring in code, I guess). I’m a GLSL newb…

Edit: #define TWOPI 6.2831853076; generates “syntax error: ‘;’ (Fragment line 5)” (<-- line with red, of course)

const float TWOPI = 6.2831853076; works fine.

And regarding error reporting, updates when comp runs, no problem.  

(note: Just found that jpeg has to be turned to jpg to attach.)


Just to make sure I am being clear…

I have started by selecting to make a new shader with an image generator protocol.

I then see what is below.

My next step is to just attempt to use time as a variable in the code, assuming it is implicitly a uniform given that I see it on the green “Image Generator” interface to the right. This creates an error that time is an undeclared identifier.

Next I declare it as a uniform. No more warning, but there seems to be no data from the time value being supplied to the image generator protocol.


All that happens when the composition is run is that the viewer is a static blue output, which would not happen if the time value on the right side of the composition was being obtained by the shader.

…so, I wish to understand what to do to obtain these values in the shader when attempting to write a shader.

I understand that it would be odd to create arbitrary uniforms/input values and receive them in the shader in this kind of editing situation, because there is no way to create nodes to supply values.

But am I correct in thinking that all of the protocol ports are supposed to get some data supplied from the VUO editor, that one can “do stuff with” when programming, to see how things work? Is there any way to get live time, width and height data input port values I see at the right hand side of the editor, supplied into the shader, while working on this specific kind of protocol file?

@George_Toledo, I think time just needs to be capitalized?

void main()
{
	gl_FragColor = vec4(sin(TIME),.4,.5,1);
}

(under ISF extensions)

Screen Shot 2021-10-05 at 11.01.37 AM.png

Edit: this also works:

float time = (sin(TIME) + 1.0) / 2.0;

void main()
{
    gl_FragColor = vec4(time,.4,.5,1);
} &nbsp;
1 Like

Attempting to be clear that I am talking about the time value on the protocol input port to the right of the screen.

If “TIME” is capitalized and it is working, it is not the same “time” variable that corresponds with the protocol input port for time, it appears to be a value that the shader can receive via standard uniforms, without receiving any data via ports.

What I am trying to understand is, when a shader is created this way, there are these time, width and height ports existing as part of the protocol. How do I get these exact port values into the shader to work with?

The protocol composition appears to be receiving some sort of values, because it does init on viewer run. So some sort of fire event has to hit it, I think? Why does it appear these protocol ports receive no data? Is it expected that no values flow in this scenario; they aren’t supplied by the editor? If so, what is the purpose of the ports existing by default?

Do you have to work on a shader a bit, then save and load it in a modules folder, and then hook it up to a new test composition to send the time, width, and height port values into the node? Is that the idea of the workflow?  

Also, thanks for pointing out the ISF extensions Jersmi…I had seen those, but I was trying to understand the relationship of these pre-existing protocol input ports to the shader when editing this type of composition. Thank you Martinus as well!  

1 Like