- Improve line portal rendering somewhat

This commit is contained in:
Magnus Norddahl 2017-05-14 08:55:30 +02:00
parent 4554d90b1d
commit 31125486ad
9 changed files with 97 additions and 120 deletions

View file

@ -159,8 +159,6 @@ void PolyRenderer::ClearBuffers()
PolyStencilBuffer::Instance()->Clear(RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0);
PolySubsectorGBuffer::Instance()->Resize(RenderTarget->GetPitch(), RenderTarget->GetHeight());
NextStencilValue = 0;
SeenLinePortals.clear();
SeenMirrors.clear();
}
void PolyRenderer::SetSceneViewport()
@ -216,13 +214,3 @@ void PolyRenderer::SetupPerspectiveMatrix()
WorldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
}
bool PolyRenderer::InsertSeenLinePortal(FLinePortal *portal)
{
return SeenLinePortals.insert(portal).second;
}
bool PolyRenderer::InsertSeenMirror(line_t *mirrorLine)
{
return SeenMirrors.insert(mirrorLine).second;
}

View file

@ -52,9 +52,6 @@ public:
uint32_t GetNextStencilValue() { uint32_t value = NextStencilValue; NextStencilValue += 2; return value; }
bool InsertSeenLinePortal(FLinePortal *portal);
bool InsertSeenMirror(line_t *mirrorLine);
bool DontMapLines = false;
RenderMemory FrameMemory;
@ -75,7 +72,4 @@ private:
PolySkyDome Skydome;
RenderPolyPlayerSprites PlayerSprites;
uint32_t NextStencilValue = 0;
std::set<FLinePortal *> SeenLinePortals;
std::set<line_t *> SeenMirrors;
};

View file

