• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

SOLVED Dynamic Outline Shader from Surface

witches

Member
Hey all.

So I'm working on an outline method where I sample a surface texture of a couple of sprites and send that through a basic outline shader and basically clear and repeat.
So far it works well, but there's a tiny outline of my sprites being created even when they're both being drawn onto the surface then THAT surface is sent through the shader. It's like the surface isn't "flattened" even though that's not necessarily how they work.
it's not until i apply a gpu_set_blendmode constant that the outline constantly stays around the sprites, but I'm not looking to blend pixels together. i can't seem to achieve the desired effect. the debugger shows that the surface is being correctly created and updated.

relevant create event
GML:
//outline shader definitions
uThickness        = shader_get_uniform(shOutline,"u_thick");
samplerSurface    = shader_get_sampler_index(shOutline, "playerTexture");

thickness = 0.003;

global.surfPlayer = -1;
draw event
GML:
/// @desc surface drawing

//double check if the surface is still accessable
if !surface_exists(global.surfPlayer){
    global.surfPlayer = surface_create(room_width,room_height);
}

//-----surface drawing-----//
surface_set_target(global.surfPlayer);

    draw_clear_alpha(0,0);
    
    draw_sprite_ext(sWitch,0,100,100,1,1,rotate,c_white,1);
    draw_sprite_ext(sWitch,0,150,150,1,1,rotate,c_white,1);
    
surface_reset_target();

var _surf = surface_get_texture(global.surfPlayer);

//-----set shader-----//
shader_set(shOutline);

    //pass shader uniforms
    texture_set_stage(samplerSurface, _surf);
    shader_set_uniform_f(uThickness,thickness);

//draw surface
draw_surface(global.surfPlayer,0,0);

shader_reset();
fragment shader
C:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform sampler2D    playerTexture;
uniform float        u_thickness;
uniform float        u_thick;


void main()
{
    //sample the original
    vec4 original = texture2D( playerTexture, v_vTexcoord );
    
    
    //make the left mask
    vec4 leftSide = texture2D( playerTexture, v_vTexcoord + vec2(u_thick,0.0) );
    vec4 maskLeft = leftSide - original;
    
    //make the bottom mask
    vec4 bottomSide = texture2D( playerTexture, v_vTexcoord + vec2(0.0,-u_thick) );
    vec4 maskBottom = bottomSide - original;

    //make the right mask
    vec4 rightSide = texture2D( playerTexture, v_vTexcoord + vec2(-u_thick,0.0) );
    vec4 maskRight = rightSide - original;

    //make the top mask
    vec4 topSide = texture2D( playerTexture, v_vTexcoord + vec2(0.0,u_thick) );
    vec4 maskTop = topSide - original;
    
    //make the top left mask
    vec4 topleftSide = texture2D( playerTexture, v_vTexcoord + vec2(u_thick,u_thick) );
    vec4 maskTopLeft = topleftSide - original;

    //make the top right mask
    vec4 toprightSide = texture2D( playerTexture, v_vTexcoord + vec2(-u_thick,u_thick) );
    vec4 maskTopRight = toprightSide - original;

    //make the bottom left mask
    vec4 bottomleftSide = texture2D( playerTexture, v_vTexcoord + vec2(u_thick,-u_thick) );
    vec4 maskBottomLeft = bottomleftSide - original;

    //make the bottom right mask
    vec4 bottomrightSide = texture2D( playerTexture, v_vTexcoord + vec2(-u_thick,-u_thick) );
    vec4 maskBottomRight = bottomrightSide - original;


    //
    //create a mask with all the combined masks
    //
    vec4 masterMask = maskLeft + maskBottom + maskRight + maskTop +
                        maskTopLeft + maskTopRight + maskBottomLeft + maskBottomRight;
    
    //make the mask white and clamp the alpha
    masterMask.rgb = vec3(255.0,255.0,255.0);
    masterMask.a = clamp(masterMask.a,0.0,1.0);
    
    
    //combine all the masks to original texture
    vec4 combined = masterMask.a + original;

    //final output
    gl_FragColor = v_vColour * combined;
}
result

this is the closest I can get to the effect. im looking for the outline to only be drawn around the total of sprites together on a surface, if that makes sense. Im looking to get only one outline that follows the contour of the sprites overlapping.
any help of direction would be greatly appreciated!
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
When you draw the sprites to the surface, try switching off alpha blending, using:
GML:
gpu_set_colorwriteenable(true, true, true, false);
The problem looks to me like it's being caused by the way surfaces treat alpha, so this may resolve the issue.
 

witches

Member
When you draw the sprites to the surface, try switching off alpha blending, using:
GML:
gpu_set_colorwriteenable(true, true, true, false);
The problem looks to me like it's being caused by the way surfaces treat alpha, so this may resolve the issue.
this method results in a blank screen unfortunately, like as if the object calling the sprites to be drawn was invisible. I tried toggling the shader off too just in case but there wasn't any difference.
Do you think maybe theres another way to combine sprites together?
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Ah... Okay, I see why you would get a blank screen... My mistake as I was recommending something that would work if the surface alpha was 1, which (of course!) in this case it's not. Sorry! There may be multiple ways to solve this issue however - although I think pre-multiplying the alpha for the sprites being drawn will be what resolves it - but rather than just suggest things at random, can I suggest that you check out this video first?

It's a really good overview of WHY you are having this issue, and then it goes on to explain multiple ways to resolve it (the bit that I think will solve it for you is about the 15min mark).
 

witches

Member
Ah... Okay, I see why you would get a blank screen... My mistake as I was recommending something that would work if the surface alpha was 1, which (of course!) in this case it's not. Sorry! There may be multiple ways to solve this issue however - although I think pre-multiplying the alpha for the sprites being drawn will be what resolves it - but rather than just suggest things at random, can I suggest that you check out this video first?

It's a really good overview of WHY you are having this issue, and then it goes on to explain multiple ways to resolve it (the bit that I think will solve it for you is about the 15min mark).
this worked out! thank you for the video and for the help! i can change the colors of the hat and it doesnt blend with the sprite behind it!
Thank you thank you!
 
Top