OSG笔记:对线求交失败

问题描述

使用以下两个求交器,对一根直线进行求交,但始终得不出结果。
直线求交器 osgUtil::LineSegmentIntersector
多面体求交器 osgUtil::PolytopeIntersector

测试代码如下:

//创建直线
void CreateModel(osg::ref_ptr<osg::Geode> pGeode)
{
	if (pGeode) return;

	osg::Vec3dArray* pVertexArray = new osg::Vec3dArray();
	pVertexArray->push_back(osg::Vec3d(0, 0, 0));
	pVertexArray->push_back(osg::Vec3d(100, 0, 0));

	osg::Geometry* pLineGeom = new osg::Geometry();
	pLineGeom->setVertexArray(pVertexArray);
	pLineGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,
		0, pVertexArray->size()));

	pGeode->addDrawable(pLineGeom);
}

//多面体求交器的测试
void TestPolytopeIntersector(osg::Camera* pCamera )
{
	if (!pCamera)
	{
		return;
	}

	osg::Vec3d ptCenter(50, 0, 0);

	//构建多面体求交器
	osg::ref_ptr<osgUtil::PolytopeIntersector> pPolyIntersector;
	osg::BoundingBox mBoundBox(
		ptCenter.x() - 51.0,
		ptCenter.y() - 51.0,
		ptCenter.z() - 51.0,
		ptCenter.x() + 51.0,
		ptCenter.y() + 51.0,
		ptCenter.z() + 51.0);
	osg::Polytope mPolytope;
	mPolytope.setToBoundingBox(mBoundBox);
	pPolyIntersector = new osgUtil::PolytopeIntersector(
		osgUtil::Intersector::CoordinateFrame::MODEL, mPolytope);

	//优化求交器
	pPolyIntersector->setIntersectionLimit(
		osgUtil::Intersector::IntersectionLimit::LIMIT_ONE_PER_DRAWABLE);

	//执行求交
	osgUtil::IntersectionVisitor intersectionVisitor;
	intersectionVisitor.setIntersector(pPolyIntersector.get());
	pCamera->accept(intersectionVisitor);

	//构造求交结果
	if (pPolyIntersector->containsIntersections())
	{
		osgUtil::PolytopeIntersector::Intersections& mIntersection = pPolyIntersector->getIntersections();
		osgUtil::PolytopeIntersector::Intersections::iterator itr;
		for (itr = mIntersection.begin();
			itr != mIntersection.end();
			++itr)
		{
			osgUtil::PolytopeIntersector::Intersection mSingleIter = (*itr);
			osg::NodePath& nodePath = mSingleIter.nodePath;

			//循环判断。
			int iCount = nodePath.size();
			for (int i = iCount - 1; i >= 0; --i)
			{
				osg::ref_ptr<osg::Node> node = nodePath[i];

				//处理省略...
			}

		}
	}
}

//直线求线器的测试
void TestLineSegmentIntersector(osg::Camera* pCamera)
{
	if (!pCamera)
	{
		return;
	}

	osg::ref_ptr<osgUtil::LineSegmentIntersector> pLineIntersector;
	pLineIntersector = new osgUtil::LineSegmentIntersector(
		osgUtil::Intersector::CoordinateFrame::MODEL,
		osg::Vec3d(10, 0, 0),
		osg::Vec3d(10, 1, 1));

	//执行求交
	osgUtil::IntersectionVisitor intersectionVisitor;
	intersectionVisitor.setIntersector(pLineIntersector.get());
	pCamera->accept(intersectionVisitor);

	//构造求交结果
	if (pLineIntersector->containsIntersections())
	{
		osgUtil::LineSegmentIntersector::Intersections& mIntersection = pLineIntersector->getIntersections();
		osgUtil::LineSegmentIntersector::Intersections::iterator itr;
		for (itr = mIntersection.begin();
			itr != mIntersection.end();
			++itr)
		{
			osgUtil::LineSegmentIntersector::Intersection mSingleIter = (*itr);
			osg::NodePath& nodePath = mSingleIter.nodePath;
			int iCount = nodePath.size();
			for (int i = iCount - 1; i >= 0; --i)
			{
				osg::ref_ptr<osg::Node> node = nodePath[i];
				//处理省略...
			}
		}
	}
}

对osg代码的探索

