void EDA_3D_CANVAS::render3DComponentShape( MODULE* module, bool aIsRenderingJustNonTransparentObjects, bool aIsRenderingJustTransparentObjects ) { double zpos = GetPrm3DVisu().GetModulesZcoord3DIU( module->IsFlipped() ); glPushMatrix(); wxPoint pos = module->GetPosition(); glTranslatef( pos.x * GetPrm3DVisu().m_BiuTo3Dunits, -pos.y * GetPrm3DVisu().m_BiuTo3Dunits, zpos ); if( module->GetOrientation() ) glRotatef( (double) module->GetOrientation() / 10.0, 0.0f, 0.0f, 1.0f ); if( module->IsFlipped() ) { glRotatef( 180.0f, 0.0f, 1.0f, 0.0f ); glRotatef( 180.0f, 0.0f, 0.0f, 1.0f ); } S3D_MASTER* shape3D = module->Models(); for( ; shape3D; shape3D = shape3D->Next() ) { if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) ) { glPushMatrix(); shape3D->Render( aIsRenderingJustNonTransparentObjects, aIsRenderingJustTransparentObjects ); if( isEnabled( FL_RENDER_SHOW_MODEL_BBOX ) ) { // Set the alpha current color to opaque float currentColor[4]; glGetFloatv( GL_CURRENT_COLOR,currentColor ); currentColor[3] = 1.0f; glColor4fv( currentColor ); CBBOX thisBBox = shape3D->getBBox(); thisBBox.GLdebug(); } glPopMatrix(); // Debug AABBox //thisBBox = shape3D->getfastAABBox(); //thisBBox.GLdebug(); } } glPopMatrix(); }
void CBBOX::ApplyTransformationAA( glm::mat4 aTransformMatrix ) { if( m_initialized == false ) return; // apply the transformation matrix for each of vertices of the bounding box // and make a union with all vertices CBBOX tmpBBox = CBBOX( S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_min.y, m_min.z, 1.0f ) ) ); tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_min.y, m_min.z, 1.0f ) ) ); tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_max.y, m_min.z, 1.0f ) ) ); tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_min.y, m_max.z, 1.0f ) ) ); tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_min.x, m_max.y, m_max.z, 1.0f ) ) ); tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_max.y, m_min.z, 1.0f ) ) ); tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_min.y, m_max.z, 1.0f ) ) ); tmpBBox.Union( S3D_VERTEX( aTransformMatrix * glm::vec4( m_max.x, m_max.y, m_max.z, 1.0f ) ) ); m_min = tmpBBox.m_min; m_max = tmpBBox.m_max; }
BVHBuildNode *CBVH_PBRT::buildUpperSAH( std::vector<BVHBuildNode *> &treeletRoots, int start, int end, int *totalNodes ) { wxASSERT( totalNodes != NULL ); wxASSERT( start < end ); wxASSERT( end <= (int)treeletRoots.size() ); int nNodes = end - start; if( nNodes == 1 ) return treeletRoots[start]; (*totalNodes)++; BVHBuildNode *node = static_cast<BVHBuildNode *>( _mm_malloc( sizeof( BVHBuildNode ), L1_CACHE_LINE_SIZE ) ); m_addresses_pointer_to_mm_free.push_back( node ); node->bounds.Reset(); node->firstPrimOffset = 0; node->nPrimitives = 0; node->splitAxis = 0; node->children[0] = NULL; node->children[1] = NULL; // Compute bounds of all nodes under this HLBVH node CBBOX bounds; bounds.Reset(); for( int i = start; i < end; ++i ) bounds.Union( treeletRoots[i]->bounds ); // Compute bound of HLBVH node centroids, choose split dimension _dim_ CBBOX centroidBounds; centroidBounds.Reset(); for( int i = start; i < end; ++i ) { SFVEC3F centroid = (treeletRoots[i]->bounds.Min() + treeletRoots[i]->bounds.Max()) * 0.5f; centroidBounds.Union(centroid); } const int dim = centroidBounds.MaxDimension(); // FIXME: if this hits, what do we need to do? // Make sure the SAH split below does something... ? wxASSERT( centroidBounds.Max()[dim] != centroidBounds.Min()[dim] ); // Allocate _BucketInfo_ for SAH partition buckets const int nBuckets = 12; BucketInfo buckets[nBuckets]; for( int i = 0; i < nBuckets; ++i ) { buckets[i].count = 0; buckets[i].bounds.Reset(); } // Initialize _BucketInfo_ for HLBVH SAH partition buckets for( int i = start; i < end; ++i ) { const float centroid = ( treeletRoots[i]->bounds.Min()[dim] + treeletRoots[i]->bounds.Max()[dim] ) * 0.5f; int b = nBuckets * ( (centroid - centroidBounds.Min()[dim] ) / (centroidBounds.Max()[dim] - centroidBounds.Min()[dim] ) ); if( b == nBuckets ) b = nBuckets - 1; wxASSERT( (b >= 0) && (b < nBuckets) ); buckets[b].count++; buckets[b].bounds.Union( treeletRoots[i]->bounds ); } // Compute costs for splitting after each bucket float cost[nBuckets - 1]; for( int i = 0; i < nBuckets - 1; ++i ) { CBBOX b0, b1; b0.Reset(); b1.Reset(); int count0 = 0, count1 = 0; for( int j = 0; j <= i; ++j ) { if( buckets[j].count ) { count0 += buckets[j].count; b0.Union( buckets[j].bounds ); } } for( int j = i + 1; j < nBuckets; ++j ) { if( buckets[j].count ) { count1 += buckets[j].count; b1.Union( buckets[j].bounds ); } } cost[i] = .125f + ( count0 * b0.SurfaceArea() + count1 * b1.SurfaceArea() ) / bounds.SurfaceArea(); } // Find bucket to split at that minimizes SAH metric float minCost = cost[0]; int minCostSplitBucket = 0; for( int i = 1; i < nBuckets - 1; ++i ) { if( cost[i] < minCost ) { minCost = cost[i]; minCostSplitBucket = i; } } // Split nodes and create interior HLBVH SAH node BVHBuildNode **pmid = std::partition( &treeletRoots[start], &treeletRoots[end - 1] + 1, HLBVH_SAH_Evaluator( minCostSplitBucket, nBuckets, dim, centroidBounds ) ); const int mid = pmid - &treeletRoots[0]; wxASSERT( (mid > start) && (mid < end) ); node->InitInterior( dim, buildUpperSAH( treeletRoots, start, mid, totalNodes ), buildUpperSAH( treeletRoots, mid, end, totalNodes ) ); return node; }
BVHPrimitiveInfo( int aPrimitiveNumber, const CBBOX &aBounds ) : primitiveNumber( aPrimitiveNumber ), bounds( aBounds ), centroid( .5f * aBounds.Min() + .5f * aBounds.Max() ) {}
BVHBuildNode *CBVH_PBRT::emitLBVH( BVHBuildNode *&buildNodes, const std::vector<BVHPrimitiveInfo> &primitiveInfo, MortonPrimitive *mortonPrims, int nPrimitives, int *totalNodes, CONST_VECTOR_OBJECT &orderedPrims, int *orderedPrimsOffset, int bit) { wxASSERT( nPrimitives > 0 ); wxASSERT( totalNodes != NULL ); wxASSERT( orderedPrimsOffset != NULL ); wxASSERT( nPrimitives > 0 ); wxASSERT( mortonPrims != NULL ); if( (bit == -1) || (nPrimitives < m_maxPrimsInNode) ) { // Create and return leaf node of LBVH treelet (*totalNodes)++; BVHBuildNode *node = buildNodes++; CBBOX bounds; bounds.Reset(); int firstPrimOffset = *orderedPrimsOffset; *orderedPrimsOffset += nPrimitives; wxASSERT( (firstPrimOffset + (nPrimitives - 1)) < (int)orderedPrims.size() ); for( int i = 0; i < nPrimitives; ++i ) { const int primitiveIndex = mortonPrims[i].primitiveIndex; wxASSERT( primitiveIndex < (int)m_primitives.size() ); orderedPrims[firstPrimOffset + i] = m_primitives[primitiveIndex]; bounds.Union( primitiveInfo[primitiveIndex].bounds ); } node->InitLeaf( firstPrimOffset, nPrimitives, bounds ); return node; } else { int mask = 1 << bit; // Advance to next subtree level if there's no LBVH split for this bit if( (mortonPrims[0].mortonCode & mask) == (mortonPrims[nPrimitives - 1].mortonCode & mask) ) return emitLBVH( buildNodes, primitiveInfo, mortonPrims, nPrimitives, totalNodes, orderedPrims, orderedPrimsOffset, bit - 1 ); // Find LBVH split point for this dimension int searchStart = 0; int searchEnd = nPrimitives - 1; while( searchStart + 1 != searchEnd ) { wxASSERT(searchStart != searchEnd); const int mid = (searchStart + searchEnd) / 2; if( (mortonPrims[searchStart].mortonCode & mask) == (mortonPrims[mid].mortonCode & mask) ) searchStart = mid; else { wxASSERT( (mortonPrims[mid].mortonCode & mask) == (mortonPrims[searchEnd].mortonCode & mask) ); searchEnd = mid; } } const int splitOffset = searchEnd; wxASSERT( splitOffset <= (nPrimitives - 1) ); wxASSERT( (mortonPrims[splitOffset - 1].mortonCode & mask) != (mortonPrims[splitOffset].mortonCode & mask) ); // Create and return interior LBVH node (*totalNodes)++; BVHBuildNode *node = buildNodes++; BVHBuildNode *lbvh[2]; lbvh[0] = emitLBVH( buildNodes, primitiveInfo, mortonPrims, splitOffset, totalNodes, orderedPrims, orderedPrimsOffset, bit - 1 ); lbvh[1] = emitLBVH( buildNodes, primitiveInfo, &mortonPrims[splitOffset], nPrimitives - splitOffset, totalNodes, orderedPrims, orderedPrimsOffset, bit - 1 ); const int axis = bit % 3; node->InitInterior( axis, lbvh[0], lbvh[1] ); return node; } }
BVHBuildNode *CBVH_PBRT::HLBVHBuild( const std::vector<BVHPrimitiveInfo> &primitiveInfo, int *totalNodes, CONST_VECTOR_OBJECT &orderedPrims ) { // Compute bounding box of all primitive centroids CBBOX bounds; bounds.Reset(); for( unsigned int i = 0; i < primitiveInfo.size(); ++i ) bounds.Union( primitiveInfo[i].centroid ); // Compute Morton indices of primitives std::vector<MortonPrimitive> mortonPrims( primitiveInfo.size() ); for( int i = 0; i < (int)primitiveInfo.size(); ++i ) { // Initialize _mortonPrims[i]_ for _i_th primitive const int mortonBits = 10; const int mortonScale = 1 << mortonBits; wxASSERT( primitiveInfo[i].primitiveNumber < (int)primitiveInfo.size() ); mortonPrims[i].primitiveIndex = primitiveInfo[i].primitiveNumber; const SFVEC3F centroidOffset = bounds.Offset( primitiveInfo[i].centroid ); wxASSERT( (centroidOffset.x >= 0.0f) && (centroidOffset.x <= 1.0f) ); wxASSERT( (centroidOffset.y >= 0.0f) && (centroidOffset.y <= 1.0f) ); wxASSERT( (centroidOffset.z >= 0.0f) && (centroidOffset.z <= 1.0f) ); mortonPrims[i].mortonCode = EncodeMorton3( centroidOffset * SFVEC3F( (float)mortonScale ) ); } // Radix sort primitive Morton indices RadixSort( &mortonPrims ); // Create LBVH treelets at bottom of BVH // Find intervals of primitives for each treelet std::vector<LBVHTreelet> treeletsToBuild; for( int start = 0, end = 1; end <= (int)mortonPrims.size(); ++end ) { const uint32_t mask = 0b00111111111111000000000000000000; if( (end == (int)mortonPrims.size()) || ( (mortonPrims[start].mortonCode & mask) != (mortonPrims[end].mortonCode & mask) ) ) { // Add entry to _treeletsToBuild_ for this treelet const int numPrimitives = end - start; const int maxBVHNodes = 2 * numPrimitives; // !TODO: implement a memory arena BVHBuildNode *nodes = static_cast<BVHBuildNode *>( _mm_malloc( maxBVHNodes * sizeof( BVHBuildNode ), L1_CACHE_LINE_SIZE ) ); m_addresses_pointer_to_mm_free.push_back( nodes ); for( int i = 0; i < maxBVHNodes; ++i ) { nodes[i].bounds.Reset(); nodes[i].firstPrimOffset = 0; nodes[i].nPrimitives = 0; nodes[i].splitAxis = 0; nodes[i].children[0] = NULL; nodes[i].children[1] = NULL; } LBVHTreelet tmpTreelet; tmpTreelet.startIndex = start; tmpTreelet.numPrimitives = numPrimitives; tmpTreelet.buildNodes = nodes; treeletsToBuild.push_back( tmpTreelet ); start = end; } } // Create LBVHs for treelets in parallel int atomicTotal = 0; int orderedPrimsOffset = 0; orderedPrims.resize( m_primitives.size() ); for( int index = 0; index < (int)treeletsToBuild.size(); ++index ) { // Generate _index_th LBVH treelet int nodesCreated = 0; const int firstBit = 29 - 12; LBVHTreelet &tr = treeletsToBuild[index]; wxASSERT( tr.startIndex < (int)mortonPrims.size() ); tr.buildNodes = emitLBVH( tr.buildNodes, primitiveInfo, &mortonPrims[tr.startIndex], tr.numPrimitives, &nodesCreated, orderedPrims, &orderedPrimsOffset, firstBit ); atomicTotal += nodesCreated; } *totalNodes = atomicTotal; // Initialize _finishedTreelets_ with treelet root node pointers std::vector<BVHBuildNode *> finishedTreelets; finishedTreelets.reserve( treeletsToBuild.size() ); for( int index = 0; index < (int)treeletsToBuild.size(); ++index ) finishedTreelets.push_back( treeletsToBuild[index].buildNodes ); // Create and return SAH BVH from LBVH treelets return buildUpperSAH( finishedTreelets, 0, finishedTreelets.size(), totalNodes ); }
BVHBuildNode *CBVH_PBRT::recursiveBuild ( std::vector<BVHPrimitiveInfo> &primitiveInfo, int start, int end, int *totalNodes, CONST_VECTOR_OBJECT &orderedPrims ) { wxASSERT( totalNodes != NULL ); wxASSERT( start >= 0 ); wxASSERT( end >= 0 ); wxASSERT( start != end ); wxASSERT( start < end ); wxASSERT( start <= (int)primitiveInfo.size() ); wxASSERT( end <= (int)primitiveInfo.size() ); (*totalNodes)++; // !TODO: implement an memory Arena BVHBuildNode *node = static_cast<BVHBuildNode *>( _mm_malloc( sizeof( BVHBuildNode ), L1_CACHE_LINE_SIZE ) ); m_addresses_pointer_to_mm_free.push_back( node ); node->bounds.Reset(); node->firstPrimOffset = 0; node->nPrimitives = 0; node->splitAxis = 0; node->children[0] = NULL; node->children[1] = NULL; // Compute bounds of all primitives in BVH node CBBOX bounds; bounds.Reset(); for( int i = start; i < end; ++i ) bounds.Union( primitiveInfo[i].bounds ); int nPrimitives = end - start; if( nPrimitives == 1 ) { // Create leaf _BVHBuildNode_ int firstPrimOffset = orderedPrims.size(); for( int i = start; i < end; ++i ) { int primitiveNr = primitiveInfo[i].primitiveNumber; wxASSERT( primitiveNr < (int)m_primitives.size() ); orderedPrims.push_back( m_primitives[ primitiveNr ] ); } node->InitLeaf( firstPrimOffset, nPrimitives, bounds ); } else { // Compute bound of primitive centroids, choose split dimension _dim_ CBBOX centroidBounds; centroidBounds.Reset(); for( int i = start; i < end; ++i ) centroidBounds.Union( primitiveInfo[i].centroid ); const int dim = centroidBounds.MaxDimension(); // Partition primitives into two sets and build children int mid = (start + end) / 2; if( fabs( centroidBounds.Max()[dim] - centroidBounds.Min()[dim] ) < (FLT_EPSILON + FLT_EPSILON) ) { // Create leaf _BVHBuildNode_ const int firstPrimOffset = orderedPrims.size(); for( int i = start; i < end; ++i ) { int primitiveNr = primitiveInfo[i].primitiveNumber; wxASSERT( (primitiveNr >= 0) && (primitiveNr < (int)m_primitives.size()) ); const COBJECT *obj = static_cast<const COBJECT *>( m_primitives[ primitiveNr ] ); wxASSERT( obj != NULL ); orderedPrims.push_back( obj ); } node->InitLeaf( firstPrimOffset, nPrimitives, bounds ); } else { // Partition primitives based on _splitMethod_ switch( m_splitMethod ) { case SPLIT_MIDDLE: { // Partition primitives through node's midpoint float pmid = centroidBounds.GetCenter( dim ); BVHPrimitiveInfo *midPtr = std::partition( &primitiveInfo[start], &primitiveInfo[end - 1] + 1, CompareToMid( dim, pmid ) ); mid = midPtr - &primitiveInfo[0]; wxASSERT( (mid >= start) && (mid <= end) ); if( (mid != start) && (mid != end) ) // for lots of prims with large overlapping bounding boxes, this // may fail to partition; in that case don't break and fall through // to SPLIT_EQUAL_COUNTS break; } case SPLIT_EQUALCOUNTS: { // Partition primitives into equally-sized subsets mid = (start + end) / 2; std::nth_element( &primitiveInfo[start], &primitiveInfo[mid], &primitiveInfo[end - 1] + 1, ComparePoints( dim ) ); break; } case SPLIT_SAH: default: { // Partition primitives using approximate SAH if( nPrimitives <= 2 ) { // Partition primitives into equally-sized subsets mid = (start + end) / 2; std::nth_element( &primitiveInfo[start], &primitiveInfo[mid], &primitiveInfo[end - 1] + 1, ComparePoints( dim ) ); } else { // Allocate _BucketInfo_ for SAH partition buckets const int nBuckets = 12; BucketInfo buckets[nBuckets]; for( int i = 0; i < nBuckets; ++i ) { buckets[i].count = 0; buckets[i].bounds.Reset(); } // Initialize _BucketInfo_ for SAH partition buckets for( int i = start; i < end; ++i ) { int b = nBuckets * centroidBounds.Offset( primitiveInfo[i].centroid )[dim]; if( b == nBuckets ) b = nBuckets - 1; wxASSERT( b >= 0 && b < nBuckets ); buckets[b].count++; buckets[b].bounds.Union( primitiveInfo[i].bounds ); } // Compute costs for splitting after each bucket float cost[nBuckets - 1]; for( int i = 0; i < (nBuckets - 1); ++i ) { CBBOX b0, b1; b0.Reset(); b1.Reset(); int count0 = 0; int count1 = 0; for( int j = 0; j <= i; ++j ) { if( buckets[j].count ) { count0 += buckets[j].count; b0.Union( buckets[j].bounds ); } } for( int j = i + 1; j < nBuckets; ++j ) { if( buckets[j].count ) { count1 += buckets[j].count; b1.Union( buckets[j].bounds ); } } cost[i] = 1.0f + ( count0 * b0.SurfaceArea() + count1 * b1.SurfaceArea() ) / bounds.SurfaceArea(); } // Find bucket to split at that minimizes SAH metric float minCost = cost[0]; int minCostSplitBucket = 0; for( int i = 1; i < (nBuckets - 1); ++i ) { if( cost[i] < minCost ) { minCost = cost[i]; minCostSplitBucket = i; } } // Either create leaf or split primitives at selected SAH // bucket if( (nPrimitives > m_maxPrimsInNode) || (minCost < (float)nPrimitives) ) { BVHPrimitiveInfo *pmid = std::partition( &primitiveInfo[start], &primitiveInfo[end - 1] + 1, CompareToBucket( minCostSplitBucket, nBuckets, dim, centroidBounds ) ); mid = pmid - &primitiveInfo[0]; wxASSERT( (mid >= start) && (mid <= end) ); } else { // Create leaf _BVHBuildNode_ const int firstPrimOffset = orderedPrims.size(); for( int i = start; i < end; ++i ) { const int primitiveNr = primitiveInfo[i].primitiveNumber; wxASSERT( primitiveNr < (int)m_primitives.size() ); orderedPrims.push_back( m_primitives[ primitiveNr ] ); } node->InitLeaf( firstPrimOffset, nPrimitives, bounds ); return node; } } break; } } node->InitInterior( dim, recursiveBuild( primitiveInfo, start, mid, totalNodes, orderedPrims ), recursiveBuild( primitiveInfo, mid, end, totalNodes, orderedPrims) ); } } return node; }
void EDA_3D_CANVAS::calcBBox() { BOARD* pcb = GetBoard(); m_fastAABBox.Reset(); for( MODULE* module = pcb->m_Modules; module; module = module->Next() ) { CBBOX tmpFastAABBox; // Compute the transformation matrix for this module based on translation, rotation and orientation. float zpos = GetPrm3DVisu().GetModulesZcoord3DIU( module->IsFlipped() ); wxPoint pos = module->GetPosition(); glm::mat4 fullTransformMatrix; fullTransformMatrix = glm::translate( glm::mat4(), S3D_VERTEX( (float)(pos.x * GetPrm3DVisu().m_BiuTo3Dunits), (float)(-pos.y * GetPrm3DVisu().m_BiuTo3Dunits), zpos ) ); if( module->GetOrientation() ) fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians( (float)(module->GetOrientation() / 10.0f) ), S3D_VERTEX( 0.0f, 0.0f, 1.0f ) ); if( module->IsFlipped() ) { fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians( 180.0f ), S3D_VERTEX( 0.0f, 1.0f, 0.0f ) ); fullTransformMatrix = glm::rotate( fullTransformMatrix, glm::radians( 180.0f ), S3D_VERTEX( 0.0f, 0.0f, 1.0f ) ); } // Compute a union bounding box for all the shapes of the model S3D_MASTER* shape3D = module->Models(); for( ; shape3D; shape3D = shape3D->Next() ) { if( shape3D->Is3DType( S3D_MASTER::FILE3D_VRML ) ) tmpFastAABBox.Union( shape3D->getFastAABBox() ); } tmpFastAABBox.ApplyTransformationAA( fullTransformMatrix ); m_fastAABBox.Union( tmpFastAABBox ); } // Create a board bounding box based on board size wxSize brd_size = getBoardSize(); wxPoint brd_center_pos = getBoardCenter(); float xsize = brd_size.x; float ysize = brd_size.y; float scale = GetPrm3DVisu().m_BiuTo3Dunits; float xmin = (brd_center_pos.x - xsize / 2.0) * scale; float xmax = (brd_center_pos.x + xsize / 2.0) * scale; float ymin = (brd_center_pos.y - ysize / 2.0) * scale; float ymax = (brd_center_pos.y + ysize / 2.0) * scale; float zmin = GetPrm3DVisu().GetLayerZcoordBIU( B_Adhes ) * scale; float zmax = GetPrm3DVisu().GetLayerZcoordBIU( F_Adhes ) * scale; m_boardAABBox = CBBOX( S3D_VERTEX(xmin, ymin, zmin), S3D_VERTEX(xmax, ymax, zmax) ); // Add BB board with BB models and scale it a bit m_fastAABBox.Union( m_boardAABBox ); m_fastAABBox_Shadow = m_fastAABBox; m_fastAABBox_Shadow.Scale( SHADOW_BOUNDING_BOX_SCALE ); }