- fixed a major clipping issue with the new renderer.

* the bunch drawer can at most process an angular range of 180°. If this gets exceeded it can run into wraparound issues that may cause holes in the geometry.
* there was no clipping to the current field of view so it always checked the full 360°.
This commit is contained in:
Christoph Oelckers 2021-04-07 00:02:36 +02:00
parent d823ae255e
commit 3d846f341a
3 changed files with 55 additions and 36 deletions

View file

@ -49,8 +49,10 @@
//
//==========================================================================
void BunchDrawer::Init(HWDrawInfo *_di, Clipper* c, vec2_t& view)
void BunchDrawer::Init(HWDrawInfo *_di, Clipper* c, vec2_t& view, binangle a1, binangle a2)
{
ang1 = a1;
ang2 = a2;
di = _di;
clipper = c;
viewx = view.x * (1/ 16.f);
@ -83,6 +85,7 @@ void BunchDrawer::StartScene()
Bunches.Clear();
CompareData.Clear();
gotsector.Zero();
gotwall.Zero();
}
//==========================================================================
@ -232,8 +235,9 @@ void BunchDrawer::ProcessBunch(int bnch)
{
show2dwall.Set(i);
//if (gl_render_walls)
if (!gotwall[i])
{
gotwall.Set(i);
ClipWall.Unclock();
Bsp.Unclock();
SetupWall.Clock();
@ -480,36 +484,25 @@ void BunchDrawer::ProcessSector(int sectnum, bool portal)
DVector2 start = { WallStartX(thiswall), WallStartY(thiswall) };
DVector2 end = { WallStartX(thiswall->point2), WallStartY(thiswall->point2) };
#endif
binangle ang1 = thiswall->clipangle;
binangle ang2 = wall[thiswall->point2].clipangle;
binangle walang1 = thiswall->clipangle;
binangle walang2 = wall[thiswall->point2].clipangle;
if (ang1.asbam() - ang2.asbam() < ANGLE_180)
// outside the visible area or seen from the backside.
if ((walang1.asbam() - ang1.asbam() > ANGLE_180 && walang2.asbam() - ang1.asbam() > ANGLE_180) ||
(walang1.asbam() - ang2.asbam() < ANGLE_180 && walang2.asbam() - ang2.asbam() < ANGLE_180) ||
(walang1.asbam() - walang2.asbam() < ANGLE_180))
{
// Backside
inbunch = false;
}
/* disabled because it only fragments the bunches without any performance gain.
else if (!clipper->SafeCheckRange(ang1, ang2))
else if (!inbunch)
{
// is it visible?
inbunch = false;
}
*/
else if (!inbunch || ang2.asbam() - startangle.asbam() >= ANGLE_180)
{
// don't let a bunch span more than 180° to avoid problems.
// This limitation ensures that the combined range of 2
// bunches will always be less than 360° which simplifies
// the distance comparison code because it prevents a
// situation where 2 bunches may overlap at both ends.
startangle = ang1;
StartBunch(sectnum, sect->wallptr + i, ang1, ang2, portal);
startangle = walang1;
StartBunch(sectnum, sect->wallptr + i, walang1, walang2, portal);
inbunch = true;
}
else
{
AddLineToBunch(sect->wallptr + i, ang2);
AddLineToBunch(sect->wallptr + i, walang2);
}
if (thiswall->point2 != sect->wallptr + i + 1) inbunch = false;
}
@ -523,14 +516,35 @@ void BunchDrawer::ProcessSector(int sectnum, bool portal)
void BunchDrawer::RenderScene(const int* viewsectors, unsigned sectcount, bool portal)
{
Bsp.Clock();
for(unsigned i=0;i<sectcount;i++)
ProcessSector(viewsectors[i], portal);
while (Bunches.Size() > 0)
auto process = [&]()
{
int closest = FindClosestBunch();
ProcessBunch(closest);
DeleteBunch(closest);
for (unsigned i = 0; i < sectcount; i++)
ProcessSector(viewsectors[i], portal);
while (Bunches.Size() > 0)
{
int closest = FindClosestBunch();
ProcessBunch(closest);
DeleteBunch(closest);
}
};
Bsp.Clock();
if (ang1.asbam() != 0 || ang2.asbam() != 0)
{
process();
}
else
{
// with a 360° field of view we need to split the scene into two halves.
// The BunchInFront check can fail with angles that may wrap around.
auto rotang = di->Viewpoint.RotAngle;
ang1 = bamang(rotang - ANGLE_90);
ang2 = bamang(rotang + ANGLE_90);
process();
clipper->Clear();
ang1 = bamang(rotang + ANGLE_90);
ang2 = bamang(rotang - ANGLE_90);
process();
}
Bsp.Unclock();
}

View file

@ -28,6 +28,8 @@ class BunchDrawer
vec2_t iview;
float gcosang, gsinang;
FixedBitArray<MAXSECTORS> gotsector;
FixedBitArray<MAXWALLS> gotwall;
binangle ang1, ang2;
private:
@ -51,7 +53,7 @@ private:
void ProcessSector(int sectnum, bool portal);
public:
void Init(HWDrawInfo* _di, Clipper* c, vec2_t& view);
void Init(HWDrawInfo* _di, Clipper* c, vec2_t& view, binangle a1, binangle a2);
void RenderScene(const int* viewsectors, unsigned sectcount, bool portal);
const FixedBitArray<MAXSECTORS>& GotSector() const { return gotsector; }
};

View file

@ -211,7 +211,7 @@ angle_t HWDrawInfo::FrustumAngle()
// but at least it doesn't overestimate too much...
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*Viewpoint.FieldOfView.Degrees*48.0 / AspectMultiplier(WidescreenRatio) / 90.0;
angle_t a1 = DAngle(floatangle).BAMs();
if (a1 >= ANGLE_180) return 0xffffffff;
if (a1 >= ANGLE_90) return 0xffffffff; // it's either below 90 or bust.
return a1;
}
@ -369,7 +369,7 @@ void HWDrawInfo::CreateScene(bool portal)
const auto& vp = Viewpoint;
angle_t a1 = FrustumAngle();
mClipper->SafeAddClipRange(bamang(vp.RotAngle + a1), bamang(vp.RotAngle - a1));
if (a1 != 0xffffffff) mClipper->SafeAddClipRange(bamang(vp.RotAngle + a1), bamang(vp.RotAngle - a1));
// reset the portal manager
portalState.StartFrame();
@ -385,7 +385,8 @@ void HWDrawInfo::CreateScene(bool portal)
geoofs = { 0,0 };
vec2_t view = { int(vp.Pos.X * 16), int(vp.Pos.Y * -16) };
mDrawer.Init(this, mClipper, view);
if (a1 != 0xffffffff) mDrawer.Init(this, mClipper, view, bamang(vp.RotAngle - a1), bamang(vp.RotAngle + a1));
else mDrawer.Init(this, mClipper, view, bamang(0), bamang(0));
if (vp.SectNums)
mDrawer.RenderScene(vp.SectNums, vp.SectCount, portal);
else
@ -421,7 +422,8 @@ void HWDrawInfo::CreateScene(bool portal)
mClipper->Clear();
mClipper->SafeAddClipRange(bamang(vp.RotAngle + a1), bamang(vp.RotAngle - a1));
mDrawer.Init(this, mClipper, view);
if (a1 != 0xffffffff) mDrawer.Init(this, mClipper, view, bamang(vp.RotAngle - a1), bamang(vp.RotAngle + a1));
else mDrawer.Init(this, mClipper, view, bamang(0), bamang(0));
mDrawer.RenderScene(&drawsect, 1, false);
for (int i = 0; i < eff.geocnt; i++)
@ -452,7 +454,8 @@ void HWDrawInfo::CreateScene(bool portal)
mClipper->Clear();
mClipper->SafeAddClipRange(bamang(vp.RotAngle + a1), bamang(vp.RotAngle - a1));
mDrawer.Init(this, mClipper, view);
if (a1 != 0xffffffff) mDrawer.Init(this, mClipper, view, bamang(vp.RotAngle - a1), bamang(vp.RotAngle + a1));
else mDrawer.Init(this, mClipper, view, bamang(0), bamang(0));
mDrawer.RenderScene(&drawsect, 1, false);
for (int i = 0; i < eff.geocnt; i++)