查看osg的代码后,发现以下事实:

  • osgUtil::LineSegmentIntersector使用了osg::TriangleFunctor。
    从osg::TriangleFunctor::setVertexArray可知:不支持osg::Vec2d、osg::Vec3d、osg::Vec4d等等,支持osg::Vec3(即osg::Vec3f)
    从osg::TriangleFunctor::drawArrays可知:不支持GL_POINTS、GL_LINES、GL_LINE_STRIP、GL_LINE_LOOP

  • osgUtil::PolytopeIntersector使用了osg::TemplatePrimitiveFunctor。
    从osg::TemplatePrimitiveFunctor::setVertexArray可知:不支持osg::Vec2d、osg::Vec3d、osg::Vec4d等等,支持osg::Vec3(即osg::Vec3f)
    从osg::TemplatePrimitiveFunctor::drawArrays可知:支持所有的基本图元类型。

osg代码整理如下:



//多面体求交器相关代码
//
void PolytopeIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)
{
	//
	//其他代码省略....
	//

	osg::TemplatePrimitiveFunctor<PolytopeIntersectorUtils::PolytopePrimitiveIntersector> func;
	func.setPolytope(_polytope, _referencePlane);
	func.setDimensionMask(_dimensionMask);
	func.setLimitOneIntersection(_intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE);

	drawable->accept(func);

	//
	//其他代码省略....
	//
}


/** Provides access to the primitives that compose an \c osg::Drawable.
*  <p>Notice that \c TemplatePrimitiveFunctor is a class template, and that it inherits
*  from its template parameter \c T. This template parameter must implement
*  <tt>operator()(const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3
*  v3, bool treatVertexDataAsTemporary)</tt>,
*  <tt>operator()(const osg::Vec3 v1, const osg::Vec3 v2, bool
*  treatVertexDataAsTemporary)</tt>, <tt>operator()(const osg::Vec3 v1,
*  const osg::Vec3 v2, const osg::Vec3 v3, bool treatVertexDataAsTemporary)</tt>,
*  and <tt>operator()(const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3 v3,
*  const osg::Vec3 v4, bool treatVertexDataAsTemporary)</tt> which will be called
*  for the matching primitive when the functor is applied to a \c Drawable.
*  Parameters \c v1, \c v2, \c v3, and \c v4 are the vertices of the primitive.
*  The last parameter, \c treatVertexDataAsTemporary, indicates whether these
*  vertices are coming from a "real" vertex array, or from a temporary vertex array,
*  created by the \c TemplatePrimitiveFunctor from some other geometry representation.
*  @see \c PrimitiveFunctor for general usage hints.
*/
template<class T>
class TemplatePrimitiveFunctor : public PrimitiveFunctor, public T
{
public:
	//
	//其他代码省略....
	//

	virtual void setVertexArray(unsigned int, const Vec2*)
	{
		notify(WARN) << "Triangle Functor does not support Vec2* vertex arrays" << std::endl;
	}

	virtual void setVertexArray(unsigned int count, const Vec3* vertices)
	{
		_vertexArraySize = count;
		_vertexArrayPtr = vertices;
	}

	virtual void setVertexArray(unsigned int, const Vec4*)
	{
		notify(WARN) << "Triangle Functor does not support Vec4* vertex arrays" << std::endl;
	}

	virtual void setVertexArray(unsigned int, const Vec2d*)
	{
		notify(WARN) << "Triangle Functor does not support Vec2d* vertex arrays" << std::endl;
	}

	virtual void setVertexArray(unsigned int, const Vec3d*)
	{
		notify(WARN) << "Triangle Functor does not support Vec3d* vertex arrays" << std::endl;
	}

	virtual void setVertexArray(unsigned int, const Vec4d*)
	{
		notify(WARN) << "Triangle Functor does not support Vec4d* vertex arrays" << std::endl;
	}


