GameMaker Using Shaders for Sprites in 3D

atma505

Member
I'm looking into methods for having sprites "face" the camera when projecting in 3D.


In GMS1, I drew a wall using the sprite as its texture. I'm sure a similar effect could be achieved using vertices in GMS2. However, it seems that shaders have the capacity for manipulating the X, Y, and Z properties of sprites. If I could use this method, it would be infinitely easier to implement animation, etc.
Is it possible to simply rotate a sprite along the X axis using a shader so that it's facing the camera rather than lying flat on the ground?
 
The problem is you have to get the position of the sprite into the vertex shader somehow.

If you supply it as a uniform, you run into the problem that every time you change a shader uniform, it is going to break the curren vertex batch. Do that enough times per frame, and performance will degrade.

So is there another way to do this in gamemaker?

a) You could try writing your own vertex buffer, though in my experience writing to vertex buffers is rather slow in gml, so doing it every frame could be a problem.

b) You could try to override the image_blend and image_alpha attributes to carry position information. Unfortunately, gml will automatically clamp those values between 0 and 1. I don't know why, since it does not appear necessary. You should be able to set each channel, rgba, as any float, but you can't.

c) Another thing you can do is use some kind of object pooling. Basically you pass an array of positions into the shader, and then draw some stuff, and that stuff needs to have an attribute that can be used to index the array, in order to pull one of the positions out of it.

I would try a and c, and find out which one of those options is actually faster. However, if you aren't drawing a ton of sprites (amount will depend on your machine, but low hundreds or there abouts), you can probably actually get away with setting a uniform individually for each one.
 

atma505

Member
What (I think) you're asking for is called billboarding, and is very possible to do with a shader!
I recommend checking out this tutorial, it explains well enough how to achieve this in GLSL es:
https://www.geeks3d.com/20140807/billboarding-vertex-shader-glsl/
In short, you set the rotation part of the world-view matrix to identity, forcing the sprite to face the camera.
This is definitely the right idea. GMS2 doesn't seem to like the vertex shader provided on the page, though.
Compile Errors
Vertex Shader: shd_2point5d at line 2 : 'version'
Vertex Shader: shd_2point5d at line 3 : ''​
I'm guessing it needs some tweaking to be Gamemaker-ready? I know nothing at all about GLSL, unfortunately.

The problem is you have to get the position of the sprite into the vertex shader somehow.

If you supply it as a uniform, you run into the problem that every time you change a shader uniform, it is going to break the current vertex batch. Do that enough times per frame, and performance will degrade.

So is there another way to do this in gamemaker?

a) You could try writing your own vertex buffer, though in my experience writing to vertex buffers is rather slow in gml, so doing it every frame could be a problem.

b) You could try to override the image_blend and image_alpha attributes to carry position information. Unfortunately, gml will automatically clamp those values between 0 and 1. I don't know why, since it does not appear necessary. You should be able to set each channel, rgba, as any float, but you can't.

c) Another thing you can do is use some kind of object pooling. Basically you pass an array of positions into the shader, and then draw some stuff, and that stuff needs to have an attribute that can be used to index the array, in order to pull one of the positions out of it.

I would try a and c, and find out which one of those options is actually faster. However, if you aren't drawing a ton of sprites (amount will depend on your machine, but low hundreds or there abouts), you can probably actually get away with setting a uniform individually for each one.
These are definitely some good options to explore! Though at the moment I wouldn't have any idea what to do with the position information once it was in the vertex shader :p I don't know a lick of GLSL -- and barely anything about Matrix functions in GML, which I feel like is where I should start.
 
Last edited by a moderator:
I can throw together a demo in GMS1.4 that would show a number of different ways of doing this. It should all be the same in GMS2 except for the d3d functions, which when you import should be replaced with the corresponding GMS2 functions.
 

atma505

Member
I can throw together a demo in GMS1.4 that would show a number of different ways of doing this. It should all be the same in GMS2 except for the d3d functions, which when you import should be replaced with the corresponding GMS2 functions.
If you've got the time :D
In GMS1 I used d3d_draw_wall to get the billboard, assigning the sprite I wanted as its texture. I'm assuming drawing vertices in GMS2 would be the equivalent. I don't know a thing about interacting with a Matrix though, or getting a vertex to face the camera (or even how to move one at all).
 
Top