[SOLVED] Is the way Love handles sprites inefficient?
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Re: Is the way Love handles sprites inefficient?
In other words, before attacking something, make sure you have at least basic understanding of it.
Re: Is the way Love handles sprites inefficient?
Normally i would matrix stored with each sprite but then i checked the documentation and i found
love.graphics
love.graphics.pop
love.graphics.push
love.graphics.rotate
love.graphics.scale
love.graphics.shear
love.graphics.translate
But how do i apply an matrix?
love.graphics
love.graphics.pop
love.graphics.push
love.graphics.rotate
love.graphics.scale
love.graphics.shear
love.graphics.translate
But how do i apply an matrix?
Re: Is the way Love handles sprites inefficient?
So does that mean that every time I apply an operation to a sprite (in another API, such as a rotation), I'm not actually modifying that sprite, but just changing the way it is drawn? Is that change computed every frame? Again, I just don't understand why having to compute that 60 times a second is more efficient than just saving a copy and computing that one time.Images aren't immutable, just as GL textures aren't, but you try to not really modify them because then you'd have to send the whole texture again.
- zorg
- Party member
- Posts: 3465
- Joined: Thu Dec 13, 2012 2:55 pm
- Location: Absurdistan, Hungary
- Contact:
Re: Is the way Love handles sprites inefficient?
I'm really interested in what kind of engine/framework/API you used before that did things that way, i can only think of one...
- create a new texture (relatively slow, there's a reason why there are warnings on the wiki saying you shouldn't use any functions starting with "new" in their name in love.update or love.draw...)
- somehow calculate for each pixel, the resultant color after a rotation of arbitrary angles. (slow as hell on the CPU, mind you)
- store all of those
Again, without restrictions, you could potentially fill your ram with just rotations of a single texture, which is, to be quite blunt and honest, stupid. Not to mention the fact that exactly when would you want to precalculate these things?
On the flip-side, and as was stated before, Löve uses OpenGL. That means that most graphical operations make use of the GPU, which is of course designed for heavy (parallelizable) work; just passing a few parameters to love.graphics.draw, to set the translation/orientation/scale/skew of a Drawable object (in this case, an Image) is more efficient, since the code only does the following:
- Modify the state of one Matrix (4x4 table of numbers in this case) - fast.
- Upload that to the GPU - fast.
- GPU modified its own coordinate system in a way that telling it to draw something will make it draw in the new system, effectively, if you rotated, it will be drawn rotated; if you scaled it, it will be scaled on the screen.
In short, doing these kinds of graphical manipulations is way faster on the GPU than any processing time you could save by wasting memory to store alternate versions of the same texture... with a few exceptions like mipmaps, but that's a whole another bag of worms i won't open.
Yes.
Yes.
Again, it's about tradeoffs. Think about how many different angles you could orient a sprite; if you don't have any restrictions, like the angles needing to be multiples of something (0°, 90°, 180°, 270° for example), then basically, you would need to do, for each angle:
- create a new texture (relatively slow, there's a reason why there are warnings on the wiki saying you shouldn't use any functions starting with "new" in their name in love.update or love.draw...)
- somehow calculate for each pixel, the resultant color after a rotation of arbitrary angles. (slow as hell on the CPU, mind you)
- store all of those
Again, without restrictions, you could potentially fill your ram with just rotations of a single texture, which is, to be quite blunt and honest, stupid. Not to mention the fact that exactly when would you want to precalculate these things?
On the flip-side, and as was stated before, Löve uses OpenGL. That means that most graphical operations make use of the GPU, which is of course designed for heavy (parallelizable) work; just passing a few parameters to love.graphics.draw, to set the translation/orientation/scale/skew of a Drawable object (in this case, an Image) is more efficient, since the code only does the following:
- Modify the state of one Matrix (4x4 table of numbers in this case) - fast.
- Upload that to the GPU - fast.
- GPU modified its own coordinate system in a way that telling it to draw something will make it draw in the new system, effectively, if you rotated, it will be drawn rotated; if you scaled it, it will be scaled on the screen.
In short, doing these kinds of graphical manipulations is way faster on the GPU than any processing time you could save by wasting memory to store alternate versions of the same texture... with a few exceptions like mipmaps, but that's a whole another bag of worms i won't open.
Currently, you should store each value separately, then either use them as parameters for love.graphics.draw (state won't be retained), or if you need to, use the above functions to set the matrix via them (state will be retained until the next frame); there's also love.graphics.origin to reset the whole matrix.
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
- slime
- Solid Snayke
- Posts: 3161
- Joined: Mon Aug 23, 2010 6:45 am
- Location: Nova Scotia, Canada
- Contact:
Re: Is the way Love handles sprites inefficient?
Rendering an axis-aligned image using the GPU is just as fast or slow as rendering an arbitrarily oriented one. This is not specific to love, but it is something love's APIs take advantage of. Rotating an image is not a bottleneck.
love's graphics APIs are relatively simple but they're at a lower level of abstraction compared to many other game engines. For the most part, love.graphics behaves quite similarly to how GPUs expect things to work. If you have only dealt with very high level hardware accelerated rendering APIs in the past, you might not be aware of how their internal functionality performs similar things that love exposes to you to do.
love's graphics APIs are relatively simple but they're at a lower level of abstraction compared to many other game engines. For the most part, love.graphics behaves quite similarly to how GPUs expect things to work. If you have only dealt with very high level hardware accelerated rendering APIs in the past, you might not be aware of how their internal functionality performs similar things that love exposes to you to do.
Re: Is the way Love handles sprites inefficient?
Using the draw function seems not useful either but seems that there is documentation about what i need in:zorg wrote: ↑Mon May 08, 2017 8:28 pm Currently, you should store each value separately, then either use them as parameters for love.graphics.draw (state won't be retained), or if you need to, use the above functions to set the matrix via them (state will be retained until the next frame); there's also love.graphics.origin to reset the whole matrix.
https://love2d.org/wiki/love.graphics.newShader
Maybe is should simply use vertex shader.
Re: Is the way Love handles sprites inefficient?
So even if I only have two configurations for a sprite that I ever use (such as a sprite pointing left and right), it's still more efficient to only use one texture, and then just flip it over the x-axis?
A side question on that - when flipping sprites by using a negative scale value when calling draw, Love doesn't perform the flip in place, but rather flips the sprite over its origin, so, in effect, the origin also shifts. What's the best way to preserve the original location of the origin on the sprite? I use an origin offset, but that requires some manual work.
Re: Is the way Love handles sprites inefficient?
yep. here's one way to think of it. to render the sprite to the left, you need to pass the texture, a quad, and a transformation matrix to the GPU. To render a sprite to the right, you need to pass the texture, a quad, and a transformation matrix to the GPU. The only difference is the numbers in the transformation matrix.
offsets are what I do to handle pivot points, too. to make this less tedious you can bundle it up in a function, like so
the definition of flipX is left as an exercise, mainly because I don't have access to my own code atm
offsets are what I do to handle pivot points, too. to make this less tedious you can bundle it up in a function, like so
Code: Select all
-- instead of
batch:add(quad, x, y, 0, 0, -1)
love.graphics.draw(tex, quad, x, y, 0, 0, -1)
-- do
batch:add(flipX(quad, x, y))
love.graphics.draw(tex, flipX(quad, x, y))
Who is online
Users browsing this forum: No registered users and 3 guests