Skip to content
  • Thank you! I needed something like this... and was inspired by yours. I've done some MATHS and came up with this that should be equivalent to yours (except I made zoom instead a "scale" aka size of the corner and made it between 0.0 and 1.0).: (You can use your zoom range if you add 0.5 to it and normalize between 0 and 1)

    shader_type canvas_item;
    
    uniform float scale : hint_range(0.0, 1.0) = 0.5;
    
    void fragment() {
    	COLOR = texture(TEXTURE, UV);
    
    	// Adjust UV to mirror both axes and give the point in the top-left quadrant
    	// Also "moves" it toward the center via the 'scale' value.
    	vec2 adjusted = (scale * 0.5) + 0.25 - abs(0.5 - UV);
    
    	// Determine if the point is within the top-left triangle of that quadrant.
    	if (adjusted.x + adjusted.y <= 0.5) {
    		COLOR.a = 0.0;
    	}
    }

    I needed one that (in this case optionally) respected aspect ratios of the texture so the corners were 45 degree angles. So I had to add some more MATHS in there to adjust the UV to one that presumed it was in a texture big enough to fit the actual texture. In this case, also, the "zoom" became "scale" as in the size of the corners relative to the image itself. It kinda got complicated again haha! But I wanted the 'scale' of 0.1 to be a little corner missing regardless of the aspect ratio of the image... so some extra MATHS to rescale it to fit that range. Phew!

    This one, to make my life easier, effectively does this instead of the equivalent line in the simpler shader above: (though, this might be easier to understand.)

    	vec2 adjusted = 0.5 - abs(0.5 - UV) + 0.25 - (scale * 0.5);

    But here's the whole thing:

    // Author: wilkie
    // License: CC0
    
    shader_type canvas_item;
    
    uniform float scale : hint_range(0.0, 1.0) = 0.5;
    
    uniform bool maintain_aspect_ratio = true;
    
    void fragment() {
    	// Pull in the texture.
    	COLOR = texture(TEXTURE, UV);
    
    	// Most of the logic presumes that there is some kind of non 1:1 aspect
    	// ratio and adjusts the texture to suit logic that must assume there is a
    	// 1:1 aspect ratio. If the maintain_aspect_ratio option is turned off,
    	// however, the logic will assume a 1:1 ratio without it being true. This
    	// will distort the triangles such that the area of the erasure is
    	// proportional to the area of the image.
    	vec2 aspect_ratio = vec2(1.0, 1.0);
    	if (maintain_aspect_ratio) {
    		// Determine the difference in ratio of the texture to that of a square
    		aspect_ratio = vec2(
    			min(1.0, TEXTURE_PIXEL_SIZE.y / TEXTURE_PIXEL_SIZE.x),
    			min(1.0, TEXTURE_PIXEL_SIZE.x / TEXTURE_PIXEL_SIZE.y)
    		);
    	}
    	
    	// Use that ratio to adjust the UV to one that reflects the UV if the
    	// texture were actually that square. So, if the original texture was, say,
    	// twice as wide as it is tall, the Y coordinate of the UV pair that would
    	// otherwise go from 0.0 to 1.0 would now go from 0.25 to 0.75 since that
    	// would be the UV values of the image if it were centered on such a square
    	// that would fit it.
    	vec2 adjusted_uv = vec2(
    		((UV.x - 0.5) * aspect_ratio.x) + 0.5,
    		((UV.y - 0.5) * aspect_ratio.y) + 0.5
    	);
    
    	// Adjust the UV to ensure all UV values are reflecting the top-left
    	// quadrant. All UVs are essentially flipped across both axes where those
    	// axes are running through the center of the texture. Right now, the check
    	// later on will effectively erase this top-left triangle. We are now going
    	// to alter the UV considered. Moving our UV left (subtracting from
    	// scaled_uv) will erase more since it moves the considered UV further into
    	// the erased triangle. Otherwise it erases less since it moves it toward
    	// the center of the image.
    	vec2 scaled_uv = 0.5 - abs(0.5 - adjusted_uv);
    	
    	// Go to completed whole. Doing nothing, this scaled_uv value means that
    	// the check further on will never pass. This renders the whole image. We
    	// use the scale value given by the uniform to then move this uv coordinate
    	// back.
    	scaled_uv += 0.25;
    	
    	// But always subtract back the amount needed to reach the texture's native
    	// size. That way a setting of '0' is a whole image regardless of aspect
    	// ratio. So we need to refit the user-provided scale from instead of a
    	// range of 0.0 to 1.0, from the ratio of missing space to 1.0.
    	// The ratio of missing space is the inverse aspect ratio divided by 2 since
    	// we want the ratio of missing space in just one quadrant of the whole
    	// texture.
    	float min_scale = (1.0 - min(aspect_ratio.x, aspect_ratio.y)) / 2.0;
    	float adjusted_scale = min_scale + (scale * (1.0 - min_scale));
    	
    	// Subtract the amount (we want a scale from 0.0 to 0.5, so we divide by 2)
    	// given by the user-defined value. This affectively "moves" the UV to the
    	// top and left of the image's top-left quadrant.
    	scaled_uv -= adjusted_scale * 0.5;
    	
    	// Values are normalized to the top-left quandrant where all UV values are
    	// between 0.0 and 0.5. When the X value and the Y values do not add up to
    	// anything greater than 0.5, they are in the top-left of this quadrant.
    	if (scaled_uv.x + scaled_uv.y <= 0.5) {
    		COLOR.a = 0.0;
    	}
    }
  • I, then, generalized this category of shader as N-sided polygons here: https://godotshaders.com/shader/polygon-mask

  • Really cool, thanks for sharing this! 🙇

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment