OSG_BASE_DLLMAPPING bool intersect(const FrustumVolume &frustum, const Volume &vol, FrustumVolume::PlaneSet &inplanes) { Pnt3f min, max; vol.getBounds(min, max); const Plane *frust = frustum.getPlanes(); FrustumVolume::PlaneSet mask = 0x1; // check the box against the 6 planes, adjust the inplanes set // accordingly for(Int32 i = 0; i < 6; i++, mask <<= 1) { if((inplanes & mask) != 0) continue; if(frust[i].isOutHalfSpace(min, max)) return false; if(frust[i].isInHalfSpace(min, max)) inplanes |= mask; } return true; }
void Camera::getFrustum(FrustumVolume& result, const Viewport& p) { Matrix mv,prt,pr; getProjection (pr , p.getPixelWidth(), p.getPixelHeight()); getProjectionTranslation(prt, p.getPixelWidth(), p.getPixelHeight()); getViewing (mv , p.getPixelWidth(), p.getPixelHeight()); pr.mult(prt); pr.mult(mv ); result.setPlanes(pr); }
/*! Calculate the frustum of this camera's visible area (w,h instead port). */ void Camera::getFrustum(FrustumVolume& result, UInt32 width, UInt32 height) { Matrix mv,prt,pr; getProjection (pr , width, height); getProjectionTranslation(prt, width, height); getViewing (mv , width, height); pr.mult(prt); pr.mult(mv ); result.setPlanes(pr); }
OSG_BASE_DLLMAPPING bool intersect(const SphereVolume &sphere, const FrustumVolume &frustum) { const Plane *frust = frustum.getPlanes(); //check the center of the sphere with each plane of the frustum for(Int32 i = 0; i < 6; i++) { if(frust[i].distance(sphere.getCenter()) < -sphere.getRadius()) return false; } return true; }
OSG_BASE_DLLMAPPING bool intersect(const CylinderVolume &cylinder, const FrustumVolume &frustum) { Pnt3f min, max; cylinder.getBounds(min, max); const Plane *frust = frustum.getPlanes(); // check each point of the box to the 6 planes for(Int32 i = 0; i < 6; i++) { if(frust[i].isOutHalfSpace(min, max)) return false; } return true; }
OSG_BEGIN_NAMESPACE OSG_BASE_DLLMAPPING bool operator ==(const FrustumVolume &lhs, const FrustumVolume &rhs) { return ((static_cast<const Volume &>(lhs) == rhs ) && (lhs.getPlanes()[0] == rhs.getPlanes()[0]) && (lhs.getPlanes()[1] == rhs.getPlanes()[1]) && (lhs.getPlanes()[2] == rhs.getPlanes()[2]) && (lhs.getPlanes()[3] == rhs.getPlanes()[3]) && (lhs.getPlanes()[4] == rhs.getPlanes()[4]) && (lhs.getPlanes()[5] == rhs.getPlanes()[5])); }
void ShaderShadowMapEngine::handleDirectionalLightEnter( DirectionalLight *dirL, RenderAction *ract, SSMEngineData *data) { RenderPartition *parentPart = ract ->getActivePartition(); FrustumVolume camFrust = parentPart->getFrustum (); Matrix matEyeToWorld (parentPart->getCameraToWorld()); Matrix matWorldToLight; Matrix matEyeToLight; calcDirectionalLightMatrices(matWorldToLight, matEyeToLight, dirL, matEyeToWorld ); // place light camera outside the scene bounding box: // - project camera frustum and scene bounding box into a // coordinate system where the directional light shines // along the -z axis. // - compute 2 AABBs that contain the projected frustum and // scene BB // - width and height of the ortho projection are determined from // the frustum AABB, while near and far are determined by the // scene AABB (offscreen objects cast shadows into the view volume) Pnt3f camVerts [10]; Pnt3f sceneVerts[10]; const Matrix &matSceneToWorld = ract->topMatrix (); BoxVolume sceneBB = ract->getActNode()->getVolume(); camFrust.getCorners(camVerts [0], camVerts [1], camVerts [2], camVerts [3], camVerts [4], camVerts [5], camVerts [6], camVerts [7] ); sceneBB .getCorners(sceneVerts[0], sceneVerts[1], sceneVerts[2], sceneVerts[3], sceneVerts[4], sceneVerts[5], sceneVerts[6], sceneVerts[7] ); camVerts [8].setValues(TypeTraits<Real32>::getMax(), TypeTraits<Real32>::getMax(), TypeTraits<Real32>::getMax() ); camVerts [9].setValues(TypeTraits<Real32>::getMin(), TypeTraits<Real32>::getMin(), TypeTraits<Real32>::getMin() ); sceneVerts[8].setValues(TypeTraits<Real32>::getMax(), TypeTraits<Real32>::getMax(), TypeTraits<Real32>::getMax() ); sceneVerts[9].setValues(TypeTraits<Real32>::getMin(), TypeTraits<Real32>::getMin(), TypeTraits<Real32>::getMin() ); for(UInt32 i = 0; i < 8; ++i) { matWorldToLight.mult(camVerts [i], camVerts [i]); matSceneToWorld.mult(sceneVerts[i], sceneVerts[i]); matWorldToLight.mult(sceneVerts[i], sceneVerts[i]); camVerts [8][0] = osgMin(camVerts [8][0], camVerts [i][0]); camVerts [9][0] = osgMax(camVerts [9][0], camVerts [i][0]); camVerts [8][1] = osgMin(camVerts [8][1], camVerts [i][1]); camVerts [9][1] = osgMax(camVerts [9][1], camVerts [i][1]); sceneVerts[8][0] = osgMin(sceneVerts[8][0], sceneVerts[i][0]); sceneVerts[9][0] = osgMax(sceneVerts[9][0], sceneVerts[i][0]); sceneVerts[8][1] = osgMin(sceneVerts[8][1], sceneVerts[i][1]); sceneVerts[9][1] = osgMax(sceneVerts[9][1], sceneVerts[i][1]); sceneVerts[8][2] = osgMin(sceneVerts[8][2], sceneVerts[i][2]); sceneVerts[9][2] = osgMax(sceneVerts[9][2], sceneVerts[i][2]); } // these points are the corners of the ortho shadow view volume Pnt3f lightMin(osgMax(camVerts[8][0], sceneVerts[8][0]), osgMax(camVerts[8][1], sceneVerts[8][1]), -sceneVerts[9][2]); Pnt3f lightMax(osgMin(camVerts[9][0], sceneVerts[9][0]), osgMin(camVerts[9][1], sceneVerts[9][1]), -sceneVerts[8][2]); // enlarge by 2% in x, y, z direction lightMin[0] -= (lightMax[0] - lightMin[0]) * 0.01f; lightMin[1] -= (lightMax[1] - lightMin[1]) * 0.01f; lightMin[2] -= (lightMax[2] - lightMin[2]) * 0.01f; lightMax[0] += (lightMax[0] - lightMin[0]) * 0.01f; lightMax[1] += (lightMax[1] - lightMin[1]) * 0.01f; lightMax[2] += (lightMax[2] - lightMin[2]) * 0.01f; Matrix matLightProj; Matrix matLightProjTrans; MatrixOrthogonal(matLightProj, lightMin[0], lightMax[0], lightMin[1], lightMax[1], lightMin[2], lightMax[2] ); updateShadowTexImage (data); updateShadowTexBuffers(data); updateRenderTargets (data); Int32 shadowTexUnit = (this->getForceTextureUnit() > 0) ? this->getForceTextureUnit() : 7; ShaderProgram *shadowFP = this->getShadowFragmentProgram(); if(shadowFP == NULL) { ShaderProgramUnrecPtr newShadowFP = ShaderProgram::createLocal(); newShadowFP->setShaderType(GL_FRAGMENT_SHADER); newShadowFP->setProgram (_dirFPCode ); newShadowFP->addUniformVariable("SSME_matEyeToLight", matEyeToLight); newShadowFP->addUniformVariable("SSME_matLightProj", matLightProj ); newShadowFP->addUniformVariable("SSME_texShadow", shadowTexUnit); this->setShadowFragmentProgram(newShadowFP); shadowFP = newShadowFP; } else { shadowFP->updateUniformVariable("SSME_matEyeToLight", matEyeToLight); shadowFP->updateUniformVariable("SSME_matLightProj", matLightProj ); } commitChanges(); this->pushPartition(ract); { RenderPartition *part = ract->getActivePartition( ); Window *win = ract->getWindow ( ); FrameBufferObject *target = data->getRenderTargets (0); Background *back = data->getBackground ( ); part->setRenderTarget(target); part->setWindow (win ); part->calcViewportDimension(0.f, 0.f, 1.f, 1.f, target->getWidth (), target->getHeight() ); part->setupProjection(matLightProj, matLightProjTrans); part->setupViewing (matWorldToLight ); part->setNear (parentPart->getNear()); part->setFar (parentPart->getFar ()); part->calcFrustum ( ); part->setBackground (back ); // force material for shadow map generation part->overrideMaterial(data->getLightPassMaterials(0), ract->getActNode ( ) ); this->recurseFrom(ract, dirL); ract->useNodeList(false ); // undo override part->overrideMaterial(NULL, ract->getActNode ( ) ); } this->popPartition(ract); }
// visibility levels bool RenderPartition::pushVisibility(Node * const pNode) { if(getFrustumCulling() == false) return true; FrustumVolume::PlaneSet inplanes = _visibilityStack.back(); if(inplanes == FrustumVolume::P_ALL) { _visibilityStack.push_back(inplanes); return true; } Color3f col; bool result = true; FrustumVolume frustum = _oFrustum; BoxVolume vol = pNode->getVolume(); // don't mess with infinite volumes if(vol.isInfinite() == false) { pNode->updateVolume(); vol = pNode->getVolume(); #if 1 vol.transform(topMatrix()); #else // not quite working Matrix m = topMatrix(); m.invert(); frustum.transform(m); #endif } if(_oDrawEnv.getStatCollector() != NULL) { _oDrawEnv.getStatCollector()->getElem(statCullTestedNodes)->inc(); } if(intersect(frustum, vol, inplanes) == false) { result = false; col.setValuesRGB(1,0,0); if(_oDrawEnv.getStatCollector() != NULL) { _oDrawEnv.getStatCollector()->getElem(statCulledNodes)->inc(); } } else { if(inplanes == FrustumVolume::P_ALL) { col.setValuesRGB(0,1,0); } else { col.setValuesRGB(0,0,1); } } if(getVolumeDrawing()) { dropVolume(this, pNode, col); } _visibilityStack.push_back(inplanes); return result; }
/*! \ingroup GrpSystemDrawablesGeometryFunctions Draw the given FrustumVolume using direct OpenGL calls by intersecting near/far with the pairwise intersection of left/right and top/bottom. */ OSG_SYSTEMLIB_DLLMAPPING void OSG::drawVolume(const FrustumVolume &volume) { Line lines[4]; // calc the intersection lines between left/right/bottom/top if(volume.getLeft().intersect(volume.getTop(), lines[0]) == false) { FWARNING(("drawVolume(Frustum): left & top parallel ?!?\n")); return; } if(volume.getLeft().intersect(volume.getBottom(), lines[1]) == false) { FWARNING(("drawVolume(Frustum): left & bottom parallel ?!?\n")); return; } if(volume.getRight().intersect(volume.getTop(), lines[2]) == false) { FWARNING(("drawVolume(Frustum): right & top parallel ?!?\n")); return; } if(volume.getRight().intersect(volume.getBottom(), lines[3]) == false) { FWARNING(("drawVolume(Frustum): right & bottom parallel ?!?\n")); return; } // calc the intersection points Pnt3f pnts[8]; if(volume.getNear().intersectInfinite(lines[0], pnts[0]) == false) { FWARNING(("drawVolume(Frustum): near & left/top parallel ?!?\n")); return; } if(volume.getFar().intersectInfinite(lines[0], pnts[1]) == false) { FWARNING(("drawVolume(Frustum): far & left/top parallel ?!?\n")); return; } if(volume.getNear().intersectInfinite(lines[1], pnts[2]) == false) { FWARNING(("drawVolume(Frustum): near & left/bottom parallel ?!?\n")); return; } if(volume.getFar().intersectInfinite(lines[1], pnts[3]) == false) { FWARNING(("drawVolume(Frustum): far & left/bottom parallel ?!?\n")); return; } if(volume.getNear().intersectInfinite(lines[2], pnts[4]) == false) { FWARNING(("drawVolume(Frustum): near & right/top parallel ?!?\n")); return; } if(volume.getFar().intersectInfinite(lines[2], pnts[5]) == false) { FWARNING(("drawVolume(Frustum): far & right/top parallel ?!?\n")); return; } if(volume.getNear().intersectInfinite(lines[3], pnts[6]) == false) { FWARNING(("drawVolume(Frustum): near & right/bottom parallel ?!?\n")); return; } if(volume.getFar().intersectInfinite(lines[3], pnts[7]) == false) { FWARNING(("drawVolume(Frustum): far & right/bottom parallel ?!?\n")); return; } // got the points, draw them glBegin(GL_LINE_LOOP); glVertex3fv(pnts[0].getValues()); glVertex3fv(pnts[1].getValues()); glVertex3fv(pnts[3].getValues()); glVertex3fv(pnts[2].getValues()); glVertex3fv(pnts[6].getValues()); glVertex3fv(pnts[7].getValues()); glVertex3fv(pnts[5].getValues()); glVertex3fv(pnts[4].getValues()); glEnd(); glBegin(GL_LINES); glVertex3fv(pnts[0].getValues()); glVertex3fv(pnts[2].getValues()); glVertex3fv(pnts[1].getValues()); glVertex3fv(pnts[5].getValues()); glVertex3fv(pnts[3].getValues()); glVertex3fv(pnts[7].getValues()); glVertex3fv(pnts[4].getValues()); glVertex3fv(pnts[6].getValues()); glEnd(); return; }
/*! Calculate the vertices (\a intVerts) and center (\a intCenter) of the intersection of \a fA and \a fB. */ void TrapezoidalShadowMapEngine::intersectFrusta( const FrustumVolume &fA, const FrustumVolume &fB, std::vector<Pnt3r> &intVerts, Pnt3r &intCenter) { const Plane *planes[12]; intVerts.clear ( ); intVerts.reserve(16); for(UInt32 i = 0; i < 6; ++i) { planes[i ] = &(fA.getPlanes()[i]); planes[6 + i] = &(fB.getPlanes()[i]); } // take all combinations of 3 planes -- but avoid choosing planes // we know to be parallel (i.e. near and far of the same frustum), or // that are known to intersect outside the frustum (i.e top/bottom, // left/right). for(UInt32 i = 0; i < 12; ++i) { // choose initial value of j such that it avoids near and far of fA for(UInt32 j = osgMax<UInt32>(2, i + 1); j < 12; ++j) { // near/far are parallel, // left/right always intersect outside the frustum, // top/bottom always intersect outside the frustum if((i == 6 && j == 7) || (i == 2 && j == 3) || (i == 8 && j == 9) || (i == 4 && j == 5) || (i == 10 && j == 11) ) continue; Line intLine; if(planes[i]->intersect(*planes[j], intLine) == false) continue; for(UInt32 k = j + 1; k < 12; ++k) { // near/far are parallel, // left/right always intersect outside the frustum, // top/bottom always intersect outside the frustum if((j == 6 && k == 7) || (j == 2 && k == 3) || (j == 8 && k == 9) || (j == 4 && k == 5) || (j == 10 && k == 11) ) continue; Pnt3r intPoint; if(planes[k]->intersectInfinite(intLine, intPoint) == false) continue; bool intPointValid = true; // check the intersection point against all planes to ensure // it is in both frusta for(UInt32 m = 0; m < 12; ++m) { // intPoint is the intersection of planes i, j, k, so // we don't have to test against those if(m == i || m == j || m == k) continue; if(planes[m]->isInHalfSpace(intPoint) == false) { intPointValid = false; break; } } if(intPointValid == true) { intCenter += intPoint.subZero(); intVerts.push_back(intPoint); } } } } intCenter /= intVerts.size(); }
void TrapezoidalShadowMapEngine::handleSpotLightEnter( SpotLight *spotL, RenderAction *ract, TSMEngineData *data) { RenderPartition *parentPart = ract->getActivePartition(); Matrixr matEyeToWorld(parentPart->getCameraToWorld()); Matrixr matWorldToLight; Matrixr matEyeToLight; Inherited::calcSpotLightMatrices(matWorldToLight, matEyeToLight, spotL, matEyeToWorld ); Matrixr matLightProj; Matrixr matLightFull(matWorldToLight); Real shadowNear = (getShadowNear() != 0.f ? getShadowNear() : parentPart->getNear() ); Real shadowFar = (getShadowFar () != 0.f ? getShadowFar () : parentPart->getFar() ); Inherited::calcPointLightRange( spotL, 0.01f, shadowNear, shadowFar, shadowNear, shadowFar); MatrixPerspective(matLightProj, spotL->getSpotCutOff(), 1.f, shadowNear, shadowFar ); matLightFull.multLeft(matLightProj); Inherited::updateShadowTexImage (data); Inherited::updateShadowTexBuffers(data); Inherited::updateRenderTargets (data); const FrustumVolume &eyeFrust = parentPart->getFrustum(); FrustumVolume lightFrust; Matrixr matNT; lightFrust.setPlanes(matLightFull); bool matNTValid = calcTrapezoidalTransform(matNT, matEyeToWorld, matLightFull, eyeFrust, lightFrust ); if(matNTValid == false) return; // Real cosSpotCutOff = osgCos(spotL->getSpotCutOff()); Int32 shadowTexUnit = (this->getForceTextureUnit() >= 0) ? this->getForceTextureUnit() : 7; ShaderProgram *shadowFP = this->getShadowFragmentProgram(); if(shadowFP == NULL) { ShaderProgramUnrecPtr newShadowFP = ShaderProgram::createLocal(); newShadowFP->setShaderType(GL_FRAGMENT_SHADER); newShadowFP->setProgram (_spotFPCode ); newShadowFP->addUniformVariable("TSME_matEyeToLight", matEyeToLight); newShadowFP->addUniformVariable("TSME_matLightProj", matLightProj ); newShadowFP->addUniformVariable("TSME_matNT", matNT ); newShadowFP->addUniformVariable("TSME_texShadow", shadowTexUnit); newShadowFP->addUniformVariable("TSME_texShadowSizeInv", Vec2f(1.f / getWidth (), 1.f / getHeight() ) ); this->setShadowFragmentProgram(newShadowFP); shadowFP = newShadowFP; } else { shadowFP->updateUniformVariable("TSME_matEyeToLight", matEyeToLight); shadowFP->updateUniformVariable("TSME_matLightProj", matLightProj ); shadowFP->updateUniformVariable("TSME_matNT", matNT ); } updateLightPassMaterial(data, 0, matNT); commitChanges(); this->pushPartition(ract); { RenderPartition *part = ract->getActivePartition( ); Window *win = ract->getWindow ( ); FrameBufferObject *target = data->getRenderTargets (0); Background *back = data->getBackground ( ); part->setRenderTarget(target); part->setWindow (win ); part->calcViewportDimension(0.f, 0.f, 1.f, 1.f, target->getWidth (), target->getHeight() ); part->setupProjection(matLightProj, Matrixr::identity()); part->setupViewing (matWorldToLight ); part->setNear (parentPart->getNear()); part->setFar (parentPart->getFar ()); part->setFrustum (lightFrust ); part->setBackground (back ); part->overrideMaterial(data->getLightPassMaterials(0), ract->getActNode ( ) ); this->recurseFrom(ract, spotL); ract->useNodeList(false ); part->overrideMaterial(NULL, ract->getActNode ( ) ); } this->popPartition(ract); }
void TrapezoidalShadowMapEngine::handlePointLightEnter( PointLight *pointL, RenderAction *ract, TSMEngineData *data) { RenderPartition *parentPart = ract->getActivePartition(); Matrixr matEyeToWorld(parentPart->getCameraToWorld()); Matrixr matLightProj; Real shadowNear = (getShadowNear() != 0.f ? getShadowNear() : parentPart->getNear() ); Real shadowFar = (getShadowFar () != 0.f ? getShadowFar () : parentPart->getFar() ); Inherited::calcPointLightRange( pointL, 0.01f, shadowNear, shadowFar, shadowNear, shadowFar); MatrixPerspective(matLightProj, Pi / 4.f, 1.f, shadowNear, shadowFar ); Matrixr matWorldToLight; Matrixr matEyeToLight; MFMatrixr mfMatNT; mfMatNT.resize(6); Inherited::calcPointLightMatrices(matWorldToLight, matEyeToLight, pointL, matEyeToWorld ); Inherited::updatePointLightShadowTexImage (data); Inherited::updatePointLightShadowTexBuffers(data); Inherited::updatePointLightRenderTargets (data); Int32 shadowTexUnit = (this->getForceTextureUnit() >= 0) ? this->getForceTextureUnit() : 7; ShaderProgram *shadowFP = this->getShadowFragmentProgram(); if(shadowFP == NULL) { ShaderProgramUnrecPtr newShadowFP = ShaderProgram::createLocal(); newShadowFP->setShaderType(GL_FRAGMENT_SHADER); newShadowFP->setProgram (_pointFPCode ); newShadowFP->addUniformVariable("TSME_matEyeToLight", matEyeToLight); newShadowFP->addUniformVariable("TSME_matLightProj", matLightProj ); newShadowFP->addUniformVariable("TSME_matNT", mfMatNT ); newShadowFP->addUniformVariable("TSME_texShadow", shadowTexUnit); newShadowFP->addUniformVariable("TSME_texShadowSizeInv", Vec2f(1.f / getWidth (), 1.f / getHeight() ) ); this->setShadowFragmentProgram(newShadowFP); shadowFP = newShadowFP; } else { shadowFP->updateUniformVariable("TSME_matEyeToLight", matEyeToLight); shadowFP->updateUniformVariable("TSME_matLightProj", matLightProj ); } const FrustumVolume &eyeFrust = parentPart->getFrustum(); for(UInt16 faceIdx = 0; faceIdx < 6; ++faceIdx) { Matrixr matWorldToLightFace (matWorldToLight ); matWorldToLightFace.multLeft(_matCubeFaceInv[faceIdx]); Matrixr matLightFull(matWorldToLightFace); matLightFull.multLeft(matLightProj); FrustumVolume lightFrust; Matrixr matNT; lightFrust.setPlanes(matLightFull); bool matNTValid = calcTrapezoidalTransform(mfMatNT[faceIdx], matEyeToWorld, matLightFull, eyeFrust, lightFrust ); if(matNTValid == false) { // setup a minimal partition to clear the cube face commitChanges(); this->pushPartition(ract, RenderPartition::CopyNothing, RenderPartition::SimpleCallback); { RenderPartition *part = ract->getActivePartition( ); Window *win = ract->getWindow ( ); FrameBufferObject *target = data->getRenderTargets (faceIdx); Background *back = data->getBackground ( ); part->setSetupMode(RenderPartition::ViewportSetup | RenderPartition::BackgroundSetup ); part->setRenderTarget(target); part->setWindow (win ); part->calcViewportDimension(0.f, 0.f, 1.f, 1.f, target->getWidth (), target->getHeight() ); part->setBackground(back); RenderPartition::SimpleDrawCallback emptyCubeFaceDraw = boost::bind( &TrapezoidalShadowMapEngine::emptyCubeFaceDrawFunc, this, _1); part->dropFunctor(emptyCubeFaceDraw); } this->popPartition(ract); } else { updateLightPassMaterial(data, faceIdx, mfMatNT[faceIdx]); commitChanges(); this->pushPartition(ract); { RenderPartition *part = ract->getActivePartition( ); Window *win = ract->getWindow ( ); FrameBufferObject *target = data->getRenderTargets (faceIdx); Background *back = data->getBackground ( ); part->setRenderTarget(target); part->setWindow (win ); part->calcViewportDimension(0.f, 0.f, 1.f, 1.f, target->getWidth (), target->getHeight() ); part->setupProjection(matLightProj, Matrixr::identity()); part->setupViewing (matWorldToLightFace ); part->setNear (parentPart->getNear()); part->setFar (parentPart->getFar ()); part->setFrustum (lightFrust ); part->setBackground (back ); part->overrideMaterial(data->getLightPassMaterials(faceIdx), ract->getActNode ( ) ); this->recurseFrom(ract, pointL); ract->useNodeList(false ); part->overrideMaterial(NULL, ract->getActNode ( ) ); } this->popPartition(ract); } } shadowFP->updateUniformVariable("TSME_matNT", mfMatNT); }
bool Line::intersect(const FrustumVolume &frustum , Real &enter , Real &exit ) const { const Real inf = 2u << 16; Pnt3r enter_point = _pos + _dir * 0.f; Pnt3r exit_point = _pos + _dir * inf; face faces[6]; const Plane *planes = frustum.getPlanes(); Line lines[2]; //ln[0] - intersection of right and top planes planes[3].intersect(planes[4], lines[0]); //ln[1] - left and bottom planes[2].intersect(planes[5], lines[1]); Pnt3r pointA; Pnt3r pointB; if(!planes[0].intersectInfinite(lines[0],pointA)) std::cout << "This should never happen (A)!!!!"; if(!planes[1].intersectInfinite(lines[1],pointB)) std::cout << "This should never happen (B)!!!!"; faces[0].point = pointA; faces[0].inner_vector = pointB - pointA; faces[1].point = pointB; faces[1].inner_vector = pointA - pointB; faces[2].point = pointB; faces[2].inner_vector = pointA - pointB; faces[3].point = pointA; faces[3].inner_vector = pointB - pointA; faces[4].point = pointA; faces[4].inner_vector = pointB - pointA; faces[5].point = pointB; faces[5].inner_vector = pointA - pointB; for(Int32 i = 0; i < 6; i++) { faces[i].inner_normal=planes[i].getNormal(); if(faces[i].inner_normal.dot(faces[i].inner_vector) < 0.f) faces[i].inner_normal=-faces[i].inner_normal; Vec3r test_enp = enter_point - faces[i].point; Vec3r test_exp = exit_point - faces[i].point; Real value_enp = test_enp.dot(faces[i].inner_normal); Real value_exp = test_exp.dot(faces[i].inner_normal); if(value_enp < 0.f && value_exp < 0.f) return false; if(value_enp > 0.f && value_exp < 0.f) planes[i].intersect(*this, exit_point ); if(value_enp < 0.f && value_exp > 0.f) planes[i].intersect(*this, enter_point); } Real a; if((a = (enter_point - _pos).dot(_dir)) != 0.f) { enter = (enter_point - _pos).dot(enter_point - _pos) / a; } else { enter = 0.f; } if((a = (exit_point - _pos).dot(_dir)) != 0.f) { exit = (exit_point - _pos).dot(exit_point - _pos) / a; } else { enter = 0.f; } return true; }