Inside3D!
     

Avirox's Rotation Tutorial Adapted to NetQuake
Goto page Previous  1, 2, 3, 4, 5  Next
 
Post new topic   Reply to topic    Inside3d Forums Forum Index -> Programming Tutorials
View previous topic :: View next topic  
Author Message
goldenboy



Joined: 05 Sep 2008
Posts: 310
Location: Kiel

PostPosted: Wed Jul 14, 2010 6:11 pm    Post subject: Reply with quote

OK, a problem has surfaced with very large rotating structures.

I have a pretty big rotate_door, which is part of a moving / rotating bridge. Problem is, the thing starts to "flicker" in non-Darkplaces engines, ie from certain angles, the thing becomes invisible.

AFAIK this happens when the thing is in too many vis leafs? portals? It gets much, much worse in a fullvised map. Probably because there are more vis (leafs/portals/whatever).

However: It doesn't happen in Darkplaces. Yay. So there is a way to fix it. (It also doesn't flicker in AguirRe's enhanced GLquake, but that might stem from the fact that BJPquake doesn't support rotating bmodels. The flickering is in my modified Quakespasm - ie a Fitzquake-derived engine). Couldn't test with newest Proquake, which has rotation support, since it can't load the map. Wink

I've also tried turning the rotate_door into a func_wall to see if it still flickers. Nope - the func_wall version does NOT flicker, but of course it also doesn't rotate and hence it can probably not be compared directly.

I'm asking someone like mh, LordHavoc, Baker or other engine capable person to give me a hand here. What does darkplaces do differently when it comes to vis culling? And once we find out, can that fix (I suppose it is a sort of fix) be applied to other engines?

I could probably also chop the thing up into a load of smaller rotate_doors, but I'm afraid this will mess up texturing and/or lighting - I'm glad the thing is textured somewhat correctly.

Why does it work in DP with no flickering, even when fullvised?

What to do?
_________________
ReMakeQuake
The Realm of Blog Magic
Back to top
View user's profile Send private message
Spike



Joined: 05 Nov 2004
Posts: 944
Location: UK

PostPosted: Wed Jul 14, 2010 6:27 pm    Post subject: Reply with quote

DP sends bsp ents to all clients regardless of VIS info, last I heard.
So no chance that it can flicker.
Other engines don't quite calculate the absmin/absmax correctly (excessively large), and then drop the ent as it is in half the map (so in too many leafs).
Basically.
_________________
What's a signature?
Back to top
View user's profile Send private message Visit poster's website
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Wed Jul 14, 2010 6:28 pm    Post subject: Reply with quote

Could you upload a progs and a sample map so the problem can be examined first hand?
_________________
Tomorrow Never Dies. I feel this Tomorrow knocking on the door ...
Back to top
View user's profile Send private message
mh



Joined: 12 Jan 2008
Posts: 910

PostPosted: Wed Jul 14, 2010 6:36 pm    Post subject: Reply with quote

I fixed this in DirectQ a while back, and - if I'm guessing right - you're on the right track with the entity being in too many leafs. Basically what happens is that leafs not in the PVS fill up the allocation of 16 leaf slots that an entity can be in, so it doesn't get sent.

The stock code (SV_WriteEntitiesToClient in sv_main.c, taken from Fitz so it should be relevant to your engine) looks something like:
Code:
         // ignore if not touching a PV leaf
         for (i=0 ; i < ent->num_leafs ; i++)
            if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
               break;
         if (i == ent->num_leafs)
            continue;      // not visible

My replacement looks like:
Code:
         // link to PVS leafs - deferred to here so that we can compare leafs that are touched to the PVS.
         // this is less optimal on one hand as it now needs to be done separately for each client, rather than once
         // only (covering all clients), but more optimal on the other as it only needs to hit one leaf and will
         // start dropping out of the recursion as soon as it does so.  on balance it should be more optimal overall.
         ent->touchleaf = false;
         SV_FindTouchedLeafs (ent, sv.worldmodel->brushhdr->nodes, pvs);

         // if the entity didn't touch any leafs in the pvs don't send it to the client
         if (!ent->touchleaf && !sv_novis.integer)
         {
            //NumCulledEnts++;
            continue;
         }

