Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Need some help with shaders

Credits go to Dizzy Egg for helping out!
This thread is locked; no one can reply to it. rss feed Print
Need some help with shaders
TorgaW
Member #23,803
August 2023

Hello everyone!
I'm a bit confused about using shaders to render bitmaps. My idea is quite simple: I generate perlin noise as a mask for a future texture, then I want to blend two other textures (eg grass and stone) based on the noise map. If there are no problems with the noise generation stage, then some difficulties arise at the stage of transferring bitmaps from c++ to the shader.
I use the al_set_shader_sampler() function, as shown in many of the official examples from Allegro:

#SelectExpand
1al_use_shader(noise_shader); 2al_set_shader_sampler("tex1", grass_tex, 1); 3al_draw_scaled_bitmap(result_bitmap, 0, 0, 32, 32, 1024, 512, 256, 256, 0); 4al_use_shader(nullptr); //disable shader for the next objects

My result is inconsistent, sometimes I get a black screen with nothing, and sometimes all my text that is drawn with al_draw_text turns into colorful rectangles.

I have checked all possible "dummy" mistakes: bitmaps are not nullptr, shader is also not nullptr, everything works fine until al_set_shader_sampler() function.

Maybe there is an obvious solution to the problem, but I can not find it. Maybe I'm using shaders incorrectly or do I need to use some special flags for the display and bitmaps? :'(
What is a right way to solve my problem and what mistakes have I done?

My shaders code is here:

Vertex:

#SelectExpand
1varying vec2 tex_uv; 2void main() 3{ 4 tex_uv = gl_MultiTexCoord0.xy; 5 gl_Position = ftransform(); 6}

Fragment:

#SelectExpand
1#ifdef GL_ES 2precision mediump float; 3#endif 4 5uniform sampler2D al_tex; 6uniform sampler2D tex1; 7uniform sampler2D tex2; 8varying vec2 tex_uv; 9 10vec2 random(vec2 uv) { 11 uv = vec2(dot(uv, vec2(121.1, 311.7)), dot(uv, vec2(262.5, 183.3))); 12 return -1.0 + 2.0 * fract(sin(uv) * 3.0); 13} 14 15float noise(vec2 uv) { 16 vec2 uv_index = floor(uv); 17 vec2 uv_fract = fract(uv); 18 19 vec2 blur = smoothstep(0.0, 1.0, uv_fract); 20 21 return mix(mix(dot(random(uv_index + vec2(0.0, 0.0)), uv_fract - vec2(0.0, 0.0)), dot(random(uv_index + vec2(1.0, 0.0)), uv_fract - vec2(1.0, 0.0)), blur.x), mix(dot(random(uv_index + vec2(0.0, 1.0)), uv_fract - vec2(0.0, 1.0)), dot(random(uv_index + vec2(1.0, 1.0)), uv_fract - vec2(1.0, 1.0)), blur.x), blur.y) + 0.5; 22} 23 24const int max_octaves = 6; 25 26float FBM(vec2 uv) 27{ 28 float result = 0.0; 29 float ampl = 1.0; 30 float freq = 0.005; 31 32 for(int oct = 0; oct < max_octaves; oct++) 33 { 34 result += ampl * noise(uv * freq); 35 ampl *= 0.5; 36 freq *= 2.0; 37 } 38 39 return result; 40} 41 42void main(void) { 43 float t = 0.0; 44 t = FBM(tex_uv.xy * 100.0); 45 vec4 color = texture2D(tex1, tex_uv); 46 gl_FragColor = color * t; 47}

I apologize if my question is not clear or contains insufficient information. Please tell me about what you need and I will send you more code or screenshots. ;D

P.S.
I don't have much experience in OpenGL programming, but really want to learn more. :)

Mark Oates
Member #1,146
March 2001
avatar

Can you provide more context about your ftransform() function? There could be an issue there. Also, the FBM() and noise() functions seems to be doing a lot, so it's difficult for me to parse out if there could be an error there.

In these types of situations, I would start by simplifying the problem to a shader that takes 2 textures and blends them based on some blend value [0.0-1.0].

Also in your source, I notice you are not binding to tex2 and it doesn't look like you are sampling from either al_tex or tex2 in the fragment shader.

Sometimes visuals can provide clues. If you don't mind posting some screenshots that could help.

--
Visit CLUBCATT.com for cat shirts, cat mugs, puzzles, art and more <-- coupon code ALLEGRO4LIFE at checkout and get $3 off any order of 3 or more items!

AllegroFlareAllegroFlare DocsAllegroFlare GitHub

TorgaW
Member #23,803
August 2023

Thanks for reply, Mark!

1. ftransform function - I have found it on reddit, this function is equivalent to gl_ModelViewProjectionMatrix * gl_Vertex. I can't tell you more, because I don't know what it does exactly ::). But I tried to test tex_uv property and it works fine. I tried to color my bitmap like gl_FragColor = vec4(tex_uv.x, tex_uv.y, 0.0, 1.0) and my bitmap had red-green gradient with black point on the lower left corner.

