GameMaker: Studio

GameMaker: Studio

View Stats:
Detonatress Jun 30, 2019 @ 4:26pm
Some help, please? Trying to use an outline shader
So I get this error:
___________________________________________ ############################################################################################ ERROR in action number 1 of Create Event for object obj_Critter: Trying to get texture from non-existing sprite. at h (line 5) - texelW = texture_get_texel_width(sprite_get_texture(sprite_index,0)) ############################################################################################ -------------------------------------------------------------------------------------------- stack frame is gml_Object_obj_Critter_CreateEvent_1 (line 5) called from - h (line -1) - {


The problem here is that I have a scan mechanic in the game that works like this:
* The player points the crosshairs and presses E
* This creates a scan screen that receives the info of what creature the player just scanned and passes this info as a sprite value to the object (obj_Critter) that is created once the scanner has fully unfolded its window.
* This object does not have a sprite by default, so it relies on the scanner object to insert that information.
* This obj_Critter or at least its sprite must follow the view just like the scanner does.
* This sprite of obj_Critter must gain a lime green outline.
image example of what I have so far without outline: https://imgur.com/yCczqcX.jpg


Codes used (based on Shaun's most recent video about it):
Shader (vertex)
// // Simple passthrough vertex shader // attribute vec3 in_Position; attribute vec4 in_Colour; attribute vec2 in_TextureCoord; varying vec2 v_vTexcoord; varying vec4 v_vColour; void main() { vec4 pos= vec4( in_Position, 1.0); gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * pos; v_vColour = in_Colour; v_vTexcoord = in_TextureCoord; }

Shader (fragment)
// // Simple passthrough fragment shader // varying vec2 v_vTexcoord; varying vec4 v_vColour; uniform float pixelH; uniform float pixelW; void main() { vec2 offsetx; offsetx.x = pixelW; vec2 offsety; offsetx.y = pixelH; float alpha = texture2D (gm_BaseTexture, v_vTexcoord) .a; alpha += ceil(texture2D(gm_BaseTexture, v_vTexcoord + offsetx).a); alpha += ceil(texture2D(gm_BaseTexture, v_vTexcoord - offsetx).a); alpha += ceil(texture2D(gm_BaseTexture, v_vTexcoord + offsety).a); alpha += ceil(texture2D(gm_BaseTexture, v_vTexcoord - offsety).a); gl_FragColor = v_vColour * texture2D (gm_BaseTexture, v_vTexcoord); gl_FragColor.a = alpha; }

Critter object Create:
///Sprite info image_speed = 0.3 upixelH = shader_get_uniform(shd_OutlineShader,"pixelH") upixelW = shader_get_uniform(shd_OutlineShader,"pixelW") texelW = texture_get_texel_width(sprite_get_texture(sprite_index,0)) texelW = texture_get_texel_height(sprite_get_texture(sprite_index,0))

Critter object Draw:
xx = 1098 yy = 250 shader_set(shd_OutlineShader); shader_set_uniform_f(upixelW,texelW); shader_set_uniform_f(upixelH,texelH); draw_self(); draw_sprite(sprite_index,image_index,view_xview[0]+xx,view_yview[0]+yy) shader_reset();


Questions:
How do I tell the shader what sprite to use for each scanned creature?
How do I tell it exactly where to put the outline?
How do I tell it what color to make the outline?
< >
Showing 1-15 of 17 comments
The Winter Bud Jun 30, 2019 @ 8:01pm 
I would say the error is because you don't have an actual sprite assigned to the critter before you call for it's texture to be assigned. Assign the sprite_index it's proper sprite before assigning it's texture to "h"
Detonatress Jul 1, 2019 @ 4:16am 
Originally posted by The Winter Bud:
I would say the error is because you don't have an actual sprite assigned to the critter before you call for it's texture to be assigned. Assign the sprite_index it's proper sprite before assigning it's texture to "h"
That's the problem. I cannot assign it statically because I've left it to the scanner to assign the sprite_index, since this critter object is supposed to gain a sprite based on what creature is scanned. And it works for normal Draw event as seen here: https://imgur.com/yCczqcX.jpg So a sprite is assigned at some point.

But how do I call the shader initiation at the right time? Do I use an alarm that counts down from a high enough number until it acquires the sprite post-creation of obj_Critter?
The Winter Bud Jul 1, 2019 @ 9:08am 
you can always use the 'end step' event which happens just before the draw event. You can check to see if the critter has a sprite first before setting the textures.
//create event image_speed = 0.3 upixelH = shader_get_uniform(shd_OutlineShader,"pixelH") upixelW = shader_get_uniform(shd_OutlineShader,"pixelW") texelW =0; texelH = 0;
//end step if(sprite_index){ texelW = texture_get_texel_width(sprite_get_texture(sprite_index,0)) texelH = texture_get_texel_height(sprite_get_texture(sprite_index,0)) }

NOTE: in your original post you have the same variable for the width and height of the texel
image_speed = 0.3 upixelH = shader_get_uniform(shd_OutlineShader,"pixelH") upixelW = shader_get_uniform(shd_OutlineShader,"pixelW") texelW = texture_get_texel_width(sprite_get_texture(sprite_index,0)) texelW = texture_get_texel_height(sprite_get_texture(sprite_index,0)) //<--HERE
Last edited by The Winter Bud; Jul 1, 2019 @ 9:11am
Detonatress Jul 1, 2019 @ 10:40am 
Originally posted by The Winter Bud:
you can always use the 'end step' event which happens just before the draw event. You can check to see if the critter has a sprite first before setting the textures.
//create event image_speed = 0.3 upixelH = shader_get_uniform(shd_OutlineShader,"pixelH") upixelW = shader_get_uniform(shd_OutlineShader,"pixelW") texelW =0; texelH = 0;
//end step if(sprite_index){ texelW = texture_get_texel_width(sprite_get_texture(sprite_index,0)) texelH = texture_get_texel_height(sprite_get_texture(sprite_index,0)) }

NOTE: in your original post you have the same variable for the width and height of the texel
image_speed = 0.3 upixelH = shader_get_uniform(shd_OutlineShader,"pixelH") upixelW = shader_get_uniform(shd_OutlineShader,"pixelW") texelW = texture_get_texel_width(sprite_get_texture(sprite_index,0)) texelW = texture_get_texel_height(sprite_get_texture(sprite_index,0)) //<--HERE
Thanks, it worked but ... I do not know how to direct its position so that it replaces the old Draw event sprite and sticks to the scanner. It currently spawns the outlined sprite of the goat up there (and it does not move with the camera view). https://imgur.com/YxoR997.jpg

I'm assuming I have to somehow declare the shader a variable to replace the sprite_index in the view_xview, view_yview line of this Draw event?
xx = 1098 yy = 250 shader_set(shd_OutlineShader); shader_set_uniform_f(upixelW,texelW); shader_set_uniform_f(upixelH,texelH); draw_self(); draw_sprite(sprite_index,image_index,view_xview[0]+xx,view_yview[0]+yy) shader_reset();
Seems I cannot replace the sprite_index with shd_OutlineShader because this happens: https://imgur.com/rNSSt9v.jpg (uses fern's sprite for some odd reason)

Also, can the outline color be changed? How do I control its RGB values?

Thank you for spotting the cloned variable, I forgot to change it.
Last edited by Detonatress; Jul 1, 2019 @ 10:45am
The Winter Bud Jul 1, 2019 @ 4:23pm 
Originally posted by Detonatress:
Also, can the outline color be changed? How do I control its RGB values?
You can use draw_sprite_ext( sprite, subimg, x, y, xscale, yscale, rot, colour, alpha )[docs.yoyogames.com]
sprite - The index of the sprite to draw.
subimg - The subimg (frame) of the sprite to draw (image_index or -1 correlate to the current frame of animation in the object).
x - The x coordinate of where to draw the sprite.
y - The y coordinate of where to draw the sprite.
xscale - The horizontal scaling of the sprite, as a multiplier: 1 = normal scaling, 0.5 is half etc...
yscale - The vertical scaling of the sprite as a multiplier: 1 = normal scaling, 0.5 is half etc...
rot The rotation of the sprite. 0=right way up, 90=rotated 90 degrees counter-clockwise etc...
colour - The colour with which to blend the sprite. c_white is to display it normally.
alpha - The alpha of the sprite (from 0 to 1 where 0 is transparent and 1 opaque).
Last edited by The Winter Bud; Jul 1, 2019 @ 4:24pm
Detonatress Jul 1, 2019 @ 5:40pm 
Originally posted by The Winter Bud:
Originally posted by Detonatress:
Also, can the outline color be changed? How do I control its RGB values?
You can use draw_sprite_ext( sprite, subimg, x, y, xscale, yscale, rot, colour, alpha )[docs.yoyogames.com]
sprite - The index of the sprite to draw.
subimg - The subimg (frame) of the sprite to draw (image_index or -1 correlate to the current frame of animation in the object).
x - The x coordinate of where to draw the sprite.
y - The y coordinate of where to draw the sprite.
xscale - The horizontal scaling of the sprite, as a multiplier: 1 = normal scaling, 0.5 is half etc...
yscale - The vertical scaling of the sprite as a multiplier: 1 = normal scaling, 0.5 is half etc...
rot The rotation of the sprite. 0=right way up, 90=rotated 90 degrees counter-clockwise etc...
colour - The colour with which to blend the sprite. c_white is to display it normally.
alpha - The alpha of the sprite (from 0 to 1 where 0 is transparent and 1 opaque).
I meant just the outline RGB, to turn it into a bright green instead of standard black. All it does is replace the color of the entire sprite.
https://imgur.com/s4MyAKK.jpg

And if I replace sprite_index with shd_OutlineShader, I get the fern only. I don't understand why the fern when sprite_index is clearly the goat.
https://imgur.com/cF7ktUq.jpg

There might be some way to pull something by combining a normal sprite + the shader behind it, I just don't know how to:
1. color the shape of the goat a flat green (no textures, just the color in the shape of the goat)
2. tell the shader which sprite it has to show, as it keeps giving me a sprite unrelated to the actual sprite_index.

Or this https://zimventures.com/2017/10/03/shader-for-dynamic-sprite-outlines-in-game-maker-studio-2/
I just don't understand how to use it for my situation though, as it would still give the wrong sprite.
Last edited by Detonatress; Jul 1, 2019 @ 5:48pm
The Winter Bud Jul 2, 2019 @ 2:58pm 
I've got to admit, I'm not as good at shaders as I'd like to be. I'l have to research this a little to see if I can be of any more help.
The Winter Bud Jul 2, 2019 @ 3:07pm 
when you change the sprite_index to shd_OutlineShader, remember that the name of the resource is just for the user. It's actually an index relating to which shader, or other resource you use. Take sprites for example. When you create a sprite and give it a name, it also has a number tied to it. It's index..aka what number of sprite it is. All resources have this mechanism tied to them. From fonts, to shaders, to rooms, etc.. shd_OutlineShader probably has the same index in the shaders as the fern does in the sprites. Gamemaker doesn't know when you pass it a shader index that it's actually a shader index. Because it's an integer. Gamemaker wants the user to program responsibly and not use other resources when assigning values

you can see the value of each resources index by drawing it to the screen or having it post to the output with show_debug_message()
// text on screen draw_text(someX,someY, "shader index of outline shader: "+string(shd_OutlineShader)); // in output window show_debug_message("sprite index of fern: "+string(sprFern));

So let's say the the shader index for the outline shader == 1
and teh sprite index for the fern == 1

sprite_index=sprFern; sprite_index=shd_OutlineShader; // both of these are saying the same thing sprite_index=1;
Last edited by The Winter Bud; Jul 2, 2019 @ 3:12pm
Detonatress Jul 2, 2019 @ 5:45pm 
Originally posted by The Winter Bud:
when you change the sprite_index to shd_OutlineShader, remember that the name of the resource is just for the user. It's actually an index relating to which shader, or other resource you use. Take sprites for example. When you create a sprite and give it a name, it also has a number tied to it. It's index..aka what number of sprite it is. All resources have this mechanism tied to them. From fonts, to shaders, to rooms, etc.. shd_OutlineShader probably has the same index in the shaders as the fern does in the sprites. Gamemaker doesn't know when you pass it a shader index that it's actually a shader index. Because it's an integer. Gamemaker wants the user to program responsibly and not use other resources when assigning values

you can see the value of each resources index by drawing it to the screen or having it post to the output with show_debug_message()
// text on screen draw_text(someX,someY, "shader index of outline shader: "+string(shd_OutlineShader)); // in output window show_debug_message("sprite index of fern: "+string(sprFern));

So let's say the the shader index for the outline shader == 1
and teh sprite index for the fern == 1

sprite_index=sprFern; sprite_index=shd_OutlineShader; // both of these are saying the same thing sprite_index=1;
I didn't expect shader to be counted as a resource number instead of a variable. Is there some other way instead of using shaders to somehow make the goat an opaque mask sprite and make it all lime green, no texture? I mean like this:
https://imgur.com/9ZcvoNM.jpg

Using 4 sprites rendered somehow as a green alpha mask, offsetting each of them + the default sprite above them, so they'd move together and produce the effect I want. But how do I tell Gamemaker to create a colored alpha mask by itself?
The Winter Bud Jul 2, 2019 @ 6:55pm 
have you checked out this article[forum.yoyogames.com]. It is dealing with the similar issue that you are.
The Winter Bud Jul 3, 2019 @ 12:26am 
<snip> . . alpha += ceil(texture2D(gm_BaseTexture, v_vTexcoord + offsety).a); alpha += ceil(texture2D(gm_BaseTexture, v_vTexcoord - offsety).a); gl_FragColor = v_vColour * texture2D (gm_BaseTexture, v_vTexcoord); // <-- this ine gl_FragColor.a = alpha; }
I believe if you can get the black outline to work you can change the color by altering the line I marked above. That is where the color of the pixel is blended with

v_vColour is a 4D vector which contains the blend color data for the sprite. It’s the color set through image_blend or draw_sprite_ext()‘s “colour” argument.

gl_FragColor is a 4D vector that is the final output of the shader for a pixel. It has four values: (R, G, B and A), all in the range of 0-1. They stand for red, green, blue and alpha, respectively.
Last edited by The Winter Bud; Jul 3, 2019 @ 9:20pm
The Winter Bud Jul 3, 2019 @ 12:36am 
To actually change the color of the outline I think you will have to set the RGB colors inside the fragment shader. Just as you set the alpha (gl_GragColor.a=alpha), you can change the R, G, and/or B values of the gl_GragColor
gl_FragColor.r = 1.0; // this would tint the pixel red
Detonatress Jul 3, 2019 @ 6:08am 
Originally posted by The Winter Bud:
To actually change the color of the outline I think you will have to set the RGB colors inside the fragment shader. Just as you set the alpha (gl_GragColor.a=alpha), you can change the R, G, and/or B values of the gl_GragColor
gl_FragColor.r = 1.0; // this would tint the pixel red
Thanks, that made it flat green, but now I'll have to figure out how to make the original texture sprite get rendered above it so it gains the green as outline. Also, there seems to be a cutoff in the nose area of the goat, as if it hit a barrier on the left.
https://imgur.com/MpZJaim.jpg
Maybe I could tell the scanner screen to display it while the obj_Critter creates the outline. (scratch that, it wouldn't show it on top since the screen is under the outline) Or is there some way to separate shader from actual sprite in a single object?

The draw_self() seems to create the original too but places it in the wrong area:
https://imgur.com/nuoeQig.jpg

EDIT: created 2 shaders and overlapped them
https://imgur.com/0W8j224.jpg
Last edited by Detonatress; Jul 3, 2019 @ 6:41am
Detonatress Jul 3, 2019 @ 6:46am 
Originally posted by The Winter Bud:
To actually change the color of the outline I think you will have to set the RGB colors inside the fragment shader. Just as you set the alpha (gl_GragColor.a=alpha), you can change the R, G, and/or B values of the gl_GragColor
gl_FragColor.r = 1.0; // this would tint the pixel red
Now all that's left is this weird slice on its nose, does it have anything to do with the bounding box or something?
https://imgur.com/uXbwn5k.jpg
The original sprite isn't limited in that area (other than its precise mask)
https://imgur.com/BLF0XXD.jpg
The Winter Bud Jul 3, 2019 @ 9:06pm 
In the article I listed it states that you need a 1 to 2 pixel zone outside the graphic to take up the border you are trying to make. If your sprite goes to the edge of the size of the sprite there's not enough room to draw the border. So to fix it, make the sprite size larger so as to give enough room to draw the border.

Originally posted by "odolwa":
Strawbry_Jam: I went back and made space around the sprite, like you suggested, and that has done the trick. Many thanks.

Just to summarize what I've got for the benefit of others:
1. The sprite has empty space around it in the Sprite Properties where it's drawn.
2. The 'Used for 3D (Must be a power of 2)' box is ticked.
.
.
.
<snip>


Thanks to everyone who contributed. I appreciate the help, whatever the outcome.
Last edited by The Winter Bud; Jul 3, 2019 @ 9:21pm
< >
Showing 1-15 of 17 comments
Per page: 1530 50