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:
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:
Fragment:
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.
P.S.
I don't have much experience in OpenGL programming, but really want to learn more.
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.
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
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:
Using this vertex shader:
Getting better/worse result by playing with values in your functions!
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:
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
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);
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.
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");
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.
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"}
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.
Make sure your vertex shader looks like this:
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"}
I have attched the shaders as well.
I had to change the clocks in Benchmark.hpp to this:
As I couldn't use the _V2 in chrono (but that might just be a Windows thing)
Thank you, Dizzy!!
IT IS WORKING!!!! FINALLY!!!
I will read about this magic flags to know more!
You are the best!! Thank you!!!
Awesome! You’re welcome, glad it’s working!
@TorgaW, Could you post your final result code please? 🙂🙏