How to pass an uniform to a fragment shader? (DEF-3065)

Hello,

I’m writing a simple fragment shader , and i’d like to pass an uniform to it.

I’m using a menu for this, so all its boxes will be modified by the shader (note that you have to define box for seeing something. At first, i tried to import DAE quad, but it’s different with menus.)

So i’ve defined in the material a constant_type_user named uniform_timer in the fragment constants of the material.

From this, i have two questions:

  1. I couldn’t change its type to anything else than its default type, which is a vec4. For my use (a timer) a simple int or at worse a float would be better.

  2. How can i modify the value of a constant_type_user ? I thouhgt it would be accessible from the attached script of the menu, but inside the script, uniform_timer is set to nil.

Thank you for reading, and happy new year as it’s my first post for 2018 :star_struck:

True. It’s a vec4 but you’re free to go ahead and only use a single value, for instance the x-value.

What if you try go.set("#gui", “uniform_timer”, vmath.vector4(time, 0, 0, 0)) ie feed the time from a .script attached to the same game object as your gui.

1 Like

Thank you for your answer.

I tried to do what you said (setting a named property), but i don’t know if the uniform variable could be see as a named property.

Let’s see with my project.

Here is my shader:

varying mediump vec4 position;
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D DIFFUSE_TEXTURE;
uniform lowp vec4 tint;

uniform lowp vec4 uniform_timer;

void main()
{
  lowp vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w);
 //  gl_FragColor = texture2D(DIFFUSE_TEXTURE, var_texcoord0.xy) * tint_pm;
  gl_FragColor = vec4(var_texcoord0.xy, uniform_timer.x, 1.0);
}

Now, here is my menu collection: an object containing two components: the gui itself, and a script just for changing the uniform_timer value.

If you look the material linked to the gui, you see uniform_timer in its fragment constants :

The script menu_uniform is used for setting the uniform value.
It just contains this:

function update(self, dt)
  go.set ("#menu", "uniform_timer", vmath.vector4(dt, 0, 0, 0))
end

If i run the game, i get this error:

ERROR:SCRIPT: /data/gui/menu_uniform.script:19: ‘#menu’ does not have any property called ‘uniform_timer’
stack traceback:
[C]: in function ‘set’
/data/gui/menu_uniform.script:19: in function </data/gui/menu_uniform.script:18>

Now, is the fragment constant of the material a real named property ?

If i add a named property to my menu_uniform script, with go.property("uniform_timer", vmath.vector4(0,0,0,0) ) , the named property is added to the interface but not to the material (i know it’s expected behaviour, but i tried just in case…)

Thank you for reading :slight_smile:

Ok, I thought that would work. For the tint of a sprite you can do either:

go.set("#mysprite", "tint", vmath.vector4(1, 0, 0, 1))

or

sprite.set_constant("#mysprite", "tint", vmath.vector4(1, 0, 0, 1))

There is sprite.set_constant, particlefx.set_constant, model.set_constant, spine.set_constant and tilemap.set_constant but no gui.set_constant. I was hoping that go.set() would work just as it does for the tint property of the sprite material. I think @Mathias_Westerdahl is back at the office tomorrow. Let’s wait for him to give us an answer.

1 Like

Thank you Britzl, even if we don’t have the answer yet, i have learned interesting things and revised some others (i have never used named properties, so it was interesting to see).

Thank you for the help :slight_smile:

If all you need is time passed into your shader, you should be able to get it there from your render script using a constant buffer.

2 Likes

Unfortunately, there is no gui.set() or gui.set_constant. It’s certainly something that we should discuss within the team. I added the ticket DEF-3065 for this.

4 Likes

Well, the more i read, the less i understand.

I put this in my render script loop:

  self.constants = render.constant_buffer()
  self.constants.uniform_timer = vmath.vector4(math.random(0,1000) / 1000.,0,0,0)
  render.draw(self.gui_background_pred, self.constants)

So in the fragment shader (FS), i should be able to retrieve uniform_timer declared like this:
uniform lowp vec4 uniform_timer;

But in the FS, uniform_timer appears to be always (0,0,0,0)

I tried also with self.constants.tint, in case of the name would be imposed. Rreading this part of the doc , it seems to be the case.

And what is the relation between constants defined in the render script, and the values defined in the material options ?

A lot of questions :thinking:

So to sum up: how can i pass variables to my shader from a GUI ?
I want to pass two variables : a time value (for shader variation), and a flag which indicates if it should apply an effect or just fill with a fixed color.
My use case is to draw a background with a selector (a box) on it. The background is shaded ok, but for the selector i just want a fixed color.
May be i can use predefined values, like tint for example , if i cannot define my own ?

Thank you for reading :slight_smile:

Ok i have found for the detection of the box currently drawn by the shader.

My background box has a black color (0,0,0,1) which i pass as a vertex shader attribute.
Then the color is passed from the vertex shader to the fragment shader, and if color is different from (0,0,0,1), then the box is traced with the color received, without modification.
Otherwise, it means that the shader is currently drawing the background.

The only things remaining is to get a changing value (the «time») for influencing shader.
But if i understand well the previous posts, it’s not possible from within a GUI ?

Almost done DONE! :slight_smile:
I’ve put my timer in the alpha of the color value of the background box.
In my script i do

 local bg = gui.get_node("box_bg")
gui.set_color( bg, vmath.vector4(0,0,0, timer ))

The only harm with this trick is to have color 0,0,0 elsewhere, because it will be considered as a background element, even if it’s on foreground. I wish i could modify materials fragment constants … but for the moment, it’s not so bad :smiley:

Thank you for reading :slight_smile:

1 Like

Using constant buffers in the render script should work, like Ross suggests. Are you sure you’re passing the constant buffer to the render.draw() call?

1 Like

My bad @britzl ! I have checked again my render script, and found the problem in my code.

As Ross said, you can define uniforms with self.constants table in the render loop.

The problem is i was doing this:

render.draw(self.NOT_THE_CORRECT_menu_pred, self.constants)

Corrected of course by passing constants table to the correct menu_pred, and voila. :slight_smile:

Thank you for the help :wink:

3 Likes

Any news about gui.set and gui.set_constant?
I was suprised to see what there is no methods to work with GUI shaders, but I can setup constants in gui material.

Also, is it possible to see multiply material in GUI in future? What if I want to make custom shader effect on GUI node?

No new info here I’m afraid. It’s still in our back log, but isn’t planned for any recent release.

We have an old ticket (issue-3419) for adding “Multiply” to gui materials, but it hasn’t been scheduled anytime soon either.

1 Like