From 3d846f341a21f27002a716b90fac5529cb17954a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 7 Apr 2021 00:02:36 +0200 Subject: [PATCH] - fixed a major clipping issue with the new renderer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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°. --- .../core/rendering/scene/hw_bunchdrawer.cpp | 74 +++++++++++-------- source/core/rendering/scene/hw_bunchdrawer.h | 4 +- source/core/rendering/scene/hw_drawinfo.cpp | 13 ++-- 3 files changed, 55 insertions(+), 36 deletions(-) diff --git a/source/core/rendering/scene/hw_bunchdrawer.cpp b/source/core/rendering/scene/hw_bunchdrawer.cpp index 6c84a911c..95a520f36 100644 --- a/source/core/rendering/scene/hw_bunchdrawer.cpp +++ b/source/core/rendering/scene/hw_bunchdrawer.cpp @@ -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 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(); } diff --git a/source/core/rendering/scene/hw_bunchdrawer.h b/source/core/rendering/scene/hw_bunchdrawer.h index ae030bf3a..d72454cd5 100644 --- a/source/core/rendering/scene/hw_bunchdrawer.h +++ b/source/core/rendering/scene/hw_bunchdrawer.h @@ -28,6 +28,8 @@ class BunchDrawer vec2_t iview; float gcosang, gsinang; FixedBitArray gotsector; + FixedBitArray 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& GotSector() const { return gotsector; } }; diff --git a/source/core/rendering/scene/hw_drawinfo.cpp b/source/core/rendering/scene/hw_drawinfo.cpp index be7841bc0..196734a83 100644 --- a/source/core/rendering/scene/hw_drawinfo.cpp +++ b/source/core/rendering/scene/hw_drawinfo.cpp @@ -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++)