@ -70,6 +70,20 @@ void PolyCull::CullNode(void *node)
void PolyCull::CullSubsector(subsector_t *sub)
{
// Check if subsector is clipped entirely by the portal clip plane
bool visible = false;
for (uint32_t i = 0; i < sub->numlines; i++)
{
seg_t *line = &sub->firstline[i];
if (PortalClipPlane.A * line->v1->fX() + PortalClipPlane.B * line->v1->fY() + PortalClipPlane.D > 0.0)
{
visible = true;
break;
}
}
if (!visible)
return;
// Update sky heights for the scene
if (!FirstSkyHeight)
{
@ -98,6 +112,13 @@ void PolyCull::CullSubsector(subsector_t *sub)
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
continue;
// Skip line if entirely behind portal clipping plane
if ((PortalClipPlane.A * line->v1->fX() + PortalClipPlane.B * line->v1->fY() + PortalClipPlane.D <= 0.0) ||
(PortalClipPlane.A * line->v2->fX() + PortalClipPlane.B * line->v2->fY() + PortalClipPlane.D <= 0.0))
{
continue;
}
angle_t angle1, angle2;
if (GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
{
@ -119,11 +140,11 @@ void PolyCull::InvertSegments()
angle_t cur = 0;
for (const auto &segment : TempInvertSolidSegments)
{
if (segment.Start != 0 || segment.End != ANGLE_MAX)
if (cur < segment.Start)
MarkSegmentCulled(cur, segment.Start - 1);
cur = segment.End + 1;
}
if (cur != 0)
if (cur < ANGLE_MAX)
MarkSegmentCulled(cur, ANGLE_MAX);
}
@ -241,32 +262,6 @@ bool PolyCull::CheckBBox(float *bspcoord)
bool PolyCull::GetAnglesForLine(double x1, double y1, double x2, double y2, angle_t &angle1, angle_t &angle2) const
{
#if 0
// Clip line to the portal clip plane
float distance1 = Vec4f::dot(PortalClipPlane, Vec4f((float)x1, (float)y1, 0.0f, 1.0f));
float distance2 = Vec4f::dot(PortalClipPlane, Vec4f((float)x2, (float)y2, 0.0f, 1.0f));
if (distance1 < 0.0f && distance2 < 0.0f)
{
return false;
}
else if (distance1 < 0.0f || distance2 < 0.0f)
{
double t1 = 0.0f, t2 = 1.0f;
if (distance1 < 0.0f)
t1 = clamp(distance1 / (distance1 - distance2), 0.0f, 1.0f);
else
t2 = clamp(distance2 / (distance1 - distance2), 0.0f, 1.0f);
double nx1 = x1 * (1.0 - t1) + x2 * t1;
double ny1 = y1 * (1.0 - t1) + y2 * t1;
double nx2 = x1 * (1.0 - t2) + x2 * t2;
double ny2 = y1 * (1.0 - t2) + y2 * t2;
x1 = nx1;
x2 = nx2;
y1 = ny1;
y2 = ny2;
}
#endif
angle2 = PointToPseudoAngle(x1, y1);
angle1 = PointToPseudoAngle(x2, y2);
return !IsSegmentCulled(angle1, angle2);

View file

@ -40,6 +40,8 @@ public:
double MaxCeilingHeight = 0.0;
double MinFloorHeight = 0.0;
static angle_t PointToPseudoAngle(double x, double y);
private:
struct SolidSegment
{
@ -62,6 +64,5 @@ private:
PolyClipPlane PortalClipPlane;
static angle_t PointToPseudoAngle(double x, double y);
static angle_t AngleToPseudo(angle_t ang);
};

View file

@ -43,44 +43,10 @@ void PolyDrawSectorPortal::Render(int portalDepth)
if (Portal->mType == PORTS_HORIZON || Portal->mType == PORTS_PLANE)
return;
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
PolyClipPlane portalPlane(0.0f, 0.0f, 0.0f, 1.0f);
if (Portal->mType != PORTS_SKYVIEWPOINT)
{
float minHeight;
float maxHeight;
bool first = true;
for (const auto &range : Shape)
{
for (int i = 0; i < range.Count; i++)
{
if (first)
{
minHeight = range.Vertices[i].z;
maxHeight = range.Vertices[i].z;
first = false;
}
else
{
minHeight = MIN(minHeight, range.Vertices[i].z);
maxHeight = MAX(maxHeight, range.Vertices[i].z);
}
}
}
if (!first && minHeight > viewpoint.Pos.Z)
{
portalPlane = PolyClipPlane(0.0f, 0.0f, 1.0f, -minHeight);
}
else if (!first && maxHeight < viewpoint.Pos.Z)
{
portalPlane = PolyClipPlane(0.0f, 0.0f, -1.0f, maxHeight);
}
}
SaveGlobals();
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
// To do: get this information from PolyRenderer instead of duplicating the code..
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
double radPitch = viewpoint.Angles.Pitch.Normalized180().Radians();
@ -100,6 +66,7 @@ void PolyDrawSectorPortal::Render(int portalDepth)
TriMatrix::translate((float)-viewpoint.Pos.X, (float)-viewpoint.Pos.Y, (float)-viewpoint.Pos.Z);
TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
PolyClipPlane portalPlane(0.0f, 0.0f, 0.0f, 1.0f);
RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue);
RenderPortal.SetPortalSegments(Segments);
RenderPortal.Render(portalDepth);
@ -211,14 +178,29 @@ void PolyDrawLinePortal::Render(int portalDepth)
worldToView = TriMatrix::scale(-1.0f, 1.0f, 1.0f) * worldToView;
TriMatrix worldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
// Calculate plane clipping
// Find portal destination line and make sure it faces the right way
line_t *clipLine = Portal ? Portal->mDestination : Mirror;
DVector2 planePos = clipLine->v1->fPos();
DVector2 planeNormal = (clipLine->v2->fPos() - clipLine->v1->fPos()).Rotated90CW();
DVector2 pt1 = clipLine->v1->fPos() - viewpoint.Pos;
DVector2 pt2 = clipLine->v2->fPos() - viewpoint.Pos;
bool backfacing = (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0);
vertex_t *v1 = backfacing ? clipLine->v1 : clipLine->v2;
vertex_t *v2 = backfacing ? clipLine->v2 : clipLine->v1;
// Calculate plane clipping
DVector2 planePos = v1->fPos();
DVector2 planeNormal = (v2->fPos() - v1->fPos()).Rotated90CW();
planeNormal.MakeUnit();
double planeD = -(planeNormal | (planePos + planeNormal * 0.001));
PolyClipPlane portalPlane((float)planeNormal.X, (float)planeNormal.Y, (float)0.0f, (float)planeD);
// Cull everything outside the portal line
// To do: this doesn't work for some strange reason..
/*angle_t angle1 = PolyCull::PointToPseudoAngle(v1->fX(), v1->fY());
angle_t angle2 = PolyCull::PointToPseudoAngle(v2->fX(), v2->fY());
Segments.clear();
Segments.push_back({ angle1, angle2 });*/
RenderPortal.LastPortalLine = clipLine;
RenderPortal.SetViewpoint(worldToClip, portalPlane, StencilValue);
RenderPortal.SetPortalSegments(Segments);
RenderPortal.Render(portalDepth);
@ -296,6 +278,9 @@ void PolyDrawLinePortal::SaveGlobals()
P_TranslatePortalXY(src, viewpoint.Path[0].X, viewpoint.Path[0].Y);
P_TranslatePortalXY(src, viewpoint.Path[1].X, viewpoint.Path[1].Y);
if (viewpoint.camera)
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
if (!viewpoint.showviewer && viewpoint.camera && P_PointOnLineSidePrecise(viewpoint.Path[0], dst) != P_PointOnLineSidePrecise(viewpoint.Path[1], dst))
{
double distp = (viewpoint.Path[0] - viewpoint.Path[1]).Length();
@ -312,8 +297,8 @@ void PolyDrawLinePortal::SaveGlobals()
}
}
//camera = nullptr;
//viewsector = R_PointInSubsector(ViewPos)->sector;
viewpoint.camera = nullptr;
viewpoint.sector = R_PointInSubsector(viewpoint.Pos)->sector;
R_SetViewAngle(viewpoint, viewwindow);
if (Mirror)

View file

@ -219,7 +219,7 @@ void RenderPolyScene::RenderPolySubsector(subsector_t *sub, uint32_t subsectorDe
}
// Render wall, and update culling info if its an occlusion blocker
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals))
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals, LastPortalLine))
{
Cull.MarkSegmentCulled(angle1, angle2);
}
@ -319,7 +319,7 @@ void RenderPolyScene::RenderLine(subsector_t *sub, seg_t *line, sector_t *fronts
}
// Render wall, and update culling info if its an occlusion blocker
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals))
if (RenderPolyWall::RenderLine(WorldToClip, PortalPlane, Cull, line, frontsector, subsectorDepth, StencilValue, TranslucentObjects, LinePortals, LastPortalLine))
{
Cull.MarkSegmentCulled(angle1, angle2);
}

