Making a shader that draws the bottom half of a sprite

S

SuperSaabrio

Guest
So I thought I was finally understanding shaders after I manage to make a basic color flash shader, but it seems I really do not.

I want to make a shader that sets every alpha value of a pixel above the half way point of the sprite to 0. Yes I know I can use draw sprite part, but the functionality isn't whats important, it's the fact that if I can understand how to do this then I can make a shader that fits my end goal.

I was under the impression that the main function loops once for every pixel on the screen and that v_vTexcoord was the x,y position within the sprite. I already tried

main()
{
gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );

if (v_vTexcoord.y > 0.5)
{
gl_FragColor.a = 0.0;
}
}

but that didn't work, so I obviously lack an understanding of how fragment shader actually works.
 
S

SuperSaabrio

Guest
Ok I figured it out, the shader takes in the texture sheet the sprite is on and v_vTexcoord is the u_v point on that texture sheet. Surprising how hard is to find info on something so simple haha.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
that v_vTexcoord was the x,y position within the sprite
It's the XY within the texture page. If your sprite is power-of-two sized and has "separate texture page" ticked, that's sprite space. Otherwise you would want to pass game-space coordinates from vertex to fragment shader via a varying, like shown here: https://yal.cc/gamemaker-draw-clip/
Code:
attribute vec3 in_Position;
attribute vec4 in_Colour;
attribute vec2 in_TextureCoord;
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vPosition;
//
void main() {
   v_vPosition = in_Position;
   gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION]
       * vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
   v_vColour = in_Colour;
   v_vTexcoord = in_TextureCoord;
}
Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vPosition;
//
uniform float u_cutafter;
//
void main() {
   vec4 col = v_vColour * texture2D(gm_BaseTexture, v_vTexcoord);
   col.a *= float(v_vPosition.y >= u_cutafter);
   gl_FragColor = col;
}
 
S

SuperSaabrio

Guest
It's the XY within the texture page. If your sprite is power-of-two sized and has "separate texture page" ticked, that's sprite space. Otherwise you would want to pass game-space coordinates from vertex to fragment shader via a varying, like shown here: https://yal.cc/gamemaker-draw-clip/
Code:
attribute vec3 in_Position;
attribute vec4 in_Colour;
attribute vec2 in_TextureCoord;
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vPosition;
//
void main() {
   v_vPosition = in_Position;
   gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION]
       * vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
   v_vColour = in_Colour;
   v_vTexcoord = in_TextureCoord;
}
Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vPosition;
//
uniform float u_cutafter;
//
void main() {
   vec4 col = v_vColour * texture2D(gm_BaseTexture, v_vTexcoord);
   col.a *= float(v_vPosition.y >= u_cutafter);
   gl_FragColor = col;
}

But I'd need the pixel position on the sprite sheet not its world location. Doesn't this method give you the world location?
 

NightFrost

Member
Yes in_Position is the room space position (whereas gl_FragCoord is view space) but you could still use it for cut-off point by sending the shader y-position plus half the sprite height, as shown in the sample code. However if you want to use texture page coordinates, you cen get them with sprite_get_uvs and calculate halfway point from those.
 
S

SuperSaabrio

Guest
Yes in_Position is the room space position (whereas gl_FragCoord is view space) but you could still use it for cut-off point by sending the shader y-position plus half the sprite height, as shown in the sample code. However if you want to use texture page coordinates, you cen get them with sprite_get_uvs and calculate halfway point from those.
yeah I managed to achieve my goal using the uv function but the in_position method might be more accurate, but doesn’t it scale with resolution?
 

NightFrost

Member
Not entirely sure what you mean by that. Sprite has same pixel size regardless of display resolution. If you mean sprites on instances that have set their scaling to other than one, I'd imagine the scaling happens only in draw output, and the shader is essentially making the check when it reads the texture page which always is in original scale. You'll just have to read the sprite height with sprite_get_height() which gets the original height, as instances' builtin sprite_height variable reflects size after scaling has been applied.
 
Top