jdolan / quetoo

Quetoo ("Q2") is a free first person shooter based on id Tech2. GPL v2 license.
http://quetoo.org
203 stars 28 forks source link

Stainmap expiration #413

Closed Panjoo closed 7 years ago

Panjoo commented 7 years ago

As much as I dig these stainmaps I think they should expire after a while. If you fire a few rockets in the same spot it shouldn't leave permanent pitch black dots behind:/

Even after just a couple minutes of running and gunning the playing field looks like butt ugly charcoal. After a while it has no purpose* anymore since the whole floor will be black with red splashes. Everything turns into a mess, lovely but it's too much!

(* interaction / indication of where was shot)

jdolan commented 7 years ago

Stains are not decals, so there are some major technical implications here..

Individually removing stains would require tracking them individually, which we do not currently do. What we do right now is just stain the surface, combining the new stain with any existing stain color data from previous stains, and re-upload it. It's like a canvas that we continually spill more paint on. "Subtracting" a stain from a surface, while leaving newer stains alone, would be incredibly tricky -- not gonna lie. I think what we might have to do is, when one stain on a surface expires, clear its stainmap and re-apply all unexpired stains again. Really not efficient. Another approach would be to clear -all- stains on a surface if it has not been stained in some configurable interval. The nice way to do this would be to ramp the stainmap's blend down over 1 or 2 seconds.. again, not trivial.

Honestly, I like the beaten up, bloodied map. If we do implement this, a cvar should govern the expiration time, and we can talk about the sane default (my inclination would be to not expire by default, which would be more efficient as well).

Paril commented 7 years ago

A map generally wouldn't last long enough to become completely black/red. If you played infinitely it would definitely happen in high frag zones, and it'd depend on the number of players.

Stainmaps are slow to modify, which is kind of problematic especially if you want them to fade since fading is over time. There is one other approach I thought of taking for the stainmap which is that instead of being a modified light map, it would be a light map + alpha channel that is defaulted at 0,0,0,0 and is modulated onto the regular lightmap, then we can basically run a whole subtraction over each pixel's alpha every like 30 seconds or something to slowly fade them out.

The main issue is that we can't really modify the stain map over the GPU, which would be the best way of approaching it...

Panjoo commented 7 years ago

That's too bad, was hoping this could be done easily like maybe lessen the black color.

fuckstain

It's the growing darkness that bothers me. How can you not find this ugly? This is after 4 minutes of playing with two bots ( I let em have it though!) It happens quickly in the so called hotspots, places that get spammed a lot.

It's not a huge problem but online I think it could become a point of concern. There's always going to be twats that sit in the server waiting for players, become bored and decide to shoot 20 rockets in one spot to make it pitch black. And then they're going paint the map knowing it won't fade away in time.

jdolan commented 7 years ago

Here's a stupid question: do you have r_stainmap 1.0 or something higher? It's a modulator, so you can always tune them down if you like (r_stainmap 0.3). And I'm happy to revisit the stain colors / intensities we have currently.

Panjoo commented 7 years ago

That's interesting. r_stainmap 1.0 is what I have yes. Just tried tuning it down like you suggested but if I do that the stainmaps do not show up anymore. Even after multiple tries, values and r_restarts. Wtf.

So it's just the lightmaps that get modified? How do you define the shape of the stain and can it be made so that it has less opaque areas instead of one round blob? Like a star or shuriken shaped figure.

Paril commented 7 years ago

Yes, and you can reset the stainmap with r_stainmap_reset I believe it is. Whoops, r_stainmap between 0 and 1 should work but I broke it. I'll push that fix.

The shape is just a circle right now, we could add other shapes but you have to keep in mind that it's an expensive operation since it's done on the CPU.

Panjoo commented 7 years ago

...we could add other shapes but you have to keep in mind that it's an expensive operation since it's done on the CPU.

This newer way of stainmapping must have some clever advantages over decals or you wouldn't have changed it, but I was also kinda happy with the way it was before though. I'm all for performance so keep it as simple as possible then. Maybe even smaller circles :)

Paril commented 7 years ago

The rationale was that stains are simpler and provide no performance hit for rendering a single frame - a map with a total of 0 stains will render exactly the same as a map that has had accumulated 800k stains on it.

We used to have decals, but they had a lot of problems (they floated over surfaces, didn't wrap around to adjacent walls, stuff like that) and stainmaps seemed like a better alternative. The only downside is that stainmaps are slower to add because they require a texture upload per surface touched by the stain, which means that more detailed maps (smaller surfaces) might cause hiccups in adding stains. I'm still investigating ways of doing this without causing performance hits.

I did consider the idea of stains fading, it's not a possibility with the current code but with some clever modifications it might be possible down the road. It would also be a way to add a cap to how dark the modification to the lightmap can get, so you can prevent them from getting too black/hiding important details.

jdolan commented 7 years ago

Decals were not clipped to geometry (only to a single plane). They did not work on edges or in corners. They sometimes floated in space if they caught the corner of a brush. They could not be applied to movers. They had to be explicitly drawn each frame, etc..

The stainmap solution is vastly superior in all of those respects. Stainmaps clip to geometry in all cases. They traverse corners, edges, etc. They never float in space. They work great on movers. And once they are added to a surface, they are essentially free to render thereafter.

If you think we should reduce their default opacity, we can do that.

jdolan commented 7 years ago

Jinx :P

Panjoo commented 7 years ago

I see, pretty cool how that works then. Thanks both for elaborating. A while ago when I first saw these newer stains I noticed that they wrapped around things while the wireframe wasn't showing anything. I was like Awwyeah, smooth! But it didn't take long before I was getting annoyed by all the black shit that wouldn't go away, lol.

For now reducing the default opacity sounds like a plan and maybe downsize the stain circles a bit.

Paril commented 7 years ago

I'll start a branch experimenting with stains to see if I can make them more to your liking.

Paril commented 7 years ago

Hey @Panjoo, I've been testing the concept of having stainmaps pull attenuation from a texture file. How's this looking?

Is this more like what you're imagining for shape of things?

jdolan commented 7 years ago

That's pretty dope. And we could have an effect texture per stain type, right? So blood stains would use one [set of] texture, explosions another, rail trails yet another, etc? What's the performance impact here? Can't be free! :)

Paril commented 7 years ago

@jdolan it's a tradeoff; a lot of the old calculations were removed, but now there's the addition of bilinear filtering on the CPU. Yes, you could use different textures for different stains (and you'd be better off doing that, too: this texture doesn't work well for small stains because it filters it to being almost invisible).

I was thinking, too, it might be possible to entirely offset the cost of drawing stainmaps over to the GPU with this system, but the caveat is it would only work if the user has framebuffer objects. Basically, instead of manually calculating which pixels in a stainmap are close enough to be rendered, we bind the lightmap texture's FBO and draw the attenuation texture over it over the position that was affected (we already have the local luxel-space x, y, and radius (which is w/h)).

If we combine this with moving stainmaps over to a new texture pass which gets modulated onto the lightmap, we can do stainmap expiration ALSO on the GPU, simply by running a pure black texture over the entire FBO with subtractive blending (with glBlendFuncSeparate, we can have it set not to touch the color and only affect the alpha layer) and having it only affect the alpha of the stainmap by (1 / 255) each "expiration tick".

With this, we could even have stainmaps processed on a second thread, and only "draw" the FBO update when it's ready to go (which in most cases will be by the next frame). Ideas?

jdolan commented 7 years ago

Sounds awesome, but really involved. I would propose we defer that to post-1.0.

Panjoo commented 7 years ago

@Paril - As for shape of explosion stains this is spot on! But sounds like this will get too complicated and will take precious time. I had no clue what would be involved when I opened this issue.

keep in mind that it's an expensive operation since it's done on the CPU.

With this in mind I'd like to see them somewhat smaller though (don't know if that would even matter), if possible bring it down to ~80% of the current size. As far as I can tell from that screenshot this should be more than enough for the effect. Regarding my main concern, the blackness, would defaulting r_stainmaps to 0.6 be a workaround for now?

Paril commented 7 years ago

I'd rather the default is 1.0 so that it's all relative to "1", I can adjust all of the stain alphas to be 60% of what they are now though.

@jdolan it's not too involved, days worth of work or so, but if you think it's not high priority enough (stainmaps -are- very CPU-intensive atm and if we can offload it to the GPU it's win-win) I can leave it for now.

jdolan commented 7 years ago

My gut tells me it's more than a day, and possibly more than a weekend, but that's only half of my concern. The other is, we'd have to maintain both code paths (software and hardware accelerated) for cards that do not support FBO. That's really unattractive in my opinion.

Paril commented 7 years ago

I mean, I still think it's a mistake to stick with GL 2.1 and not just jump to 3.0. I know we're holding back because of KaadmY, but would make things so much nicer to work with down the road with most of these features (fbo, etc) being core in 3.0.

Maybe this weekend I'll tackle this because the concept is really interesting to me and I'm wondering exactly how much faster it'll be. I'm really concerned that the Super Shotgun causes noticable hiccup in the net graph for me still.

jdolan commented 7 years ago

👍 Interestingly, I've never seen a hiccup for stainmaps, but I believe you.

Panjoo commented 7 years ago

@Paril - The effect shown in this clip you made (https://streamable.com/9t8rw ) is looking very good. Nice star shape and expiration effect, is this done with the alpha of the stainmaps like you mentioned earlier?

kaadmy commented 7 years ago

I can reliably reproduce a crash that seems to be only on Linux that happens when stains touch moving objects.

Paril commented 7 years ago

@Panjoo I made the star shape really quickly in GIMP, it's shit but I appreciate the pity ;) It is very simple: you set r_stainmap_expire_time (that's the current name, it may change) to however many milliseconds you want a fully-opaque stain to remain for - that is to say, the middle of a BFG, which is pretty darn close to 255 alpha. Every game tick, it increases a timer that is hooked up to 255 / expire_time, and once that timer is > 1 it will perform a subtraction on all stainmaps by that value (so, if you have 1000, then approx every 25 ms, it will remove 1 from all components (r,g,b,a) of the stainmap).

It's a linear ramp, so it will always take the same amount of time to remove a stain, but stains that are lighter will be quicker to go away since they have lower alpha values.

This branch also introduces the ability to assign a texture to stains, like the rocket does, so we can make some neat effects that way (note that because the stainmap is low res though it's unlikely you'll notice more than some very faint lines - on edge, for instance, the rocket stain looks nowhere near as good as on darkzone). I'd like to add a blood stain stain texture with some droplets as well, which will look a little better than just a streak of red.

kaadmy commented 7 years ago

Does @Paril's work close this issue yet, or is it still in progress?

Paril commented 7 years ago

It will when it's merged. I can't do it from America. When I get home this'll be ready to go.

jdolan commented 7 years ago

As far as I'm concerned, the only real issue with @Paril's pending changes is the stain jumping. He thinks there's a radius check that's borked somewhere. Once that is resolved, I'd like to see that branch merged down so that we can close this issue.

Paril commented 7 years ago

This is now merged.