/** 创建一个多面体求交器*/ osgUtil::PolytopeIntersector* pI =new osgUtil::PolytopeIntersector(poly); /** 构造一个交集访问器*/ osgUtil::IntersectionVisitor iv(pI); 对于求交集 则应当对于场景根节点做请求访问的操作..这当中可能需要避开自身节点等一些不必要的节点等. /** 设置避开自身节点*/ _model->setNodeMask(0x0); /** 根节点请求访问操作*/ root->accept(iv); /** 恢复自身节点的NodeMask*/ _model->setNodeMask(0xffffffff);对于setNodeMask()避开节点等.我想应当在Vistor中在详述..
if(pI->containsIntersections()) { typedef osgUtil::PolytopeIntersector::Intersections inters; for(inters::iterator it=pI->getIntersections().begin();\ it!=pI->getIntersections().end();it++) /** ……*/ }
固然,这些只是相对于简单的操作.而我们是想要深入到了解在root->accept(iv)之后到底做了什么事情?它到底如何求得了我们想要的数据? 那现在开始我们的代码解读之旅……当然这其中,我想有必要略去一些关系到Vistor的内容.因为这些详述起来,不是简短的能够说的清楚...
现在我们定位到: osgUtil/IntersectionVisitor.cpp 第226行:
void IntersectionVisitor::apply(osg::Geode& geode) { // osg::notify(osg::NOTICE)<<"apply(Geode&)"<<std::endl; if (!enter(geode)) return; // osg::notify(osg::NOTICE)<<"inside apply(Geode&)"<<std::endl; for(unsigned int i=0; i<geode.getNumDrawables(); ++i) { intersect( geode.getDrawable(i) ); } leave(); }
inline void intersect(osg::Drawable* drawable) { _intersectorStack.back()->intersect(*this, drawable); }
void PolytopeIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable) { /** 之上部分省略……*/ osg::TemplatePrimitiveFunctor<PolytopeIntersectorUtils::PolytopePrimitiveIntersector> func; func.setPolytope( _polytope, _referencePlane ); func.setDimensionMask( _dimensionMask ); drawable->accept(func); /** 之下部分省略……*/ }
void Geometry::accept(PrimitiveFunctor& functor) const { if (!_vertexData.array.valid() || _vertexData.array->getNumElements()==0) return; if (!_vertexData.indices.valid()) { switch(_vertexData.array->getType()) { case(Array::Vec2ArrayType): functor.setVertexArray(_vertexData.array->getNumElements(),static_cast<const Vec2*>(_vertexData.array->getDataPointer())); break; case(Array::Vec3ArrayType): functor.setVertexArray(_vertexData.array->getNumElements(),static_cast<const Vec3*>(_vertexData.array->getDataPointer())); break; case(Array::Vec4ArrayType): functor.setVertexArray(_vertexData.array->getNumElements(),static_cast<const Vec4*>(_vertexData.array->getDataPointer())); break; case(Array::Vec2dArrayType): functor.setVertexArray(_vertexData.array->getNumElements(),static_cast<const Vec2d*>(_vertexData.array->getDataPointer())); break; case(Array::Vec3dArrayType): functor.setVertexArray(_vertexData.array->getNumElements(),static_cast<const Vec3d*>(_vertexData.array->getDataPointer())); break; case(Array::Vec4dArrayType): functor.setVertexArray(_vertexData.array->getNumElements(),static_cast<const Vec4d*>(_vertexData.array->getDataPointer())); break; default: notify(WARN)<<"Warning: Geometry::accept(PrimitiveFunctor&) cannot handle Vertex Array type"<<_vertexData.array->getType()<<std::endl; return; } for(PrimitiveSetList::const_iterator itr=_primitives.begin(); itr!=_primitives.end(); ++itr) { (*itr)->accept(functor); } } /** *//** 后面对于存在索引数组的暂时省略……*/ }
void DrawArrays::accept(PrimitiveFunctor& functor) const { functor.drawArrays(_mode,_first,_count); }
void operator()(const Vec3_type v1, const Vec3_type v2, const Vec3_type v3, bool treatVertexDataAsTemporary) { ++_index; if ((_dimensionMask & PolytopeIntersector::DimTwo) == 0) return; PlaneMask selector_mask = 0x1; PlaneMask inside_mask = 0x0; _candidates.clear(); for(PlaneList::const_iterator it=_planes.begin(); it!=_planes.end(); ++it, selector_mask <<= 1) { const osg::Plane& plane=*it; const value_type d1=plane.distance(v1); const value_type d2=plane.distance(v2); const value_type d3=plane.distance(v3); const bool d1IsNegative = (d1<0.0f); const bool d2IsNegative = (d2<0.0f); const bool d3IsNegative = (d3<0.0f); if (d1IsNegative && d2IsNegative && d3IsNegative) return; // triangle outside if (!d1IsNegative && !d2IsNegative && !d3IsNegative) { inside_mask |= selector_mask; continue; // completly inside } // edge v1-v2 intersects if (d1==0.0f) { _candidates.push_back( CandList_t::value_type(selector_mask, v1) ); } else if (d2==0.0f) { _candidates.push_back( CandList_t::value_type(selector_mask, v2) ); } else if (d1IsNegative && !d2IsNegative) { _candidates.push_back( CandList_t::value_type(selector_mask, (v1-(v2-v1)*(d1/(-d1+d2))) ) ); } else if (!d1IsNegative && d2IsNegative) { _candidates.push_back( CandList_t::value_type(selector_mask, (v1+(v2-v1)*(d1/(d1-d2))) ) ); } // edge v1-v3 intersects if (d3==0.0f) { _candidates.push_back( CandList_t::value_type(selector_mask, v3) ); } else if (d1IsNegative && !d3IsNegative) { _candidates.push_back( CandList_t::value_type(selector_mask, (v1-(v3-v1)*(d1/(-d1+d3))) ) ); } else if (!d1IsNegative && d3IsNegative) { _candidates.push_back( CandList_t::value_type(selector_mask, (v1+(v3-v1)*(d1/(d1-d3))) ) ); } // edge v2-v3 intersects if (d2IsNegative && !d3IsNegative) { _candidates.push_back( CandList_t::value_type(selector_mask, (v2-(v3-v2)*(d2/(-d2+d3))) ) ); } else if (!d2IsNegative && d3IsNegative) { _candidates.push_back( CandList_t::value_type(selector_mask, (v2+(v3-v2)*(d2/(d2-d3))) ) ); } } if (_plane_mask==inside_mask) { // triangle lies inside of all planes _candidates.push_back( CandList_t::value_type(_plane_mask, v1) ); _candidates.push_back( CandList_t::value_type(_plane_mask, v2) ); _candidates.push_back( CandList_t::value_type(_plane_mask, v3) ); addIntersection(_index, _candidates); return; } if (_candidates.empty() && _planes.size()<3) return; unsigned int numCands=checkCandidatePoints(inside_mask); if (numCands>0) { addIntersection(_index, _candidates); return; } // handle case where the polytope goes through the triangle // without containing any point of it LinesList& lines=getPolytopeLines(); _candidates.clear(); // check all polytope lines against the triangle // use algorithm from "Real-time rendering" (second edition) pp.580 const Vec3_type e1=v2-v1; const Vec3_type e2=v3-v1; for (LinesList::const_iterator it=lines.begin(); it!=lines.end(); ++it) { const PlanesLine& line=*it; Vec3_type p=line.dir^e2; const value_type a=e1*p; if (osg::absolute(a)<eps()) continue; const value_type f=1.0f/a; const Vec3_type s=(line.pos-v1); const value_type u=f*(s*p); if (u<0.0f || u>1.0f) continue; const Vec3_type q=s^e1; const value_type v=f*(line.dir*q); if (v<0.0f || u+v>1.0f) continue; const value_type t=f*(e2*q); _candidates.push_back(CandList_t::value_type(line.mask, line.pos+line.dir*t)); } numCands=checkCandidatePoints(inside_mask); if (numCands>0) { addIntersection(_index, _candidates); return; } }
for(PolytopeIntersectorUtils::Intersections::const_iterator it=func.intersections.begin(); it!=func.intersections.end(); ++it) { const PolytopeIntersectorUtils::PolytopeIntersection& intersection = *it; Intersection hit; hit.distance = intersection._distance; hit.maxDistance = intersection._maxDistance; hit.primitiveIndex = intersection._index; hit.nodePath = iv.getNodePath(); hit.drawable = drawable; hit.matrix = iv.getModelMatrix(); osg::Vec3 center; for (unsigned int i=0; i<intersection._numPoints; ++i) { center += intersection._points[i]; } center /= float(intersection._numPoints); hit.localIntersectionPoint = center; hit.numIntersectionPoints = intersection._numPoints; std::copy(&intersection._points[0], &intersection._points[intersection._numPoints], &hit.intersectionPoints[0]); insertIntersection(hit); }