From 8a66eff437836ab87fc3a93630bfce48310c2e11 Mon Sep 17 00:00:00 2001 From: "Dileep V. Reddy" Date: Tue, 11 Feb 2025 19:51:21 -0700 Subject: [PATCH] Added visual rendering for LinePortals and SkyPortals for OoB viewpoints. SkyPortals will be stenciled, and will always use perspective projection. Disabled interpolation when portalgroup changes (portal transition occurs) if viewpoint is OoB (was necessary for fog of war when r_radarclipper is set to true). Tightened up radar clipper by making it more aggressive. Voided walls wont' get filled in by a floor or ceiling sky (because of the stencil). Ceiling sky will be half-infinitely tall upwards, and floor sky will be half-infinitely tall downwards. Use only floor skies and a good GLSKYBOX for top-down/isometric cameras. Level.ReplaceTextures("F_SKY1", "SKY1", TexMan.NOT_FLOOR); (zscript) is a nice trick for WorldLoaded(). --- src/rendering/hwrenderer/hw_entrypoint.cpp | 1 + src/rendering/hwrenderer/scene/hw_bsp.cpp | 75 ++++++----------- src/rendering/hwrenderer/scene/hw_clipper.cpp | 18 ++--- .../hwrenderer/scene/hw_drawinfo.cpp | 81 ++++++++++--------- src/rendering/hwrenderer/scene/hw_drawinfo.h | 1 + src/rendering/hwrenderer/scene/hw_portal.cpp | 24 ++++-- src/rendering/hwrenderer/scene/hw_portal.h | 4 +- src/rendering/hwrenderer/scene/hw_sky.cpp | 2 +- src/rendering/hwrenderer/scene/hw_walls.cpp | 2 - src/rendering/r_utility.cpp | 20 ++++- src/rendering/r_utility.h | 1 + 11 files changed, 118 insertions(+), 111 deletions(-) diff --git a/src/rendering/hwrenderer/hw_entrypoint.cpp b/src/rendering/hwrenderer/hw_entrypoint.cpp index e55c041a6..0252fbc40 100644 --- a/src/rendering/hwrenderer/hw_entrypoint.cpp +++ b/src/rendering/hwrenderer/hw_entrypoint.cpp @@ -167,6 +167,7 @@ sector_t* RenderViewpoint(FRenderViewpoint& mainvp, AActor* camera, IntRect* bou bool iso_ortho = (camera->ViewPos != NULL) && (camera->ViewPos->Flags & VPSF_ORTHOGRAPHIC); if (iso_ortho && (camera->ViewPos->Offset.Length() > 0)) inv_iso_dist = 1.0/camera->ViewPos->Offset.Length(); di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio * inv_iso_dist, iso_ortho); + di->ProjectionMatrix2 = eye.GetProjection(fov, ratio, fovratio, false); // Regular ol' perspective projection matrix // Stereo mode specific viewpoint adjustment vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees()); diff --git a/src/rendering/hwrenderer/scene/hw_bsp.cpp b/src/rendering/hwrenderer/scene/hw_bsp.cpp index 2c1abdf7c..ced71a6fa 100644 --- a/src/rendering/hwrenderer/scene/hw_bsp.cpp +++ b/src/rendering/hwrenderer/scene/hw_bsp.cpp @@ -287,15 +287,16 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) auto &clipperr = *rClipper; angle_t startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY()); angle_t endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY()); + angle_t paddingR = 0x00200000; // Make radar clipping more aggressive (reveal less) if(Viewpoint.IsAllowedOoB() && r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && (startAngleR - endAngleR >= ANGLE_180)) { - if (!seg->backsector) clipperr.SafeAddClipRange(startAngleR, endAngleR); + if (!seg->backsector) clipperr.SafeAddClipRange(startAngleR - paddingR, endAngleR + paddingR); else if((seg->sidedef != nullptr) && !uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ) && (currentsector->sectornum != seg->backsector->sectornum)) { if (in_area == area_default) in_area = hw_CheckViewArea(seg->v1, seg->v2, seg->frontsector, seg->backsector); backsector = hw_FakeFlat(seg->backsector, in_area, true); - if (hw_CheckClip(seg->sidedef, currentsector, backsector)) clipperr.SafeAddClipRange(startAngleR, endAngleR); + if (hw_CheckClip(seg->sidedef, currentsector, backsector)) clipperr.SafeAddClipRange(startAngleR - paddingR, endAngleR + paddingR); } } @@ -313,7 +314,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) { currentsubsector->flags |= SSECMF_DRAWN; } - if ((r_radarclipper || !(Level->flags3 & LEVEL3_NOFOGOFWAR)) && clipperr.SafeCheckRange(startAngleR, endAngleR)) + if (Viewpoint.IsAllowedOoB() && (r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR)) && clipperr.SafeCheckRange(startAngleR, endAngleR)) { currentsubsector->flags |= SSECMF_DRAWN; } @@ -326,31 +327,7 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) return; } - if (Viewpoint.IsAllowedOoB()) // No need for vertical clipping if viewpoint not allowed out of bounds - { - auto &clipperv = *vClipper; - angle_t startPitch = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), currentsector->floorplane.ZatPoint(seg->v1)); - angle_t endPitch = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), currentsector->ceilingplane.ZatPoint(seg->v1)); - angle_t startPitch2 = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), currentsector->floorplane.ZatPoint(seg->v2)); - angle_t endPitch2 = clipperv.PointToPseudoPitch(seg->v2->fX(), seg->v2->fY(), currentsector->ceilingplane.ZatPoint(seg->v2)); - angle_t temp; - // Wall can be tilted from viewpoint perspective. Find vertical extent on screen in psuedopitch units (0 to 2, bottom to top) - if(int(startPitch) > int(startPitch2)) // Handle zero crossing - { - temp = startPitch; startPitch = startPitch2; startPitch2 = temp; // exchange - } - if(int(endPitch) > int(endPitch2)) // Handle zero crossing - { - temp = endPitch; endPitch = endPitch2; endPitch2 = temp; // exchange - } - - if (!clipperv.SafeCheckRange(startPitch, endPitch2)) - { - return; - } - } - - if (!r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR) || clipperr.SafeCheckRange(startAngleR, endAngleR)) + if (Viewpoint.IsAllowedOoB() && (!r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR) || clipperr.SafeCheckRange(startAngleR, endAngleR))) currentsubsector->flags |= SSECMF_DRAWN; uint8_t ispoly = uint8_t(seg->sidedef->Flags & WALLF_POLYOBJ); @@ -729,8 +706,8 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) if(Viewpoint.IsAllowedOoB() && sector->isSecret() && sector->wasSecret() && !r_radarclipper) return; - // cull everything if subsector outside vertical clipper - if ((sub->polys == nullptr) && (!Viewpoint.IsOrtho() || !((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper))) + // cull everything if subsector outside all relevant clippers + if ((sub->polys == nullptr)) { auto &clipper = *mClipper; auto &clipperv = *vClipper; @@ -739,7 +716,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) seg_t * seg = sub->firstline; bool anglevisible = false; bool pitchvisible = !(Viewpoint.IsAllowedOoB()); // No vertical clipping if viewpoint is not allowed out of bounds - bool radarvisible = false; + bool radarvisible = !(Viewpoint.IsAllowedOoB()) || !r_radarclipper || (Level->flags3 & LEVEL3_NOFOGOFWAR) || ((sub->flags & SSECMF_DRAWN) && !deathmatch); angle_t pitchtemp; angle_t pitchmin = ANGLE_90; angle_t pitchmax = 0; @@ -748,13 +725,19 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) { if((seg->v1 != nullptr) && (seg->v2 != nullptr)) { - angle_t startAngle = clipper.GetClipAngle(seg->v2); - angle_t endAngle = clipper.GetClipAngle(seg->v1); - if (startAngle-endAngle >= ANGLE_180) anglevisible |= clipper.SafeCheckRange(startAngle, endAngle); - angle_t startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY()); - angle_t endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY()); - if (startAngleR-endAngleR >= ANGLE_180) - radarvisible |= (clipperr.SafeCheckRange(startAngleR, endAngleR) || (Level->flags3 & LEVEL3_NOFOGOFWAR) || ((sub->flags & SSECMF_DRAWN) && !deathmatch)); + if (!anglevisible) + { + angle_t startAngle = clipper.GetClipAngle(seg->v2); + angle_t endAngle = clipper.GetClipAngle(seg->v1); + if (startAngle-endAngle >= ANGLE_180) anglevisible |= clipper.SafeCheckRange(startAngle, endAngle); + } + if (!radarvisible) + { + angle_t startAngleR = clipperr.PointToPseudoAngle(seg->v2->fX(), seg->v2->fY()); + angle_t endAngleR = clipperr.PointToPseudoAngle(seg->v1->fX(), seg->v1->fY()); + if (startAngleR-endAngleR >= ANGLE_180) radarvisible |= clipperr.SafeCheckRange(startAngleR, endAngleR); + } + if (!pitchvisible) { pitchmin = clipperv.PointToPseudoPitch(seg->v1->fX(), seg->v1->fY(), sector->floorplane.ZatPoint(seg->v1)); @@ -988,8 +971,8 @@ void HWDrawInfo::RenderOrthoNoFog() { if (Viewpoint.IsOrtho() && ((Level->flags3 & LEVEL3_NOFOGOFWAR) || !r_radarclipper)) { - double vxdbl = Viewpoint.camera->X(); - double vydbl = Viewpoint.camera->Y(); + double vxdbl = Viewpoint.OffPos.X; + double vydbl = Viewpoint.OffPos.Y; double ext = Viewpoint.camera->ViewPos->Offset.Length() ? 3.0 * Viewpoint.camera->ViewPos->Offset.Length() * tan (Viewpoint.FieldOfView.Radians()*0.5) : 100.0; FBoundingBox viewbox(vxdbl, vydbl, ext); @@ -1014,16 +997,8 @@ void HWDrawInfo::RenderBSP(void *node, bool drawpsprites) viewy = FLOAT2FIXED(Viewpoint.Pos.Y); if (r_radarclipper && !(Level->flags3 & LEVEL3_NOFOGOFWAR) && Viewpoint.IsAllowedOoB()) { - if (Viewpoint.camera->tracer != NULL) - { - viewx = FLOAT2FIXED(Viewpoint.camera->tracer->X()); - viewy = FLOAT2FIXED(Viewpoint.camera->tracer->Y()); - } - else - { - viewx = FLOAT2FIXED(Viewpoint.camera->X()); - viewy = FLOAT2FIXED(Viewpoint.camera->Y()); - } + viewx = FLOAT2FIXED(Viewpoint.OffPos.X); + viewy = FLOAT2FIXED(Viewpoint.OffPos.Y); } validcount++; // used for processing sidedefs only once by the renderer. diff --git a/src/rendering/hwrenderer/scene/hw_clipper.cpp b/src/rendering/hwrenderer/scene/hw_clipper.cpp index 059a39981..7444af309 100644 --- a/src/rendering/hwrenderer/scene/hw_clipper.cpp +++ b/src/rendering/hwrenderer/scene/hw_clipper.cpp @@ -394,18 +394,10 @@ angle_t Clipper::PointToPseudoAngle(double x, double y) { double vecx = x - viewpoint->Pos.X; double vecy = y - viewpoint->Pos.Y; - if ((viewpoint->camera != NULL) && amRadar) + if (amRadar) { - if (viewpoint->camera->tracer != NULL) - { - vecx = x - viewpoint->camera->tracer->X(); - vecy = y - viewpoint->camera->tracer->Y(); - } - else - { - vecx = x - viewpoint->camera->X(); - vecy = y - viewpoint->camera->Y(); - } + vecx = x - viewpoint->OffPos.X; + vecy = y - viewpoint->OffPos.Y; } if (vecx == 0 && vecy == 0) @@ -467,7 +459,7 @@ angle_t Clipper::PointToPseudoPitch(double x, double y, double z) angle_t Clipper::PointToPseudoOrthoAngle(double x, double y) { - DVector3 disp = DVector3( x, y, 0 ) - viewpoint->camera->Pos(); + DVector3 disp = DVector3(x, y, 0) - viewpoint->OffPos; if (viewpoint->camera->ViewPos->Offset.XY().Length() == 0) { return AngleToPseudo( viewpoint->Angles.Yaw.BAMs() ); @@ -491,7 +483,7 @@ angle_t Clipper::PointToPseudoOrthoAngle(double x, double y) angle_t Clipper::PointToPseudoOrthoPitch(double x, double y, double z) { - DVector3 disp = DVector3( x, y, z ) - viewpoint->camera->Pos(); + DVector3 disp = DVector3(x, y, z) - viewpoint->OffPos; if (viewpoint->camera->ViewPos->Offset.XY().Length() > 0) { double yproj = viewpoint->PitchSin * disp.XY().Length() * deltaangle(disp.Angle(), viewpoint->Angles.Yaw).Cos(); diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index 4068fbbb8..10ee57b88 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -160,6 +160,7 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni VPUniforms.mProjectionMatrix.loadIdentity(); VPUniforms.mViewMatrix.loadIdentity(); VPUniforms.mNormalViewMatrix.loadIdentity(); + ProjectionMatrix2.loadIdentity(); VPUniforms.mViewHeight = viewheight; if (lightmode == ELightMode::Build) { @@ -684,60 +685,70 @@ void HWDrawInfo::DrawCorona(FRenderState& state, ACorona* corona, double dist) static ETraceStatus TraceCallbackForDitherTransparency(FTraceResults& res, void* userdata) { - int* count = (int*)userdata; + BitArray* CurMapSections = (BitArray*)userdata; double bf, bc; - (*count)++; + switch(res.HitType) { case TRACE_HitWall: if (!(res.Line->sidedef[res.Side]->Flags & WALLF_DITHERTRANS)) { - bf = res.Line->sidedef[res.Side]->sector->floorplane.ZatPoint(res.HitPos.XY()); - bc = res.Line->sidedef[res.Side]->sector->ceilingplane.ZatPoint(res.HitPos.XY()); - if ((res.HitPos.Z <= bc) && (res.HitPos.Z >= bf)) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS; + sector_t* linesec = res.Line->sidedef[res.Side]->sector; + if (linesec->subsectorcount > 0 && (*CurMapSections)[linesec->subsectors[0]->mapsection]) + { + bf = res.Line->sidedef[res.Side]->sector->floorplane.ZatPoint(res.HitPos.XY()); + bc = res.Line->sidedef[res.Side]->sector->ceilingplane.ZatPoint(res.HitPos.XY()); + if ((res.HitPos.Z <= bc) && (res.HitPos.Z >= bf)) res.Line->sidedef[res.Side]->Flags |= WALLF_DITHERTRANS; + } } break; case TRACE_HitFloor: - if (res.HitPos.Z == res.Sector->floorplane.ZatPoint(res.HitPos)) + if (res.Sector->subsectorcount > 0 && (*CurMapSections)[res.Sector->subsectors[0]->mapsection]) { - res.Sector->floorplane.dithertransflag = true; - } - else if (res.Sector->e->XFloor.ffloors.Size()) // Maybe it was 3D floors - { - F3DFloor *rover; - int kk; - for (kk = 0; kk < (int)res.Sector->e->XFloor.ffloors.Size(); kk++) + if (res.HitPos.Z == res.Sector->floorplane.ZatPoint(res.HitPos)) { - rover = res.Sector->e->XFloor.ffloors[kk]; - if ((rover->flags&(FF_EXISTS | FF_RENDERPLANES | FF_THISINSIDE)) == (FF_EXISTS | FF_RENDERPLANES)) + res.Sector->floorplane.dithertransflag = true; + } + else if (res.Sector->e->XFloor.ffloors.Size()) // Maybe it was 3D floors + { + F3DFloor *rover; + int kk; + for (kk = 0; kk < (int)res.Sector->e->XFloor.ffloors.Size(); kk++) { - if (res.HitPos.Z == rover->top.plane->ZatPoint(res.HitPos)) + rover = res.Sector->e->XFloor.ffloors[kk]; + if ((rover->flags&(FF_EXISTS | FF_RENDERPLANES | FF_THISINSIDE)) == (FF_EXISTS | FF_RENDERPLANES)) { - rover->top.plane->dithertransflag = true; - break; // Out of for loop + if (res.HitPos.Z == rover->top.plane->ZatPoint(res.HitPos)) + { + rover->top.plane->dithertransflag = true; + break; // Out of for loop + } } } } } break; case TRACE_HitCeiling: - if (res.HitPos.Z == res.Sector->ceilingplane.ZatPoint(res.HitPos)) + if (res.Sector->subsectorcount > 0 && (*CurMapSections)[res.Sector->subsectors[0]->mapsection]) { - res.Sector->ceilingplane.dithertransflag = true; - } - else if (res.Sector->e->XFloor.ffloors.Size()) // Maybe it was 3D floors - { - F3DFloor *rover; - int kk; - for (kk = 0; kk < (int)res.Sector->e->XFloor.ffloors.Size(); kk++) + if (res.HitPos.Z == res.Sector->ceilingplane.ZatPoint(res.HitPos)) { - rover = res.Sector->e->XFloor.ffloors[kk]; - if ((rover->flags&(FF_EXISTS | FF_RENDERPLANES | FF_THISINSIDE)) == (FF_EXISTS | FF_RENDERPLANES)) + res.Sector->ceilingplane.dithertransflag = true; + } + else if (res.Sector->e->XFloor.ffloors.Size()) // Maybe it was 3D floors + { + F3DFloor *rover; + int kk; + for (kk = 0; kk < (int)res.Sector->e->XFloor.ffloors.Size(); kk++) { - if (res.HitPos.Z == rover->bottom.plane->ZatPoint(res.HitPos)) + rover = res.Sector->e->XFloor.ffloors[kk]; + if ((rover->flags&(FF_EXISTS | FF_RENDERPLANES | FF_THISINSIDE)) == (FF_EXISTS | FF_RENDERPLANES)) { - rover->bottom.plane->dithertransflag = true; - break; // Out of for loop + if (res.HitPos.Z == rover->bottom.plane->ZatPoint(res.HitPos)) + { + rover->bottom.plane->dithertransflag = true; + break; // Out of for loop + } } } } @@ -763,13 +774,11 @@ void HWDrawInfo::SetDitherTransFlags(AActor* actor) DVector3 vvec = actorpos - Viewpoint.Pos; if (Viewpoint.IsOrtho()) { - vvec += Viewpoint.camera->Pos() - actorpos; - vvec *= 5.0; // Should be 4.0? (since zNear is behind screen by 3*dist in VREyeInfo::GetProjection()) + vvec = 5.0 * Viewpoint.camera->ViewPos->Offset.Length() * Viewpoint.ViewVector3D; // Should be 4.0? (since zNear is behind screen by 3*dist in VREyeInfo::GetProjection()) } double distance = vvec.Length() - actor->radius; DVector3 campos = actorpos - vvec; sector_t* startsec; - int count = 0; vvec = vvec.Unit(); campos.X -= horix; campos.Y += horiy; campos.Z += actor->Height * 0.25; @@ -777,10 +786,10 @@ void HWDrawInfo::SetDitherTransFlags(AActor* actor) { startsec = Level->PointInRenderSubsector(campos)->sector; Trace(campos, startsec, vvec, distance, - 0, 0, actor, results, 0, TraceCallbackForDitherTransparency, &count); + 0, 0, actor, results, TRACE_PortalRestrict, TraceCallbackForDitherTransparency, &CurrentMapSections); campos.Z += actor->Height * 0.5; Trace(campos, startsec, vvec, distance, - 0, 0, actor, results, 0, TraceCallbackForDitherTransparency, &count); + 0, 0, actor, results, TRACE_PortalRestrict, TraceCallbackForDitherTransparency, &CurrentMapSections); campos.Z -= actor->Height * 0.5; campos.X += horix; campos.Y -= horiy; } diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index ce848e297..e4cbeb98e 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -150,6 +150,7 @@ struct HWDrawInfo Clipper *rClipper; // Radar clipper FRenderViewpoint Viewpoint; HWViewpointUniforms VPUniforms; // per-viewpoint uniform state + VSMatrix ProjectionMatrix2; TArray Portals; TArray Decals[2]; // the second slot is for mirrors which get rendered in a separate pass. TArray hudsprites; // These may just be stored by value. diff --git a/src/rendering/hwrenderer/scene/hw_portal.cpp b/src/rendering/hwrenderer/scene/hw_portal.cpp index b0ea3a8c9..b103f0f81 100644 --- a/src/rendering/hwrenderer/scene/hw_portal.cpp +++ b/src/rendering/hwrenderer/scene/hw_portal.cpp @@ -125,6 +125,7 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di { HWPortal * best = nullptr; unsigned bestindex = 0; + bool usestencil = outer_di->Viewpoint.IsAllowedOoB(); // Find the one with the highest amount of lines. // Normally this is also the one that saves the largest amount @@ -145,7 +146,7 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di } // If the portal area contains the current camera viewpoint, let's always use it because it's likely to give the largest area. - if (p->boundingBox.contains(outer_di->Viewpoint.Pos)) + if (p->boundingBox.contains(usestencil ? outer_di->Viewpoint.OffPos : outer_di->Viewpoint.Pos)) { best = p; bestindex = i; @@ -157,7 +158,13 @@ bool FPortalSceneState::RenderFirstSkyPortal(int recursion, HWDrawInfo *outer_di if (best) { portals.Delete(bestindex); - RenderPortal(best, state, false, outer_di); + if (usestencil) + { + tempmatrix = outer_di->VPUniforms.mProjectionMatrix; // ensure perspective projection matrix for skies + outer_di->VPUniforms.mProjectionMatrix = outer_di->ProjectionMatrix2; + } + RenderPortal(best, state, usestencil, outer_di); + if (usestencil) outer_di->VPUniforms.mProjectionMatrix = tempmatrix; delete best; return true; } @@ -410,20 +417,23 @@ void HWScenePortalBase::ClearClipper(HWDrawInfo *di, Clipper *clipper) // Set the clipper to the minimal visible area clipper->SafeAddClipRange(0, 0xffffffff); + auto outvp = outer_di->Viewpoint; + DVector3 outPos = clipper->amRadar ? outvp.OffPos : outvp.Pos; + angle_t padding = clipper->amRadar ? 0x00200000 : 0x00000000; // Make radar clipping more aggressive (reveal less) for (unsigned int i = 0; i < lines.Size(); i++) { - DAngle startAngle = (DVector2(lines[i].glseg.x2, lines[i].glseg.y2) - outer_di->Viewpoint.Pos).Angle() + angleOffset; - DAngle endAngle = (DVector2(lines[i].glseg.x1, lines[i].glseg.y1) - outer_di->Viewpoint.Pos).Angle() + angleOffset; + DAngle startAngle = (DVector2(lines[i].glseg.x2, lines[i].glseg.y2) - outPos).Angle() + angleOffset; + DAngle endAngle = (DVector2(lines[i].glseg.x1, lines[i].glseg.y1) - outPos).Angle() + angleOffset; if (deltaangle(endAngle, startAngle) < nullAngle) { - clipper->SafeRemoveClipRangeRealAngles(startAngle.BAMs(), endAngle.BAMs()); + clipper->SafeRemoveClipRangeRealAngles(startAngle.BAMs() + padding, endAngle.BAMs() - padding); } } // and finally clip it to the visible area angle_t a1 = di->FrustumAngle(); - if (a1 < ANGLE_180) clipper->SafeAddClipRangeRealAngles(di->Viewpoint.Angles.Yaw.BAMs() + a1, di->Viewpoint.Angles.Yaw.BAMs() - a1); + if (!clipper->amRadar && a1 < ANGLE_180) clipper->SafeAddClipRangeRealAngles(di->Viewpoint.Angles.Yaw.BAMs() + a1, di->Viewpoint.Angles.Yaw.BAMs() - a1); // lock the parts that have just been clipped out. clipper->SetSilhouette(); @@ -608,6 +618,8 @@ bool HWLineToLinePortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *cl P_TranslatePortalZ(origin, vp.Pos.Z); P_TranslatePortalXY(origin, vp.Path[0].X, vp.Path[0].Y); P_TranslatePortalXY(origin, vp.Path[1].X, vp.Path[1].Y); + P_TranslatePortalXY(origin, vp.OffPos.X, vp.OffPos.Y); + P_TranslatePortalZ(origin, vp.OffPos.Z); if (!vp.showviewer && vp.camera != nullptr && P_PointOnLineSidePrecise(vp.Path[0], glport->lines[0]->mDestination) != P_PointOnLineSidePrecise(vp.Path[1], glport->lines[0]->mDestination)) { double distp = (vp.Path[0] - vp.Path[1]).Length(); diff --git a/src/rendering/hwrenderer/scene/hw_portal.h b/src/rendering/hwrenderer/scene/hw_portal.h index 29481f9e3..760b8c435 100644 --- a/src/rendering/hwrenderer/scene/hw_portal.h +++ b/src/rendering/hwrenderer/scene/hw_portal.h @@ -112,6 +112,8 @@ struct FPortalSceneState int skyboxrecursion = 0; + VSMatrix tempmatrix; + void BeginScene() { UniqueSkies.Clear(); @@ -145,7 +147,7 @@ public: virtual bool NeedDepthBuffer() { return true; } virtual void DrawContents(HWDrawInfo *di, FRenderState &state) { - if (Setup(di, state, di->mClipper)) + if (Setup(di, state, (di->Viewpoint.IsAllowedOoB() ? di->rClipper : di->mClipper))) { di->DrawScene(DM_PORTAL); Shutdown(di, state); diff --git a/src/rendering/hwrenderer/scene/hw_sky.cpp b/src/rendering/hwrenderer/scene/hw_sky.cpp index 6d77a275d..93fc827cc 100644 --- a/src/rendering/hwrenderer/scene/hw_sky.cpp +++ b/src/rendering/hwrenderer/scene/hw_sky.cpp @@ -130,7 +130,6 @@ void HWSkyInfo::init(HWDrawInfo *di, sector_t* sec, int skypos, int sky1, PalEnt void HWWall::SkyPlane(HWWallDispatcher *di, sector_t *sector, int plane, bool allowreflect) { int ptype = -1; - if (di->di && di->di->Viewpoint.IsAllowedOoB()) return; // Couldn't prevent sky portal occlusion. Skybox is bad in ortho too. FSectorPortal *sportal = sector->ValidatePortal(plane); if (sportal != nullptr && sportal->mFlags & PORTSF_INSKYBOX) sportal = nullptr; // no recursions, delete it here to simplify the following code @@ -155,6 +154,7 @@ void HWWall::SkyPlane(HWWallDispatcher *di, sector_t *sector, int plane, bool al case PORTS_PORTAL: case PORTS_LINKEDPORTAL: { + if (di->di && di->di->Viewpoint.IsAllowedOoB()) return; auto glport = sector->GetPortalGroup(plane); if (glport != NULL) { diff --git a/src/rendering/hwrenderer/scene/hw_walls.cpp b/src/rendering/hwrenderer/scene/hw_walls.cpp index 5c5e357d5..97b0c91a6 100644 --- a/src/rendering/hwrenderer/scene/hw_walls.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls.cpp @@ -2181,8 +2181,6 @@ void HWWall::Process(HWWallDispatcher *di, seg_t *seg, sector_t * frontsector, s } bool isportal = seg->linedef->isVisualPortal() && seg->sidedef == seg->linedef->sidedef[0]; - // Don't render portal insides if in orthographic mode - if (di->di) isportal &= !(di->di->Viewpoint.IsOrtho()); //return; // [GZ] 3D middle textures are necessarily two-sided, even if they lack the explicit two-sided flag diff --git a/src/rendering/r_utility.cpp b/src/rendering/r_utility.cpp index cd0c3d0c2..035ac6de7 100644 --- a/src/rendering/r_utility.cpp +++ b/src/rendering/r_utility.cpp @@ -550,8 +550,12 @@ void R_InterpolateView(FRenderViewpoint& viewPoint, const player_t* const player const int prevPortalGroup = viewLvl->PointInRenderSubsector(iView->Old.Pos)->sector->PortalGroup; const int curPortalGroup = viewLvl->PointInRenderSubsector(iView->New.Pos)->sector->PortalGroup; - const DVector2 portalOffset = viewLvl->Displacements.getOffset(prevPortalGroup, curPortalGroup); - viewPoint.Pos = iView->Old.Pos * inverseTicFrac + (iView->New.Pos - portalOffset) * ticFrac; + if (viewPoint.IsAllowedOoB() && prevPortalGroup != curPortalGroup) viewPoint.Pos = iView->New.Pos; + else + { + const DVector2 portalOffset = viewLvl->Displacements.getOffset(prevPortalGroup, curPortalGroup); + viewPoint.Pos = iView->Old.Pos * inverseTicFrac + (iView->New.Pos - portalOffset) * ticFrac; + } viewPoint.Path[0] = viewPoint.Path[1] = iView->New.Pos; } } @@ -708,6 +712,18 @@ void FRenderViewpoint::SetViewAngle(const FViewWindow& viewWindow) ViewVector3D.Y = v.Y * PitchCos; ViewVector3D.Z = -PitchSin; + if (IsOrtho() || IsAllowedOoB()) // These auto-ensure that camera and camera->ViewPos exist + { + if (camera->tracer != NULL) + { + OffPos = camera->tracer->Pos(); + } + else + { + OffPos = Pos + ViewVector3D * camera->ViewPos->Offset.Length(); + } + } + if (IsOrtho() && (camera->ViewPos->Offset.XY().Length() > 0.0)) { ScreenProj = 1.34396 / camera->ViewPos->Offset.Length() / tan (FieldOfView.Radians()*0.5); // [DVR] Estimated. +/-1 should be top/bottom of screen. diff --git a/src/rendering/r_utility.h b/src/rendering/r_utility.h index d82b03e68..0c2f47833 100644 --- a/src/rendering/r_utility.h +++ b/src/rendering/r_utility.h @@ -26,6 +26,7 @@ struct FRenderViewpoint FRotator HWAngles; // Actual rotation angles for the hardware renderer DVector2 ViewVector; // HWR only: direction the camera is facing. DVector3 ViewVector3D; // 3D direction the camera is facing. + DVector3 OffPos; // Viewpoint position to use for Ortho and OoB calculations AActor *ViewActor; // either the same as camera or nullptr FLevelLocals *ViewLevel; // The level this viewpoint is on.