From 8bbb63e91328d37a0f3df8240a7c089f25f03eb5 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 26 Nov 2016 09:01:58 +0100 Subject: [PATCH] Add portal plane clipping --- src/r_poly.cpp | 2 +- src/r_poly_cull.cpp | 12 +++++++++++- src/r_poly_cull.h | 3 ++- src/r_poly_intersection.h | 11 +++++++++++ src/r_poly_portal.cpp | 16 ++++++++++++---- src/r_poly_portal.h | 3 ++- 6 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/r_poly.cpp b/src/r_poly.cpp index 729774174..b262ca01d 100644 --- a/src/r_poly.cpp +++ b/src/r_poly.cpp @@ -44,7 +44,7 @@ void RenderPolyScene::Render() ClearBuffers(); SetSceneViewport(); SetupPerspectiveMatrix(); - MainPortal.SetViewpoint(WorldToClip, GetNextStencilValue()); + MainPortal.SetViewpoint(WorldToClip, Vec4f(0.0f), GetNextStencilValue()); MainPortal.Render(0); Skydome.Render(WorldToClip); MainPortal.RenderTranslucent(0); diff --git a/src/r_poly_cull.cpp b/src/r_poly_cull.cpp index 04d5c3c24..37ddf9103 100644 --- a/src/r_poly_cull.cpp +++ b/src/r_poly_cull.cpp @@ -28,11 +28,12 @@ #include "r_poly_cull.h" #include "r_poly.h" -void PolyCull::CullScene(const TriMatrix &worldToClip) +void PolyCull::CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPlane) { ClearSolidSegments(); PvsSectors.clear(); frustumPlanes = FrustumPlanes(worldToClip); + PortalClipPlane = portalClipPlane; // Cull front to back MaxCeilingHeight = 0.0; @@ -174,6 +175,11 @@ bool PolyCull::CheckBBox(float *bspcoord) if (result == IntersectionTest::outside) return false; + // Skip if its in front of the portal: + + if (PortalClipPlane != Vec4f(0.0f) && IntersectionTest::plane_aabb(PortalClipPlane, aabb) == IntersectionTest::outside) + return false; + // Occlusion test using solid segments: static const int lines[4][4] = @@ -219,6 +225,10 @@ bool PolyCull::GetSegmentRangeForLine(double x1, double y1, double x2, double y2 { double znear = 5.0; + // Cull if entirely behind the portal clip plane (tbd: should we clip the segment?) + if (Vec4f::dot(PortalClipPlane, Vec4f((float)x1, (float)y1, 0.0f, 1.0f)) < 0.0f && Vec4f::dot(PortalClipPlane, Vec4f((float)x2, (float)y2, 0.0f, 1.0f)) < 0.0f) + return false; + // Transform to 2D view space: x1 = x1 - ViewPos.X; y1 = y1 - ViewPos.Y; diff --git a/src/r_poly_cull.h b/src/r_poly_cull.h index e011ef583..f1fe56ed5 100644 --- a/src/r_poly_cull.h +++ b/src/r_poly_cull.h @@ -28,7 +28,7 @@ class PolyCull { public: - void CullScene(const TriMatrix &worldToClip); + void CullScene(const TriMatrix &worldToClip, const Vec4f &portalClipPlane); bool GetSegmentRangeForLine(double x1, double y1, double x2, double y2, int &sx1, int &sx2) const; void MarkSegmentCulled(int x1, int x2); @@ -59,4 +59,5 @@ private: const int SolidCullScale = 3000; FrustumPlanes frustumPlanes; + Vec4f PortalClipPlane; }; diff --git a/src/r_poly_intersection.h b/src/r_poly_intersection.h index b06bc1200..2ce164e5e 100644 --- a/src/r_poly_intersection.h +++ b/src/r_poly_intersection.h @@ -26,6 +26,8 @@ #include #include +class Vec3f; + class Vec4f { public: @@ -33,6 +35,7 @@ public: Vec4f(const Vec4f &) = default; Vec4f(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) { } Vec4f(float v) : x(v), y(v), z(v), w(v) { } + Vec4f(const Vec3f &xyz, float w); static float dot(const Vec4f &a, const Vec4f &b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } static float dot3(const Vec4f &a, const Vec4f &b) { return a.x * b.x + a.y * b.y + a.z * b.z; } @@ -51,6 +54,9 @@ public: float x, y, z, w; }; +inline bool operator==(const Vec4f &a, const Vec4f &b) { return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; } +inline bool operator!=(const Vec4f &a, const Vec4f &b) { return a.x != b.x || a.y != b.y || a.z != b.z || a.w == b.w; } + class Vec3f { public: @@ -75,6 +81,9 @@ public: float x, y, z; }; +inline bool operator==(const Vec3f &a, const Vec3f &b) { return a.x == b.x && a.y == b.y && a.z == b.z; } +inline bool operator!=(const Vec3f &a, const Vec3f &b) { return a.x != b.x || a.y != b.y || a.z != b.z; } + inline Vec3f operator+(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x + b.x, a.y + b.y, a.z + b.z); } inline Vec3f operator-(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x - b.x, a.y - b.y, a.z - b.z); } inline Vec3f operator*(const Vec3f &a, const Vec3f &b) { return Vec3f(a.x * b.x, a.y * b.y, a.z * b.z); } @@ -90,6 +99,8 @@ inline Vec3f operator-(float a, const Vec3f &b) { return Vec3f(a - b.x, a - b.y, inline Vec3f operator*(float a, const Vec3f &b) { return Vec3f(a * b.x, a * b.y, a * b.z); } inline Vec3f operator/(float a, const Vec3f &b) { return Vec3f(a / b.x, a / b.y, a / b.z); } +inline Vec4f::Vec4f(const Vec3f &xyz, float w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } + typedef TriMatrix Mat4f; class AxisAlignedBoundingBox diff --git a/src/r_poly_portal.cpp b/src/r_poly_portal.cpp index 715d47582..757285d77 100644 --- a/src/r_poly_portal.cpp +++ b/src/r_poly_portal.cpp @@ -45,16 +45,17 @@ RenderPolyPortal::~RenderPolyPortal() { } -void RenderPolyPortal::SetViewpoint(const TriMatrix &worldToClip, uint32_t stencilValue) +void RenderPolyPortal::SetViewpoint(const TriMatrix &worldToClip, const Vec4f &portalPlane, uint32_t stencilValue) { WorldToClip = worldToClip; StencilValue = stencilValue; + PortalPlane = portalPlane; } void RenderPolyPortal::Render(int portalDepth) { ClearBuffers(); - Cull.CullScene(WorldToClip); + Cull.CullScene(WorldToClip, PortalPlane); RenderSectors(); RenderPortals(portalDepth); } @@ -340,7 +341,7 @@ void PolyDrawSectorPortal::Render(int portalDepth) TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z); TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView; - RenderPortal.SetViewpoint(worldToClip, StencilValue); + RenderPortal.SetViewpoint(worldToClip, Vec4f(0.0f), StencilValue); RenderPortal.Render(portalDepth); RestoreGlobals(); @@ -440,7 +441,14 @@ void PolyDrawLinePortal::Render(int portalDepth) TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z); TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView; - RenderPortal.SetViewpoint(worldToClip, StencilValue); + // Calculate plane clipping + DVector2 planePos = Portal->mDestination->v1->fPos(); + DVector2 planeNormal = (Portal->mDestination->v2->fPos() - Portal->mDestination->v1->fPos()).Rotated90CW(); + planeNormal.MakeUnit(); + double planeD = -(planeNormal | (planePos + planeNormal * 5.0)); + Vec4f portalPlane((float)planeNormal.X, (float)planeNormal.Y, 0.0f, (float)planeD); + + RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue); RenderPortal.Render(portalDepth); RestoreGlobals(); diff --git a/src/r_poly_portal.h b/src/r_poly_portal.h index 56a125d2c..e2b131b32 100644 --- a/src/r_poly_portal.h +++ b/src/r_poly_portal.h @@ -83,7 +83,7 @@ class RenderPolyPortal public: RenderPolyPortal(); ~RenderPolyPortal(); - void SetViewpoint(const TriMatrix &worldToClip, uint32_t stencilValue); + void SetViewpoint(const TriMatrix &worldToClip, const Vec4f &portalPlane, uint32_t stencilValue); void Render(int portalDepth); void RenderTranslucent(int portalDepth); @@ -99,6 +99,7 @@ private: SpriteRange GetSpritesForSector(sector_t *sector); TriMatrix WorldToClip; + Vec4f PortalPlane; uint32_t StencilValue = 0; PolyCull Cull; uint32_t NextSubsectorDepth = 0;