Shaders outline shader with gpu_set_tex_filter

jonjons

Member
hello, is there a way to merge a shader with the (gpu_set_tex_filter)
iam trying to draw a surface with an outline shader, problem is once i set the (gpu_set_tex_filter) the shader doesnt cover the blur edges. It leaves an empty space around the sprite.
and i also cant apply (gpu_set_tex_filter) to the outline the shader makes.

Is there a way to get the (gpu_set_tex_filter) working togheter with the shader ?
GML:
//-----draw----

surface_reset_target();


var sx = image_xscale;
var sy = image_yscale;

//--------//--shader--//-----------

shader_set(shd_outLine);
var texture = surface_get_texture(surfAnim);
var texture_with    = texture_get_texel_width(texture);
var texture_height    = texture_get_texel_height(texture);
shader_set_uniform_f(uniform_Handle, texture_with, texture_height);
//-----------------//---------------

gpu_set_tex_filter(gpuOn);

draw_surface_ext(surfAnim, x-sx*AnimXoffset, y-sy*AnimYoffset, image_xscale, image_yscale, image_angle, c_white, image_alpha );

shader_reset();
 
D

Deleted member 13992

Guest
I sometimes toggle gpu_set_texfilter before and after shader_set/reset and it works for me. That said I might be scaling things differently than you are. Also, I do it to smooth (or not) textures sent to the shader, which might be different.

Could you post screenshots of what it looks like with and without the shader? That would be helpful to have a better idea of what you're after.
 
Do you leave a transparent border around your sprite, and do you have your texture page NOT set to "Automatically crop"?
These have to be right, for using outline shaders, otherwise it will cut.
 

jonjons

Member
Ive tried everything setting the texteure page to not Automatically crop, changing the gpu_set_texfilter position.
and using 2 diferent outline shader nothing worked...

shader1.png

//--------//----
shader2.png

the image gets blured but the ouline always stays in pixel form
 
D

Deleted member 13992

Guest
If you want the shader outline pixels to be blurred in the same way as the sprite when you scale up, you want to surface_set_target to a new surface, apply the shader as you do now, surface_reset_target, then scale it up. I don't know how you're scaling your view exactly, but in theory that should make it consistent.