With my SV_FindTouchedLeafs looking like:
Code:
/*
===============
SV_FindTouchedLeafs

moved to here, deferred find until we hit actual sending to client, and
added test vs client pvs in finding.

note - if directq is being used as a server, this may increase the server processing
===============
*/
void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node, byte *pvs)
{
   mplane_t   *splitplane;
   int         sides;
   int         leafnum;

loc0:;
   // ent already touches a leaf
   if (ent->touchleaf) return;

   // hit solid
   if (node->contents == CONTENTS_SOLID) return;

   // add an efrag if the node is a leaf
   // this is used for sending ents to the client so it needs to stay
   if (node->contents < 0)
   {
loc1:;
      leafnum = ((mleaf_t *) node) - sv.worldmodel->brushhdr->leafs - 1;

      if ((pvs[leafnum >> 3] & (1 << (leafnum & 7))) || sv_novis.integer)
         ent->touchleaf = true;

      return;
   }

   // NODE_MIXED
   splitplane = node->plane;
   sides = BOX_ON_PLANE_SIDE (ent->v.absmin, ent->v.absmax, splitplane);

   // recurse down the contacted sides, start dropping out if we hit anything
   if ((sides & 1) && !ent->touchleaf && node->children[0]->contents != CONTENTS_SOLID)
   {
      if (!(sides & 2) && node->children[0]->contents < 0)
      {
         node = node->children[0];
         goto loc1;
      }
      else if (!(sides & 2))
      {
         node = node->children[0];
         goto loc0;
      }
      else SV_FindTouchedLeafs (ent, node->children[0], pvs);
   }

   if ((sides & 2) && !ent->touchleaf && node->children[1]->contents != CONTENTS_SOLID)
   {
      // test for a leaf and drop out if so, otherwise it's a node so go round again
      node = node->children[1];

      if (node->contents < 0)
         goto loc1;
      else goto loc0;   // SV_FindTouchedLeafs (ent, node, pvs);
   }
}

The old SV_FindTouchedLeafs in world.c (and the call to it in SV_LinkEdict) is then removed from the codebase.

A more quick and dirty solution would be to increase the define of MAX_ENT_LEAFS to something like 32, but you're going to get some extra memory usage overhead from that.
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines


Last edited by mh on Wed Jul 14, 2010 10:33 pm; edited 1 time in total
Back to top
View user's profile Send private message Visit poster's website
Spike



Joined: 05 Nov 2004
Posts: 944
Location: UK

PostPosted: Wed Jul 14, 2010 6:54 pm    Post subject: Reply with quote

q2 tracks the headnode when it overflows.
though alternatively just set some flag that says 'too many' and just ignore which nodes its in.
_________________
What's a signature?
Back to top
View user's profile Send private message Visit poster's website
goldenboy



Joined: 05 Sep 2008
Posts: 310
Location: Kiel

PostPosted: Wed Jul 14, 2010 7:07 pm    Post subject: Reply with quote

Right, first off thanks you guys for being so helpful. It's cool knowing you.

This bridge has quietly waited for two years until the day we would finally have proper rotation... now we have, and it's rotating brilliantly (even properly textured, which seems odd and might be coincidence), only to be intercepted by the next problem Razz ah well, that is life.

OK. I tried the quick and dirty way that mh suggested first. I had to raise MAX_ENT_LEAFS to 128 before it worked in the fullvised map. But yeah, that does fix it.

So it can be fixed. I'll try mh's cleaner solution next.

Baker, I'll mail it to you. It's a key section of an RMQ map, so I'd rather not link it atm, but I'll send it to any engine coder who's interested. Makes a good test case I guess.

Quote:
DP sends bsp ents to all clients regardless of VIS info, last I heard.


That sounds like the cleanest possible solution, but it's probably above my skill level to implement that. I only have a basic understanding of the things involved. Engine coding is only done to get maps running in my case. Smile
_________________
ReMakeQuake
The Realm of Blog Magic
Back to top
View user's profile Send private message
Spike



Joined: 05 Nov 2004
Posts: 944
Location: UK

PostPosted: Wed Jul 14, 2010 7:12 pm    Post subject: Reply with quote

From memory, halflife raised the limit to 64. The cheats. :P
_________________
What's a signature?
Back to top
View user's profile Send private message Visit poster's website
mh



Joined: 12 Jan 2008
Posts: 910

PostPosted: Wed Jul 14, 2010 7:15 pm    Post subject: Reply with quote

I wouldn't mind a copy of it, just to test that my fix actually does work with it, before you make any changes to your own engine.

