• 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!

How accurate are the trigonometric functions?*

Nux

GameMaker Staff
GameMaker Dev.
*More specifically Sine and Cosine.

I'm wondering whether it's worth me implementing a custom, less accurate, version of these two functions using corresponding Turner series; as seen here the Tuner series approximation is accurate enough for what I wish to use it for, this being graphics, where the inaccuracy is negligible due to human perception and my game being fairly low-res.

I'm pretty much just wondering if using this series is a faster alternative to sin(x) and cos(x).

Sorry if this is a repeat thread.
 

GMWolf

aka fel666
*More specifically Sine and Cosine.

I'm wondering whether it's worth me implementing a custom, less accurate, version of these two functions using corresponding Turner series; as seen here the Tuner series approximation is accurate enough for what I wish to use it for, this being graphics, where the inaccuracy is negligible due to human perception and my game being fairly low-res.

I'm pretty much just wondering if using this series is a faster alternative to sin(x) and cos(x).

Sorry if this is a repeat thread.
The trigonometric functions should be fast enough for pretty much any use.
Rather than implement your own (which will probs end up being slower), find ways to call them less often instead.
But to get any form of performance hit, you must really be calling it millions of time every step!
Are you already experiencing performance issues? If not, you worry too much.
 

FrostyCat

Redemption Seeker
It's probably not worth your time. On native platforms, sin() and cos() are hooked into hardware-level CPU operations (e.g. FSIN and FCOS on x86/x64), finishing the job in one stroke instead of the many that your series expansion would entail.

A rule of thumb for people who are after performance is that hardware beats software 99% of the time.
 

Nux

GameMaker Staff
GameMaker Dev.
Are you already experiencing performance issues? If not, you worry too much.
Not right now, but I've got a lot of special effects prototypes in the works that use sinusoidal movement, so I was afraid having many of those in a single game would cause major lag. For example, I have created a drawing script that uses primitives to smoothly bend a blade of grass as the player walks through it. This includes a large amount of trig functions for calculating the x and y components of a direction vector, as well as the normal positions either side of this path repetitively until the quality I desire has been reached (usually about 5 or 10 iterations). But you're probably right with me worrying too much.

@FrostyCat Thanks, that makes more sense; I was under the impression that trigonometric functions were calculated in a similar way, and that I could cut some corners.
 

chamaeleon

Member
If you're willing to cut corners, you could investigate storing sin/cos values in an array and perform lookups on the closest entry (possibly coupled with interpolation). No idea what size array would give you sufficiently small granularity, or whether it would in fact be faster than the built-in functions.. Just a thought experiment. :)
 

GMWolf

aka fel666
For example, I have created a drawing script that uses primitives to smoothly bend a blade of grass as the player walks through it.
This sort of effect is best done on the GPU.
Write a shader or something.
 

Nux

GameMaker Staff
GameMaker Dev.
@chamaeleon I had thought about using that approach, but like you I have no idea whether it would be beneficial.

@Fel666 I would write a shader if I had more experience; currently I only know the basics such as outlines, colour swaps, distortion, and basic texture stuff. Do you know if there are any tutorials that would help create an effect similar to this specifically? Most I find usually just overlay a texture, add dithering, or add chromatic aberration.
 
@chamaeleon I had thought about using that approach, but like you I have no idea whether it would be beneficial.

@Fel666 I would write a shader if I had more experience; currently I only know the basics such as outlines, colour swaps, distortion, and basic texture stuff. Do you know if there are any tutorials that would help create an effect similar to this specifically? Most I find usually just overlay a texture, add dithering, or add chromatic aberration.
looking at that video, it is hard to tell because the camera is in motion, but it looks like the grass blades are just rotating around their origin. In which case you don't even need a shader to do that.
 

Nux

GameMaker Staff
GameMaker Dev.
@flyingsaucerinvasion They're not gamemaker paths; what is happening is I divide the height into a supplied number of edges, then at each division, I increment the angle it is offset, and use a primitive triangle strip texture to bend the sprite.
 

