mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-02-21 03:11:43 +00:00
- Improve line portal rendering somewhat
This commit is contained in:
parent
4554d90b1d
commit
31125486ad
9 changed files with 97 additions and 120 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -80,6 +80,8 @@ public:
|
|||
|
||||
static const uint32_t SkySubsectorDepth = 0x7fffffff;
|
||||
|
||||
line_t *LastPortalLine = nullptr;
|
||||
|
||||
private:
|
||||
void ClearBuffers();
|
||||
void RenderPortals(int portalDepth);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue