Working scissor with correct projected bounding box rect

This commit is contained in:
Olivier Prat 2017-10-19 16:23:13 +02:00
parent 111966b987
commit 382262da3d
3 changed files with 98 additions and 12 deletions

View file

@ -185,13 +185,14 @@ glm::ivec4 DrawOutlineMask::computeOutlineRect(const render::ShapeBounds& shapes
for (const auto& item : items) {
const auto& aabb = item.bound;
const auto projectedCube = viewFrustum.getProjectedPolygon(aabb);
glm::vec2 bottomLeft;
glm::vec2 topRight;
if (projectedCube.getAnyInView()) {
minMaxBounds.x = std::min(minMaxBounds.x, projectedCube.getMinX());
minMaxBounds.y = std::min(minMaxBounds.y, projectedCube.getMinY());
minMaxBounds.z = std::max(minMaxBounds.z, projectedCube.getMaxX());
minMaxBounds.w = std::max(minMaxBounds.w, projectedCube.getMaxY());
if (viewFrustum.getProjectedRect(aabb, bottomLeft, topRight)) {
minMaxBounds.x = std::min(minMaxBounds.x, bottomLeft.x);
minMaxBounds.y = std::min(minMaxBounds.y, bottomLeft.y);
minMaxBounds.z = std::max(minMaxBounds.z, topRight.x);
minMaxBounds.w = std::max(minMaxBounds.w, topRight.y);
}
}
}

View file

@ -10,6 +10,7 @@
//
#include <algorithm>
#include <array>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
@ -509,12 +510,12 @@ CubeProjectedPolygon ViewFrustum::computeProjectedPolygon(const TBOX& box) const
const glm::vec3& bottomNearRight = box.getCorner();
glm::vec3 topFarLeft = box.calcTopFarLeft();
int lookUp = ((_position.x < bottomNearRight.x)) // 1 = right | compute 6-bit
+ ((_position.x > topFarLeft.x) << 1) // 2 = left | code to
+ ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera
+ ((_position.y > topFarLeft.y) << 3) // 8 = top | with respect to
+ ((_position.z < bottomNearRight.z) << 4) // 16 = front/near | the 6 defining
+ ((_position.z > topFarLeft.z) << 5); // 32 = back/far | planes
int lookUp = ((_position.x < bottomNearRight.x)) // 1 = right | compute 6-bit
+ ((_position.x > topFarLeft.x) << 1) // 2 = left | code to
+ ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera
+ ((_position.y > topFarLeft.y) << 3) // 8 = top | with respect to
+ ((_position.z < bottomNearRight.z) << 4) // 16 = front/near | the 6 defining
+ ((_position.z > topFarLeft.z) << 5); // 32 = back/far | planes
int vertexCount = hullVertexLookup[lookUp][0]; //look up number of vertices
@ -577,6 +578,89 @@ CubeProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const {
return computeProjectedPolygon(box);
}
bool ViewFrustum::getProjectedRect(const AABox& box, glm::vec2& bottomLeft, glm::vec2& topRight) const {
using Edge = std::pair<int, int>;
const int VERTEX_COUNT = 8;
const int EDGE_COUNT = 12;
// In theory, after clipping a box with a plane, only 4 new vertices at max
// should be created but due to potential imprecisions (edge almost parallel to
// near plane for instance) there might be more
const int MAX_VERTEX_COUNT = VERTEX_COUNT + 4 + 2;
std::array<glm::vec3, MAX_VERTEX_COUNT> vertices;
std::array<Edge, EDGE_COUNT> boxEdges{
Edge(BOTTOM_LEFT_NEAR, BOTTOM_RIGHT_NEAR),
Edge(TOP_LEFT_NEAR, TOP_RIGHT_NEAR),
Edge(BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR),
Edge(TOP_LEFT_FAR, TOP_RIGHT_FAR),
Edge(BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR),
Edge(BOTTOM_LEFT_FAR, TOP_LEFT_FAR),
Edge(BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR),
Edge(BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR),
Edge(BOTTOM_LEFT_NEAR, BOTTOM_LEFT_FAR),
Edge(TOP_LEFT_NEAR, TOP_LEFT_FAR),
Edge(BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR),
Edge(TOP_RIGHT_NEAR, TOP_RIGHT_FAR)
};
std::array<float, VERTEX_COUNT> distancesToNearPlane;
std::bitset<MAX_VERTEX_COUNT> areVerticesInside;
int vertexCount = VERTEX_COUNT;
int i;
// Clip the hull with the near plane.
const auto& nearPlane = _planes[NEAR_PLANE];
for (i = 0; i < VERTEX_COUNT; i++) {
vertices[i] = box.getVertex(static_cast<BoxVertex>(i));
distancesToNearPlane[i] = nearPlane.distance(vertices[i]);
}
for (i = 0; i < EDGE_COUNT; i++) {
const auto& edgeVertexIndices = boxEdges[i];
const auto& startVertex = vertices[edgeVertexIndices.first];
const auto& endVertex = vertices[edgeVertexIndices.second];
float startVertexDistance = distancesToNearPlane[edgeVertexIndices.first];
float endVertexDistance = distancesToNearPlane[edgeVertexIndices.second];
bool isStartPointInside = startVertexDistance >= 0.0f;
bool isEndPointInside = endVertexDistance >= 0.0f;
areVerticesInside.set(edgeVertexIndices.first, isStartPointInside);
areVerticesInside.set(edgeVertexIndices.second, isEndPointInside);
if (isStartPointInside != isEndPointInside) {
// One of the two vertices is behind the near plane so add a new clipped vertex
// add tag it as projectable.
vertices[vertexCount] = startVertex + (endVertex - startVertex) * (startVertexDistance / (startVertexDistance - endVertexDistance));
areVerticesInside.set(vertexCount);
vertexCount++;
}
}
// Project points that are inside
bottomLeft.x = std::numeric_limits<float>::max();
bottomLeft.y = std::numeric_limits<float>::max();
topRight.x = -std::numeric_limits<float>::max();
topRight.y = -std::numeric_limits<float>::max();
for (i = 0; i < vertexCount; i++) {
if (areVerticesInside[i]) {
bool isPointInside;
auto projectedPoint = projectPoint(vertices[i], isPointInside);
bottomLeft.x = std::min(bottomLeft.x, projectedPoint.x);
bottomLeft.y = std::min(bottomLeft.y, projectedPoint.y);
topRight.x = std::max(topRight.x, projectedPoint.x);
topRight.y = std::max(topRight.y, projectedPoint.y);
}
}
bottomLeft.x = glm::clamp(bottomLeft.x, -1.0f, 1.0f);
bottomLeft.y = glm::clamp(bottomLeft.y, -1.0f, 1.0f);
topRight.x = glm::clamp(topRight.x, -1.0f, 1.0f);
topRight.y = glm::clamp(topRight.y, -1.0f, 1.0f);
return areVerticesInside.any();
}
// Similar strategy to getProjectedPolygon() we use the knowledge of camera position relative to the
// axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for
// squares and square-roots. Just compares.

View file

@ -120,6 +120,7 @@ public:
glm::vec2 projectPoint(glm::vec3 point, bool& pointInView) const;
CubeProjectedPolygon getProjectedPolygon(const AACube& box) const;
CubeProjectedPolygon getProjectedPolygon(const AABox& box) const;
bool getProjectedRect(const AABox& box, glm::vec2& bottomLeft, glm::vec2& topRight) const;
void getFurthestPointFromCamera(const AACube& box, glm::vec3& furthestPoint) const;
float distanceToCamera(const glm::vec3& point) const;