diff --git a/src/rendering/hwrenderer/scene/hw_fakeflat.cpp b/src/rendering/hwrenderer/scene/hw_fakeflat.cpp index fe8525138..3d0015e0e 100644 --- a/src/rendering/hwrenderer/scene/hw_fakeflat.cpp +++ b/src/rendering/hwrenderer/scene/hw_fakeflat.cpp @@ -35,6 +35,7 @@ #include "hw_drawinfo.h" #include "hw_cvars.h" #include "hw_drawcontext.h" +#include "hw_visibleset.h" #include "r_utility.h" #include "texturemanager.h" @@ -46,7 +47,7 @@ extern thread_local bool isWorkerThread; // //========================================================================== -bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector) +bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector, CameraFrustum* frustum) { line_t *linedef = sidedef->linedef; double bs_floorheight1; @@ -155,6 +156,25 @@ bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsecto return true; } + if (frustum) + { + // Is the line visible by the camera's clip frustum? + DVector3 p0(linedef->v1->fX(), std::min(bs_ceilingheight1, fs_ceilingheight1), linedef->v1->fY()); + DVector3 p1(linedef->v2->fX(), std::min(bs_ceilingheight2, fs_ceilingheight2), linedef->v2->fY()); + DVector3 p2(linedef->v1->fX(), std::max(bs_floorheight1, fs_floorheight1), linedef->v1->fY()); + DVector3 p3(linedef->v2->fX(), std::max(bs_floorheight2, fs_floorheight2), linedef->v2->fY()); + DVector3 aabbMin = p0; + DVector3 aabbMax = p0; + aabbMin.X = std::min(aabbMin.X, p1.X); aabbMin.Y = std::min(aabbMin.Y, p1.Y); aabbMin.Z = std::min(aabbMin.Z, p1.Z); + aabbMax.X = std::max(aabbMax.X, p1.X); aabbMax.Y = std::max(aabbMax.Y, p1.Y); aabbMax.Z = std::max(aabbMax.Z, p1.Z); + aabbMin.X = std::min(aabbMin.X, p2.X); aabbMin.Y = std::min(aabbMin.Y, p2.Y); aabbMin.Z = std::min(aabbMin.Z, p2.Z); + aabbMax.X = std::max(aabbMax.X, p2.X); aabbMax.Y = std::max(aabbMax.Y, p2.Y); aabbMax.Z = std::max(aabbMax.Z, p2.Z); + aabbMin.X = std::min(aabbMin.X, p3.X); aabbMin.Y = std::min(aabbMin.Y, p3.Y); aabbMin.Z = std::min(aabbMin.Z, p3.Z); + aabbMax.X = std::max(aabbMax.X, p3.X); aabbMax.Y = std::max(aabbMax.Y, p3.Y); aabbMax.Z = std::max(aabbMax.Z, p3.Z); + if (!frustum->IsAABBVisible(aabbMin, aabbMax)) + return true; + } + return false; } diff --git a/src/rendering/hwrenderer/scene/hw_fakeflat.h b/src/rendering/hwrenderer/scene/hw_fakeflat.h index fdecdf253..2b9859998 100644 --- a/src/rendering/hwrenderer/scene/hw_fakeflat.h +++ b/src/rendering/hwrenderer/scene/hw_fakeflat.h @@ -10,8 +10,10 @@ enum area_t : int area_default }; +struct CameraFrustum; + // Global functions. -bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector); +bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsector, CameraFrustum* frustum = nullptr); void hw_ClearFakeFlat(HWDrawContext* drawctx); sector_t * hw_FakeFlat(HWDrawContext* drawctx, sector_t * sec, area_t in_area, bool back, sector_t *localcopy = nullptr); area_t hw_CheckViewArea(vertex_t *v1, vertex_t *v2, sector_t *frontsector, sector_t *backsector); diff --git a/src/rendering/hwrenderer/scene/hw_visibleset.cpp b/src/rendering/hwrenderer/scene/hw_visibleset.cpp index c760c36b2..10ce5b464 100644 --- a/src/rendering/hwrenderer/scene/hw_visibleset.cpp +++ b/src/rendering/hwrenderer/scene/hw_visibleset.cpp @@ -52,6 +52,10 @@ void HWVisibleSet::FindPVS(HWDrawInfo* di, int sliceIndex, int sliceCount) in_area = di->in_area; mClipPortal = di->mClipPortal; + VSMatrix m = di->VPUniforms.mProjectionMatrix; + m.multMatrix(di->VPUniforms.mViewMatrix); + ClipFrustum.Set(m); + CurrentMapSections = &di->CurrentMapSections; no_renderflags = TArrayView(di->no_renderflags.data(), di->no_renderflags.size()); @@ -381,7 +385,7 @@ void HWVisibleSet::AddLine(seg_t* seg, bool portalclip) backsector = hw_FakeFlat(&drawctx, seg->backsector, in_area, true); - if (hw_CheckClip(seg->sidedef, currentsector, backsector)) + if (hw_CheckClip(seg->sidedef, currentsector, backsector, &ClipFrustum)) { clipper.SafeAddClipRange(startAngle, endAngle); } @@ -653,3 +657,91 @@ void HWVisibleSetThreads::WorkerMain(int sliceIndex) WorkCondvar.wait(lock); } } + +///////////////////////////////////////////////////////////////////////////// + +void CameraFrustum::Set(const VSMatrix& worldToProjection) +{ + Planes[0] = LeftFrustum(worldToProjection); + Planes[1] = TopFrustum(worldToProjection); + Planes[2] = RightFrustum(worldToProjection); + Planes[3] = BottomFrustum(worldToProjection); + Planes[4] = NearFrustum(worldToProjection); + Planes[5] = FarFrustum(worldToProjection); + + for (int i = 0; i < 6; i++) + { + AbsPlaneNormals[i] = Planes[i].XYZ(); + AbsPlaneNormals[i].X = std::abs(AbsPlaneNormals[i].X); + AbsPlaneNormals[i].Y = std::abs(AbsPlaneNormals[i].Y); + AbsPlaneNormals[i].Z = std::abs(AbsPlaneNormals[i].Z); + } +} + +DVector4 CameraFrustum::LeftFrustum(const VSMatrix& matrix) +{ + return Normalize(DVector4( + matrix.mMatrix[3 + 0 * 4] + matrix.mMatrix[0 + 0 * 4], + matrix.mMatrix[3 + 1 * 4] + matrix.mMatrix[0 + 1 * 4], + matrix.mMatrix[3 + 2 * 4] + matrix.mMatrix[0 + 2 * 4], + matrix.mMatrix[3 + 3 * 4] + matrix.mMatrix[0 + 3 * 4])); +} + +DVector4 CameraFrustum::RightFrustum(const VSMatrix& matrix) +{ + return Normalize(DVector4( + matrix.mMatrix[3 + 0 * 4] - matrix.mMatrix[0 + 0 * 4], + matrix.mMatrix[3 + 1 * 4] - matrix.mMatrix[0 + 1 * 4], + matrix.mMatrix[3 + 2 * 4] - matrix.mMatrix[0 + 2 * 4], + matrix.mMatrix[3 + 3 * 4] - matrix.mMatrix[0 + 3 * 4])); +} + +DVector4 CameraFrustum::TopFrustum(const VSMatrix& matrix) +{ + return Normalize(DVector4( + matrix.mMatrix[3 + 0 * 4] - matrix.mMatrix[1 + 0 * 4], + matrix.mMatrix[3 + 1 * 4] - matrix.mMatrix[1 + 1 * 4], + matrix.mMatrix[3 + 2 * 4] - matrix.mMatrix[1 + 2 * 4], + matrix.mMatrix[3 + 3 * 4] - matrix.mMatrix[1 + 3 * 4])); +} + +DVector4 CameraFrustum::BottomFrustum(const VSMatrix& matrix) +{ + return Normalize(DVector4( + matrix.mMatrix[3 + 0 * 4] + matrix.mMatrix[1 + 0 * 4], + matrix.mMatrix[3 + 1 * 4] + matrix.mMatrix[1 + 1 * 4], + matrix.mMatrix[3 + 2 * 4] + matrix.mMatrix[1 + 2 * 4], + matrix.mMatrix[3 + 3 * 4] + matrix.mMatrix[1 + 3 * 4])); +} + +DVector4 CameraFrustum::NearFrustum(const VSMatrix& matrix) +{ + return Normalize(DVector4( + matrix.mMatrix[3 + 0 * 4] + matrix.mMatrix[2 + 0 * 4], + matrix.mMatrix[3 + 1 * 4] + matrix.mMatrix[2 + 1 * 4], + matrix.mMatrix[3 + 2 * 4] + matrix.mMatrix[2 + 2 * 4], + matrix.mMatrix[3 + 3 * 4] + matrix.mMatrix[2 + 3 * 4])); +} + +DVector4 CameraFrustum::FarFrustum(const VSMatrix& matrix) +{ + return Normalize(DVector4( + matrix.mMatrix[3 + 0 * 4] - matrix.mMatrix[2 + 0 * 4], + matrix.mMatrix[3 + 1 * 4] - matrix.mMatrix[2 + 1 * 4], + matrix.mMatrix[3 + 2 * 4] - matrix.mMatrix[2 + 2 * 4], + matrix.mMatrix[3 + 3 * 4] - matrix.mMatrix[2 + 3 * 4])); +} + +DVector4 CameraFrustum::Normalize(DVector4 v) +{ + double length = std::sqrt(v.XYZ() | v.XYZ()); + if (length > DBL_EPSILON) + { + double rcpLength = 1.0 / length; + v.X *= rcpLength; + v.Y *= rcpLength; + v.Z *= rcpLength; + v.W *= rcpLength; + } + return v; +} diff --git a/src/rendering/hwrenderer/scene/hw_visibleset.h b/src/rendering/hwrenderer/scene/hw_visibleset.h index e8d504aa2..d2d92c79a 100644 --- a/src/rendering/hwrenderer/scene/hw_visibleset.h +++ b/src/rendering/hwrenderer/scene/hw_visibleset.h @@ -13,6 +13,50 @@ class Clipper; class HWPortal; struct HWDrawInfo; +struct CameraFrustum +{ + void Set(const VSMatrix& worldToProjection); + + bool IsSphereVisible(const DVector3& point, double radius) const + { + for (int i = 0; i < 6; i++) + { + if ((Planes[i].XYZ() | point) < -radius) + return false; + } + return true; + } + + bool IsAABBVisible(const DVector3& aabbMin, const DVector3& aabbMax) const + { + DVector3 aabbCenter = (aabbMin + aabbMax) * 0.5; + DVector3 aabbExtents = (aabbMax - aabbMin) * 0.5; + for (int i = 0; i < 6; i++) + { + double distance = Planes[i] | DVector4(aabbCenter, 1.0); + double radius = AbsPlaneNormals[i] | aabbExtents; + bool outside = distance < -radius; + //bool inside = distance > radius; + //bool intersect = distance > -radius && distance < radius; + if (outside) + return false; + } + return true; + } + +private: + static DVector4 LeftFrustum(const VSMatrix& matrix); + static DVector4 RightFrustum(const VSMatrix& matrix); + static DVector4 TopFrustum(const VSMatrix& matrix); + static DVector4 BottomFrustum(const VSMatrix& matrix); + static DVector4 NearFrustum(const VSMatrix& matrix); + static DVector4 FarFrustum(const VSMatrix& matrix); + static DVector4 Normalize(DVector4 v); + + DVector3 AbsPlaneNormals[6]; + DVector4 Planes[6]; +}; + class HWVisibleSet { public: @@ -77,6 +121,7 @@ private: HWDrawContext drawctx; FLevelLocals* Level = nullptr; FRenderViewpoint Viewpoint; + CameraFrustum ClipFrustum; TArrayView no_renderflags; BitArray* CurrentMapSections = nullptr; TArray section_renderflags;