0 votes

I'm trying to achieve an effect similar to this one but instead of drawing the original pixels using a shader, I want to draw them using a sprite node.

Light color mixing.

This is what each sprite currently looks like:
Current state.

Overlapping sprite areas:
Overlapping areas.

Approximate desired shader effect:
Desired effect.

I tried importing the textures using uniform sampler2Ds and experimenting with textureLod, SCREENTEXTURE and SCREENUV but I couldn't find a way to calculate the area where the sprites are overlapping.

Any help is appreciated.

in Engine by (160 points)

This is the shader code that I'm using for the top image's shader.

shader_type canvas_item;
render_mode unshaded; // No lighting/shading

uniform vec4 colour_one : hint_color;
uniform vec4 colour_two : hint_color;
uniform vec4 colour_three : hint_color;
uniform vec2 colour_one_pos = vec2(0.333, 0.4);
uniform vec2 colour_two_pos = vec2(0.666, 0.4);
uniform vec2 colour_three_pos = vec2(0.5, 0.6);

uniform float circle_radius = 0.3;

void fragment(){
    COLOR.a = 0.0;

    bool in_colour_one = distance(colour_one_pos, UV) <= circle_radius;
    bool in_colour_two = distance(colour_two_pos, UV) <= circle_radius;
    bool in_colour_three = distance(colour_three_pos, UV) <= circle_radius;

    if (in_colour_one && in_colour_two && in_colour_three){
        COLOR = colour_one + colour_two + colour_three;
    }
    else if (in_colour_one && in_colour_two){
        COLOR = colour_one + colour_two;
    }
    else if (in_colour_one && in_colour_three){
        COLOR = colour_one + colour_three;
    }
    else if(in_colour_two && in_colour_three){
        COLOR = colour_two + colour_three;
    }
    else{
        if (in_colour_one){
            COLOR = colour_one;
        }
        if (in_colour_two){
            COLOR = colour_two;
        }
        if (in_colour_three){
            COLOR = colour_three;
        }
    }
}

Have you tried the additive blend mode?

render_mode unshaded, blend_add;

Sorry, I'm still new to shaders. I have not tried the additive blend mode but how would I use it to combine the colors in the area where two sprites overlap?

1 Answer

+3 votes
Best answer

You don't need a shader to achieve this effect. It is done through additive blend mode, which is closer to how light behaves. Basically, colors are combined by adding them together.

Go to the inspector for each of your sprites and add a new CanvasItemMaterial in their material property. Then in that material, change blend mode to Add.

If you use a shader, this is essentially the same, except you write render_mode blend_add on the top.
Note that there is no way to implement a custom blending operation with shader code (at least not with more than 2 layers), only the predefined modes are available.

If however you want to blend between colors within your shader, you could write it as a simple addition (same as the code you already posted, simplified a bit):

bool in_colour_one = distance(colour_one_pos, UV) <= circle_radius;
bool in_colour_two = distance(colour_two_pos, UV) <= circle_radius;
bool in_colour_three = distance(colour_three_pos, UV) <= circle_radius;

if (in_colour_one) {
    COLOR.rgb += colour_one.rgb;
}
if (in_colour_two) {
    COLOR.rgb += colour_two.rgb;
}
if (in_colour_three) {
    COLOR.rgb += colour_three.rgb;
}
by (27,774 points)
selected by
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.