Vertex shader question

Hi everyone,
I've been learning a bit about vertex shaders.
I'm still finding it a bit hard to understand,
but I'm beginning to understand how you'd do things
like split up/shake/swivel an object's sprite using verteces.

However, what I don't yet "see" is how I can pass an object without a sprite,
but one that uses a draw_sprite function in its draw event, through a shader as well.

Basically, I have an object that can "become" multiple sprites, by conditions
in its draw event. I only want one of those potential sprites to be able to
use the properties of the vertex shader.

Basically, if a certain condition is met, the object will draw a certain sprite,
and if a collision with the player is found, only with that sprite must the object
appear to "shake" a bit. I'm not gonna use the build in coordinates, rotation, scales,
of things like draw_sprite_general. I really want that smooth "bending shaky"
effect.

So the question is: what are some of the basics I need to understand
in order to have an object with no sprite attached, that draws a sprite in its draw event,
and then have that sprite do some "vertex shader" magic?
The conditions before the shader can be accessed is something i can probably figure out myself.
I' like to understand the shader-aspect part of it, and how to properly place the code
for the shader in the object's draw event, which i often mess up to be honest.
 
I'm not quite sure what your question is.

If you want to draw something using a shader, you set the shader, then draw the stuff, then reset the shader or set a different shader.

If you want to draw a whole bunch of stuff at once, and you only want some of it to be affected by the shader, then there are two options. The first option is to draw the stuff that will be affected seperately from the stuff that will not be. The second option is to get the vertex shader to behave differently depending on some attribute of the thing being drawn. An example of how you could do the second thing is by encoding a flag into the colour or alpha argument of draw_sprite_ext.
 

Binsk

Member
Your explanation is very vague and hard to understand. I have no idea what you mean by "become" multiple sprites. Can it render multiple sprites at once? Does it change from one sprite to the next? I'm assuming the later.

One thing you need to realize, everything that is drawn on screen passes through a vertex and fragment shader. If you aren't specifically writing your own then it will use a "default" shader, so to speak. A shader is simply a piece of software that runs on your GPU instead of your CPU. Its job is to take all the details and game logic for a particular image, model, or other visual element and convert it into a grid of values (aka colors) to change the pixels on your screen to. This both involves determining WHERE on the screen to draw things and what COLOR to make them.

Now the "magic" that you speak of is essentially modifying the "where" part by adding some of your own logic to the vertex shader. What is a vertex shader, though? What data is it dealing with? Everything you draw, including your sprites, are rendered out of triangles. Your sprite is essentially two triangles put together in the shape of a rectangle where then the image for your sprite is stretched across them like a painting. If you morph the triangles you then morph the painting. Every triangle is made out of three points known as "vertices" or vertex, singular. So your sprite will have 6 vertices defining its shape. Can you guess what the vertex shader's job is? It takes the location of every vertex for your sprite and converts it from where it is in your game to where it needs to be on your screen. Your vertex shader code will be run once for every vertex in the sprite to determine where it needs to be. This also means that you are limited to trying to get your affect out of just 6 points, that's not a whole lot. If you want more precision you'll have to draw your sprite out of more triangles and thus give you more vertices to work with.

That said, you also must remember that there is a fragment shader as well. This shader is responsible for determining the color of each pixel. It will be run for every visible pixel of your sprite. While you can't change location with a fragment shader you can change color to get some effect going here as well; its worth noting.

So, when drawing your sprite you are just drawing two triangles. If you don't specify a shader then GameMaker will use a default "normal" shader. If you want to write your own then you need to specify to use it with shader_set before drawing the sprite and then reset it back to the default with shader_reset when finished so that nothing else uses your shader.

Hopefully this helps you better understand how the vertex shader works. If it does then what you'd need to do next is learn how to pass data to it properly, at least whatever data you may need to make the wave, perhaps how to render a sprite with more triangles (look into vertex buffers) so you can have enough vertices to morph to actually MAKE the image wave, and perhaps a way to determine which vertex you are on in the shader (whether that be the actual vertex ID or even just a difference in position) so you know how much to wave it in relation to the others.

It should be an interesting challenge but I'm sure you can figure it out.

EDIT: Before you try writing your own shader take a look at the default code when you create a new shader. Make sure you understand what EVERY single piece does. If you don't understand a single element you need to look up what its for or ask us here. Once you understand exactly how the default one is working can you then start writing your own.

Shaders are all about math, most of it involving matrices. It gets confusing really fast if you are missing a piece of information.
 
