+1 vote

Hello!
I want to replicate the glow/stroke effect from Age of Empires II (see photo bellow).

Basically, I want to stroke the part of the sprite that is behind another sprite.
So if I have a "soldier" on Z = 0 and a "building" on Z = 1 I want to show the contour of the soldier on Z = 3 if that makes sense.

Does anybody know how to do that?
Thanks!

Example: What i want

in Engine by (16 points)

This is typically done in 3D using a Z-buffer, but in 2D there is no such thing so you have to rely on draw order and separate buildings and units in two drawing passes.
One way is to draw all units in a buffer, then you add a shader on buildings that reads the units buffer. If a building pixel is opaque and the units buffer is also opaque, then you can draw the outline instead of the unit.
If the building pixel is transparent, then you draw the unit.

1) Draw terrain
2) Draw units in buffer
3) Draw this buffer on screen
4) Draw buildings (which now can access the units buffer in their shader to draw outlines)

This is theory, I don't know yet how it applies with Godot, probably using viewports and a RenderTexture.

Yeah, I was thinking about something similar but I have no idea on how to do it in Godot.
Thanks for confirming my theory!

How about a Sprite > CanvasItem > Behind Parent on/off and glow on /off too?
or am out?

I don't really understand what you want to do. Can you please provide a demo or something?
Thanks a lot1

In Sprite node there is Behind Parent so with a script + enable/disable glow
but maybe I'm wrong .....something like... Area2D.getoverlappingbodies(Method)?
I'm novice in GDscript

if Area.overlaps_body() :
Sprite.is_draw_behind_parent_enabled(true)
else:
Sprite.is_draw_behind_parent_enabled(false)




is_draw_behind_parent_enabled()

enter image description here

That would work. But If I would to use this on an animated sprite with 8 rotation and 5 animations wouldn't this require to double every frame? Zylann's solutions seems very good after some more documentation. Thanks!

Putting a sprite above the unit is a simple solution too but it has limitations:
1) You have to detect when to do it obviously
2) You can't have it partially hidden, it's all or nothing

You can animate Behind Parent and call this animation?...in Godot is everything animatable....but I guess that's the same as by script and it is the worst solution :-)

Maybe you can add a light that takes the parent sprite and only affect buildings mask, but that will need some light shader work to get the correct output (like the outline) and a fine lighting mask setup.

This is Cubio with a light on wall tilemap layer:
https://lut.im/xttobLEAv4/Txh4JTu5TQ2hmrh1.png

1 Answer

0 votes
Best answer

This probably isn't the optimal method, but it's easy to set up at least. The scene should look like this:

root
    mask_sprite1
    mask_sprite2 ...etc
    BackBufferCopy
    background
    building_sprite1
    building_sprite2 ...etc
    unit_sprite1
    unit_sprite2 ...etc

The mask sprites are in the same positions as the corresponding building sprites and have the same textures. The BackBufferCopy is set to copy the viewport. The mask-sprites are drawn with this fragment shader:

COLOR = color(1.0, 0.0, 0.0, tex(TEXTURE, UV).a);

The unit-sprites are drawn with this fragment shader:

uniform float outline_thickness = 2.0;
uniform color outline_color = color(1.0, 1.0, 1.0, 1.0);

color col;

if(texscreen(SCREEN_UV).r < 1.0) {
    col = tex(TEXTURE, UV);
}
else {
    float alpha = 4 * tex(TEXTURE, UV).a;
    alpha -= tex(TEXTURE, UV + vec2(TEXTURE_PIXEL_SIZE.x * outline_thickness, 0.0)).a;
    alpha -= tex(TEXTURE, UV + vec2(-TEXTURE_PIXEL_SIZE.x * outline_thickness, 0.0)).a;
    alpha -= tex(TEXTURE, UV + vec2(0.0, TEXTURE_PIXEL_SIZE.y * outline_thickness)).a;
    alpha -= tex(TEXTURE, UV + vec2(0.0, -TEXTURE_PIXEL_SIZE.y * outline_thickness)).a;
    col = color(outline_color.rgb, alpha);
}

COLOR = col;
by (1,554 points)
selected by

If this works I'll love you forever. :)
Seems like it's time to learn how to make fragment shaders.

Thanks!

Can't seem to make it work. :(
Can you provide a project please?

Here's a simple demo. You can move the 'unit' with the arrow keys and pan the camera by clicking and dragging.

https://mega.nz/#!QCBFTaoD!xYz62oA5Wh7vYg3xgy1kUA3U0R2td7uCdHmDYcU3Dfg

Thanks a lot! You're awesome!
I've been trying to make it work for an hour now but with no success.

Exactly what I wanted. Time to see how the code works now. :D

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.