Nux

GameMaker Staff
GameMaker Dev.
I'd prefer to have dynamic animations than pre-rendered ones, especially for something such as grass where I may add wind which blows on the grass. If it turns out they're way too expensive, then I'll add an option to disable them.
 
I wouldn't say they are way too expensive, but I would question whether the effect is noticable enough to warrent a complicated solution. An example of a simpler, yet less precise solution would be, you could have a wavey sprite animation, and have it go slowly in the wind, but have it go more quickly when the player walks through the grass. You could even set the direction of the animation so that it moves according to which direction the player is moving.
 

GMWolf

aka fel666
that seems a little expensive for an effect that is so subtle. Have you thoguht about prerendering the animation?
That's why you would do that sort o f effect with a shader, at near 0 cost! (Well, much lower cost than CPU, and perhaps even pre rendered u under some circumstances)
 
That's why you would do that sort o f effect with a shader, at near 0 cost! (Well, much lower cost than CPU, and perhaps even pre rendered u under some circumstances)
the problem would be getting the current state of the grass into the shader (the player can interact with the grass). Which means most likely breaking the vertex batch.
 

GMWolf

aka fel666
the problem would be getting the current state of the grass into the shader (the player can interact with the grass). Which means most likely breaking the vertex batch.
Setting the shader will break the vertex batch anyways. But if you draw all your grass at the same time it should be ok.
And a simple attribute shold be enough to pass the player position.
 

sylvain_l

Member
but I would question whether the effect is noticable enough to warrent a complicated solution.
it "feels" more than it's clearly seen. And it feels really good. (as the water effect)
having the scene reacting to the presence of the player make the scene much more alive.

but I agree, that there is perhaps too much put into that effect compared to the player sprite.
@Nux to be honest the grass feels to good compared to the skirt of the player^^'
I don't think it's a real problem, just that I overlooked the small amazing grass anims you provided. Not sure I would have notice the thing if I would have been playing the game/without the 2nd anim. But the grass is amazing, more dynamic, while the skirt feels more "mechanic" (looks to act like a sprite anim)
 

jo-thijs

Member
@Nux, as for optimizing trigonometric functions, that won't do you any good.
As FrostyCat already mentioned, those operaions are often implemented as a single instruction, so that it is optimized at hardware level.
On top of that, I've heard somewhere that the CORDIC algorithm is often used to calculate trigonometric functions,
which is very though to beat performace wise and precision wise.
Using tailor series, you would get something way less precise and way slower.
Using interpolation between an array of precalculated results would waste a lot of memory,
would be less precise and would very likely still be slower, as you require memory accesses.

As for using shaders like Fel666 suggested, I first thought that would be the best solution, until I understood what exactly you are doing.
You select a number n >= 1 and divide the height of your sprite in n segments, leading to a division of your sprite in n rectangles.
You then perform an affine transformation on each rectangle and draw the result through primitives, causing 2(n+1) vertices to be drawn.
I don't think shaders will be able to help a lot with this.

Instead, I would suggest you don't focus on optimising drawing a single sprite, but optimisig when calculations need to be performed.
For example, you probably don't need to do all the trigonometry and primitive drawing for sprites outside the view,
so just make a quick check if the sprite could be in view (consider worst case rotation) and if not, then just skip everything.
Now you only need to be concerned with the amout of grass that can be on screen at once, which I guess won't be all that much.
 

Nux