Your explanation is very vague and hard to understand. I have no idea what you mean by "become" multiple sprites. Can it render multiple sprites at once? Does it change from one sprite to the next? I'm assuming the later.

One thing you need to realize, everything that is drawn on screen passes through a vertex and fragment shader. If you aren't specifically writing your own then it will use a "default" shader, so to speak. A shader is simply a piece of software that runs on your GPU instead of your CPU. Its job is to take all the details and game logic for a particular image, model, or other visual element and convert it into a grid of values (aka colors) to change the pixels on your screen to. This both involves determining WHERE on the screen to draw things and what COLOR to make them.

Now the "magic" that you speak of is essentially modifying the "where" part by adding some of your own logic to the vertex shader. What is a vertex shader, though? What data is it dealing with? Everything you draw, including your sprites, are rendered out of triangles. Your sprite is essentially two triangles put together in the shape of a rectangle where then the image for your sprite is stretched across them like a painting. If you morph the triangles you then morph the painting. Every triangle is made out of three points known as "vertices" or vertex, singular. So your sprite will have 6 vertices defining its shape. Can you guess what the vertex shader's job is? It takes the location of every vertex for your sprite and converts it from where it is in your game to where it needs to be on your screen. Your vertex shader code will be run once for every vertex in the sprite. This also means that you are limited to trying to get your affect out of just 6 points, that's not a whole lot. If you want more precision you'll have to draw your sprite out of more triangles and thus give you more vertices to work with.

That said, you also must remember that there is a fragment shader as well. This shader is responsible for determining the color of each pixel. It will be run for every visible pixel of your sprite. While you can't change location with a fragment shader you can change color to get some effect going here as well; its worth noting.

So, when drawing your sprite you are just drawing two triangles. If you don't specify a shader then GameMaker will use a default "normal" shader. If you want to write your own then you need to specify to use it with shader_set before drawing the sprite and then reset it back to the default with shader_reset when finished so that nothing else uses your shader.

Hopefully this helps you better understand how the vertex shader works. If it does then what you'd need to do next is learn how to pass data to it properly, at least whatever data you may need to make the wave, perhaps how to render a sprite with more triangles (look into vertex buffers) so you can have enough vertices to morph to actually MAKE the image wave, and perhaps a way to determine which vertex you are on in the shader (whether that be the actual vertex ID or even just a difference in position) so you know how much to wave it in relation to the others.

It should be an interesting challenge but I'm sure you can figure it out.
Sorry i should've been more clear. Yes it changes from 1 sprite to the other, but also draw multiple ones (shadow underneath + object sprite). Shaders are early beginnings for me, so forming a solid question might be a bit tricky at this point :p However, your response pretty much answered my question, or at least, what I meant by it. I i understand correctly, I don't need to think of extra things in order to do what i want.
Just set the shader, call the draw function in the draw event, then basically turn the shader off again?
 

Binsk

Member
Sorry i should've been more clear. Yes it changes from 1 sprite to the other, but also draw multiple ones (shadow underneath + object sprite). Shaders are early beginnings for me, so forming a solid question might be a bit tricky at this point :p However, your response pretty much answered my question, or at least, what I meant by it. I i understand correctly, I don't need to think of extra things in order to do what i want.
Just set the shader, call the draw function in the draw event, then basically turn the shader off again?
Yes, if your shader is already written then that is all you have to do. Setting the shader is essentially just telling the GPU to use a different piece of "software" to calculate where to draw things. It will use that setting until you change it to something else with another shader_set or by resetting it to GameMaker's default.
 
If you can, you'll want to draw everything that will use your shader all at once. Because every time you turn the shader on and off, it will cause performance to degrade further.
 
Thanks for the replies!
Maybe one more question, this time I'll try to be a little clearer.
How easy would it be for the "turn shader on and off" part to be conditional? Say i have an object's draw_sprite code, which should just be that and nothing else, EXCEPT when the player collides with it. Upon collision a shader should trigger a tranformation of that draw_sprite code.

is it as easy as
if (condition) {set shader}

draw_sprite

if (same condition) {turn shader off}
 
I think this would be simpler:

if (condition) {
set_shader
draw_something
shader_reset
} else {
draw_something
}
ah nice, thanks :) I think all of these comments gave me the confidence to start learning about vertex shaders now. It seemed a little bit intimidating at first, but you made is sound accessible to me ^_^
 
We've not really yet gone into any of the details of how vertex shaders work or what you can do with them.
I just really needed a starting point in order to understand the underlying logic a bit more, just copying off off tutorial videos without properly understanding what it meant was no way to go. It's probably quite a lot to learn, but i'm taking up the challenge :)
 
Top