(deleted stuff that wasn't actually needed; mental note to self: read the original code first!!! Embarassed )

Also note the nifty "sv_novis" cvar. Wink
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines


Last edited by mh on Wed Jul 14, 2010 9:50 pm; edited 1 time in total
Back to top
View user's profile Send private message Visit poster's website
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Wed Jul 14, 2010 7:41 pm    Post subject: Reply with quote

goldenboy wrote:
That sounds like the cleanest possible solution, but it's probably above my skill level to implement that.


My bsp understanding is limited, but I'd guess it is probably just commenting out this in SV_WriteEntitiesToClient in sv_main.c

Code:
         for (i=0 ; i < ent->num_leafs ; i++)
            if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
               break;

         if (i == ent->num_leafs)
            continue;      // not visible


mh wrote:
Also note the nifty "sv_novis" cvar. Wink


Hmmm Very Happy
_________________
Tomorrow Never Dies. I feel this Tomorrow knocking on the door ...
Back to top
View user's profile Send private message
mh



Joined: 12 Jan 2008
Posts: 910

PostPosted: Wed Jul 14, 2010 7:50 pm    Post subject: Reply with quote

It's BSP entities only isn't it, so you'd need to get the model name (something like pr_strings + ent->v.model), check if the first char is '*', then ignore the PVS test if so.

It's a solution to this problem for sure, but one I'd be dubious about as there is a possibility of alias or instanced brush models also being big enough enough to need a fix. Add enough models to the mix, take a map that's well stocked with even just inline brush models (like ne_tower for example) and you're entering a world of hurt. I just prefer the more general fix, it seems cleaner overall.

Edit: my code works with this one.
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
goldenboy



Joined: 05 Sep 2008
Posts: 310
Location: Kiel

PostPosted: Wed Jul 14, 2010 9:48 pm    Post subject: Reply with quote

Confirmed, adapted mh's fix to FitzSDL/QS/RMQ engine. Works like a charm. Giant rotating bmodels, here I come.
_________________
ReMakeQuake
The Realm of Blog Magic
Back to top
View user's profile Send private message
mh



Joined: 12 Jan 2008
Posts: 910

PostPosted: Wed Jul 14, 2010 10:19 pm    Post subject: Reply with quote

Oddly enough, it also works perfectly with Enhanced GLQuake (aguirRe's engine) and he doesn't seem to have done anything to particularly fix this one - although I haven't looked too far yet. It does suffer from a "keyname too long" Sys_Error when parsing globals though, on account of the fact that he reduced the max key name length to 32 (from 64).
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
goldenboy



Joined: 05 Sep 2008
Posts: 310
Location: Kiel

PostPosted: Wed Jul 14, 2010 11:20 pm    Post subject: Reply with quote

Yeah, but I guess it doesn't rotate there.

There is also no flicker when the offending thing is turned into a simple func_wall.

The problem only appears if the thing rotates, and the engine actually supports the rotation, I think.
_________________
ReMakeQuake
The Realm of Blog Magic
Back to top
View user's profile Send private message
mh



Joined: 12 Jan 2008
Posts: 910

PostPosted: Wed Jul 14, 2010 11:25 pm    Post subject: Reply with quote

Of course, you're right (and you had mentioned it before now that I check back).
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
Spike



Joined: 05 Nov 2004
Posts: 944
Location: UK

PostPosted: Wed Jul 14, 2010 11:47 pm    Post subject: Reply with quote

Quote:

if (ent->v.solid == SOLID_BSP &&
(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) )
{ // expand for rotation
float max, v;
int i;

max = 0;
for (i=0 ; i<3 ; i++)
{
v =fabs( ent->v.mins[i]);
if (v > max)
max = v;
v =fabs( ent->v.maxs[i]);
if (v > max)
max = v;
}
for (i=0 ; i<3 ; i++)
{
ent->v.absmin[i] = ent->v.origin[i] - max;
ent->v.absmax[i] = ent->v.origin[i] + max;
}
}


that code will pick the biggest axis and assume that all are that large.
On a long thin (bridge) thing, your absmin/absmax is huuuge. It also extends up and down too, by the same distance...
This is even worse if you didn't change the origin in qbsp.

This is why a func_wall is fine, but anything bsp with rotation will flicker, and also why you need so many leafs.
_________________
What's a signature?
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Inside3d Forums Forum Index -> Programming Tutorials All times are GMT
Goto page Previous  1, 2, 3, 4, 5  Next
Page 2 of 5

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2004 phpBB Group