1:03 PM -- altered the logic to catch "door lifts."
3:06 PM -- added check for vertical secret doors
So here are the fixes I am currently implementing to eliminate z-fighting in Quake, mod-side. I seem to be constantly tweaking stuff to try and refine it, to achieve no z-fighting but also no negative side-effects (or as few as possible).
I suppose the correct way to do this would be addressing each instance individually, but apparently there are a LOT of them. This guy on Quakeone says he addressed over 60 instances: http://quakeone.com/forums/quake-mod-re ... -beta.html
Of course, altering each map itself is a very non-ideal solution, and rather difficult to implement as well.
I guess I should point out that I'm only looking at DM mode -- there are many many more doors and weird things in Single-Player mode, which is probably where the vast majority of those 60+ instances are. Trying to make some logic that would address all those without lots of side-effects would be... impossible, heh. They certainly could be fixed easily in QuakeC, but it would require the "correct" method of altering each instance specifically. But I'm not really attempting to fix single-player Quake -- DM mode is all you see online.... Though maybe if I had the full list of all the z-fighting locations, I'd look at addressing them.... It wouldn't really be that difficult; just a couple lines of code for each instance. Hm, I wonder if that guy who fixed all the maps has a list of all the locations he fixed? heh
Ok, so first off....
plats.qc
Code: Select all
void () func_plat =
{
// anti-z-fighting hack
// plats are elevators, so just make sure they are above floor level.
self.origin_z = self.origin_z + 0.15;
misc.qc
Code: Select all
void () func_wall =
{
[...]
setmodel(self, self.model);
//anti-z-fighting hack
// wall entities shall be moved perpendicular to their wide side
// these are often "exit" signs lined up with nearby walls
// +x is good on e2m2, but -x is good on e2m3 & e2m5
if (self.size_x > self.size_y) self.origin_y = self.origin_y - 0.15;
else if (self.size_x < self.size_y) self.origin_x = self.origin_x - 0.15;};
doors.qc
Code: Select all
void () fd_secret_use =
{
[...]
// anti-z-fighting hack
// if it's a vertical secret door, move it less far down
if (self.spawnflags & SECRET_1ST_DOWN) self.dest1 = self.dest1 + (v_up * 0.15);
// slide it a tad less far into the wall to avoid potential z-fighting
self.dest2 = (v_forward * -0.15) + (self.dest1) + (v_forward * (self.t_length));
//self.dest2 = (self.dest1) + (v_forward * (self.t_length));
SUB_CalcMove(self.dest1, self.speed, fd_secret_move1);
sound(self, CHAN_VOICE, self.noise2, ATTN_NORM, ATTN_NORM);
};
Regular doors get much more complex....
Here's my current (often changing) code:
doors.qc
Code: Select all
void () func_door =
{
[...]
if (!(self.dmg)) {
self.dmg = 2;
}
// anti-z-fighting hack
// these are vertical moving doors/bars and (sometimes secret) lifts
if (self.movedir == '0 0 -1' || self.movedir == '0 0 1') {
// if they move upward and are wider than 32 on both sides they are most likely lifts.
// need to alter origin completely; don't want them making strange moves while ridden.
// sink them into the floor a tad in case they are on floor plane (some secret lifts)
// many also flagged to "start open" so let's try this to catch lifts and similar:
if ((self.size_x >= 32 && self.size_y >= 32) || self.spawnflags & DOOR_START_OPEN) {
self.origin_z = self.origin_z - 0.15;
// the following will almost never be needed for lifts, but there is a tiny
// place on back corner of fat water lift on e2m6.... Meh.
if (self.size_x > self.size_y) self.origin_y = self.origin_y - 0.15;
else if (self.size_x < self.size_y) self.origin_x = self.origin_x - 0.15;
}
// for other vert doors, only move a tad perpendicular to wide side, so as to not
// increase the gap they are blocking which can allow players to slip through bars.
// let's do this only if it's a slow door. regular speed doors may flicker
// during move, but they won't be moving long. handle them like non-vert doors (safer).
// if it's not a lift & it moves downward, forget it. sinking in floor = no z-fighting
else if (self.speed * 3 < self.size_z && self.movedir_z == 1) {
if (self.size_x > self.size_y) self.origin_y = self.origin_y - 0.15;
// -x hides exit bars in wall e2m7
else if (self.size_x < self.size_y) self.origin_x = self.origin_x - 0.15;
}
setorigin(self, self.origin);
}
self.pos1 = self.origin;
[...]
THEN I have to start looking at other vertical-moving doors.... Of which there are a wide variety. One bad one is the bars at the exit of e2m7. This code catches it because it's so slow moving (upward). It's tricky changing the origin of doors, because that can cause cracks in the wall, which can be more noticeable... so that's why I'm trying to narrow down what I move here (since this fix can be less "safe"). Normal door speed is 100 -- those bars move at 30. I compare the speed * 3 to the height of the door to determine if it's going to take a long time to move (giving lots of time to see potential ugly z-fighting).
For all doors not adjusted there, we go to:
doors.qc
Code: Select all
void () door_hit_top =
{
// anti-z-fighting hack. just slightly alter door's position after the end of
// its move to be sure it's not perfectly aligned with floor or wall.
// lifts & slow vert doors doors don't need this - they are completely repositioned.
// but we will do this for non-lift, non-slow vert doors, if they move upward
if ( (self.movedir_z != -1 && self.movedir_z != 1) || ( (self.size_x < 32 || self.size_y < 32) && self.speed * 3 >= self.size_z && self.movedir_z == 1 ) ) {
// move them perpendicular to wide side, and down a bit for ones that slide along floor
if (self.size_x > self.size_y) {
// -x is good for end doors on e1m2
setorigin(self, self.origin - '0 0.15 0.15');
}
else if (self.size_x < self.size_y) {
// -y good for knight door at start of e4m5
setorigin(self, self.origin - '0.15 0 0.15');
}
// if they dont have a wide side they are probably
// a flat side-sliding floor door that does't need any adjustment
}
So I check for the doors I haven't already adjusted, and simply move them slightly AFTER they have reached their normal end position. The downward adjustment gets rid of the top of the gate you can see in the room behind the big spike & zombie pit in e1m3.
Waiting to move the door until after it's moved (usually into a wall) is pretty safe. But you will still see flickering WHILE the door is moving, if it has z issues. But yeah, as long as they aren't big slow doors, the flickering won't last very long.
One issue that could possibly arise is that, since the door will be moving back toward it's original position (door_hit_top just means it's fully "open"), there will be some sideways movement since I altered it, and if you are pressing against the long side of a door as it's sliding closed, you could get hurt and trigger the "door blocked" stuff....
Previously I was altering the open position of the door from the start, which looked much nicer (no flickering), but due to there being the tiny forward movement, when a player was pressing against a door as it opened, the above situation would happen.... It's much less likely anyone is pressing against a door that is closing, so I don't think this will be an issue. If it does turn out to be an issue, I can just reposition the door prior to closing it. Also, this adjustment could cause issues if it's actually a "door lift" with soemthing riding on it... so hopefully I've narrowed it down to not adjust those.
But I think I've pretty much got things working well with only very minor side-effects. In theory. Since I have no idea where all 60+ instances of z-fighting occur, I just have to try to use logic that SHOULD catch them all, and hopefully not cause unwanted effects for everything else.
If you see any entities z-fighting, or acting in a strange manner, or possessing crack, report it to your local FvF authority immediately!