Welcome, Guest. Please login or register.

Author Topic: Setting Sprite Z (Depth) for Draw Order  (Read 3847 times)

0 Members and 1 Guest are viewing this topic.

Cornstalks

  • Full Member
  • ***
  • Posts: 180
    • View Profile
    • My Website
Setting Sprite Z (Depth) for Draw Order
« on: April 08, 2012, 08:50:32 pm »
I know this wouldn't be a part of SFML 2.0's initial release, but I think it'd be really useful to be able to set a sprite's z-depth so that sprites can be overlapped and rendered correctly.

For example, imagine a 2.5D RTS (like Starcraft). For the most part, units don't overlap too much, but they can a little bit (put two drones by each other). If I could set the sprite's z-depth based on their (x, y) locations, it would be easy to ensure a consistent drawing order. In addition, flying units could be given a distinct depth offset so that they always appear on top of other units, but they overlap other flying units in a consistent way as well.

It's possible to sort the sprites in a specific way and then render them in order, to simulate the depth effect, but that's not nearly as efficient as just setting the z value for each sprite.

Your thoughts?

[edit]

In my example above, I could easily do this with a shader (and using a vertex shader may even be more efficient in this case) with something like z = x + y * mapWidth + isFlying * flyingOffset. I'm not sure if the vertex shader would be the most appropriate place to do this in all situations though; I haven't thought of one where a vertex shader wouldn't work well yet, but I'll give it more thought.
« Last Edit: April 08, 2012, 09:07:25 pm by Cornstalks »

Groogy

  • Hero Member
  • *****
  • Posts: 1485
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Re: Setting Sprite Z (Depth) for Draw Order
« Reply #1 on: April 08, 2012, 09:02:02 pm »
I can say that Laurent will give you the answer no this will not be implemented and he has already denied this request several times before. Did you even do a quick search on the forum before posting?

If you really need to do this you can implement it yourself by just simply drawing the objects back to front and you will get the desired result. Also giving different objects distinct depths is bad. Like you are saying you want to do with the flying units. You should implement a layer system to handle that. Or funky bugs can appear.

It's possible to sort the sprites in a specific way and then render them in order, to simulate the depth effect, but that's not nearly as efficient as just setting the z value for each sprite.
If you do it right it will be efficient. Certainly more efficient than using the depth buffer when you could do without it.
« Last Edit: April 08, 2012, 09:05:09 pm by Groogy »
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Cornstalks

  • Full Member
  • ***
  • Posts: 180
    • View Profile
    • My Website
Re: Setting Sprite Z (Depth) for Draw Order
« Reply #2 on: April 08, 2012, 09:18:51 pm »
I can say that Laurent will give you the answer no this will not be implemented and he has already denied this request several times before. Did you even do a quick search on the forum before posting?
I'm pretty sure he'll say no too, but it's worth asking :). I did do a search, but google gives dead links to the old forum (I found one google cached page where someone requested it but I'm pretty sure Laurent's answer was on page 2, which I couldn't get to with google's cached version) and this forum's search feature gave nothing relevant (that I could find, at least; maybe there's a fancier search option that does a better job, but I didn't find it).

If you really need to do this you can implement it yourself by just simply drawing the objects back to front and you will get the desired result. Also giving different objects distinct depths is bad. Like you are saying you want to do with the flying units. You should implement a layer system to handle that. Or funky bugs can appear.
Could you elaborate? I'm not saying it's the best solution, but I can't think of a situation in which funky bugs would appear. Layers could help, but drawing sprites in the same layer still requires them to be sorted.

It's possible to sort the sprites in a specific way and then render them in order, to simulate the depth effect, but that's not nearly as efficient as just setting the z value for each sprite.
If you do it right it will be efficient. Certainly more efficient than using the depth buffer when you could do without it.
Really? Unless I have really wrong ideas about how to do the sorting, I didn't think a depth buffer was *that* expensive.

Also, I made an edit after you posted about being able to use a vertex shader for this. So far I haven't thought of a game where a vertex shader couldn't do this for you, and unless I can I guess this request is kind of moot.