https://i.ibb.co/7RTSs0X/tex-uv-gradient.png

2. FBM function - It combines multiple octaves of perlin noise. This function is well-tested and works fine. It outputs values between 0.0 and 1.0 based on tex_uv.

https://i.ibb.co/r6BQdTV/FBM-result.png

3. About sampling - I have not yet implemented my blending code, because it's not working and I can't go to this stage. I think it will be like mix(texture2d, texture2d, blend_value).
I have tried to use fragment shader from Allegro examples (ex_shader_multitex_pixel.glsl) and it doesn't work too, same bad result :'(.

4. And finally my results after calling al_set_shader_sampler("tex1", grass_tex, 1): just a black screen without any yellow text, that I have :'(

P.S. Changing unit value from 1 to 10 in al_set_shader_sampler made this:
https://i.ibb.co/hFmNSvf/bad-result.png

Dizzy Egg
Member #10,824
March 2009
avatar

Not sure if it will help, but here is my standard Allegro vertex code:

attribute vec4 al_pos;
attribute vec4 al_color;
attribute vec2 al_texcoord;
uniform mat4 al_projview_matrix;
varying vec4 varying_color;
varying vec2 varying_texcoord;


void main()
{
   varying_color = al_color;
   varying_texcoord = al_texcoord;
   gl_Position = al_projview_matrix * al_pos;
}

Then in your fragment I would use:

varying vec2 varying_texcoord;

//Your functions here...

void main(void) {
    float t = 0.0;
    t = FBM(varying_texcoord.xy * 100.0);
    vec4 color = texture2D(tex1, varying_textcoord);
    gl_FragColor = color * t;
}

EDIT:

Ok, got it working. You need to mix the texture you're drawing (with al_draw_bitmap) with the texture you send in:

#SelectExpand
1#ifdef GL_ES 2precision mediump float; 3#endif 4 5uniform sampler2D al_tex; //texture used in al_draw_bitmap 6varying vec4 varying_color; 7varying vec2 varying_texcoord; 8uniform sampler2D tex1; 9uniform sampler2D tex2; 10varying vec2 tex_uv; 11 12vec2 random(vec2 uv) { 13 uv = vec2(dot(uv, vec2(121.1, 311.7)), dot(uv, vec2(262.5, 183.3))); 14 return -1.0 + 2.0 * fract(sin(uv) * 3.0); 15} 16 17float noise(vec2 uv) { 18 vec2 uv_index = floor(uv); 19 vec2 uv_fract = fract(uv); 20 21 vec2 blur = smoothstep(0.0, 1.0, uv_fract); 22 23 return mix(mix(dot(random(uv_index + vec2(0.0, 0.0)), uv_fract - vec2(0.0, 0.0)), dot(random(uv_index + vec2(1.0, 0.0)), uv_fract - vec2(1.0, 0.0)), blur.x), mix(dot(random(uv_index + vec2(0.0, 1.0)), uv_fract - vec2(0.0, 1.0)), dot(random(uv_index + vec2(1.0, 1.0)), uv_fract - vec2(1.0, 1.0)), blur.x), blur.y) + 0.5; 24} 25 26const int max_octaves = 6; 27 28float FBM(vec2 uv) 29{ 30 float result = 0.0; 31 float ampl = 1.0; 32 float freq = 0.005; 33 34 for(int oct = 0; oct < max_octaves; oct++) 35 { 36 result += ampl * noise(uv * freq); 37 ampl *= 0.5; 38 freq *= 2.0; 39 } 40 41 return result; 42} 43 44void main(void) { 45 float t = 0.0; 46 t = FBM(varying_texcoord.xy * 100.0); 47 vec4 color = texture2D(al_tex, varying_texcoord.xy); 48 vec4 texture_color = texture2D(tex1, varying_texcoord.xy) * t; 49 gl_FragColor = mix(color, texture_color, texture_color.a); 50}

Using this vertex shader:

#SelectExpand
1attribute vec4 al_pos; 2attribute vec4 al_color; 3attribute vec2 al_texcoord; 4uniform mat4 al_projview_matrix; 5varying vec4 varying_color; 6varying vec2 varying_texcoord; 7 8 9void main() 10{ 11 varying_color = al_color; 12 varying_texcoord = al_texcoord; 13 gl_Position = al_projview_matrix * al_pos; 14}

Getting better/worse result by playing with values in your functions!

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

TorgaW
Member #23,803
August 2023

Thanks for reply, Dizzy!

Unfortunately it doesn't help. I setup vertex shader as yours and my result was just black bitmap.
I also tried to draw UV gradient, as I drew before, but result also is a black bitmap. Then I tried to normalize varying_texcoord (I saw this technique on shader toy) with dividing varying_texcoord.x and varying_texcoord.y by image size. It does not help too, just black bitmap. So I don't know what value is stored in the varying_texcoord.

With gl_Position I have result, that only upper right quarter of the bitmap is affected and it is stretched to the full game window, but should be only 512x512 pixels.

I draw my bitmap with this code:

#SelectExpand
1//enable ALLEGRO_PROGRAMMABLE_PIPELINE option. 2//while loop ... 3//... 4//create result bitmap 512x512. 5//fill it with al_clear_to_color(/*black color*/). 6//... 7//... 8al_use_shader(noise_shader); //enable shader. it is not null. 9al_draw_bitmap(result_bitmap, 0, 0, 0); //draw bitmap on screen (backbuffer is a target bitmap). also not null. 10al_use_shader(nullptr); //disable shader for next bitmaps in a queue.

For some reasons next bitmaps also black or glitched like my screen text.

If someone want to see entire project code, I can create github repo with it and share.

Edit.

Thanks, Dizzy! I will try your new code.

Edit #2.

Result is the same: https://i.ibb.co/wh6bGcJ/image.png

Dizzy Egg
Member #10,824
March 2009
avatar

Are you using my vertex shader and fragment shader??

EDIT:

Probably best to show all your code!

EDIT2:

You need to set the texture:

al_set_shader_sampler("tex1", grass_tex, 1);

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

TorgaW
Member #23,803
August 2023

I'm using both shaders.

My code: https://github.com/TorgaW/shader_trouble_allegro5

If you see some bad code or inefficient way of doing something, please, let me know! I would be really appreciate!
I'm creating a 2d game as a "pet" project for the future job!

Edit

I did it, but it is not working.

Dizzy Egg
Member #10,824
March 2009
avatar

noise_shader = ShaderManager::GetShader("PerlinNoise");

Shouldn't that be:

noise_shader = ShaderManager::GetShader("PerlinNoise.glsl");

??

Or even:

noise_shader = ShaderManager::GetShader("Resources/Shaders/PerlinNoise.glsl");

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

TorgaW
Member #23,803
August 2023

No, because it is stored in the std::map and “PerlinNoise” is a key to get pointer to the shader struct. If you change Perlin.glsl to
<code start=“1”>
//functions…
//…
void main()
{
float t = FBM(gl_FragCoord.xy);
gl_FragColor = vec4(t,t,t, 0.0);
}
</code>
You will see the black and white bitmap with noise.
So I think trouble is not here.

Dizzy Egg
Member #10,824
March 2009
avatar

Nevermind, I can see you set the render target to backbuffer.

In order for the shader to work with the 2 textures, we would need to change the fragment shader MAIN to this:

void main(void) {
    float t = 0.0;
    t = FBM(varying_texcoord.xy * 100.0);
    vec4 texture_1_color = texture2D(tex1, varying_texcoord.xy);
    vec4 texture_2_color = texture2D(tex2, varying_texcoord.xy) * t;
    gl_FragColor = mix(texture_1_color, texture_2_color, texture_2_color.a);
}

Also I noticed your sprites are very small - you would need to do some scaling or it won't look great!

I've attached my result using your sprites, drawn to 256 x 256.

{"name":"613342","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/b\/7bec85543c7831f15971703668b4eca9.png","w":257,"h":256,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/b\/7bec85543c7831f15971703668b4eca9"}613342

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

TorgaW
Member #23,803
August 2023

Hello, Dizzy! Thanks for reply!

I set up your code and have this result:

https://i.postimg.cc/QdC77wLf/image.png

Grass texture is blending with white color (why? :'( :'().
And no yellow text are drawn.

Fragment:

float t = 0.0;
t = FBM(varying_texcoord.xy * 200.0);
vec4 texture_1_color = texture2D(tex1, varying_texcoord.xy);
vec4 texture_2_color = texture2D(tex2, varying_texcoord.xy) * t;
gl_FragColor = mix(texture_1_color, texture_2_color, texture_2_color.a);

Vertex:

varying_color = al_color;
varying_texcoord = gl_MultiTexCoord0.xy;
gl_Position = ftransform();

C++:

//creating bitmap before loop
result_bitmap = al_create_bitmap(256, 256); //create bitmap
al_set_target_bitmap(result_bitmap); //set as target
al_clear_to_color(al_map_rgb_f(1.0, 1.0, 1.0)); //fill bitmap with white color 
Render::SetViewportAsRenderTarget(); //set backbuffer as render target

//..
//in loop
al_use_shader(noise_shader);
al_set_shader_sampler("tex1", grass_tex, 1);
al_set_shader_sampler("tex2", dirt_tex, 2);
al_draw_bitmap(result_bitmap, 0, 0, 0);
al_use_shader(nullptr);

I have no ideas what is going on :(

Result image in attachments.

Dizzy Egg
Member #10,824
March 2009
avatar

Make sure your vertex shader looks like this:

#SelectExpand
1attribute vec4 al_pos; 2attribute vec4 al_color; 3attribute vec2 al_texcoord; 4uniform mat4 al_projview_matrix; 5varying vec4 varying_color; 6varying vec2 varying_texcoord; 7 8 9void main() 10{ 11 varying_color = al_color; 12 varying_texcoord = al_texcoord; 13 gl_Position = al_projview_matrix * al_pos; 14 15}

Also, you're drawing result_bitmap at 0,0 - are you sure you're not drawing it over your text??

EDIT:

Ok, I finally got your engine up and running! I had to change some bits. In Game.cpp I changed your display setup to this:

    al_set_new_display_flags(ALLEGRO_FULLSCREEN | ALLEGRO_PROGRAMMABLE_PIPELINE | ALLEGRO_OPENGL);

    al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 4, ALLEGRO_SUGGEST);
    al_set_new_display_option(ALLEGRO_SAMPLES, 16, ALLEGRO_SUGGEST);
    al_set_new_display_option(ALLEGRO_RENDER_METHOD, 1, ALLEGRO_SUGGEST);
    al_set_new_display_option(ALLEGRO_SUPPORT_NPOT_BITMAP, 1, ALLEGRO_SUGGEST);

    game_display = al_create_display(1920, 1080);

And here is the result:

{"name":"613344","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/9\/4921614292aa1f86fbe2017d1f856353.png","w":1030,"h":692,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/9\/4921614292aa1f86fbe2017d1f856353"}613344

I have attched the shaders as well.

I had to change the clocks in Benchmark.hpp to this:

#SelectExpand
1class Benchmark 2{ 3private: 4 std::chrono::steady_clock::time_point start; 5 std::chrono::steady_clock::time_point end; 6public: 7 Benchmark(){}; 8 ~Benchmark(){}; 9 inline void Start() 10 { 11 start = std::chrono::high_resolution_clock::now(); 12 }; 13 inline void Stop() 14 { 15 end = std::chrono::high_resolution_clock::now(); 16 }; 17 inline uint64_t GetTimeNano() 18 { 19 return std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count(); 20 }; 21 inline uint64_t GetTimeMicro() 22 { 23 return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count(); 24 }; 25 inline uint64_t GetTimeMili() 26 { 27 return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); 28 }; 29};

As I couldn't use the _V2 in chrono (but that might just be a Windows thing)

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

TorgaW
Member #23,803
August 2023

Thank you, Dizzy!!

IT IS WORKING!!!! FINALLY!!!

I will read about this magic flags to know more!

You are the best!! Thank you!!! ;D

Dizzy Egg
Member #10,824
March 2009
avatar

Awesome! You’re welcome, glad it’s working! 8-)

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

Mark Oates
Member #1,146
March 2001
avatar

@TorgaW, Could you post your final result code please? 🙂🙏

--
Visit CLUBCATT.com for cat shirts, cat mugs, puzzles, art and more <-- coupon code ALLEGRO4LIFE at checkout and get $3 off any order of 3 or more items!

AllegroFlareAllegroFlare DocsAllegroFlare GitHub

Go to: