Some observations and rambling about things I've learnt.

D

Deleted member 27649

What is this?​

I'm an amateur artist turned amateur mapper in this engine I know pretty much nothing about its internal workings or theory. But I've taken some notes of things that might be useful, during the development of my now finished map, Full Throttle. It's experience, after all. It's good to share it.

I'm not a good writer of... anything, really. I swear I make an attempt to write good text, and read and reread everything I've written. But, I hope it's good enough that this is written down somewhere. Maybe it's also written down somewhere else, but if I (and most probably many other people) can't find it, does it exist?

post script: honestly this might be more of a rant or rambling than anything.



Brush entity lighting​

There is an irritating amount of things not in the FGD that should be. vrad_brush_cast_shadows seems to be perfectly functional, within reason, yet it's annoyingly hidden and I only found out about its existance after meddling with newer, custom FGDs, like Spud's or TeamSpen's. No one ever mentions it. In the VDC (Valve Developer Community) it's super easy to miss.

I suppose you can always just blocklights it. It's irritating and ugly, though.


Wait, why am I using brush entities?​

I started using func_illusionary (and later non-solid func_brush) because it was nice for trims that would stick out and eat explosions or catch players. In hindsight, that was not a wise choice.


Brush models render cost​

I am not graphics programmer and have no idea what is actually going on, and I probably didn't test anything very well, but it seems func_brushes are really *not* as cheap as I thought.

+showbudget indicated brush models were eating a lot of time of drawing the scene, and when I disabled r_drawbrushmodels I got a really significant boost. Admittedly, it was in an empty listen server, with mat_wireframe enabled, in my PC that probably isn't representative of your average machine running TF2 (If such a thing even exists). But, surely, there's a reason brush entities aren't used that often, besides the limits on how many entities can exist. And I guess, complexity?


Making it all func_details​

Was annoying because my existing clipping was made around trims not being solid. And also, I ran into tjunc limits. Of course I did. It's not really that interesting? I had to make some elaborate brushwork into props using Propper. Some turned out to have awful lighting. Can't really enable lightmaps for them because of how prop lightmapping seems to work, and how Propper seems to work. Something about materials? So I had to keep some func_brushes. Guh. Also, displacements can be nice, I guess? I assume they're cheaper than brush models, they don't suffer from tjuncs I suppose...


Displacement costs and transparency​

+showbudget told me displacements in my map were eating more time than any map should. Irritatingly, I couldn't really get rid of some. Because tjuncs, and also because of some really irritating transparency rubbish?

Some ramps made out of thin trims of perfecly opaque material and mostly made out of $translucent metal grates just... had some faces go invisible. Not sure why. Was it related to the perfectly stock blockbullets2 I was using? Which is, you know, %compileNodraw, %compileDetail, $translucent, base texture was the stock tools/toolsblockbullets. I really don't get it. I turned them into displacements. It worked! Unfortunately, $translucent (not sure if $alphatest also does this?) materials on displacements mean that bullets and rockets and probably everything but players go right through them. Sigh.


Surface properties hell​

I initially used the stock clipping and blockbullets materials. Unfortunately, when you shoot them with your gun, it has no visual impact effects (like momentary metallic sparks), and when you walk on them, they have default footstep sounds. This sucks.

So I started experimenting.

I made some custom blockbullets materials with '%surfaceprop's. They turned out to have correct footstep sounds, but didn't have impact effects. If you have, say, a metal wall covered with a blockbullets brush to smooth out explosions, when you shoot it it will not sound like metal, even with $surfaceprop metal!

I remembered some weird ef_nodraw func_brushes with metal materials I saw in some decompiled Valve maps. They were in displacement chickenwire fences. I realised that was Valve's way to have correct impact effects!

Unfortunately, when you walk on func_brushes, it incorrectly sounds like the default footstep sounds. Guh. If that wasn't bad enough, func_brushes also bounce stickies off them, even when they are completely static BSP collision func_brushes. Guh. And also, they eat up entity limits, and, I'm not sure, but I think even when they are ef_nodraws they still contribute to the cost of rendering brush models! Guh.

I tried nodraws with surface properties, same result as blockbullets, except now it cuts vis and casts shadows. Sigh.


We can't have everything (angry!)​

I really, really wish there was a way to block bullets and projectiles and explosions etc. without stopping their *visual* part, so the bullets will still visually hit the wall behind the clips, still have impact effects, still leave bullet holes.

I also really wish that non-solid stuff could visually seem like bullets are hitting them, even though in reality they are going straight through.

Everything could be so much nicer, more consistent, with wonderfully smooth collisions with lovelingly accurate eyecandy effects.

But we can't get that. We can't get anything, actually. I ask, why, just *why*, can't we have func_brushes not bounce off stickies? Why can't we have func_brushes have proper footstep sounds? Why can't we have properly solid $translucent displacements? What the hell does translucency have to do with it? Is it some backwards compatibility? Is it impossible to actually have the option to *choose*? Is it *really* a slippery slope to add, say, a compile flag for a really basic feature?


Cheating vis: func_detail vs func_brush​

So I have fake open spaces that actually are separated by toolsskybox walls. This engine benefits from having nicely divided spaces and rooms. This is ok to do. Unfortunately, this means structures that should be visible in both sides of the sky walls won't be.

func_details can sortof be used to remedy this. If it's a single brush that has a bit present in both sides of the sky wall, it will be drawn in its entirety from both sides. However, if it's a func_detail made from multiple brushes, if a brush isn't present on both sides of the sky wall, then it won't be drawn. So if you have, say, a sticking out roof made of two brushes, and they connect in the middle of the sky wall, then you'll only be able to see one roof brush from each side, the other not being drawn.

This is problematic. But, as it turns out, func_brushes (and I assume most brush entities) will be drawn in their entirety if you can see them at all. Wonderful!

However, func_brushes have plenty downsides, as I mentioned earlier. Perf is not great. They eat up entity limits. No, you can't cheat the entity limit by making every single func_brush into one, single func_brush, because that'll make *every* brush draw at once just because you see one bit of it. As I've mentioned many many times before, brush models are surprisingly expensive.

Also, displacements work similarly to func_details, in this regard. Which is nice, I guess. And I probably don't need to mention what happens if you have a world brush going through another world brush. They'll be cut up, won't be able to see from both sides, very sad. Also, I think the compiler does not like overlapping world brushes.


Cheating vis, part 2: skip + func_brush​

So there might be a large tower I have that is entirely on one side of a sky wall. It'll never be rendered from the other side. However, if I make a decently sized skip volume on the other side, and add it to the func_brush, it works! It draws the tower from both sides!

However, I'm not sure how reliable this is. I mean, entity %compileSkip brushes? That seems like a bad idea. I guess you could use something else, like a $translucent nodraw, or an NPC clip? NPC clip seems nice in TF2 because I don't think TFBots have anything to do with %compilenpcclip. They don't collide with it, they don't think it's solid, etc. Maybe it's bad for the boss NPCs? I wouldn't know.

And, obviously, there's all the issues func_brush has that I'm making sure to mention at every relevant moment.


Cheating vis, part 3: prop models​

You can't add a skip brush to a prop_static, unfortunately. So you can't cheat vis that way.

You can, however, somehow increase the bounding box of the prop to extend through the sky wall, having the prop be drawn from both sides. Doing this is complicated, though!

Either you'll have to decompile the model and do some rubbish to extend the bounding box, like, say, if it's a big tree, adding a small rock or pebble to a bit far away, or maybe use some .qc parameters, or... honestly, I don't know, I haven't done this.

Also, I think you have bad bounding boxes in your prop models, *bad* things start to happen. Not sure what they would be. Feel free to dive into that rabbit hole, yourself.


Cheating vis, part 4: 3d skybox behaviour​

The 3dsky is drawn *bellow* the world. Bellow world brushes, bellow static props, bellow entities, bellow everything. If you try to have a 3dsky pillar in the middle of real world ground, not only can you really not interact with the pillar, but the ground will eat up the pillar until there's nothing but sky behind it.

This is to say 3dsky geo should be outside of the map, such that the map will and it will never overlap.

This doesn't mean it won't affect with the world at all, as the 3dsky *will* light and shadow the world and all (unless you tell vrad not to, for whatever reason).


Cheating vis, part 5: prop model and 3d skies​

I had some trees in a side of a sky wall that wasn't been drawn in the other side of the sky wall. I didn't want to and couldn't attempt to do any hacky bounding box stuffs, so I instead replaced it with a 3dsky version.

Immediately I noticed the fact the ground the trees stood on was being drawn above the tree.

I attempted to have both world and 3dsky versions of the tree, exactly at the same place. Thankfully, the prop models I was using matched *perfectly* and didn't suffer from z-fighting and other issues.

Unfortunately, the lighting screwed up as the world tree seemed to be very shadowed and darkened. The 3dsky tree didn't suffer from that, as I saw when only it was being drawn, so maybe I could just disable shadows on the 3dsky trees and it'd work.

Unfortunately I was running out of time due to a deadline and didn't bother testing. The trees I was struggling with were surrounded by 3dsky trees and weren't really visibly on top of ground unless the player were in a bad spot that had a bunch of other visual issues. I removed the world trees and moved on. I still kept some duplicate trees, though, but they don't look too bad as they are isolated.


Cheating vis, part 6: areaportals and sky walls​

Some geo was big and distant and I couldn't apply any of the previously mentioned tricks to them.

So I cut some bits of the sky wall into areaportals. Areaportals still separate areas very nicely, and areaportals cull stuff that you can't see perfectly through it.

I was able to see some big far away buildings correctly, and the performance impact was minimal, thankfully.

I didn't abuse this too much, though, limiting it only at some select problematic bits. Areaportals are very cheap and will greatly help your perf, but they aren't free! Areaportals that do nothing much will only cost performance in exchange for, well, nothing, and if you use too many areaportals, it'll start to really hurt.


