diff --git a/README.md b/README.md index d75a320e..8a03ad56 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,6 @@ any other issue with this release. * [#62](https://github.com/BlueBrain/Livre/issues/62): Missing bricks in first frame after load_equalizer change -* [LIV-157](https://bbpteam.epfl.ch/project/issues/browse/LIV-157): - Livre renders overlapping LOD nodes from different levels ## About diff --git a/doc/Changelog.md b/doc/Changelog.md index 9e102284..75b677f9 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -17,6 +17,9 @@ Changelog {#Changelog} extension, based on the format used by ImageVis3D) * [#75](https://github.com/BlueBrain/Livre/pull/75): Separate ZeroEQ communication to class zeq::Communicator +* [#88](https://github.com/BlueBrain/Livre/pull/88): + Fix [LIV-157)](https://bbpteam.epfl.ch/project/issues/browse/LIV-157) + rendering of overlapping LOD nodes from different levels # Release 0.3 (2015-07-07) {#Release030} diff --git a/livre/Lib/Render/AvailableSetGenerator.cpp b/livre/Lib/Render/AvailableSetGenerator.cpp index 18810c84..e14c5be9 100644 --- a/livre/Lib/Render/AvailableSetGenerator.cpp +++ b/livre/Lib/Render/AvailableSetGenerator.cpp @@ -153,20 +153,29 @@ void AvailableSetGenerator::generateRenderingSet( const Frustum&, CollectionTraversal colTraverser; colTraverser.traverse( frameInfo.allNodesList, collector ); - NodeIdDashNodeMap::const_iterator it = nodeIdDashNodeMap.begin(); - while( it != nodeIdDashNodeMap.end() ) + if( !frameInfo.notAvailableRenderNodeList.empty( )) { - DashRenderNode childNode( it->second ); - if( !frameInfo.notAvailableRenderNodeList.empty() && - hasParentInMap( childNode, nodeIdDashNodeMap )) + NodeIdDashNodeMap::const_iterator it = nodeIdDashNodeMap.begin(); + size_t previousMapSize = 0; + do { - it = nodeIdDashNodeMap.erase( it ); - } - else - { - frameInfo.renderNodeList.push_back( it->second ); - ++it; + previousMapSize = nodeIdDashNodeMap.size(); + while( it != nodeIdDashNodeMap.end( )) + { + DashRenderNode childNode( it->second ); + if( hasParentInMap( childNode, nodeIdDashNodeMap )) + it = nodeIdDashNodeMap.erase( it ); + else + ++it; + } } + while( previousMapSize != nodeIdDashNodeMap.size( )); + } + + for( NodeIdDashNodeMap::const_iterator it = nodeIdDashNodeMap.begin(); + it != nodeIdDashNodeMap.end(); ++it ) + { + frameInfo.renderNodeList.push_back( it->second ); } } diff --git a/livre/core/Files.cmake b/livre/core/Files.cmake index d9d555bc..4dd513d3 100644 --- a/livre/core/Files.cmake +++ b/livre/core/Files.cmake @@ -44,7 +44,6 @@ set(LIVRECORE_HEADERS Events/EventHandlerFactory.h Events/EventInfo.h Events/EventMapper.h - Maths/BinarySearch.h Maths/Maths.h Maths/Plane.h Maths/Quantizer.h diff --git a/livre/core/Maths/BinarySearch.h b/livre/core/Maths/BinarySearch.h deleted file mode 100644 index e50815c8..00000000 --- a/livre/core/Maths/BinarySearch.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (c) 2011-2014, EPFL/Blue Brain Project - * Ahmet Bilgili - * - * This file is part of Livre - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License version 3.0 as published - * by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _BinarySearch_h_ -#define _BinarySearch_h_ - -#include - -namespace livre -{ - -/** - * Searches a value between limits, for a given function. - * @param function is an object that can run operator( T ) - * @param begin is the lower limit. - * @param end is the upper limit. - * @param y the value to search. - * @param epsilon is the error to stop. - * @param error is true if it cannot find the valu between given limits. - * @return The value between limits. - */ -template < class FunctionClass, class T, class U > -T binarySearch( FunctionClass& function, - T begin, - T end, - U y, - T epsilon, - bool &error ) -{ - float l = begin; - float h = end; - - float lVal = function( l ); - float hVal = function( h ); - - if( y < lVal || y > hVal ) - { - LBINFO << "y :" << y << " is not between " << lVal << " " << hVal << std::endl; - error = true; - return y > hVal ? h : l; - } - - float x = ( l + h ) / 2.0; - while( fabs( l - h ) > epsilon ) - { - x = ( l + h ) / 2.0; - const float functionVal = function( x ); - if( functionVal >= y ) - h = x; - else if( functionVal < y ) - l = x; - } - error = false; - return h; -} - -} - -#endif // _BinarySearch_h_ diff --git a/livre/core/Maths/Plane.cpp b/livre/core/Maths/Plane.cpp index e722c6cd..c3af8a15 100644 --- a/livre/core/Maths/Plane.cpp +++ b/livre/core/Maths/Plane.cpp @@ -66,19 +66,7 @@ Vector3f Plane::getNormal( ) const Vector3f Plane::getAbsNormal( ) const { - return Vector3f( fabs( a_ ), fabs( b_ ), fabs( c_ ) ); -} - -bool Plane::intersectOrUnder(const Boxf& bb) const -{ - const Vector3f halfExtents = bb.getDimension() * 0.5f; - const Vector3f& center = bb.getCenter( ); - - const float distToCenter = center.dot( getNormal() ); - const float radius = halfExtents.dot( getAbsNormal() ); - - const float dMax = distToCenter + radius; - return dMax >= -d_; + return Vector3f( std::abs( a_ ), std::abs( b_ ), std::abs( c_ ) ); } void Plane::set( const float a, const float b, const float c, const float d ) diff --git a/livre/core/Render/Frustum.cpp b/livre/core/Render/Frustum.cpp index 08aba874..0513772f 100644 --- a/livre/core/Render/Frustum.cpp +++ b/livre/core/Render/Frustum.cpp @@ -42,14 +42,14 @@ const Plane& Frustum::getMVPlane( const PlaneId id ) const bool Frustum::boxInFrustum( const Boxf &worldBox ) const { - for (uint32_t i = 0; i < 6; i++) - { - if( !wPlanes_[ i ].intersectOrUnder( worldBox ) ) - { - return false; - } - } - return true; + const Vector3f& min = worldBox.getMin(); + const Vector3f& max = worldBox.getMax(); + const Vector2f x( min[0], max[0] ); + const Vector2f y( min[1], max[1] ); + const Vector2f z( min[2], max[2] ); + + vmml::Visibility vis = vmmlFrustumCuller_.test_aabb( x, y, z ); + return vis == vmml::VISIBILITY_FULL || vis == vmml::VISIBILITY_PARTIAL; } bool Frustum::isInitialized( ) const @@ -151,8 +151,10 @@ void Frustum::initialize( const Matrix4f& modelViewMatrix, viewDir_[ 2 ] = column[ 2 ]; // Meaningful for only symmetric frusta - fovx_ = std::atan( std::abs( vmmlFrustum_.array[ PL_LEFT ] ) / fabs( vmmlFrustum_.array[ PL_NEAR ] ) ) * 2.0f; - fovy_ = std::atan( std::abs( vmmlFrustum_.array[ PL_TOP ] ) / fabs( vmmlFrustum_.array[ PL_NEAR ] ) ) * 2.0f; + fovx_ = std::atan( std::abs( vmmlFrustum_.array[ PL_LEFT ] ) + / std::abs( vmmlFrustum_.array[ PL_NEAR ] ) ) * 2.0f; + fovy_ = std::atan( std::abs( vmmlFrustum_.array[ PL_TOP ] ) + / std::abs( vmmlFrustum_.array[ PL_NEAR ] ) ) * 2.0f; isInitialized_ = true; } @@ -183,8 +185,10 @@ void Frustum::initialize( const Matrix4f &modelViewMatrix, initializePlaneCenters_( ); // Meaningful for only symmetric frusta - fovx_ = std::atan( std::abs( vmmlFrustum_.array[ PL_LEFT ] ) / fabs( vmmlFrustum_.array[ PL_NEAR ] ) ) * 2.0f; - fovy_ = std::atan( std::abs( vmmlFrustum_.array[ PL_TOP ] ) / fabs( vmmlFrustum_.array[ PL_NEAR ] ) ) * 2.0f; + fovx_ = std::atan( std::abs( vmmlFrustum_.array[ PL_LEFT ] ) / + std::abs( vmmlFrustum_.array[ PL_NEAR ] ) ) * 2.0f; + fovy_ = std::atan( std::abs( vmmlFrustum_.array[ PL_TOP ] ) / + std::abs( vmmlFrustum_.array[ PL_NEAR ] ) ) * 2.0f; isInitialized_ = true; } @@ -238,7 +242,8 @@ void Frustum::initializePlaneCenters_() planeCenters_[ PL_BOTTOM ] = planeCenters_[ PL_BOTTOM ] / planeCenters_[ PL_BOTTOM ][ 3 ]; } -void Frustum::computeFrustumVertices_( Vector3f frustumVertices[], Vector3f frustumNormals[] ) const +void Frustum::computeFrustumVertices_( Vector3f frustumVertices[], + Vector3f frustumNormals[] ) const { float farLeft; float farRight; @@ -300,22 +305,34 @@ void Frustum::computeFrustumVertices_( Vector3f frustumVertices[], Vector3f frus frustumVertices[7][2] = -f; // compute normals - frustumNormals[0] = (frustumVertices[5] - frustumVertices[1]).cross(frustumVertices[2] - frustumVertices[1]); + frustumNormals[0] = (frustumVertices[5] + - frustumVertices[1]).cross(frustumVertices[2] + - frustumVertices[1]); frustumNormals[0].normalize(); - frustumNormals[1] = (frustumVertices[3] - frustumVertices[0]).cross(frustumVertices[4] - frustumVertices[0]); + frustumNormals[1] = (frustumVertices[3] + - frustumVertices[0]).cross(frustumVertices[4] + - frustumVertices[0]); frustumNormals[1].normalize(); - frustumNormals[2] = (frustumVertices[6] - frustumVertices[2]).cross(frustumVertices[3] - frustumVertices[2]); + frustumNormals[2] = (frustumVertices[6] + - frustumVertices[2]).cross(frustumVertices[3] + - frustumVertices[2]); frustumNormals[2].normalize(); - frustumNormals[3] = (frustumVertices[4] - frustumVertices[0]).cross(frustumVertices[1] - frustumVertices[0]); + frustumNormals[3] = (frustumVertices[4] + - frustumVertices[0]).cross(frustumVertices[1] + - frustumVertices[0]); frustumNormals[3].normalize(); - frustumNormals[4] = (frustumVertices[1] - frustumVertices[0]).cross(frustumVertices[3] - frustumVertices[0]); + frustumNormals[4] = (frustumVertices[1] + - frustumVertices[0]).cross(frustumVertices[3] + - frustumVertices[0]); frustumNormals[4].normalize(); - frustumNormals[5] = (frustumVertices[7] - frustumVertices[4]).cross(frustumVertices[5] - frustumVertices[4]); + frustumNormals[5] = (frustumVertices[7] + - frustumVertices[4]).cross(frustumVertices[5] + - frustumVertices[4]); frustumNormals[5].normalize(); } diff --git a/livre/core/Render/Frustum.h b/livre/core/Render/Frustum.h index 5a1df192..c133a03e 100644 --- a/livre/core/Render/Frustum.h +++ b/livre/core/Render/Frustum.h @@ -166,43 +166,25 @@ class Frustum void computeFrustumVertices_( Vector3f frustumVertices[], Vector3f frustumNormals[] ) const; - void computeLimitsFromProjectionMatrix_( ); - void initializePlanes_( const Matrix4f &matrix, Plane *planes ); - void initialize_( ); - void initializePlaneCenters_( ); Plane wPlanes_[ 6 ]; - Plane mvPlanes_[ 6 ]; - Matrix4f mvpMatrix_; - Matrix4f modelViewMatrix_; - Matrix4f invModelViewMatrix_; - Matrix4f projectionMatrix_; - Matrix4f invProjectionMatrix_; - bool isInitialized_; - float fovy_; - float fovx_; - Vector3f eye_; - Vector3f viewDir_; - Vector4f planeCenters_[ 6 ]; - Frustumf vmmlFrustum_; - FrustumCullerf vmmlFrustumCuller_; }; diff --git a/livre/core/Render/RenderBrick.cpp b/livre/core/Render/RenderBrick.cpp index 89ce528f..741c6216 100644 --- a/livre/core/Render/RenderBrick.cpp +++ b/livre/core/Render/RenderBrick.cpp @@ -51,6 +51,7 @@ #include #include +#include #include namespace livre @@ -128,10 +129,14 @@ void RenderBrick::getScreenCoordinates( const Frustum& frustum, } } - xMin = std::max( (int)floor( xMin + 0.5 ), pvp[0] ); - yMin = std::max( (int)floor( yMin + 0.5 ), pvp[1] ); - xMax = std::min( (int)floor( xMax + 0.5 ), pvp[0] + pvp[2] ); - yMax = std::min( (int)floor( yMax + 0.5 ), pvp[1] + pvp[3] ); + xMin = maths::clamp( xMin + 0.5, (double)pvp[0], + (double)pvp[0] + (double)pvp[2] ); + yMin = maths::clamp( yMin + 0.5, (double)pvp[1], + (double)pvp[1] + (double)pvp[3] ); + xMax = maths::clamp( xMax + 0.5, (double)pvp[0], + (double)pvp[0] + (double)pvp[2] ); + yMax = maths::clamp( yMax + 0.5, (double)pvp[1], + (double)pvp[1] + (double)pvp[3] ); minScreenPos = Vector2i( xMin, yMin ); maxScreenPos = Vector2i( xMax, yMax );