Jerkyness because of shadow rendering
by Bullitt Sesariza · in Torque Game Engine · 01/21/2008 (7:29 pm) · 16 replies
Hi, I'm using AIPlayers as moving obstacles in my games. The problem is there's a jerkyness in the game. And when I did some profiling it turns out that almost 60% of the process is for PlayerRenderShadow. So it seems that most of the process is used up for rendering the shadows of the AIPlayers. FYI, there're currently approx. 20+ AIPlayers on the screen at a given time and still a lot more off screen (which weren't rendered so AFAIK didn't really matter). The number of the player on screen at a time couldn't be reduced, so the only way to solve this would be to find another way for rendering a shadow. It still need to move with the object (AIPlayer) though. Is there any other simpler way to cast a shadow that won't cost a lot of processing time? Thanks a lot in advance.
#2
I assume the slow performance comes from the fact that it's doing everything in software (on the CPU): creating a shadow bitmap for each object, plotting pixels on the bitmap, uploading the bitmap to the GPU and then deleting/refreshing the bitmap. All of this could be happening every few milliseconds for every object that casts a dynamic shadow.
There really isn't an easy solution, I'm afraid. Nevertheless, here's some resources you may find helpful:
Duncan Gray's New Shadow Class. A really nice piece of work that, unfortunately, was killed off by lack of TLK support. I managed to get it merged with TGE 1.4.2 but had some issues that were never resolved. It appears it's no longer supported but the idea behind it (rendering shadows using render-to-texture support) is good. Might serve as a useful starting point.
Brett Fattori's Stencil Shadow Resource. No experience with this one. It's an old resource but it may be useful.
You may try tweaking the Player_GenericShadowLevel and Player_NoShadowLevel defines in shapeBase.h. The comments just above the defines will explain why these might be useful to you.
01/22/2008 (10:17 am)
The dynamic shadow renderer is fairly slow and as you've seen, it really starts to hamper performance with large numbers of objects. TLK (and TGE 1.5) offer some per-object shadow tweaks (disabling shadow movement and animation) that can really improve performance but in your case these won't be helpful. I assume the slow performance comes from the fact that it's doing everything in software (on the CPU): creating a shadow bitmap for each object, plotting pixels on the bitmap, uploading the bitmap to the GPU and then deleting/refreshing the bitmap. All of this could be happening every few milliseconds for every object that casts a dynamic shadow.
There really isn't an easy solution, I'm afraid. Nevertheless, here's some resources you may find helpful:
Duncan Gray's New Shadow Class. A really nice piece of work that, unfortunately, was killed off by lack of TLK support. I managed to get it merged with TGE 1.4.2 but had some issues that were never resolved. It appears it's no longer supported but the idea behind it (rendering shadows using render-to-texture support) is good. Might serve as a useful starting point.
Brett Fattori's Stencil Shadow Resource. No experience with this one. It's an old resource but it may be useful.
You may try tweaking the Player_GenericShadowLevel and Player_NoShadowLevel defines in shapeBase.h. The comments just above the defines will explain why these might be useful to you.
#3
It's fairly easy to copy just the FBO shadow rendering section from that old resource of mine and add that to the current 1.5x series shadow class. You don't need the whole derived from sceneobject complications if all you want is faster shadows.
I did start messing with that when I eventually bought 1.5 and got it working fairly quickly for dynamic shadows but static shadows was a no no because TLK chooses to treat it like diff shadows which is fine for large objects but sucks for small objects like trees and fences etc. Basically there is no light source available to project static shadows from unless you spend a lot of time scratching through TLK code to try and get that implemented and I was not going to do that.
An excuse given elsewhere in the forums was that projected shadows for statics was slow, but thats a misconception based on ignorance. The method I implemented did a render to texture for statics once at game start then used those textures throughout the game with only occasional updating required when the camera got close and the majority of the work was done in the GPU. So it's not done on a frame by frame basis like dynamic shadows and therefore has very little impact on performance.
So now you are stuck with a TGE 1.5x series of poor performing dynamic shadows and near non existent static shadows. That business decision was probably based on a shortest time to market strategy.
01/22/2008 (2:30 pm)
Chris's explanation is correct. The current TGE shadow drawing is software CPU based requiring CPU texture drawing and then coping that texture to the GPU for rendering, done for all dynamic objects for each frame. It's further complicated by TLK which does this shadow creation/copy for each light-source that can influence the object. It looks cool yes but its CPU expensive. They should have included an FBO render-to-texture shadow implementation.It's fairly easy to copy just the FBO shadow rendering section from that old resource of mine and add that to the current 1.5x series shadow class. You don't need the whole derived from sceneobject complications if all you want is faster shadows.
I did start messing with that when I eventually bought 1.5 and got it working fairly quickly for dynamic shadows but static shadows was a no no because TLK chooses to treat it like diff shadows which is fine for large objects but sucks for small objects like trees and fences etc. Basically there is no light source available to project static shadows from unless you spend a lot of time scratching through TLK code to try and get that implemented and I was not going to do that.
An excuse given elsewhere in the forums was that projected shadows for statics was slow, but thats a misconception based on ignorance. The method I implemented did a render to texture for statics once at game start then used those textures throughout the game with only occasional updating required when the camera got close and the majority of the work was done in the GPU. So it's not done on a frame by frame basis like dynamic shadows and therefore has very little impact on performance.
So now you are stuck with a TGE 1.5x series of poor performing dynamic shadows and near non existent static shadows. That business decision was probably based on a shortest time to market strategy.
#4
01/22/2008 (2:35 pm)
Try setShadowDetailLevel(0). much lower fidelity shadow, but also much faster.
#5
01/22/2008 (4:58 pm)
You can also try caching the shadow textures, and only updating them every other frame.
#6
@Chris
Isn't that only some different algorithms to cast shadows? And AFAIK stencil will be slower than the current one. CMIIW. But I'll have a look at them though
@Duncan
Maybe I'll do that. Yeah, IMHO TGE doesn't use GPU that much. Or maybe this is because it's a feature in TGEA?
@Orion
Have tried that. It's true that it's faster, but no shadow made it unrealistic.
@Jaimi
Don't know how to do it but I'll give it a shot.
BTW, when I try set the detail level to 0, the one using most of the process now is TSShapeInstanceRender. Maybe it's because there're lot of objects in one scene. But because it's unavoidable, any chance that it can be made faster?
Thanks again.
EDIT: I've searched the forum for the TSShapeInstanceRender and in one of them it's said that it's a driver issue. Well, have upgraded the driver and without the shadow ( setShadowDetailLevel(0) ) it's at 50 FPS. But with shadows ( setShadowDetailLevel(1) ) it drops to 20. :D
01/23/2008 (11:04 pm)
Thanks for the feedback guys. @Chris
Isn't that only some different algorithms to cast shadows? And AFAIK stencil will be slower than the current one. CMIIW. But I'll have a look at them though
@Duncan
Maybe I'll do that. Yeah, IMHO TGE doesn't use GPU that much. Or maybe this is because it's a feature in TGEA?
@Orion
Have tried that. It's true that it's faster, but no shadow made it unrealistic.
@Jaimi
Don't know how to do it but I'll give it a shot.
BTW, when I try set the detail level to 0, the one using most of the process now is TSShapeInstanceRender. Maybe it's because there're lot of objects in one scene. But because it's unavoidable, any chance that it can be made faster?
Thanks again.
EDIT: I've searched the forum for the TSShapeInstanceRender and in one of them it's said that it's a driver issue. Well, have upgraded the driver and without the shadow ( setShadowDetailLevel(0) ) it's at 50 FPS. But with shadows ( setShadowDetailLevel(1) ) it drops to 20. :D
#7
If you don't want to go that route, you may try the following:
1). Tweaking Shadow::smSmallestVisibleSize. Upping the value will cause shadows to stop rendering earlier.
2). Disabling the blur effect the renderer applies to shadow bitmaps. The blur results in smooth edges but there's really no need to perform that extra step if it's not noticeable. You can turn the blur effect off on a per-detail basis by modifying the Shadow::PixelSizeDetail arrays. Changing the 1 to a 0 will turn the blur off.
3). Tweaking the shadow bitmap expire time. In TGE 1.4.2, the highest detail shadows are refreshed every 5ms which might be too often for your game. Upping the value will cause the renderer to wait longer before going through the whole process of creating/updating the shadow bitmap, etc. The timeout value is the second number in the Shadow::PixelSizeDetail arrays.
01/23/2008 (11:51 pm)
Well, Duncan's resource is really just a good starting point. Revamping the shadow renderer to use FBOs/render-to-texture support will result in some fairly significant performance gains. If you don't want to go that route, you may try the following:
1). Tweaking Shadow::smSmallestVisibleSize. Upping the value will cause shadows to stop rendering earlier.
2). Disabling the blur effect the renderer applies to shadow bitmaps. The blur results in smooth edges but there's really no need to perform that extra step if it's not noticeable. You can turn the blur effect off on a per-detail basis by modifying the Shadow::PixelSizeDetail arrays. Changing the 1 to a 0 will turn the blur off.
3). Tweaking the shadow bitmap expire time. In TGE 1.4.2, the highest detail shadows are refreshed every 5ms which might be too often for your game. Upping the value will cause the renderer to wait longer before going through the whole process of creating/updating the shadow bitmap, etc. The timeout value is the second number in the Shadow::PixelSizeDetail arrays.
#8
BTW, I think I'll use the easier one before doing Duncan's resource.
01/24/2008 (12:36 am)
Well, I've looked at the resource. And because I am using TGE 1.5.2, so maybe it wouldn't work. However as Duncan and you suggested, maybe I'll just copied the necessary part from the resource. Have downloaded the resource and see some of its source codes. But I don't know which one I should look. And copying the source directly is a no-no becuase there are some additions from other resources such as air control, advanced camera, etc. Can you give me some suggestions of what are the important ones?BTW, I think I'll use the easier one before doing Duncan's resource.
#9
01/24/2008 (10:06 am)
Update: I've tried all those 3 other ways that you've suggested. And it only give a small increase (maybe only 2-3 FPS) and it's still rather jerky. So IMHO the only way for me now is using FBO shadow from Duncan's resource. Any idea where to begin from the resource? Where is the chunk of code that has the FBO shadow in there? Thanks.
#11
01/24/2008 (3:21 pm)
Most of the changes are in shadow.cc and framebuffer.cc. The other WinGL etc changes are only modded to include the framebuffer OpenGL extensions. ( A bit of a pain) It would be nice if the TGE file structure allowed for easier additions of OpenGL extensions.
#12
01/27/2008 (6:06 pm)
Thanks Duncan. BTW, my boss said to give it a rest for now and start to work on the gameplay itself. After all, it's not too lagged that it can't be played. Just a jerky animation & rendering. Thanks though.
#14
01/29/2008 (10:20 am)
As he describes there: Heavily modded TGE without TLK so most likely heavily modded TGE 1.4 or the like.
#15
01/29/2008 (2:03 pm)
Is the frame rate low or are the players jumping/warping around the screen? If the players are jumping around the screen the issue is network related. The stock AIPlayers are *very* heavy weight, getting more than 12 on screen without warping is not easy (beware of packet size/speed tweaks as these limit minimal required connection speeds/latency).
#16
Now that you mentioned it, they are warping around the screen. But the frame rate itself is pretty low (avg. 24 fps). Also, my game is a local only game (similar to GPGT Maze Runner game), so I don't see why it would warp like that because practically there's no networking involved.
01/29/2008 (7:27 pm)
@JohnNow that you mentioned it, they are warping around the screen. But the frame rate itself is pretty low (avg. 24 fps). Also, my game is a local only game (similar to GPGT Maze Runner game), so I don't see why it would warp like that because practically there's no networking involved.
Torque Owner Kevin Summers
Does Torque offload processing to the GPU? Something like shadow rendering I would think would
be something ideal for the GPU to be doing, but as I'm still only a 1 year newbie in this arena of
game programming I really don't know enough yet to know how you diferentiate between processing
something on the CPU or the GPU in code.
Do we need to start writing code that detects specific chipsets and take advantage of those? or does
Torque use "Shader Engines" and rely on the capabilities of the GPU to take on those tasks?
I don't mean to take over your thread Bullit, but I think the question applies, and may help.