|
|
@@ -67,6 +67,11 @@ void Clusterer::prepare(const PerspectiveFrustum& fr,
|
|
|
m_clusters.resize(m_alloc, clusterCount);
|
|
|
}
|
|
|
|
|
|
+ if(m_counts[2] != m_splitInfo.getSize())
|
|
|
+ {
|
|
|
+ m_splitInfo.resize(m_alloc, m_counts[2]);
|
|
|
+ }
|
|
|
+
|
|
|
initClusters();
|
|
|
}
|
|
|
|
|
|
@@ -115,6 +120,16 @@ void Clusterer::initClusters()
|
|
|
ANKI_ASSERT(min.xyz() < max.xyz());
|
|
|
cluster(x, y, z).m_min = min.xyz();
|
|
|
cluster(x, y, z).m_max = max.xyz();
|
|
|
+
|
|
|
+ // Set split info
|
|
|
+ if(x == 0 && y == 0)
|
|
|
+ {
|
|
|
+ Vec2 xy(min.x(), min.y());
|
|
|
+ Vec2 sizes(max.x() - min.x(), max.y() - min.y());
|
|
|
+
|
|
|
+ m_splitInfo[z].m_xy = xy;
|
|
|
+ m_splitInfo[z].m_sizes = sizes;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -125,164 +140,88 @@ void Clusterer::bin(const CollisionShape& cs, ClustererTestResult& rez) const
|
|
|
{
|
|
|
rez.m_count = 0;
|
|
|
|
|
|
- if(isa<Sphere>(cs))
|
|
|
- {
|
|
|
- // Specialized
|
|
|
- binSphere(dcast<const Sphere&>(cs), rez);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- binGeneric(cs, rez);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//==============================================================================
|
|
|
-void Clusterer::findTilesFromAabb(const Aabb& box, U& tileBeginX, U& tileBeginY,
|
|
|
- U& tileEndX, U& tileEndY) const
|
|
|
-{
|
|
|
- // Project front face of the AABB
|
|
|
- const Vec4& minv = box.getMin();
|
|
|
- const Vec4& maxv = box.getMax();
|
|
|
-
|
|
|
- Array<Vec4, 8> projPoints;
|
|
|
- projPoints[0] = Vec4(minv.x(), minv.y(), maxv.z(), 1.0);
|
|
|
- projPoints[1] = Vec4(maxv.x(), minv.y(), maxv.z(), 1.0);
|
|
|
- projPoints[2] = Vec4(maxv.x(), maxv.y(), maxv.z(), 1.0);
|
|
|
- projPoints[3] = Vec4(minv.x(), maxv.y(), maxv.z(), 1.0);
|
|
|
- projPoints[4] = Vec4(minv.x(), minv.y(), minv.z(), 1.0);
|
|
|
- projPoints[5] = Vec4(maxv.x(), minv.y(), minv.z(), 1.0);
|
|
|
- projPoints[6] = Vec4(maxv.x(), maxv.y(), minv.z(), 1.0);
|
|
|
- projPoints[7] = Vec4(minv.x(), maxv.y(), minv.z(), 1.0);
|
|
|
-
|
|
|
- Vec2 min2(MAX_F32), max2(MIN_F32);
|
|
|
- for(Vec4& p : projPoints)
|
|
|
- {
|
|
|
- p = m_projMat * p;
|
|
|
- p /= abs(p.w());
|
|
|
-
|
|
|
- for(U i = 0; i < 2; ++i)
|
|
|
- {
|
|
|
- min2[i] = min(min2[i], p[i]);
|
|
|
- max2[i] = max(max2[i], p[i]);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- min2 = min2 * 0.5 + 0.5;
|
|
|
- max2 = max2 * 0.5 + 0.5;
|
|
|
-
|
|
|
- // Find tiles affected
|
|
|
- F32 tcountX = m_counts[0];
|
|
|
- F32 tcountY = m_counts[1];
|
|
|
-
|
|
|
- I xFrom = floor(tcountX * min2.x());
|
|
|
- xFrom = clamp<I>(xFrom, 0, tcountX);
|
|
|
-
|
|
|
- I xTo = ceil(tcountX * max2.x());
|
|
|
- xTo = min<U>(xTo, tcountX);
|
|
|
+ Aabb box;
|
|
|
+ cs.computeAabb(box);
|
|
|
|
|
|
- I yFrom = floor(tcountY * min2.y());
|
|
|
- yFrom = clamp<I>(yFrom, 0, tcountY);
|
|
|
+ U beginZ, endZ;
|
|
|
|
|
|
- I yTo = ceil(tcountY * max2.y());
|
|
|
- yTo = min<I>(yTo, tcountY);
|
|
|
+ // Find splits that cover the box
|
|
|
+ findSplitsFromAabb(box, beginZ, endZ);
|
|
|
|
|
|
- ANKI_ASSERT(xFrom >= 0 && xFrom <= tcountX
|
|
|
- && xTo >= 0 && xTo <= tcountX);
|
|
|
- ANKI_ASSERT(yFrom >= 0 && yFrom <= tcountX
|
|
|
- && yTo >= 0 && yFrom <= tcountY);
|
|
|
-
|
|
|
- tileBeginX = xFrom;
|
|
|
- tileBeginY = yFrom;
|
|
|
- tileEndX = xTo;
|
|
|
- tileEndY = yTo;
|
|
|
-}
|
|
|
-
|
|
|
-//==============================================================================
|
|
|
-void Clusterer::findSplitsFromAabb(const Aabb& box, U& zFrom, U& zTo) const
|
|
|
-{
|
|
|
- zFrom = calcK(box.getMax().z());
|
|
|
- zTo = calcK(box.getMin().z()) + 1;
|
|
|
- ANKI_ASSERT(zFrom <= zTo);
|
|
|
-}
|
|
|
-
|
|
|
-//==============================================================================
|
|
|
-void Clusterer::binSphere(const Sphere& s, ClustererTestResult& rez) const
|
|
|
-{
|
|
|
- Aabb aabb;
|
|
|
- s.computeAabb(aabb);
|
|
|
-
|
|
|
- const Vec4& scent = s.getCenter();
|
|
|
- const F32 srad = s.getRadius();
|
|
|
-
|
|
|
- // Find the tiles that are covered
|
|
|
- //
|
|
|
-
|
|
|
- U tileBeginX, tileBeginY, tileEndX, tileEndY;
|
|
|
-
|
|
|
- if(ANKI_UNLIKELY(scent.getLengthSquared() <= srad * srad))
|
|
|
+ // For each split find the x and y clusters
|
|
|
+ for(U z = beginZ; z < endZ; ++z)
|
|
|
{
|
|
|
- // The eye is inside the sphere. All tiles are covered
|
|
|
- tileBeginX = tileBeginY = 0;
|
|
|
- tileEndX = m_counts[0];
|
|
|
- tileEndY = m_counts[1];
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- findTilesFromAabb(aabb, tileBeginX, tileBeginY, tileEndX, tileEndY);
|
|
|
- }
|
|
|
+ const SplitInfo& info = m_splitInfo[z];
|
|
|
|
|
|
- U zFrom, zTo;
|
|
|
- findSplitsFromAabb(aabb, zFrom, zTo);
|
|
|
+ I beginX = -1, endX = -1, beginY = -1, endY = -1;
|
|
|
|
|
|
- // Detailed tests
|
|
|
- for(U z = zFrom; z < zTo; ++z)
|
|
|
- {
|
|
|
- for(U y = tileBeginY; y < tileEndY; ++y)
|
|
|
+ // Find beginX
|
|
|
+ F32 x = box.getMin().x();
|
|
|
+ if(x <= info.m_xy.x())
|
|
|
{
|
|
|
- for(U x = tileBeginX; x < tileEndX; ++x)
|
|
|
- {
|
|
|
- const Cluster& cl = cluster(x, y, z);
|
|
|
- Aabb clusterAabb(cl.m_min.xyz0(), cl.m_max.xyz0());
|
|
|
- if(testCollisionShapes(s, clusterAabb))
|
|
|
- {
|
|
|
- Array<U8, 3> ids = {static_cast<U8>(x),
|
|
|
- static_cast<U8>(y), static_cast<U8>(z)};
|
|
|
- rez.m_clusterIds[rez.m_count++] = ids;
|
|
|
- }
|
|
|
- }
|
|
|
+ beginX = 0;
|
|
|
}
|
|
|
- }
|
|
|
-}
|
|
|
+ else if(x >= (info.m_xy.x() + info.m_sizes.x() * m_counts[0]))
|
|
|
+ {
|
|
|
+ beginX = m_counts[0];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ beginX = (x - info.m_xy.x()) / info.m_sizes.x();
|
|
|
+ }
|
|
|
+ ANKI_ASSERT(beginX >= 0 && beginX <= m_counts[0]);
|
|
|
|
|
|
-//==============================================================================
|
|
|
-void Clusterer::binGeneric(const CollisionShape& cs,
|
|
|
- ClustererTestResult& rez) const
|
|
|
-{
|
|
|
- Aabb aabb;
|
|
|
- cs.computeAabb(aabb);
|
|
|
+ // Find endX
|
|
|
+ x = box.getMax().x();
|
|
|
+ if(x <= info.m_xy.x())
|
|
|
+ {
|
|
|
+ endX = 0;
|
|
|
+ }
|
|
|
+ else if(x >= (info.m_xy.x() + info.m_sizes.x() * m_counts[0]))
|
|
|
+ {
|
|
|
+ endX = m_counts[0];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ endX = ceil((x - info.m_xy.x()) / info.m_sizes.x());
|
|
|
+ }
|
|
|
+ ANKI_ASSERT(endX >= 0 && endX <= m_counts[0]);
|
|
|
|
|
|
- U tileBeginX, tileBeginY, tileEndX, tileEndY;
|
|
|
- if(ANKI_UNLIKELY(aabb.getMax().z() >= -m_near))
|
|
|
- {
|
|
|
- // The eye is inside the sphere. All tiles are covered
|
|
|
- tileBeginX = tileBeginY = 0;
|
|
|
- tileEndX = m_counts[0];
|
|
|
- tileEndY = m_counts[1];
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- findTilesFromAabb(aabb, tileBeginX, tileBeginY, tileEndX, tileEndY);
|
|
|
- }
|
|
|
+ // Find beginY
|
|
|
+ F32 y = box.getMin().y();
|
|
|
+ if(y <= info.m_xy.y())
|
|
|
+ {
|
|
|
+ beginY = 0;
|
|
|
+ }
|
|
|
+ else if(y >= (info.m_xy.y() + info.m_sizes.y() * m_counts[1]))
|
|
|
+ {
|
|
|
+ beginY = m_counts[1];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ beginY = (y - info.m_xy.y()) / info.m_sizes.y();
|
|
|
+ }
|
|
|
+ ANKI_ASSERT(beginY >= 0 && beginY <= m_counts[1]);
|
|
|
|
|
|
- U zFrom, zTo;
|
|
|
- findSplitsFromAabb(aabb, zFrom, zTo);
|
|
|
+ // Find endY
|
|
|
+ y = box.getMax().y();
|
|
|
+ if(y <= info.m_xy.y())
|
|
|
+ {
|
|
|
+ endY = 0;
|
|
|
+ }
|
|
|
+ else if(y >= (info.m_xy.y() + info.m_sizes.y() * m_counts[1]))
|
|
|
+ {
|
|
|
+ endY = m_counts[1];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ endY = ceil((y - info.m_xy.y()) / info.m_sizes.y());
|
|
|
+ }
|
|
|
+ ANKI_ASSERT(endY >= 0 && endY <= m_counts[1]);
|
|
|
|
|
|
- // Detailed tests
|
|
|
- for(U z = zFrom; z < zTo; ++z)
|
|
|
- {
|
|
|
- for(U y = tileBeginY; y < tileEndY; ++y)
|
|
|
+ for(I y = beginY; y < endY; ++y)
|
|
|
{
|
|
|
- for(U x = tileBeginX; x < tileEndX; ++x)
|
|
|
+ for(I x = beginX; x < endX; ++x)
|
|
|
{
|
|
|
const Cluster& cl = cluster(x, y, z);
|
|
|
Aabb clusterAabb(cl.m_min.xyz0(), cl.m_max.xyz0());
|
|
|
@@ -297,5 +236,13 @@ void Clusterer::binGeneric(const CollisionShape& cs,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+//==============================================================================
|
|
|
+void Clusterer::findSplitsFromAabb(const Aabb& box, U& zFrom, U& zTo) const
|
|
|
+{
|
|
|
+ zFrom = calcK(box.getMax().z());
|
|
|
+ zTo = calcK(box.getMin().z()) + 1;
|
|
|
+ ANKI_ASSERT(zFrom <= zTo);
|
|
|
+}
|
|
|
+
|
|
|
} // end namespace anki
|
|
|
|