GameMaker Staff
GameMaker Dev.
skirt feels more "mechanic"
I wanted to make the skirt use physics but I got lazy and drew it. 8^(
When I finish college I plan on re-making everything in a more robust way that would allow me to make the skirt and hair look more dynamic.

@jo-thijs If shaders can't help in the way I desire, then I'm sure that what you suggest with de-activating instances outside the view, and only calling the updates every 1/10th of a second would help a lot much like fel had suggested in his first post (calling them less often), because I'm not really keen on ditching the grass I've already made for a more static version (pre-drawn sprites, or rotating around the origin) because they definitely look cool when you're not viewing them at ~20 fps online.
 

jo-thijs

Member
I wanted to make the skirt use physics but I got lazy and drew it. 8^(
When I finish college I plan on re-making everything in a more robust way that would allow me to make the skirt and hair look more dynamic.

@jo-thijs If shaders can't help in the way I desire, then I'm sure that what you suggest with de-activating instances outside the view, and only calling the updates every 1/10th of a second would help a lot much like fel had suggested in his first post (calling them less often), because I'm not really keen on ditching the grass I've already made for a more static version (pre-drawn sprites, or rotating around the origin) because they definitely look cool when you're not viewing them at ~20 fps online.
I'm not sure if (de)activating the grass is a good idea.
I was talking about using an if statement that skips the draw event and possibly step event if the grass is guaranteed to be outside the view.
You could also work with setting the variable visible in the step event, based on whether you can quickly guarantee that the grass lies outside the view.

If you do want to work with (de)activation of instances, you should be careful not re(de)activate instances too often.
I would suggest you'd separate the room in rectangles which are about half as wide and high as the view.
You would then look at which rectangles intersect the view and when this changes, you would reactivate all the grass.
You would then deactivate every grass object if it lies in none of the rectangles colliding with the view.

So, you would have a controller object with:
Create event:
Code:
w = view_wview * 0.5;
h = view_hview * 0.5;

bl = 0; // border left
br = 0; // border right
bt = 0; // border top
bb = 0; // border bottom

event_user(0);
Other user 0 event:
Code:
var pbl = bl;
var pbr = br;
var pbt = bt;
var pbb = bb;

bl = ceil(view_xview / w) * w - 1;
br = floor((view_xview + view_wview) / w) * w + 1;
bt = ceil(view_yview / h) * h - 1;
bb = floor((view_yview + view_hview) / h) * h + 1;

if pbl != bl || pbr != br || pbt != bt || pbb != bb {
    instance_activate_object(obj_grass);
    with obj_grass {
        if max_left >= other.br
        || max_right < other.bl
        || max_top >= other.bb
        || max_bottom < other.bt {
            instance_deactivate_object(id);
        }
    }
}
Step event:
Code:
event_user(0);
And obj_grass would calculate max_left as its x - some constant margin in its create event and the same for the other max_* variables.

If you need to (de)activate nearly every object in your game, then it might be worth using instance_(de)activate_region instead of a with loop and instance_activate_object.
 

GMWolf

aka fel666
As for using shaders like Fel666 suggested, I first thought that would be the best solution, until I understood what exactly you are doing.
You select a number n >= 1 and divide the height of your sprite in n segments, leading to a division of your sprite in n rectangles.
You then perform an affine transformation on each rectangle and draw the result through primitives, causing 2(n+1) vertices to be drawn.
I don't think shaders will be able to help a lot with this.
they will totaly help with this.
you just build a vertex buffer of the different segments.
and you animate the segments in the vertex shader.
its easier than it sounds. Ill make a full tutorial on it in a couple days :)
 

TheouAegis

Member
If you aren't going to be using fractional angles or not going to have too many angles, you could just use a LUT. Of course you also sacrifice some precision unless you compile with algorithms instead of hard numbers, but in the end a LUT would probably be the fastest implementation.
 

GMWolf

aka fel666
If you aren't going to be using fractional angles or not going to have too many angles, you could just use a LUT. Of course you also sacrifice some precision unless you compile with algorithms instead of hard numbers, but in the end a LUT would probably be the fastest implementation.
PLEASE. sin and cos is plenty fast for this use. The problem is rebuilding the vertex buffers like that! its very slow!

dont optimize on individual functions like that. optimize on algorithms and bandwidth.
 

jo-thijs

Member
If you aren't going to be using fractional angles or not going to have too many angles, you could just use a LUT. Of course you also sacrifice some precision unless you compile with algorithms instead of hard numbers, but in the end a LUT would probably be the fastest implementation.
As I mentioned before, I think that would actually be slower.
To calculate a cosine, you need 1 hardware optimized instruction.
To make a lookup in a table, you first need to calculate the index, which might already cost an addition and a multiplication.
You would then need to conver it to a pointer, which would probably cost some float to int conversions, memory accesses, bitshifts, additions, and whatever type and boundary checks GameMaker might perform.
Finally, you would perform a memory accesses to find the final value.

they will totaly help with this.
you just build a vertex buffer of the different segments.
and you animate the segments in the vertex shader.
its easier than it sounds. Ill make a full tutorial on it in a couple days :)
PLEASE. sin and cos is plenty fast for this use. The problem is rebuilding the vertex buffers like that! its very slow!

