-inline ClippingBox RenderAlgorithms::CalculateScreenSpaceAABB( const SceneGraph::RenderItem& item )
-{
- // Calculate extent vector of the AABB:
- const Vector3& actorSize = item.mSize;
- const float halfActorX = actorSize.x * 0.5f;
- const float halfActorY = actorSize.y * 0.5f;
-
- // Transform to absolute oriented bounding box.
- const Matrix& worldMatrix = item.mModelViewMatrix;
-
- // To transform the actor bounds to screen-space, We do a fast, 2D version of a matrix multiply optimized for 2D quads.
- // This reduces float multiplications from 64 (16 * 4) to 12 (4 * 3).
- // We create an array of 4 corners and directly initialize the first 3 with the matrix multiplication result of the respective corner.
- // This causes the construction of the vector arrays contents in-place for optimization.
- // We skip the 4th corner here as we can calculate that from the other 3, bypassing matrix multiplication.
- // Note: The below * operators trigger a fast (2D) matrix multiply (only 4 multiplications are done).
- Vector2 corners[4]{ worldMatrix * Vector2( -halfActorX, -halfActorY ),
- worldMatrix * Vector2( halfActorX, -halfActorY ),
- worldMatrix * Vector2( halfActorX, halfActorY ) };
-
- // As we are dealing with a rectangle, we can do a fast calculation to get the 4th corner from knowing the other 3 (even if rotated).
- corners[3] = Vector2( corners[0] + ( corners[2] - corners[1] ) );
-
- // Calculate the AABB:
- // We use knowledge that opposite corners will be the max/min of each other. Doing this reduces the normal 12 branching comparisons to 3.
- // The standard equivalent min/max code of the below would be:
- // Vector2 AABBmax( std::max( corners[0].x, std::max( corners[1].x, std::max( corners[3].x, corners[2].x ) ) ),
- // std::max( corners[0].y, std::max( corners[1].y, std::max( corners[3].y, corners[2].y ) ) ) );
- // Vector2 AABBmin( std::min( corners[0].x, std::min( corners[1].x, std::min( corners[3].x, corners[2].x ) ) ),
- // std::min( corners[0].y, std::min( corners[1].y, std::min( corners[3].y, corners[2].y ) ) ) );
- unsigned int smallestX = 0u;
- // Loop 3 times to find the index of the smallest X value.
- // Note: We deliberately do NOT unroll the code here as this hampers the compilers output.
- for( unsigned int i = 1u; i < 4u; ++i )
- {
- if( corners[i].x < corners[smallestX].x )
- {
- smallestX = i;
- }
- }
-
- // As we are dealing with a rectangle, we can assume opposite corners are the largest.
- // So without doing min/max branching, we can fetch the min/max values of all the remaining X/Y coords from this one index.
- Vector4 aabb( corners[smallestX].x, corners[( smallestX + 3u ) % 4].y, corners[( smallestX + 2u ) % 4].x, corners[( smallestX + 1u ) % 4].y );
-
- // Convert maximums to extents.
- aabb.z -= aabb.x;
- aabb.w -= aabb.y;
-
- // Return the AABB in screen-space pixels (x, y, width, height).
- // Note: This is a algebraic simplification of: ( viewport.x - aabb.width ) / 2 - ( ( aabb.width / 2 ) + aabb.x ) per axis.
- return ClippingBox( ( mViewportRectangle.width / 2 ) - aabb.z - aabb.x, ( mViewportRectangle.height / 2 ) - aabb.w - aabb.y, aabb.z, aabb.w );
-}
-