0

I am trying set a uniform float of a Clutter.ShaderEffect. This works well if floating point Numbers are passed to set_uniform_value(). However, when you pass an integer Number, an OpenGL error (1282, Invalid operation) is thrown. It seems that the implementation assumes in this case that the uniform is actually of type int. Here is a minimal example:

const {Clutter, GObject} = imports.gi;

Clutter.init(null);

let stage  = new Clutter.Stage({width: 200, height: 200});
let shader = new Clutter.ShaderEffect({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});

shader.set_shader_source(`
  uniform float value;

  void main(void) {
    cogl_color_out = vec4(value, 0, 0, 1);
  }
`);

// This creates the OpenGL Error.
// shader.set_uniform_value('value', 1);

// This works however:
shader.set_uniform_value('value', 0.999);

stage.add_effect(shader);

stage.connect('destroy', () => Clutter.main_quit());
stage.show();

Clutter.main();

So how do I force set_uniform_value() to interpret the value as floating point number? Reading the documentation (https://gjs-docs.gnome.org/clutter6~6_api/clutter.shadereffect#method-set_uniform_value), I would assume that I could pass a GObject.Value - maybe like this:

let value = new GObject.Value();
value.init(GObject.TYPE_FLOAT);
value.set_float(1.0);
shader.set_uniform_value('value', value);

But this yields the error Invalid uniform of type 'GValue' for name 'value'. Maybe I now have a GObject.Value containing a GObject.Value containing a GObject.TYPE_FLOAT?

Simme
  • 565
  • 4
  • 7

2 Answers2

1

if someone looks for this question, I have the answer:

https://gjs-docs.gnome.org/clutter7~7_api/clutter.shadereffect#method-set_uniform_value value - a GObject.Value GObject.TYPE_FLOAT for float

and in gjs GTK Javascript they have https://gjs-docs.gnome.org/clutter7~7_api/clutter.value_set_shader_float

value_set_shader_float(value,[float]) method - Value must have been initialized using %CLUTTER_TYPE_SHADER_FLOAT.

and in Javascript version of GTK they dont have any way to initialize that CLUTTER_TYPE_SHADER_FLOAT or GObject.TYPE_FLOAT

The solution is:

function make_float(val) {
    return Math.floor(val)==val?val+0.000001:val;
}
Danil S
  • 67
  • 7
  • 1
    I wouldn't call it a solution, it's rather a workaround. What happens if there are cases where you want the integer value in the shader? For example, you cannot pass a zero this way which might be important in some cases. Btw, you could also use `return Number.isInteger(val) ? val+0.0000001 : val` which I think is more readable. – Simme Apr 13 '21 at 06:30
1

As of GJS 1.68.0 (GNOME 40), passing a GObject.Value works:

let value = new GObject.Value();
value.init(GObject.TYPE_FLOAT);
value.set_float(1);
shader.set_uniform_value('value', value);
ptomato
  • 56,175
  • 13
  • 112
  • 165