bool intersection(Vector4 start1, Vector4 end1, Vector4 start2, Vector4 end2, Vector4 *out_intersection) { Vector4 dir1 = Vector4Subtract(end1, start1); Vector4 dir2 = Vector4Subtract(end2, start2); //считаем уравнения прямых проходящих через отрезки float a1 = -dir1.y; float b1 = +dir1.x; float d1 = -(a1*start1.x + b1*start1.y); float a2 = -dir2.y; float b2 = +dir2.x; float d2 = -(a2*start2.x + b2*start2.y); //подставляем концы отрезков, для выяснения в каких полуплоскотях они float seg1_line2_start = a2*start1.x + b2*start1.y + d2; float seg1_line2_end = a2*end1.x + b2*end1.y + d2; float seg2_line1_start = a1*start2.x + b1*start2.y + d1; float seg2_line1_end = a1*end2.x + b1*end2.y + d1; //если концы одного отрезка имеют один знак, значит он в одной полуплоскости и пересечения нет. if (seg1_line2_start * seg1_line2_end >= 0 || seg2_line1_start * seg2_line1_end >= 0) return false; float u = seg1_line2_start / (seg1_line2_start - seg1_line2_end); *out_intersection = Vector4Add(start1, Vector4MultiplyScalar(dir1, u)); return true; }
void octGridGetVisibleNodes( tOctGrid const* pOctGrid, CCamera const* pCamera, std::vector<tOctNode const*>& aVisibleNodes ) { // determine the extent of the frustum tVector4 topLeftNear = { 9999.0f, -9999.0f, 9999.0f }; tVector4 bottomRightFar = { -9999.0f, 9999.0f, -9999.0f }; getExtent( &topLeftNear, &bottomRightFar, &pCamera->mFarBottomLeft ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mFarBottomRight ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mFarTopLeft ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mFarTopRight ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mNearBottomLeft ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mNearBottomRight ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mNearTopLeft ); getExtent( &topLeftNear, &bottomRightFar, &pCamera->mNearTopRight ); tVector4 nodeSize = { pOctGrid->mDimension.fX / (float)pOctGrid->miNumNodesInDimension, pOctGrid->mDimension.fY / (float)pOctGrid->miNumNodesInDimension, pOctGrid->mDimension.fZ / (float)pOctGrid->miNumNodesInDimension, 1.0 }; tVector4 gridNearTopLeft = { -nodeSize.fX * (float)pOctGrid->miNumNodesInDimension * 0.5f, nodeSize.fY * (float)pOctGrid->miNumNodesInDimension * 0.5f, -nodeSize.fZ * (float)pOctGrid->miNumNodesInDimension * 0.5f, 1.0f }; tVector4 gridFarBottomRight = { nodeSize.fX * (float)pOctGrid->miNumNodesInDimension * 0.5f, -nodeSize.fY * (float)pOctGrid->miNumNodesInDimension * 0.5f, nodeSize.fZ * (float)pOctGrid->miNumNodesInDimension * 0.5f, 1.0f }; // get the octnode indices in the grid float fLeft = topLeftNear.fX / nodeSize.fX; float fRight = bottomRightFar.fX / nodeSize.fX; float fTop = topLeftNear.fY / nodeSize.fY; float fBottom = bottomRightFar.fY / nodeSize.fY; float fNear = topLeftNear.fZ / nodeSize.fZ; float fFar = bottomRightFar.fZ / nodeSize.fZ; // X int iLeft = (int)ceilf( fLeft ); int iRight = (int)ceilf( fRight ); // Y int iTop = (int)ceilf( fTop ); int iBottom = (int)ceilf( fBottom ); // Z int iNear = (int)ceilf( fNear ); int iFar = (int)ceilf( fFar ); // floor for sign correctness if( fLeft < 0.0 ) { iLeft = (int)floorf( fLeft ); } if( fRight < 0.0 ) { iRight = (int)floorf( fRight ); } if( fTop < 0.0 ) { iTop = (int)floorf( fTop ); } if( fBottom < 0.0 ) { iBottom = (int)floorf( fBottom ); } if( fNear < 0.0 ) { iNear = (int)floorf( fNear ); } if( fFar < 0.0 ) { iFar = (int)floorf( fFar ); } // grid index extent int iGridLeft = (int)floorf( gridNearTopLeft.fX / nodeSize.fX ); int iGridRight = (int)ceilf( gridFarBottomRight.fX / nodeSize.fX ); int iGridTop = (int)ceilf( gridNearTopLeft.fY / nodeSize.fY ); int iGridBottom = (int)ceilf( gridFarBottomRight.fY / nodeSize.fY ); int iGridNear = (int)floorf( gridNearTopLeft.fZ / nodeSize.fZ ); int iGridFar = (int)ceilf( gridFarBottomRight.fZ / nodeSize.fZ ); // clamp if( iLeft < iGridLeft ) { iLeft = iGridLeft; } if( iRight >= iGridRight ) { iRight = iGridRight - 1; } if( iBottom < iGridBottom ) { iBottom = iGridBottom; } if( iTop >= iGridTop ) { iTop = iGridTop - 1; } if( iNear < iGridNear ) { iNear = iGridNear; } if( iFar >= iGridFar ) { iFar = iGridFar - 1; } int iNumNodes = pOctGrid->miNumNodesInDimension; int iHalfNumNodes = iNumNodes >> 1; // shift to (0, num nodes) iLeft += iHalfNumNodes; iRight += iHalfNumNodes; iTop += iHalfNumNodes; iBottom += iHalfNumNodes; iNear += iHalfNumNodes; iFar += iHalfNumNodes; // check for nodes in boundary tOctNode const* aNodes = pOctGrid->maNodes; for( int iZ = iNear; iZ <= iFar; iZ++ ) { for( int iY = iBottom; iY <= iTop; iY++ ) { for( int iX = iLeft; iX <= iRight; iX++ ) { int iIndex = iZ * iNumNodes * iNumNodes + iY * iNumNodes + iX; tOctNode const* pOctNode = &aNodes[iIndex]; bool bInFrustum = pCamera->cubeInFrustum( pOctNode->mpCenter, pOctNode->mfSize ); if( bInFrustum ) { aVisibleNodes.push_back( pOctNode ); //OUTPUT( "%d OCTNODE IN FRUSTUM ( %f, %f, %f )\n", (int)aVisibleNodes.size(), pOctNode->mpCenter->fX, pOctNode->mpCenter->fY, pOctNode->mpCenter->fZ ); } } // for x = left to right } // for y = bottom to top } // for z = near to far #if 0 aVisibleNodes.clear(); // camera direction tVector4 const* pCamPos = pCamera->getPosition(); tVector4 const* pLookAt = pCamera->getLookAt(); tVector4 dir; Vector4Subtract( &dir, pLookAt, pCamPos ); Vector4Normalize( &dir, &dir ); tVector4 const* aCenters = pOctGrid->maNodeCenters; float fNodeSize = pOctGrid->maNodes[0].mfSize; // brute force for now for( int iZ = 0; iZ < iNumNodes; iZ++ ) { for( int iY = 0; iY < iNumNodes; iY++ ) { for( int iX = 0; iX < iNumNodes; iX++ ) { bool bInFrustum = pCamera->cubeInFrustum( aCenters, fNodeSize ); ++aCenters; if( bInFrustum ) { int iIndex = iZ * iNumNodes * iNumNodes + iY * iNumNodes + iX; WTFASSERT2( iIndex < pOctGrid->miNumNodes, "nodes out of bounds while getting visible" ); aVisibleNodes.push_back( &pOctGrid->maNodes[iIndex] ); } } // for x = 0 to num nodes } // for y = 0 to num nodes } // for z = 0 to num nodes #endif // #if 0 }