• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Shaders Trying to get transparency with tiles

J

jwrose

Guest
So, after doing some research it seems that tiles don't have support for alpha like regular objects/instances. I'm trying to achieve the effect using a shader, but the examples I'm finding are either incomplete or trying to do more than I actually need. The most closest example I found was here:
https://www.reddit.com/r/gamemaker/comments/85ikh2/gms2_how_to_set_a_tile_layers_alpha/
but its a bit old and I haven't been able to get it working.

What I'm trying to do is set an entire tile layer to be less visible through GML. This seems surprisingly hard to do but is on the roadmap for Gamemaker. For now, shaders seem to be the right direction. Can anyone provide me some solid direction in doing this?

Thanks so much everyone!
 
If you want to hardcode the alpha in the shader it's really simple:

Code:
// any create event:
// -----------------------
layer_shader(layer_get_id("Tiles_1"), shd_set_alpha);

// fragment shader:
// -----------------------
// set the static alpha as a macro or constant
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

#define alpha 0.5

void main() {
    gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord ) * vec4(1.0, 1.0, 1.0, alpha);
}

If the alpha needs to stay dynamic, you'll need to do a little bit more. Then you can change the alpha by changing global.layer_alpha from any object.
Code:
// any create event:
// -----------------------
var layer_id = layer_get_id("Tiles_1");
layer_script_begin(layer_id, scr_shader_set_alpha);
layer_script_end(layer_id, scr_shader_reset_alpha);
global.u_layer_alpha = shader_get_uniform(shd_set_alpha, "alpha");
global.layer_alpha = 0.5;

// scr_shader_set_alpha:
// ------------------------------
if (event_type == ev_draw) {
   if (event_number == 0) {
      shader_set(shd_set_alpha);
      shader_set_uniform_f(global.u_layer_alpha, global.layer_alpha);
    }
}

// scr_shader_reset_alpha:
// ---------------------------------
if (event_type == ev_draw) {
   if (event_number == 0) {
      shader_reset();
    }
}

// fragment shader:
// -----------------------
// same as before exept alpha now is a uniform instead of a macro
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform float alpha;

void main() {
    gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord ) * vec4(1.0, 1.0, 1.0, alpha);
}
And if you're interested in learning this stuff, my video tutorials tend to be a little long but are suited for people completely new to shaders (link in signature)
 
Last edited:
J

jwrose

Guest
Thank you!
I just did the hardcoded method and confirmed its working as expected. I'm going to tinker with the dynamic version now. This is a HUGE help. Also, I am going to check out your videos! I started in Gamemaker about 5 months ago and things were going pretty well- until I got to shaders.
 
J

jwrose

Guest
Thanks again for your help!
After tinkering with it a bit, I had to take a few days off from game development. I have run into some error messages. Its referring to oSign, but I didn't add any code to it. I've put all my code in oPlayer.
The thing I noticed in the code you provided was references to shd_set_alpha, but that isn't being recognized. Is that something I need to declare or a shader I need to make... or is this the same thing as scr_shader_set_alpha? I may just be missing something. Anyway, thanks for any additional help you can provide!
upload_2019-1-22_22-28-6.png
 
To make my example work you need to create a shader ressource called shd_set_alpha. The vertex shader can stay as it is and the fragmentshader code is what i posted earlier.

Your error message doesnt say the shader is wrong. The error is in the argumenttype of the second argument in sprite_get_uvs.

edit: correct fatfingered errors
 
Last edited:
Pretty sure it's the first argument in sprite_get_uvs, if I'm not mistaken. Annoyingly, they switch up the number for the debugger (argument0 is referred to as argument 1, argument1 is referred to as argument 2, so on).
 
J

jwrose

Guest
Thanks for the quick responses! Digging into it again! Something isn't quite right (I'm sure its my end) since the error was in a script not being called. After removing it, a new error has popped up in a totally different place. Maybe I didn't close something properly.
 
J

jwrose

Guest
Sorry to keep bugging you guys about this, but I'm really not sure what's going on here. I know it may be impossible to troubleshoot without seeing my whole project (given the nature of the errors), but I'm hoping that there may be something that you think of that may help point me in the right direction.

