// static FrustumUtils::IntersectionResult FrustumUtils::intersectBoundingBox( const BoundingBox3f& box, Plane3f planes[ 6 ] ) { auto boxCorners = box.corners(); // by default, we assume the box is completely inside IntersectionResult result = INSIDE; // and keep track, for each corner of the box // how many vertices are inside vs outside int nVerticesInside; int nVerticesOutside; // for each plane do ... for( int i = 0; i < 6; ++i ) { // reset counters for corners nVerticesInside and nVerticesOutside nVerticesInside = 0; nVerticesOutside = 0; // for each corner of the box do ... // get nVerticesOutside of the cycle as soon as a box as corners // both inside and nVerticesOutside of the frustum for( int k = 0; k < 8 && ( nVerticesInside == 0 || nVerticesOutside == 0 ); k++ ) { // is the corner inside or outside? float d = planes[ i ].distance( boxCorners[ k ] ); if( d < 0 ) { ++nVerticesInside; } else { ++nVerticesOutside; } } // if none of the box corners are on the inside halfspace // then it's guaranteed to be outside, done if( nVerticesInside == 0 ) { return OUTSIDE; } // otherwise, at least some of them are inside // but if some of them are *also* outside // then we know for now that it intersects this plane // (but it's not guaranteed to actually intersect the entire frustum) else if( nVerticesOutside != 0 ) { result = INTERESECTING; } // otherwise, we know that some vertices are inside // and none are outside // --> this box is completely inside (for this plane anyway) else { assert( nVerticesInside == 8 ); assert( nVerticesOutside == 0 ); } } return result; }
// virtual Matrix4f DirectionalLight::lightMatrix( const Camera& camera, const BoundingBox3f& sceneBoundingBox ) { const float feather = 1.01; Matrix3f lightLinear = lightBasis(); Vector3f eye = camera.getEye(); // get the corners of the view frustum in light coordinates // with the z = 0 plane at the eye QVector< Vector3f > frustumCorners = camera.getFrustumCorners(); BoundingBox3f frustumBB; for( int i = 0; i < frustumCorners.size(); ++i ) frustumBB.enlarge(frustumCorners[i]); BoundingBox3f sceneAndFrustum = BoundingBox3f::intersect(frustumBB, sceneBoundingBox); QVector< Vector3f > sceneCorners = sceneBoundingBox.corners(); QVector< Vector3f > sceneAndFrustumCorners = sceneAndFrustum.corners(); for( int i = 0; i < sceneAndFrustumCorners.size(); ++i ) { sceneAndFrustumCorners[ i ] = lightLinear * ( sceneAndFrustumCorners[ i ] - eye ); sceneCorners[ i ] = lightLinear * ( sceneCorners[ i ] - eye ); } BoundingBox3f inLightCoordinates; for(int i = 0; i < sceneAndFrustumCorners.size(); ++i) inLightCoordinates.enlarge(sceneAndFrustumCorners[i]); Vector3f maxCorner = inLightCoordinates.maximum(); Vector3f minCorner = inLightCoordinates.minimum(); Vector3f center = inLightCoordinates.center(); maxCorner = center + feather * (maxCorner - center); minCorner = center + feather * (minCorner - center); // add eye point for(int j = 0; j < 3; ++j) { maxCorner[j] = qMax( maxCorner[ j ], 0.0f ); minCorner[j] = qMin( minCorner[ j ], 0.0f ); } // bound the near plane to the scene for( int i = 0; i < sceneCorners.size(); ++i ) { minCorner[2] = qMin( minCorner[2], sceneCorners[ i ][ 2 ] ); } // finally, compute the full light matrix Matrix4f lightMatrix; lightMatrix.setSubmatrix3x3( 0, 0, lightLinear ); Vector3f origin = 0.5 * ( minCorner + maxCorner ); origin[2] = minCorner[2]; lightMatrix.setCol( 3, Vector4f( -origin, 1.f ) - Vector4f( lightLinear * eye, 0.f ) ); for(int i = 0; i < 3; ++i) { lightMatrix.setRow( i, lightMatrix.getRow( i ) * ( ( i == 2 ) ? 1.f : 2.f ) / ( maxCorner[i] - minCorner[i] ) ); } return lightMatrix; }