dont optimize on individual functions like that. optimize on algorithms and bandwidth.
I think I get your point.
You're not trying to involve shaders to push CPU cycles to the GPU,
but you're trying to use vertex buffers to optimize the primitive drawing.

I've never worked with GameMaker's vertex buffers before, so I don't know how much speed gain you'd get from that.
I also don't know how much speed you would lose by setting the shader and resetting the the uniform variables every time.

I guess that's worth a try.
 

GMWolf

aka fel666
What you really want to optimize is how much data you push to the GPU.
When drawing sprite parts, you are pushing vertex data to the GPU (on top of recalculate VBOs)
By usijng a shader everything is already on the GPU. And doing a bit of vertex manipulation on thr vertex ahader is practically free. Most importantly you don't ruibuild vertex data, which is most probably your bottleneck.
 
Last edited:

Nux

GameMaker Staff
GameMaker Dev.
@jo-thijs Thanks for the input, I've never really thought of doing deactivation like that; I had previously implemented a deactivation system where instances are (de)activated every 2 or so seconds (so not very often). But that also means if the player traveled fast enough they could escape the map, so i might experiment with your idea.
 
@Fel666 I would write a shader if I had more experience; currently I only know the basics such as outlines, colour swaps, distortion, and basic texture stuff. Do you know if there are any tutorials that would help create an effect similar to this specifically? Most I find usually just overlay a texture, add dithering, or add chromatic aberration.
Just thought I would throw my 2-cents in here. I really like that effect in the video and the programmer in me loves that it would/could be dynamic on a per blade basis.

But, stepping back from that mentality - no end user would really notice if you did a few variations in sprite animations (3-5 variations flowing left, 3-5 flowing right, etc... and then randomly choose one variation based on direction needed). This would be massively less expensive computationally. Plus, I'd wager it will take you a lot less time to accomplish.

If you were working on a higher resolution game, or a 3D based game - I can see more of an argument for it. But, at that pixelated 8-16bit style graphics, the cool factor will be lost on 99.9% of the people playing.

I will be curious to see how it turns out though, either way - and good luck with whatever you choose!
 
Setting the shader will break the vertex batch anyways. But if you draw all your grass at the same time it should be ok.
And a simple attribute shold be enough to pass the player position.
I think the way the player interacts with the grass is a little more complicated than just the player's current position.

This makes me think that the method for drawing the grass when the player is interacting with it should just be totally seperate than the way it draws when it is simply blowing in the wind. That way you will only be drawing that one or two instances of grass using the more complex teqnique. Meaning, it doesn't matter really how expensive the effort is, because only one or two instances of grass will be using it at any one time.
 

TheouAegis

Member
As I mentioned before, I think that would actually be slower.
To calculate a cosine, you need 1 hardware optimized instruction.
To make a lookup in a table, you first need to calculate the index, which might already cost an addition and a multiplication.
You would then need to conver it to a pointer, which would probably cost some float to int conversions, memory accesses, bitshifts, additions, and whatever type and boundary checks GameMaker might perform.
Finally, you would perform a memory accesses to find the final value.