	virtual void drawArrays(GLenum mode, GLint first, GLsizei count)
	{
		if (_vertexArrayPtr == 0 || count == 0) return;

		switch (mode)
		{
		case(GL_TRIANGLES) : {
			const Vec3* vlast = &_vertexArrayPtr[first + count];
			for (const Vec3* vptr = &_vertexArrayPtr[first]; vptr < vlast; vptr += 3)
				this->operator()(*(vptr), *(vptr + 1), *(vptr + 2), _treatVertexDataAsTemporary);
			break;
		}
		case(GL_TRIANGLE_STRIP) : {
			const Vec3* vptr = &_vertexArrayPtr[first];
			for (GLsizei i = 2; i < count; ++i, ++vptr)
			{
				if ((i % 2)) this->operator()(*(vptr), *(vptr + 2), *(vptr + 1), _treatVertexDataAsTemporary);
				else       this->operator()(*(vptr), *(vptr + 1), *(vptr + 2), _treatVertexDataAsTemporary);
			}
			break;
		}
		case(GL_QUADS) : {
			const Vec3* vptr = &_vertexArrayPtr[first];
			for (GLsizei i = 3; i < count; i += 4, vptr += 4)
			{
				this->operator()(*(vptr), *(vptr + 1), *(vptr + 2), *(vptr + 3), _treatVertexDataAsTemporary);
			}
			break;
		}
		case(GL_QUAD_STRIP) : {
			const Vec3* vptr = &_vertexArrayPtr[first];
			for (GLsizei i = 3; i < count; i += 2, vptr += 2)
			{
				this->operator()(*(vptr), *(vptr + 1), *(vptr + 3), *(vptr + 2), _treatVertexDataAsTemporary);
			}
			break;
		}
		case(GL_POLYGON) : // treat polygons as GL_TRIANGLE_FAN
		case(GL_TRIANGLE_FAN) : {
			const Vec3* vfirst = &_vertexArrayPtr[first];
			const Vec3* vptr = vfirst + 1;
			for (GLsizei i = 2; i < count; ++i, ++vptr)
			{
				this->operator()(*(vfirst), *(vptr), *(vptr + 1), _treatVertexDataAsTemporary);
			}
			break;
		}
		case(GL_POINTS) : {
			const Vec3* vlast = &_vertexArrayPtr[first + count];
			for (const Vec3* vptr = &_vertexArrayPtr[first]; vptr < vlast; vptr += 1)
				this->operator()(*(vptr), _treatVertexDataAsTemporary);
			break;
		}
		case(GL_LINES) : {
			const Vec3* vlast = &_vertexArrayPtr[first + count - 1];
			for (const Vec3* vptr = &_vertexArrayPtr[first]; vptr < vlast; vptr += 2)
				this->operator()(*(vptr), *(vptr + 1), _treatVertexDataAsTemporary);
			break;
		}
		case(GL_LINE_STRIP) : {
			const Vec3* vlast = &_vertexArrayPtr[first + count - 1];
			for (const Vec3* vptr = &_vertexArrayPtr[first]; vptr < vlast; vptr += 1)
				this->operator()(*(vptr), *(vptr + 1), _treatVertexDataAsTemporary);
			break;
		}
		case(GL_LINE_LOOP) : {
			const Vec3* vlast = &_vertexArrayPtr[first + count - 1];
			for (const Vec3* vptr = &_vertexArrayPtr[first]; vptr < vlast; vptr += 1)
				this->operator()(*(vptr), *(vptr + 1), _treatVertexDataAsTemporary);
			this->operator()(*(vlast), _vertexArrayPtr[first], _treatVertexDataAsTemporary);
			break;
		}
		default:
			break;
		}
	}

	//
	//其他代码省略....
	//
};





//线性求交器相关代码
//
void LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)
{
	//
	//其他代码省略....
	//

	osg::KdTree* kdTree = iv.getUseKdTreeWhenAvailable() ? dynamic_cast<osg::KdTree*>(drawable->getShape()) : 0;
	if (kdTree) //此处是其他逻辑,没研究了
	{
		//
		//其他代码省略....
		//

		return;
	}

	//
	//其他代码省略....
	//

	osg::TriangleFunctor<LineSegmentIntersectorUtils::TriangleIntersector> ti;
	ti.set(s, e);
	ti._limitOneIntersection = (_intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE);
	drawable->accept(ti);

	//
	//其他代码省略....
	//
}



/** Provides access to the triangles that compose an \c osg::Drawable. If the \c
*  Drawable is not composed of triangles, the \c TriangleFunctor will convert
*  the primitives to triangles whenever possible.
*  <p>Notice that \c TriangleFunctor is a class template, and that it inherits
*  from its template parameter \c T. This template parameter must implement
*  <tt>T::operator() (const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3
*  v3, bool treatVertexDataAsTemporary)</tt>, which will be called for every
*  triangle when the functor is applied to a \c Drawable. Parameters \c v1, \c
*  v2, and \c v3 are the triangle vertices. The fourth parameter, \c
*  treatVertexDataAsTemporary, indicates whether these vertices are coming from
*  a "real" vertex array, or from a temporary vertex array, created by the \c
*  TriangleFunctor from some other geometry representation.
*  @see \c PrimitiveFunctor for general usage hints.
*/
template<class T>
class TriangleFunctor : public PrimitiveFunctor, public T
{
public:
	//
	//其他代码省略....
	//