View file

@ -80,6 +80,8 @@ public:
static const uint32_t SkySubsectorDepth = 0x7fffffff;
line_t *LastPortalLine = nullptr;
private:
void ClearBuffers();
void RenderPortals(int portalDepth);

View file

@ -37,36 +37,51 @@
EXTERN_CVAR(Bool, r_drawmirrors)
bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals)
bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, line_t *lastPortalLine)
{
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
double topTexZ = frontsector->GetPlaneTexZ(sector_t::ceiling);
double bottomTexZ = frontsector->GetPlaneTexZ(sector_t::floor);
PolyDrawLinePortal *polyportal = nullptr;
if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors))
{
if (PolyRenderer::Instance()->InsertSeenMirror(line->linedef))
if (lastPortalLine == line->linedef ||
(line->linedef->v1->fX() * clipPlane.A + line->linedef->v1->fY() * clipPlane.B + clipPlane.D <= 0.0f) ||
(line->linedef->v2->fX() * clipPlane.A + line->linedef->v2->fY() * clipPlane.B + clipPlane.D <= 0.0f))
{
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(line->linedef)));
polyportal = linePortals.back().get();
return false;
}
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(line->linedef)));
polyportal = linePortals.back().get();
}
else if (line->linedef && line->linedef->isVisualPortal())
{
FLinePortal *portal = line->linedef->getPortal();
if (PolyRenderer::Instance()->InsertSeenLinePortal(portal))
if (lastPortalLine == line->linedef ||
(line->linedef->v1->fX() * clipPlane.A + line->linedef->v1->fY() * clipPlane.B + clipPlane.D <= 0.0f) ||
(line->linedef->v2->fX() * clipPlane.A + line->linedef->v2->fY() * clipPlane.B + clipPlane.D <= 0.0f))
{
for (auto &p : linePortals)
return false;
}
FLinePortal *portal = line->linedef->getPortal();
for (auto &p : linePortals)
{
if (p->Portal == portal) // To do: what other criterias do we need to check for?
{
if (p->Portal == portal) // To do: what other criterias do we need to check for?
{
polyportal = p.get();
break;
}
}
if (!polyportal)
{
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(portal)));
polyportal = linePortals.back().get();
polyportal = p.get();
break;
}
}
if (!polyportal)
{
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(portal)));
polyportal = linePortals.back().get();
}
}
RenderPolyWall wall;
@ -78,13 +93,6 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const PolyClipPlan
wall.SubsectorDepth = subsectorDepth;
wall.StencilValue = stencilValue;
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
double topTexZ = frontsector->GetPlaneTexZ(sector_t::ceiling);
double bottomTexZ = frontsector->GetPlaneTexZ(sector_t::floor);
if (line->backsector == nullptr)
{
if (line->sidedef)
@ -244,6 +252,14 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c
vertices[3].u = (float)texcoordsU.u1;
vertices[3].v = (float)texcoordsVLeft.v2;
}
else
{
for (int i = 0; i < 4; i++)
{
vertices[i].u = 0.0f;
vertices[i].v = 0.0f;
}
}
// Masked walls clamp to the 0-1 range (no texture repeat)
if (Masked)
@ -259,7 +275,7 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c
args.SetFaceCullCCW(true);
args.SetStencilTestValue(StencilValue);
args.SetWriteStencil(true, StencilValue + 1);
if (tex)
if (tex && !Polyportal)
args.SetTexture(tex);
args.SetClipPlane(clipPlane);
@ -270,10 +286,6 @@ void RenderPolyWall::Render(const TriMatrix &worldToClip, const PolyClipPlane &c
args.SetWriteSubsectorDepth(false);
args.DrawArray(vertices, 4, PolyDrawMode::TriangleFan);
Polyportal->Shape.push_back({ vertices, 4, true, SubsectorDepth });
angle_t angle1, angle2;
if (cull.GetAnglesForLine(v1.X, v1.Y, v2.X, v2.Y, angle1, angle2))
Polyportal->Segments.push_back({ angle1, angle2 });
}
else if (!Masked)
{

View file

@ -31,7 +31,7 @@ class PolyCull;
class RenderPolyWall
{
public:
static bool RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals);
static bool RenderLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, line_t *lastPortalLine);
static void Render3DFloorLine(const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput);
void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);