Show full-screen texture only in front of a sprite

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By pferft

Hi everyone,

I have a half-transparent TextureRect (some paper-texture) placed all over the screen. The only thing happening in the background is an animated sprite moving across from one point to another (the scene will be instanced occasionally in my project). So this looks like some “Okami” paper-effect…

However, instead of showing the whole full-screen paper, I’d like it to only appear in front of my sprite while the rest of the texture shouldn’t be visible at all. Is there any usual approach how to achieve this?

I think you’re describing a sprite mask here, and for that there’s an example project that demonstrates using Light2D to mask sprites. The ordering of your textures may differ but I think this is the desired result.

https://github.com/godotengine/godot-demo-projects/tree/master/2d/light2d_as_mask

Another approach may be to blend the textures, perhaps using a shader.

spaceyjase | 2022-01-06 09:21

Thanks for your help, spaceyjase and Hugo4IT!

I read the entry in the docs before, but for a beginner like me getting an explanation is obviously much better…

So it works, just as you described it to me! Only one following question came up:
regulating Paper Influence shifts the transparency of the paper texture, making the sprite behind more or less “pale”… is it possible to change the paper texture’s transparancy mode to “add” or “multiply” within the shader-code? That might show the texture while keeping the sprite’s contrast.
There’s “blend_add” and “blend_mul” mentioned as render modes in the docs, but I’m not able to apply them. I know it’s possible to select such a blend mode on a new CanvasItemMaterial, but could it also be added to our running shader?

pferft | 2022-01-11 15:38

:bust_in_silhouette: Reply From: Hugo4IT

What you’re looking for is a technique called masking (wikipedia doesn’t have a page for digital masking :/). You can easily achieve this using shaders, I’ll guide you through adding the shader I created for you, but I highly recommend you read Godot’s documentation on shaders:

First, create a ShaderMaterial:

Then, create a Shader:

another screenshot

Clicking the newly created Shader will open it in the bottom window (press Shift+F12 to maximize it). Then you can paste my shader code (again, make sure to read the documentation, so you understand what’s going on):

shader_type canvas_item;

uniform sampler2D paper_texture;
uniform sampler2D paper_normal;
uniform float paper_influence: hint_range(0.0, 1.0) = 0.5;

void fragment() {
	vec4 original_color = texture(TEXTURE, UV);
	COLOR = mix(original_color, vec4(texture(paper_texture, SCREEN_UV).rgb, original_color.a), paper_influence);
	NORMALMAP = mix(NORMAL, texture(paper_normal, SCREEN_UV).xyz, paper_influence);
}

You can now adjust the settings:

A screenshot of the settings

A description of the settings:

  • paper_texture: The overlay texture.
  • paper_normal: Behaves like a sprite’s normal map, you can leave it empty.
  • paper_influence: How much of the overlay is visible, 0 is only the sprite’s texture, 1 is only the overlay texture, anything in between is a mix of both.

Demo

I used a brick texture as it is much easier to see, also, please excuse the terrible gif quality, the noise is from ffmpeg throwing a fit.

A gif preview