	virtual void setVertexArray(unsigned int, const Vec2*)
	{
		notify(WARN) << "Triangle Functor does not support Vec2* vertex arrays" << std::endl;
	}

	virtual void setVertexArray(unsigned int count, const Vec3* vertices)
	{
		_vertexArraySize = count;
		_vertexArrayPtr = vertices;
	}

	virtual void setVertexArray(unsigned int, const Vec4*)
	{
		notify(WARN) << "Triangle Functor does not support Vec4* vertex arrays" << std::endl;
	}

	virtual void setVertexArray(unsigned int, const Vec2d*)
	{
		notify(WARN) << "Triangle Functor does not support Vec2d* vertex arrays" << std::endl;
	}

	virtual void setVertexArray(unsigned int, const Vec3d*)
	{
		notify(WARN) << "Triangle Functor does not support Vec3d* vertex arrays" << std::endl;
	}

	virtual void setVertexArray(unsigned int, const Vec4d*)
	{
		notify(WARN) << "Triangle Functor does not support Vec4d* vertex arrays" << std::endl;
	}

	virtual void drawArrays(GLenum mode, GLint first, GLsizei count)
	{
		if (_vertexArrayPtr == 0 || count == 0) return;

		switch (mode)
		{
		case(GL_TRIANGLES) :
		{
			const Vec3* vlast = &_vertexArrayPtr[first + count];
			for (const Vec3* vptr = &_vertexArrayPtr[first]; vptr < vlast; vptr += 3)
				this->operator()(*(vptr), *(vptr + 1), *(vptr + 2), _treatVertexDataAsTemporary);
			break;
		}
		case(GL_TRIANGLE_STRIP) :
		{
			const Vec3* vptr = &_vertexArrayPtr[first];
			for (GLsizei i = 2; i < count; ++i, ++vptr)
			{
				if ((i % 2)) this->operator()(*(vptr), *(vptr + 2), *(vptr + 1), _treatVertexDataAsTemporary);
				else       this->operator()(*(vptr), *(vptr + 1), *(vptr + 2), _treatVertexDataAsTemporary);
			}
			break;
		}
		case(GL_QUADS) :
		{
			const Vec3* vptr = &_vertexArrayPtr[first];
			for (GLsizei i = 3; i < count; i += 4, vptr += 4)
			{
				this->operator()(*(vptr), *(vptr + 1), *(vptr + 2), _treatVertexDataAsTemporary);
				this->operator()(*(vptr), *(vptr + 2), *(vptr + 3), _treatVertexDataAsTemporary);
			}
			break;
		}
		case(GL_QUAD_STRIP) :
		{
			const Vec3* vptr = &_vertexArrayPtr[first];
			for (GLsizei i = 3; i < count; i += 2, vptr += 2)
			{
				this->operator()(*(vptr), *(vptr + 1), *(vptr + 2), _treatVertexDataAsTemporary);
				this->operator()(*(vptr + 1), *(vptr + 3), *(vptr + 2), _treatVertexDataAsTemporary);
			}
			break;
		}
		case(GL_POLYGON) : // treat polygons as GL_TRIANGLE_FAN
		case(GL_TRIANGLE_FAN) :
		{
			const Vec3* vfirst = &_vertexArrayPtr[first];
			const Vec3* vptr = vfirst + 1;
			for (GLsizei i = 2; i < count; ++i, ++vptr)
			{
				this->operator()(*(vfirst), *(vptr), *(vptr + 1), _treatVertexDataAsTemporary);
			}
			break;
		}
		case(GL_POINTS) :
		case(GL_LINES) :
		case(GL_LINE_STRIP) :
		case(GL_LINE_LOOP) :
		default:
			// can't be converted into to triangles.
			break;
		}
	}

	//
	//其他代码省略....
	//

};

解决方案

由上可知,要对线进行求交,需使用osgUtil::PolytopeIntersector, 并且顶点数组一定要使用osg::Vec3(即osg::Vec3f)。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值