moderngl / moderngl-window

A cross platform utility library for ModernGL making window creation and resource loading simple
MIT License
244 stars 57 forks source link

Does moderngl-window supports loading sampler1D? #71

Closed aegroto closed 4 years ago

aegroto commented 4 years ago

I'm trying to pass to a GLSL shader some data contained in a numpy's ndarray. I've tried to pass it to my shader on each frame like this:

self.prog['frequency_bins'].value = frequency_bins
self.prog['current_frequencies'].value = current_frequencies

In the fragment shader I declare the variables:

uniform sampler1D frequency_bins;
uniform sampler1D current_frequencies;

But I get this error:

Traceback (most recent call last):
  File "main.py", line 180, in <module>
    main()
  File "main.py", line 177, in main
    mglw.run_window_config(VideoWindow)
  File "/home/lorenzo/.local/lib/python3.6/site-packages/moderngl_window/__init__.py", line 198, in run_window_config
    window.render(current_time, delta)
  File "/home/lorenzo/.local/lib/python3.6/site-packages/moderngl_window/context/base/window.py", line 599, in render
    self.render_func(time, frame_time)
  File "main.py", line 165, in render
    self.prog['frequency_bins'].value = frequency_bins
  File "/home/lorenzo/.local/lib/python3.6/site-packages/moderngl/program_members/uniform.py", line 164, in value
    self.mglo.value = value
moderngl.error.Error: cannot detect uniform type

I've not faced any problem using sampler2D, but for that type I can use the load_texture_2d(...) function, loading them from the disk. Is there a way to pass arrays directly from python to shaders? I may bake those data into textures and load them from files but I find this cumbersome. I'm sure there's a way, maybe using the direct moderngl context.

I don't know how much useful it can be, but here's the full project: https://gitlab.com/aegroto/py-glsl-audiovisualizer. It should run without any issues, still the test files I use are not included for size reasons. I may upload those later on though.

einarf commented 4 years ago

You cannot write data directly to sampler uniforms like that. Samplers actually read from the texture channel assigned to them, so data needs to be written to a texture.

We don't actually have 1D texture support in moderngl simply because you can make an (n, 1) 2d texture achieving pretty much the same. I still think the sampler needs to be sampler2D were you leave the y/v coordinate as 0.

If you have data in an np array you an just create a texture manually (Writing this from memory)

# Using 1 component with default 8 bit data. You might need to specify another dtype.
# Assuming size is 256 x 1
tex1 = ctx.texture((256, 1), 1, data=data1)
tex2 = ctx.texture((256, 1), 1, data=data2)

# Update the texture per frame (if needed) use:
# https://moderngl.readthedocs.io/en/latest/reference/texture.html#moderngl.Texture.write

# Assign texture channels to samplers
program['frequency_bins'].value = 0
program['current_frequencies'].value = 1

# Bind textures to the channels 
tex1.use(location=0)
tex2.use(location=1)
uniform sampler2D frequency_bins;
uniform sampler2D current_frequencies;

You could also use the frequency data as vertex data, but I'm guessing you are already have some geometry.

Be free to ask if you have more issues, but please post code somewhere so I can fully understand what is going on .We also have a discord server linked from the readme on gihub with help channels.

aegroto commented 4 years ago

Ok, so, I think I'll use 2d samplers. I'll get in the Discord if I've got any more doubts, thanks a lot for your help.

einarf commented 4 years ago

Yup. sampler2D works just fine. We've discussed adding the opengl 1D type, but techincally it's not really needed and we've planning to merge all texture types into one type in the future anyway.

When people have trouble with something we try sometimes to make what they are trying do into a public example. Activities like this happens on discord.