Groogy

  • Hero Member
  • *****
  • Posts: 1485
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Re: Setting Sprite Z (Depth) for Draw Order
« Reply #3 on: April 08, 2012, 09:42:52 pm »
Well I can say that it is impossible for a vertex shader to do this for you since this is not resolved in the vertex shader. You have no control of the depth-test. You can only modify a pair of states. It's all done in the GPU hardware. And no the depth buffer is not that expensive but it is still a lot more expensive than having none. Remember that the depth test is done on each pixel also for pixels that fails. And then we have the write operations. It does cost a lot compared to having none at all. It is cheaper to do a per-entity compare instead.

The funky bug that can appear with the "I put floating things at z-depth 0.1f" is that if you have a tile-system and calculate the depth based on objects height you can easily get some tiles or objects on the edge that might cut those floating things. But if you then say "I put a limit to 0.5f" then you have more or less created an indirect layer. So why not create a proper system to manage layers and draw entities in separate passes? There is only advantages as you both get a full 32 bit floating point accuracy instead of only half of that and it will become easier to sort things after depth as you have more or less done a form of divide-and-conquer algorithm in a higher level.
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Cornstalks

  • Full Member
  • ***
  • Posts: 180
    • View Profile
    • My Website
Re: Setting Sprite Z (Depth) for Draw Order
« Reply #4 on: April 08, 2012, 09:58:58 pm »
Well I can say that it is impossible for a vertex shader to do this for you since this is not resolved in the vertex shader. You have no control of the depth-test. You can only modify a pair of states. It's all done in the GPU hardware. And no the depth buffer is not that expensive but it is still a lot more expensive than having none. Remember that the depth test is done on each pixel also for pixels that fails. And then we have the write operations. It does cost a lot compared to having none at all. It is cheaper to do a per-entity compare instead.
Couldn't the vertex shader just set the z value, which would then be used when doing the depth test to determine which fragments to draw? The reason I was thinking of using the vertex shader is exactly because it's done on the GPU, so CPU cycles wouldn't be needed in maintaining a sorted list of sprites. But I guess it would actually take some profiling to see what the speed differences were, if there are any.

The funky bug that can appear with the "I put floating things at z-depth 0.1f" is that if you have a tile-system and calculate the depth based on objects height you can easily get some tiles or objects on the edge that might cut those floating things. But if you then say "I put a limit to 0.5f" then you have more or less created an indirect layer. So why not create a proper system to manage layers and draw entities in separate passes? There is only advantages as you both get a full 32 bit floating point accuracy instead of only half of that and it will become easier to sort things after depth as you have more or less done a form of divide-and-conquer algorithm in a higher level.
Yeah, I guess it'd be like a layer system without actually programming any layer management (the isFlying could be turned into a layer variable instead), which I think could turn out as an elegant alternative (though like I said, I've only just thought about this so there could be issues I haven't thought of yet, so it may not be that elegant... but it could be, I think). But you wouldn't have to restrict z values to the [-1, 1] range, as they get homoginized after the vertex shader, so you could still perform decent depth testing. You could also disable it for certain things, like the background/tilemap and UI.

I'll have to give the vertex shader idea some more thought, but I think it has potential.

Either way, I'd still like to hear Laurent's opinion on this (I'm expecting him to say no, but I'm interested in why as well).

[edit]

I just thought about alpha blending from sprites, as that would probably be needed... I don't think the depth buffer would be much help there (as alpha blending resorts to rendering with the painter's algorithm, right?), so I think you're right in that a sprite's depth with a depth-buffer wouldn't actually help that much. Never mind, I guess.
« Last Edit: April 08, 2012, 10:25:46 pm by Cornstalks »

Groogy

  • Hero Member
  • *****
  • Posts: 1485
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Re: Setting Sprite Z (Depth) for Draw Order
« Reply #5 on: April 08, 2012, 10:39:04 pm »
Couldn't the vertex shader just set the z value, which would then be used when doing the depth test to determine which fragments to draw? The reason I was thinking of using the vertex shader is exactly because it's done on the GPU, so CPU cycles wouldn't be needed in maintaining a sorted list of sprites. But I guess it would actually take some profiling to see what the speed differences were, if there are any.
Sure you could but it's an incorrect way of doing it. First the GPU's optimize to cut away unneeded pixels by testing before reaching the fragment shader. Now comes the funny thing, you can write to the depth buffer in the fragment shader. So if you want to give explicit values to the depth buffer then that is done in the fragment shader and all optimizations the GPU could do would be thrown away. So the better choice would be writing it in the vertex shader. But then you won't have a per-pixel resolution on the depth.