Anyway, as I said before, I was getting an error that was from a script that I wasn't even using. I removed it, and then I got a new error involving a draw event for another (VERY SIMPLE) object that did not even have a draw event. The error also references a script that I've been using. If I remove the content of that script, then I get a new error about ANOTHER script.
upload_2019-1-25_0-20-29.png

So, I started commenting things out from this new code, line by line, to see what was triggering this (I thought maybe it was a conflict with some other code I had somewhere). If these two lines are commented out, the game runs:
Code:
layer_script_begin(tiles_id, scr_shader_set_alpha);
layer_script_end(tiles_id, scr_shader_reset_alpha);
I put these these (along with the other create event lines) in my player object's create event. I tried placing the code my camera's create event and other objects, but I got the same result. I even removed the new code provided for scr_shader_set_alpha and scr_shader_reset_alpha and I still got the errors. So, somehow, these two fairly simple lines are affecting a lot more than I would expect. Below is the whole snippet of create event code. I made minor modifications just to be 100% sure I didn't have conflicting variable names. Anyway, again, I appreciate any help. This has left me scratching my head.

Code:
tiles_id = layer_get_id("Tiles");
layer_script_begin(tiles_id, scr_shader_set_alpha);
layer_script_end(tiles_id, scr_shader_reset_alpha);
global.u_layer_alpha = shader_get_uniform(scr_shader_set_alpha, "alpha");
global.layer_alpha = 0.5;
 
Instead of simply commenting out lines and hoping that it'll fix it, you should be reading the error message. It says that the target variable has not been set (or created) in oEnemy (which is the instance that is calling the script). It even gives you the specific line which is causing the error (line 4 in the script scr_damage_target_self_destruct). The line in question is
Code:
if (instance_exists(target)) {
This means that you haven't initialised the target variable before the computer tries to access it. Error messages are not just random popups, 95% of them are telling you the exact problem that is occurring. You just have to take the time to read them and then think logically about why the line that it tells you is causing the error.
 
J

jwrose

Guest
I haven't been completely ignoring them because I removed the code form the first error message because it was unnecessary, and now its gone to a totally different script.
And that's the tricky thing. That code worked prior to this new code and has been working for weeks. The reason I am really stumped here these errors seem to be the result of a cascading effect across objects and scripts that, from normal code interactions, are not related to what this new code is doing. In this error message, oSign is mentioned as well as a self destruct script. Those two do not interact in any way. oSign isn't even in the room that's trying to load.

The script that has the error now only fires when an enemy bullet hits the player- but the error is occurring when the room loads and there's no collision like that occurring. Target is declared as oPlayer and this is also used in a bunch of other places without issue. Anyway, being new to shaders I was curious if there's some other aspect of shaders that I'm not taking into account that can affect things in unexpected ways.

Thank you for the push-back though, because it forces me to re-evaluate and I have eliminated a few more possibilities while putting together this response and testing.
 
Ah ok, yeah, very occasionally the error is a cascade type thing which REALLY stems from interactions elsewhere but the compiler only sees the error at a different part. Is the script that has the error still the one you posted above? Because it shouldn't be saying target hasn't been set until it's actually reading target. These sort of bugs often require painstakingly stepping through the code in the debugger, line by line, checking the values of the variables regularly and seeing everything that happened up until the error pops. Then you've gotta really sit down and think about the logical flow of the code. Usually, the error is self-evident after you figure it out, but that doesn't help before you do.
 
J

jwrose

Guest
Just a quick follow-up, thanks for all your help!
I've been working on this VERY part-time for the last few weeks but I finally figured out what I did wrong.
The Reverend, of course your code was fine. Noob mistake on my end. We have different naming conventions and I didn't think that through. When I saw scr_shader_set_alpha, I glommed on to the "shader" part and added that code to a shader with that name instead of a script ("scr"... duh, I should have realized it!). Anyway, once I changed that it seems to be running just great. I guess with that code trying to be run as a shader, things went haywire which is why I kept getting bizarre errors with seemingly unrelated objects and scripts.

Thanks again!!!
 
Top