The DirectQ update will be happening later on today (maybe 5/6/7 hours time) - keep yer peepers peeled!
Following that I'm going to fork the code and do some experimental work on dynamic light updates. The idea of updating lightmaps entirely on the GPU has been nagging me for over a year now, and the only thing holding me back has been an unwillingness to mess too much with working code, and some doubts about to handle dynamic lights from muzzleflashes, explosions, etc.
I'm feeling that the time is right to tackle it.
I already know how to handle animating lightstyles, and there are some interesting tradeoffs involved. There's going to be a 4x increase in texture memory usage, 3 extra texture lookups per surface, and the "no animating lightstyles" case is going to have no performance difference whatsoever from the "lots of animating lightstyles" case. The size of a surface vertex will also get slightly (4 bytes) bigger. On the other hand it completely avoids needing to update lightmap textures at runtime, CPU/GPU sync issues go away, a lot of horrible CPU-side work goes away, and codepaths become cleaner.
It also enables mappers to go nuts with lots of animating lightstyles without having to worry about "is this going to slow down the scene?"
It's going to be a balancing act of course; will the gains balance the losses? Will there be a general increase or not? If there is a decrease will it be worth accepting it (even if it's only on code-cleanliness grounds - a small enough decrease might tip the balance there)? That's why it's a fork of the code rather than the main codebase, and that's why I'm not making any promises that it's ever going to make it into a released version. It is an itch I have to scratch though.
Regarding muzzleflashes/explosions, I have some ideas brewing that might or might not take shape. One of them involves dropping the max number of these lights to something like 64, stating that each surface can only be affected by the 4 closest (I might be able to get away with 2, but I think 1 is right out) and doing some shader voodoo from there. Too early to talk much more about these.
I've mentioned before that RMQ maps make heavy use of animating lightstyles, so all of these are options for RMQ too, especially now that we're on a shaders-only path. I suspect that in the RMQ case we're going to see some performance improvement, although it's hard to tell at present as a lot of the content is suboptimal to begin with (un-vised maps, etc).
Friday, September 2, 2011
Updates for 2nd September 2011
Posted by
mhquake
at
2:21 PM
Subscribe to:
Post Comments (Atom)
4 comments:
This is something I've thought about often. My long-standing idea is to upload each lightstyle seperately to the GPU, and additively combine them in the framebuffer at run time, then multiply the texture on top of that in a seperate pass. My only worry is the extra fillrate cost of multipass rendering, and the extra memory for lightmaps.
I assume your approach would be much more modern, combining them all in the shader without all the extra passes.
Regarding dlights, In my scheme these would also be added on top of the other lightmaps using a projected circular texture. The unsolved part of that is the edge of the texture would look more or less soft based on the scale of the circle, which could look really bad where the edge crosses two polygons at different normals. I guess it would be much better to just use more of a doom3-style per-pixel lighting for these. Without shadows, and with the appropriate lookup texture, it would probably look very much like a cleaned-up version of the original quake dlights.
Anyway I'm curious to see how you tackle it.
You've more or less nailed it with the animations; I've also worried about the cost of multiple blends, even doing 3 extra texture lookups in a single pass within a shader might be expensive enough. The extra 4 bytes per vertex are going to be d_lightstylevalue[surrf->styles[maps]] without the * 22 in, so it seems straightforward to do. I think the shader-based approach is at least definitely worth trying. Worst case is I'll have satisfied my own curiosity and be able to say "tried that, didn't work".
For dlights I'm going to upload them all into the constants registers; that's why I need to cut my current max from 128 down to 64 (limited constants register space on my target hardware). Each dlight gets two slots - position and colour - then I can eval the distance between the dlight position and the surface vertex in a shader and use some attenuation formula to get a final intensity (if I need anything else I'll have two spare floats per dlight to play with). Haven't yet decided whether to do it per-pixel or per-vertex; I'll probably try per-vertex at least to begin with. Each surface vertex also needs some extra bytes here so that I can index into the constants and pull out the correct lights. If I make these un-normalized bytes I can have up to 4 lights per surface; the computations might be a little heavy though.
I have shader code for procedurally generating circular textures (currently used for particles and coronas) so I may adapt some of that too.
A concern about dlights is that they would take the surface vertex size above 32 bytes.
I'm not too worried about memory usage; a typical ID1 map would go up to under 4MB texture memory for lightmaps, and the tradeoff is that you save on needing to keep a copy in system memory (not relevant for D3D though as it lets you write directly to the texture data).
Curiosity got the better of me and I went and did animations. It worked out vey clean with minimal code changes.
The result is in. Too slow for my liking; it dropped from about 1100 FPS timedemos to about 800, and that was a single pass without dynamics coming in.
Did a quick double-check and confirmed that it was coloured light to blame; with white light you can pack each lightmap into each component of a 32-bit texture and just do a dot product with the styles to get the final intensity; with coloured light it's 4 texture lookups. White light is just as fast as the CPU version.
All the same it satisfied one part of my curiosity. There might still be mileage in doing something with dlights.
Just added dynamic lights; they're using a fairly simple linear attenuation, nothing fancy with normals or anything like that.
Up to 4 lights per surface and I just take the first 4 that hit the surface, no sorting to get the closest. It works.
They look good. Even per-vertex they look good.
No clamping, no stairsteps.
They're fast. I couldn't measure any speed difference in timedemos.
They work on moving bmodels.
They could easily be made work on water surfaces.
I think this one worked. :)
Post a Comment