Seems you are right. It's negligible in the short run, but running running from angle=0;angle+=0.05;angle<360 showed that the LUT was on average 500microseconds slower. Glad I don't need to worry about sine LUTs on a PC. :D
 

GMWolf

aka fel666
Seems you are right. It's negligible in the short run, but running running from angle=0;angle+=0.05;angle<360 showed that the LUT was on average 500microseconds slower. Glad I don't need to worry about sine LUTs on a PC. :D
As a general rule, small optimizations like these are never worth it.
 
J

JealousOfCrows

Guest
For a good idea on how to implement this with shaders. http://xorshaders.weebly.com/tutorials/8-wind-shader

That should get you started. I am currently attempting this as well. With your own creativity you should be able to alter the code to move the grass specifically in a direction relative to where the player collided with it.
 

GMWolf

aka fel666
Here is my tutorial on swaying grass:
I did not get to show how you could get the effects when a player walks into it, as the tutorial was already plenty long.
But in short you simply pass your players position as a uniform, and work of that, though you will loose the spring action your grass has right now.
 

jo-thijs

Member
Here is my tutorial on swaying grass:
I did not get to show how you could get the effects when a player walks into it, as the tutorial was already plenty long.
But in short you simply pass your players position as a uniform, and work of that, though you will loose the spring action your grass has right now.
That does look like it would be more efficient.
The only thing that causes overhead is setting and resetting the shader
and passing information per blade of grass to the shader.

Passing the player position as a uniform alone will not be able to reproduce the effect Nux created.
As I've never worked with vertex buffers before, how would you best pass along per vertex information that changes through time?

Also, I think managing which grass has to be drawn and which grass can skip the draw event is still an optimization in large rooms with lots of grass,
even when using your primitive building method, because vertex_submit always renders every vertex, right?

I'm also thinking about the following option.
You have a single object with a single vertex buffer for a row of subsequent blades of grass, which is a logical design choice.
However, could it have benefits to group those objects together in their create event, leaving 1 object per view_width by view_height rectangle containing the vertices for all blades of grass in that rectangle?
It would allow my previous suggestion for skipping draw events per rectangle to be even more efficient, you could replace the with structure with something that performs in constant time.
 

GMWolf

aka fel666
The only thing that causes overhead is setting and resetting the shad
er
and passing information per blade of grass to the shader.
And you can optimise that further by first setting the shader, drawing all the grass, then resetting. costing only one batch.

Passing the player position as a uniform alone will not be able to reproduce the effect Nux created.
As I've never worked with vertex buffers before, how would you best pass along per vertex information that changes through time?
It wont get the same efect, but you can get something close where the grass bends under the player.
I wouldn't pass per blade information at all. but if you have to, use an array or something.
another option is to group them together, and do pass per group animation. (you could have a goup ID attribute, and pass an array of matrices, for example).

Also, I think managing which grass has to be drawn and which grass can skip the draw event is still an optimization in large rooms with lots of grass,
even when using your primitive building method, because vertex_submit always renders every vertex, right?
you can already do this per object. just check if the grass object is in the view before drawing it. For that reason you may want to split very long patches of grass into two or more objects (but then the number of draw calls will increase).

However, could it have benefits to group those objects together in their create event, leaving 1 object per view_width by view_height rectangle containing the vertices for all blades of grass in that rectangle?
you could do that. It probably will help a little, but as it stands this is already plenty fast.
 

jo-thijs

Member
And you can optimise that further by first setting the shader, drawing all the grass, then resetting. costing only one batch.


It wont get the same efect, but you can get something close where the grass bends under the player.
I wouldn't pass per blade information at all. but if you have to, use an array or something.
another option is to group them together, and do pass per group animation. (you could have a goup ID attribute, and pass an array of matrices, for example).


you can already do this per object. just check if the grass object is in the view before drawing it. For that reason you may want to split very long patches of grass into two or more objects (but then the number of draw calls will increase).