Something like this (untested, so it's more for the theory). I'm also going under the assumption that this is yoru draw event for the sprite and that you're scaling up the view elsewhere.

GML:
//-----draw----

if (!surface_exists(surface_canvas)) {
    surface_canvas = surface_create(sprite_w+2, sprite_h+2);     //<---- create surface if doesn't already exist
}

surface_set_target(surface_canvas);    //<---- set surface target


var sx = image_xscale;
var sy = image_yscale;

//--------//--shader--//-----------

shader_set(shd_outLine);
var texture = surface_get_texture(surfAnim);
var texture_with    = texture_get_texel_width(texture);
var texture_height    = texture_get_texel_height(texture);
shader_set_uniform_f(uniform_Handle, texture_with, texture_height);
//-----------------//---------------

gpu_set_tex_filter(gpuOn);  //<---- if it was already on by default, no need for this anymore

draw_surface_ext(surfAnim, x-sx*AnimXoffset, y-sy*AnimYoffset, image_xscale, image_yscale, image_angle, c_white, image_alpha );

shader_reset();

surface_reset_target();    //<---- reset  surface target

draw_surface_ext(surface_canvas, x-1, y-1, 1, 1, 0, c_white, 1);    //<---- draw surface with shader drawn in
1. create small surface "surface_canvas" explicitly for "surfAnim"
2. turn shader on
3. draw "surfAnim" to "surface_canvas"
4. turn shader off
5. draw "surface_canvas" to application surface

Maybe someone has a more elegant way of doing this, but I think this should work. to give you the sprite and outline with the same amount of scaling "blur". I do this kind of surface juggling a lot in my game, it works.
 

jonjons

Member
thanks adding another surface worked...
but isnt it to costly to do it this way. Is there a way to know how GM handles the draw calls.
what was supossed to work to save resources is becoming more and more costly by each line of code.

i started by drawing sprites on to surface to handle it better... now endede up with sprites on surfaces and surfaces on surfaces


GML:
if (! ddSurf)
{


var sx = image_xscale;

draw_self();



draw_sprite_ext(sprPos[part1_Pos], part1_Index, x+sx*part1_X, y+part1_Y, part1_ScX*sx, part1_ScY, sx*part1_A, part1_Color, part1_Alpha ); //-Left-Hand
draw_sprite_ext(sprPos[part2_Pos], part2_Index, x+sx*part2_X, y+part2_Y, part2_ScX*sx, part2_ScY, sx*part2_A, part2_Color, part2_Alpha ); //-Left-armDown
draw_sprite_ext(sprPos[part3_Pos], part3_Index, x+sx*part3_X, y+part3_Y, part3_ScX*sx, part3_ScY, sx*part3_A, part3_Color, part3_Alpha ); //-Left-armUp

draw_sprite_ext(sprPos[part4_Pos], part4_Index, x+sx*part4_X, y+part4_Y, part4_ScX*sx, part4_ScY, sx*part4_A, part4_Color, part4_Alpha ); //-Left-foot
draw_sprite_ext(sprPos[part5_Pos], part5_Index, x+sx*part5_X, y+part5_Y, part5_ScX*sx, part5_ScY, sx*part5_A, part5_Color, part5_Alpha ); //-Left-legDown
draw_sprite_ext(sprPos[part6_Pos], part6_Index, x+sx*part6_X, y+part6_Y, part6_ScX*sx, part6_ScY, sx*part6_A, part6_Color, part6_Alpha ); //-Left-legUp

draw_sprite_ext(sprPos[part7_Pos], part7_Index, x+sx*part7_X, y+part7_Y, part7_ScX*sx, part7_ScY, sx*part7_A, part7_Color, part7_Alpha ); //-waist
draw_sprite_ext(sprPos[part8_Pos], part8_Index, x+sx*part8_X, y+part8_Y, part8_ScX*sx, part8_ScY, sx*part8_A, part8_Color, part8_Alpha ); //-torso
draw_sprite_ext(sprPos[part9_Pos], part9_Index, x+sx*part9_X, y+part9_Y, part9_ScX*sx, part9_ScY, sx*part9_A, part9_Color, part9_Alpha ); //-head

draw_sprite_ext(sprPos[part10_Pos], part10_Index, x+sx*part10_X, y+part10_Y, part10_ScX*sx, part10_ScY, sx*part10_A, part10_Color, part10_Alpha ); //-Right-foot
draw_sprite_ext(sprPos[part11_Pos], part11_Index, x+sx*part11_X, y+part11_Y, part11_ScX*sx, part11_ScY, sx*part11_A, part11_Color, part11_Alpha ); //-Right-legDown
draw_sprite_ext(sprPos[part12_Pos], part12_Index, x+sx*part12_X, y+part12_Y, part12_ScX*sx, part12_ScY, sx*part12_A, part12_Color, part12_Alpha ); //-Right-legUp

draw_sprite_ext(sprPos[part13_Pos], part13_Index, x+sx*part13_X, y+part13_Y, part13_ScX*sx, part13_ScY, sx*part13_A, part13_Color, part13_Alpha ); //-Right-Hand
draw_sprite_ext(sprPos[part14_Pos], part14_Index, x+sx*part14_X, y+part14_Y, part14_ScX*sx, part14_ScY, sx*part14_A, part14_Color, part14_Alpha ); //-Right-armDown
draw_sprite_ext(sprPos[part15_Pos], part15_Index, x+sx*part15_X, y+part15_Y, part15_ScX*sx, part15_ScY, sx*part15_A, part15_Color, part15_Alpha ); //-Right-armUp   



}
else
{

    
surface_set_target(surfAnim);
draw_clear_alpha(c_black, 1);

gpu_set_tex_filter(false);
draw_sprite_ext(sprPos[part1_Pos], part1_Index, AnimXoffset+part1_X, AnimYoffset+part1_Y, part1_ScX, part1_ScY, part1_A, part1_Color, part1_Alpha ); //-Left-Hand
draw_sprite_ext(sprPos[part2_Pos], part2_Index, AnimXoffset+part2_X, AnimYoffset+part2_Y, part2_ScX, part2_ScY, part2_A, part2_Color, part2_Alpha ); //-Left-armDown
draw_sprite_ext(sprPos[part3_Pos], part3_Index, AnimXoffset+part3_X, AnimYoffset+part3_Y, part3_ScX, part3_ScY, part3_A, part3_Color, part3_Alpha ); //-Left-armUp

draw_sprite_ext(sprPos[part4_Pos], part4_Index, AnimXoffset+part4_X, AnimYoffset+part4_Y, part4_ScX, part4_ScY, part4_A, part4_Color, part4_Alpha ); //-Left-foot
draw_sprite_ext(sprPos[part5_Pos], part5_Index, AnimXoffset+part5_X, AnimYoffset+part5_Y, part5_ScX, part5_ScY, part5_A, part5_Color, part5_Alpha ); //-Left-legDown
draw_sprite_ext(sprPos[part6_Pos], part6_Index, AnimXoffset+part6_X, AnimYoffset+part6_Y, part6_ScX, part6_ScY, part6_A, part6_Color, part6_Alpha ); //-Left-legUp

draw_sprite_ext(sprPos[part7_Pos], part7_Index, AnimXoffset+part7_X, AnimYoffset+part7_Y, part7_ScX, part7_ScY, part7_A, part7_Color, part7_Alpha ); //-waist
draw_sprite_ext(sprPos[part8_Pos], part8_Index, AnimXoffset+part8_X, AnimYoffset+part8_Y, part8_ScX, part8_ScY, part8_A, part8_Color, part8_Alpha ); //-torso
draw_sprite_ext(sprPos[part9_Pos], part9_Index, AnimXoffset+part9_X, AnimYoffset+part9_Y, part9_ScX, part9_ScY, part9_A, part9_Color, part9_Alpha ); //-head

draw_sprite_ext(sprPos[part10_Pos], part10_Index, AnimXoffset+part10_X, AnimYoffset+part10_Y, part10_ScX, part10_ScY, part10_A, part10_Color, part10_Alpha ); //-Right-foot
draw_sprite_ext(sprPos[part11_Pos], part11_Index, AnimXoffset+part11_X, AnimYoffset+part11_Y, part11_ScX, part11_ScY, part11_A, part11_Color, part11_Alpha ); //-Right-legDown
draw_sprite_ext(sprPos[part12_Pos], part12_Index, AnimXoffset+part12_X, AnimYoffset+part12_Y, part12_ScX, part12_ScY, part12_A, part12_Color, part12_Alpha ); //-Right-legUp

draw_sprite_ext(sprPos[part13_Pos], part13_Index, AnimXoffset+part13_X, AnimYoffset+part13_Y, part13_ScX, part13_ScY, part13_A, part13_Color, part13_Alpha ); //-Right-Hand
draw_sprite_ext(sprPos[part14_Pos], part14_Index, AnimXoffset+part14_X, AnimYoffset+part14_Y, part14_ScX, part14_ScY, part14_A, part14_Color, part14_Alpha ); //-Right-armDown
draw_sprite_ext(sprPos[part15_Pos], part15_Index, AnimXoffset+part15_X, AnimYoffset+part15_Y, part15_ScX, part15_ScY, part15_A, part15_Color, part15_Alpha ); //-Right-armUp   


surface_reset_target();



var sx = image_xscale;
var sy = image_yscale;

gpu_set_tex_filter(gpuOn);

/*
//--------//--shader-1-//---------------------------
shader_set(shd_outLine);
var texture = surface_get_texture(surfAnim);
var texelW    = 1 * texture_get_texel_width(texture);
var texelH    = 1 * texture_get_texel_height(texture);
shader_set_uniform_f(upixelW, texelW);
shader_set_uniform_f(upixelH, texelH);
//------------------------------------------------
*/

//--------//--shader-2-//---------------------------
surface_set_target(surfAnim2);
draw_clear_alpha(c_black, 1);

shader_set(shd_outLine2);
var s_tex = shader_get_sampler_index(shd_outLine2, "texture_Pixel");
gpu_set_texfilter_ext(s_tex, true);

var texture = surface_get_texture(surfAnim);
var texture_with    = texture_get_texel_width(texture);
var texture_height    = texture_get_texel_height(texture);

shader_set_uniform_f(uniform_handle, texture_with, texture_height);


draw_surface_ext(surfAnim, x-sx*AnimXoffset, y-sy*AnimYoffset, image_xscale, image_yscale, image_angle, c_white, 1 );

shader_reset();

surface_reset_target();


draw_surface_ext(surfAnim2, x-sx*AnimXoffset, y-sy*AnimYoffset, image_xscale, image_yscale, image_angle, c_white, 1 );

}


draw_sprite_ext(plr_walk,image_index,x-50,y+2, image_xscale, image_yscale, image_angle,c_white, 1);
 
D

Deleted member 13992

Guest
How exactly do you draw the sprite to "surfAnim"? You can perhaps integrate the outline shader there instead. I'm sure it can be optimized further, but I cant say for sure how because I don't have a big picture of how your game is set up. But I wouldnt be surprised that where you draw the character sprite to surfAnim, you can pass it though the outline shader there instead.

Extra surfaces have a cost, of course. If they're small, used sparingly and aren't being recreated every frame, it's minimal. But not free (nothing is). You can use the debugger to know how many milliseconds (or hundredths of a millisecond) are spent on your object's draw call before, and after the changes, if you like. I do that pretty often.

I have dozens of medium-sized (480x270 or more) surfaces being copied, drawn to, with a few shaders, every frame, and I'm still running at 1600fps on average on desktop (and 200+ fps on a non-gamer laptop with slow integrated graphics). It's prudent to use surfaces sparingly and optimally, but you don't have to be too afraid of using them either. You should still be able to handle several without the engine making too big a dent in performance.

Mobile might be another story, though.
 
Last edited by a moderator:

jonjons

Member
I don't have a big picture of how your game is set up
iam using this app Skeleton Animation, setting the shader here would be a big mess, i would have to add texture_get_texel... for all body parts.

but for has much has i try i cant seem to get along of how the debugger works, for me it never does anything... it shows the mem and fps, but clicking on an object doesnt do anything... yes i double click bu whatever...

debug.png
 

jonjons

Member
How exactly do you draw the sprite to "surfAnim"?
its on the 7º comment

I have dozens of medium-sized (480x270 or more) surfaces being copied, drawn to, with a few shaders, every frame, and I'm still running at 1600fps on average on desktop (and 200+ fps on a non-gamer laptop with slow integrated graphics). It's prudent to use surfaces sparingly and optimally, but you don't have to be too afraid of using them either. You should still be able to handle several without the engine making too big a dent in performance.
but how can you measure draw calls ?
for example if you had 10 sprites in the draw event being drawn with draw_sprite( image01....., )... this would count 10 draw calls, every step.
you draw these 10 sprites on to a surface...then draw the surface... how many draw calls does it make ?
It should only make 1 draw call, only the surface shows up on screen.
Or does it count has 11 draw calls ( 10 sprites + 1 surface ) in every step ?
 
Top