Anyway you just disregarded completely the fact that sorting per-entity is much faster than anything the GPU can throw at it. There is a reason why KD-tree's are still in use in commercial games and they do the depth sorting on a per-vertex basis and not only on a per-entity basis. Also a lot of this information is needed on a gameplay basis as well and not only on the GPU so you still need to calculate and store it.

But you wouldn't have to restrict z values to the [-1, 1] range, as they get homoginized after the vertex shader, so you could still perform decent depth testing. You could also disable it for certain things, like the background/tilemap and UI.

I'll have to give the vertex shader idea some more thought, but I think it has potential.
The values have to be in the range of 0 and 1.f for the z in order to be visible within the native device box. Usually this truncation is done by the projection matrix but I bet you don't have any like that? I might get this wrong but from you it sounds like you think the vertex shader does it for you. No it does not. If you do not explicitly have anything that performs this transformation(unless you already have the values between 0 and 1) the GPU will clip the geometry.
« Last Edit: April 08, 2012, 10:42:07 pm by Groogy »
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Cornstalks

  • Full Member
  • ***
  • Posts: 180
    • View Profile
    • My Website
Re: Setting Sprite Z (Depth) for Draw Order
« Reply #6 on: April 08, 2012, 11:16:11 pm »
Sure you could but it's an incorrect way of doing it. First the GPU's optimize to cut away unneeded pixels by testing before reaching the fragment shader. Now comes the funny thing, you can write to the depth buffer in the fragment shader. So if you want to give explicit values to the depth buffer then that is done in the fragment shader and all optimizations the GPU could do would be thrown away. So the better choice would be writing it in the vertex shader. But then you won't have a per-pixel resolution on the depth.
I never suggested using the fragment shader. I've always been talking about doing this in the vertex shader.

Anyway you just disregarded completely the fact that sorting per-entity is much faster than anything the GPU can throw at it. There is a reason why KD-tree's are still in use in commercial games and they do the depth sorting on a per-vertex basis and not only on a per-entity basis. Also a lot of this information is needed on a gameplay basis as well and not only on the GPU so you still need to calculate and store it.
I guess that depends on how busy you're keeping the GPU. I've got spare GPU cycles, whereas I have less CPU cycles to spare.

The values have to be in the range of 0 and 1.f for the z in order to be visible within the native device box. Usually this truncation is done by the projection matrix but I bet you don't have any like that? I might get this wrong but from you it sounds like you think the vertex shader does it for you. No it does not. If you do not explicitly have anything that performs this transformation(unless you already have the values between 0 and 1) the GPU will clip the geometry.
I should've said this explicitly, but I didn't. I figured if I'd be writing a vertex shader to do this, I could easily change the orthographic projection matrix to use different near/far planes instead of using the default [1, -1] (I think that's what the default is...).

Anyway, like I said, I'm pretty sure alpha blending would screw this all up so I don't think a z-buffer would actually be of much help if it were to be used to order sprites.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 28695
    • View Profile
    • SFML's website
    • Email
Re: Setting Sprite Z (Depth) for Draw Order
« Reply #7 on: April 09, 2012, 08:01:04 am »
Using the search I found this, which summarizes my thougts pretty well:
http://en.sfml-dev.org/forums/index.php?topic=6817.msg44921#msg44921
:)
Laurent Gomila - SFML developer

Cornstalks

  • Full Member
  • ***
  • Posts: 180
    • View Profile
    • My Website
Re: Setting Sprite Z (Depth) for Draw Order
« Reply #8 on: April 09, 2012, 02:19:25 pm »
Thank you. I think those are all valid points. After I thought about alpha blending I realized this wasn't really going to work.