you could do that. It probably will help a little, but as it stands this is already plenty fast.
Ok, thanks for the info!
 

Nux

GameMaker Staff
GameMaker Dev.
@Fel666 That was a really in-depth tutorial and it's helped me understand vertex shaders. Currently I have to finish exams for my A levels, which will be finished this month. So in a couple of weeks I'll be sure to experiment and try create something similar to the effect I had previously.

I have a quick question about the shader syntax, if I define a custom vertex format does it become an "attribute" within the shader? For example if I define:
Code:
Vertex_Format_Add_Custom(vertex_type_float1,vertex_usage_textcoord)
...within GML, do I then need to add
Code:
Attribute Float [name of variable]
...within the vertex shader?

Also, do the vertexes need to be "connected", or can I have a vertex buffer containing a primitive which gives the appearance of separate pieces of grass which don't intercept? I'm not quite sure how you went about this, but I suspect it's because at the tip of each grass blade, two vertices overlap, which would make the link between blades appear invisible.
 

GMWolf

aka fel666
@Fel666 That was a really in-depth tutorial and it's helped me understand vertex shaders. Currently I have to finish exams for my A levels, which will be finished this month. So in a couple of weeks I'll be sure to experiment and try create something similar to the effect I had previously.

I have a quick question about the shader syntax, if I define a custom vertex format does it become an "attribute" within the shader? For example if I define:
Code:
Vertex_Format_Add_Custom(vertex_type_float1,vertex_usage_textcoord)
...within GML, do I then need to add
Code:
Attribute Float [name of variable]
...within the vertex shader?

Also, do the vertexes need to be "connected", or can I have a vertex buffer containing a primitive which gives the appearance of separate pieces of grass which don't intercept? I'm not quite sure how you went about this, but I suspect it's because at the tip of each grass blade, two vertices overlap, which would make the link between blades appear invisible.
You are correct about the attributes.

As for the connectedness, triangles don't need to be connected. In the tutorial, you can set the separation to be larger than the grass blade width to see this.
 

TheouAegis

Member
As a general rule, small optimizations like these are never worth it.
I wouldn't call it "small" if trig functions weren't hardware level. Think back about how long it took you to calculate sine and cosine without a calculator back in school. :p It is good to know that our computers are optimized to handle sin and cos in ways that would make the old Greeks cry.
 

GMWolf

aka fel666
I wouldn't call it "small" if trig functions weren't hardware level.
Even then it would be small.
Seriously, these sorts of things should not be the focus of optimization.
Better amgorithms, data structures and use of hardware should always be your focus.
 

jo-thijs

Member
I wouldn't call it "small" if trig functions weren't hardware level. Think back about how long it took you to calculate sine and cosine without a calculator back in school. :p It is good to know that our computers are optimized to handle sin and cos in ways that would make the old Greeks cry.
Even then it would be small.
Seriously, these sorts of things should not be the focus of optimization.
Better amgorithms, data structures and use of hardware should always be your focus.
Now we're getting to vague to make really meaningful statements about optimization.

While human effort to calculate something can be a good estimate for how difficult something will be for a machine to calculate,
as you will be tied to the same complexities, it is not a good estimate in this case, as it's not the complexity of the calculations,
but the amount of digits to work with that make it difficult for humans to calculate, which is something that doesn't bother computers as much.

You can give implementations of algorithms to calculate sine and cosine that are worthwile to optimize, but you should give a specific algorithm to discuss then.
In general, you'll be usig a library for these kind of operations and the libraries will often be difficult to optimize, to the extend that it is often not worth it.

As for Fel666, that would technically fall under better algorithms.
It's just that those operations tend to already have very good algorithms.
 

GMWolf

aka fel666
As for Fel666, that would technically fall under better algorithms.
It's just that those operations tend to already have very good algorithms.
I'm talking big picture algorithms.
Use algorithms that reduce the complexity of the problem, so that smaller algorithms are called less often.

Or in this case, make better use of the hardware available.
 
Top