Fix solid segment culling

This commit is contained in:
Magnus Norddahl 2016-11-13 11:44:07 +01:00
parent af7a7ab7d7
commit 27eb8e36ae
2 changed files with 34 additions and 39 deletions

View file

@ -47,9 +47,9 @@ void RenderPolyBsp::Render()
// Setup working buffers // Setup working buffers
PolyVertexBuffer::Clear(); PolyVertexBuffer::Clear();
SolidSegments.clear(); SolidSegments.clear();
SolidSegments.reserve(MAXWIDTH / 2 + 2); SolidSegments.reserve(SolidCullScale + 2);
SolidSegments.push_back({ -0x7fff, 0 }); SolidSegments.push_back({ -0x7fff, -SolidCullScale });
SolidSegments.push_back({ viewwidth, 0x7fff }); SolidSegments.push_back({ SolidCullScale , 0x7fff });
SectorSpriteRanges.clear(); SectorSpriteRanges.clear();
SectorSpriteRanges.resize(numsectors); SectorSpriteRanges.resize(numsectors);
SortedSprites.clear(); SortedSprites.clear();
@ -1027,12 +1027,12 @@ bool RenderPolyBsp::CheckBBox(float *bspcoord)
{ {
// Start using a quick frustum AABB test: // Start using a quick frustum AABB test:
AxisAlignedBoundingBox aabb(Vec3f(bspcoord[BOXLEFT], bspcoord[BOXBOTTOM], -1000.0f), Vec3f(bspcoord[BOXRIGHT], bspcoord[BOXTOP], 1000.0f)); AxisAlignedBoundingBox aabb(Vec3f(bspcoord[BOXLEFT], bspcoord[BOXBOTTOM], (float)ViewPos.Z - 1000.0f), Vec3f(bspcoord[BOXRIGHT], bspcoord[BOXTOP], (float)ViewPos.Z + 1000.0f));
auto result = IntersectionTest::frustum_aabb(frustumPlanes, aabb); auto result = IntersectionTest::frustum_aabb(frustumPlanes, aabb);
if (result == IntersectionTest::outside) if (result == IntersectionTest::outside)
return false; return false;
// Occlusion test using solid segments (which seems to be quite broken, actually): // Occlusion test using solid segments:
int boxx; int boxx;
int boxy; int boxy;
@ -1089,51 +1089,45 @@ bool RenderPolyBsp::CheckBBox(float *bspcoord)
bool RenderPolyBsp::GetSegmentRangeForLine(double x1, double y1, double x2, double y2, int &sx1, int &sx2) const bool RenderPolyBsp::GetSegmentRangeForLine(double x1, double y1, double x2, double y2, int &sx1, int &sx2) const
{ {
double znear = 5.0;
// Transform to 2D view space:
x1 = x1 - ViewPos.X; x1 = x1 - ViewPos.X;
y1 = y1 - ViewPos.Y; y1 = y1 - ViewPos.Y;
x2 = x2 - ViewPos.X; x2 = x2 - ViewPos.X;
y2 = y2 - ViewPos.Y; y2 = y2 - ViewPos.Y;
// Sitting on a line?
if (y1 * (x1 - x2) + x1 * (y2 - y1) >= -EQUAL_EPSILON)
return false;
double rx1 = x1 * ViewSin - y1 * ViewCos; double rx1 = x1 * ViewSin - y1 * ViewCos;
double rx2 = x2 * ViewSin - y2 * ViewCos; double rx2 = x2 * ViewSin - y2 * ViewCos;
double ry1 = x1 * ViewTanCos + y1 * ViewTanSin; double ry1 = x1 * ViewCos + y1 * ViewSin;
double ry2 = x2 * ViewTanCos + y2 * ViewTanSin; double ry2 = x2 * ViewCos + y2 * ViewSin;
if (rx1 >= -ry1) // Cull if line is entirely behind view
if (ry1 < znear && ry2 < znear) return false;
// Clip line, if needed
double t1 = 0.0f, t2 = 1.0f;
if (ry1 < znear)
t1 = clamp((znear - ry1) / (ry2 - ry1), 0.0, 1.0);
if (ry2 < znear)
t2 = clamp((znear - ry1) / (ry2 - ry1), 0.0, 1.0);
if (t1 != 0.0 || t2 != 1.0)
{ {
if (rx1 > ry1) return false; // left edge is off the right side double nx1 = rx1 * (1.0 - t1) + rx2 * t1;
if (ry1 == 0) return false; double ny1 = ry1 * (1.0 - t1) + ry2 * t1;
sx1 = xs_RoundToInt(CenterX + rx1 * CenterX / ry1); double nx2 = rx1 * (1.0 - t2) + rx2 * t2;
} double ny2 = ry1 * (1.0 - t2) + ry2 * t2;
else rx1 = nx1;
{ rx2 = nx2;
if (rx2 < -ry2) return false; // wall is off the left side ry1 = ny1;
if (rx1 - rx2 - ry2 + ry1 == 0) return false; // wall does not intersect view volume ry2 = ny2;
sx1 = 0;
} }
if (rx2 <= ry2) sx1 = (int)floor(clamp(rx1 / ry1 * (SolidCullScale / 3), (double)-SolidCullScale, (double)SolidCullScale));
{ sx2 = (int)floor(clamp(rx2 / ry2 * (SolidCullScale / 3), (double)-SolidCullScale, (double)SolidCullScale));
if (rx2 < -ry2) return false; // right edge is off the left side
if (ry2 == 0) return false;
sx2 = xs_RoundToInt(CenterX + rx2 * CenterX / ry2);
}
else
{
if (rx1 > ry1) return false; // wall is off the right side
if (ry2 - ry1 - rx2 + rx1 == 0) return false; // wall does not intersect view volume
sx2 = viewwidth;
}
// Does not cross a pixel. if (sx1 > sx2)
if (sx2 <= sx1) std::swap(sx1, sx2);
return false; return sx1 != sx2;
return true;
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View file

@ -162,6 +162,7 @@ private:
}; };
std::vector<SolidSegment> SolidSegments; std::vector<SolidSegment> SolidSegments;
const int SolidCullScale = 3000;
PolySkyDome skydome; PolySkyDome skydome;
}; };