Side note: Valve Developer Community lies/inaccuracy​

Well, actually I'm only guessing that last bit. I have no idea how truly costly areaportals are, and what happens when you have bunch of them. I'm trusting my common sense and what the VDC says. The VDC is not really up to date, and not really that well written, you should know. VDC says overlays are way more expensive than decals, when apparently the opposite is true. VDC sometimes makes func_occluders seem like a super specialised super expensive optimisation tool, when apparently they are not really expensive in today's computers.

Sigh.


toolsskybox brushes block shadows and cast their own lights​

If you split a big structure in two with a big sky wall, you'll see that the shadows will probably be cut in the middle, or that there's a lot of ambient lighting being weirld shined on the structure.

Areaportals still let light and shadows go through, even when they are closed. So, the way I've dealt with the more problematic examples of this was to just replace a bit of the sky wall with a closed areaportal.

Closed areaportals don't let vis go through and don't do any of the culling calculations thingy. I'm assuming they are pretty much identical to a world brush when it comes to this situation. Except, of course, the lighting bit.

Unfortunately, players, bullets, rockets etc. all go through the areaportal.

Players weren't a problem as it was at an unnaccessible rooftop but I didn't want a weird hole rockets and grenades could go through. I added a super basic blockbullets2 brush to accompany the areaportal.

Unfortunately that did mean rockets exploded when hitting the blockbullets. I added a func_nogrenades volume around it, so that when a rocket hit the wall, it didn't explode, but just vanished with a small white flash.

It's not perfect as when a rocket hits a sky brush it just vanishes without anything, and it also eats up some of the entity limits I presume, but, eh. Also, I think stickybombs stick to the blockbullets wall, regardless. I'm not sure I care enough to go back and 'fix' that.


What is expensive and cheap water anyways?​

I don't know. I thought expensive water was when it had expensive water reflection that 'perfectly' reflects the world, or maybe thought that this also included water that refracts. The VDC is confusing, seems to DEMAND of the mapper that TWO BODIES OF "expensive" WATER SHOULD NEVER BE IN THE SAME PVS!!!!!, but, I have a body of reflective+refractive water and a body of a different material that is just refractive water that are not aligned at all and are in the same potentially visible set. I'm not sure what the wiki was talking about. I don't recall it actually separating reflective and/or refractive water from those really cheap water materials that are clearly quite fake-ish.

I did run into some weird water rendering bugs, at one point, but I didn't really test anything, couldn't really reproduce it reliably, and couldn't be bothered. I'm not sure it has anything to do with the above paragraph.


Disabling materials from casting shadows​

I don't know how you're supposed to do that. I made some tests with $translucent, which apparently makes the material completely *stop* casting shadows, regardless of the albedo? It was almost good enough for me but then I realised $translucent displacements don't really work. And, more importantly, $translucent also makes the brush not block vis. Very lame.

Of course, hint does not actually block visilibity, it only makes cuts in it. You can have a wall of hints, but you can still see the other side.

I haven't tried anything with $alphatest, by the way.


Custom FGD annoyance​

I've been having some irritating times while experimenting with custom FGDs. Sometimes they have things that don't do anything, sometimes they have things that break stuff, sometimes they have bad defaults that are unhelpful if not broken, and sometimes they lack perfectly functional and useful features.

As an example, I had some headaches with one that had env_sprite's rendermode set to 0 instead of 9 by default, which had the stock glow sprites just draw as black squares in-game.


Modern Hammer editor and uniformscale​

Little fun fact! If you use Hammer++, you can set on uniformscale on prop_statics to scale them in the editor! You'll have to turn SmartEdit off or get a custom FGD, though. Oh, and it won't actually compile scaled in anything but CSGO. But it's useful for previewing models scaled by the 3d skybox, I found!


Hammer++ @ExtendClass FGD feature​

// The ExtendClass is a new special class type // It should take the name of another class in other FGDs // If the class is not found in other FGDs, this class will simply be ignored // This classes helpers+keyvalues defined will be *appended* to the actual class found in other FGDs // If the keyvalue/helper share names in this class and actual class, it will be overwritten with the keyvalue/helper defined here instead // A helper will not be appended if the exact name and parameters are already defined in the actual class (stops duplicates) // The class description is ignored here as well // Extension classes are parsed LAST, after all FGDs have been loaded first // The purpose of all this is to not break thirdparty FGDs, and (hopefully) keep compatibility

Taken from \bin\hammerplusplus\hammerplusplus_fgd.fgd.


func_lod and its bad fading distance thingy​

Only in Left 4 Dead and later can you set a start and end to the fade distance. In TF2, it seems like it starts fading from 0? I'm not sure, I don't have the patience.


Ending thoughts on smoothing collisions and clipping​

I probably focused on the wrong things, there. As an amateur mapper I am bound to do that. What I have in the end is are compromises on top of compromises, a tad unpolished and, while perhaps ok in a vacuum, quite bad when there already are set standards that are followed.