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().

This commit is contained in:
Dileep V. Reddy 2025-02-11 19:51:21 -07:00 committed by Ricardo Luís Vaz Silva
commit 8a66eff437
11 changed files with 118 additions and 111 deletions

View file

@ -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());

View file

@ -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.

View file

@ -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();

View file

@ -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;
}

View file

@ -150,6 +150,7 @@ struct HWDrawInfo
Clipper *rClipper; // Radar clipper
FRenderViewpoint Viewpoint;
HWViewpointUniforms VPUniforms; // per-viewpoint uniform state
VSMatrix ProjectionMatrix2;
TArray<HWPortal *> Portals;
TArray<HWDecal *> Decals[2]; // the second slot is for mirrors which get rendered in a separate pass.
TArray<HUDSprite> hudsprites; // These may just be stored by value.

View file

@ -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();

View file

@ -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);

View file

@ -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)
{

View file

@ -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

View file

@ -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.

View file

@ -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.