30a06a033e
"Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
303 lines
13 KiB
C++
303 lines
13 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
|
*
|
|
* This library is open source and may be redistributed and/or modified under
|
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
|
* (at your option) any later version. The full license is in LICENSE file
|
|
* included with this distribution, and on the openscenegraph.org website.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* OpenSceneGraph Public License for more details.
|
|
*/
|
|
|
|
#ifndef OSG_TERMPLATEPRIMITIVEFUNCTOR
|
|
#define OSG_TERMPLATEPRIMITIVEFUNCTOR 1
|
|
|
|
#include <osg/PrimitiveSet>
|
|
#include <osg/Notify>
|
|
|
|
namespace osg {
|
|
|
|
|
|
/** 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:
|
|
|
|
TemplatePrimitiveFunctor()
|
|
{
|
|
_vertexArraySize=0;
|
|
_vertexArrayPtr=0;
|
|
_modeCache=0;
|
|
_treatVertexDataAsTemporary=false;
|
|
}
|
|
|
|
virtual ~TemplatePrimitiveFunctor() {}
|
|
|
|
void setTreatVertexDataAsTemporary(bool treatVertexDataAsTemporary) { _treatVertexDataAsTemporary=treatVertexDataAsTemporary; }
|
|
bool getTreatVertexDataAsTemporary() const { return _treatVertexDataAsTemporary; }
|
|
|
|
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 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];
|
|
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];
|
|
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];
|
|
for(const Vec3* vptr=&_vertexArrayPtr[first];vptr<vlast;vptr+=1)
|
|
this->operator()(*(vptr),*(vptr+1),_treatVertexDataAsTemporary);
|
|
this->operator()(*(vlast-1),_vertexArrayPtr[first],_treatVertexDataAsTemporary);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
template<class IndexType>
|
|
void drawElementsTemplate(GLenum mode,GLsizei count,const IndexType* indices)
|
|
{
|
|
if (indices==0 || count==0) return;
|
|
|
|
typedef const IndexType* IndexPointer;
|
|
|
|
switch(mode)
|
|
{
|
|
case(GL_TRIANGLES): {
|
|
IndexPointer ilast = &indices[count];
|
|
for(IndexPointer iptr=indices;iptr<ilast;iptr+=3)
|
|
this->operator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)],_treatVertexDataAsTemporary);
|
|
break;
|
|
}
|
|
case(GL_TRIANGLE_STRIP): {
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=2;i<count;++i,++iptr)
|
|
{
|
|
if ((i%2)) this->operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+2)],
|
|
_vertexArrayPtr[*(iptr+1)],_treatVertexDataAsTemporary);
|
|
else this->operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],
|
|
_vertexArrayPtr[*(iptr+2)],_treatVertexDataAsTemporary);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_QUADS): {
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=3;i<count;i+=4,iptr+=4)
|
|
{
|
|
this->operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],
|
|
_vertexArrayPtr[*(iptr+2)],_vertexArrayPtr[*(iptr+3)],
|
|
_treatVertexDataAsTemporary);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_QUAD_STRIP): {
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=3;i<count;i+=2,iptr+=2)
|
|
{
|
|
this->operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],
|
|
_vertexArrayPtr[*(iptr+3)],_vertexArrayPtr[*(iptr+2)],
|
|
_treatVertexDataAsTemporary);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
|
|
case(GL_TRIANGLE_FAN): {
|
|
IndexPointer iptr = indices;
|
|
const Vec3& vfirst = _vertexArrayPtr[*iptr];
|
|
++iptr;
|
|
for(GLsizei i=2;i<count;++i,++iptr)
|
|
{
|
|
this->operator()(vfirst,_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],
|
|
_treatVertexDataAsTemporary);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_POINTS): {
|
|
IndexPointer ilast = &indices[count];
|
|
for(IndexPointer iptr=indices;iptr<ilast;iptr+=1)
|
|
this->operator()(_vertexArrayPtr[*iptr],_treatVertexDataAsTemporary);
|
|
break;
|
|
}
|
|
case(GL_LINES): {
|
|
IndexPointer ilast = &indices[count];
|
|
for(IndexPointer iptr=indices;iptr<ilast;iptr+=2)
|
|
this->operator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)],
|
|
_treatVertexDataAsTemporary);
|
|
break;
|
|
}
|
|
case(GL_LINE_STRIP): {
|
|
IndexPointer ilast = &indices[count];
|
|
for(IndexPointer iptr=indices;iptr<ilast;iptr+=1)
|
|
this->operator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)],
|
|
_treatVertexDataAsTemporary);
|
|
break;
|
|
}
|
|
case(GL_LINE_LOOP): {
|
|
IndexPointer ilast = &indices[count];
|
|
for(IndexPointer iptr=indices;iptr<ilast;iptr+=1)
|
|
this->operator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)],
|
|
_treatVertexDataAsTemporary);
|
|
break;
|
|
this->operator()(_vertexArrayPtr[*(ilast-1)],_vertexArrayPtr[indices[0]],
|
|
_treatVertexDataAsTemporary);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
virtual void drawElements(GLenum mode,GLsizei count,const GLubyte* indices)
|
|
{
|
|
drawElementsTemplate(mode, count, indices);
|
|
}
|
|
|
|
virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices)
|
|
{
|
|
drawElementsTemplate(mode, count, indices);
|
|
}
|
|
|
|
virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices)
|
|
{
|
|
drawElementsTemplate(mode, count, indices);
|
|
}
|
|
|
|
/** Note:
|
|
* begin(..),vertex(..) & end() are convenience methods for adapting
|
|
* non vertex array primitives to vertex array based primitives.
|
|
* This is done to simplify the implementation of primtive functor
|
|
* subclasses - users only need override drawArray and drawElements.
|
|
*/
|
|
virtual void begin(GLenum mode)
|
|
{
|
|
_modeCache = mode;
|
|
_vertexCache.clear();
|
|
}
|
|
|
|
virtual void vertex(const Vec2& vert) { _vertexCache.push_back(osg::Vec3(vert[0],vert[1],0.0f)); }
|
|
virtual void vertex(const Vec3& vert) { _vertexCache.push_back(vert); }
|
|
virtual void vertex(const Vec4& vert) { _vertexCache.push_back(osg::Vec3(vert[0],vert[1],vert[2])/vert[3]); }
|
|
virtual void vertex(float x,float y) { _vertexCache.push_back(osg::Vec3(x,y,0.0f)); }
|
|
virtual void vertex(float x,float y,float z) { _vertexCache.push_back(osg::Vec3(x,y,z)); }
|
|
virtual void vertex(float x,float y,float z,float w) { _vertexCache.push_back(osg::Vec3(x,y,z)/w); }
|
|
virtual void end()
|
|
{
|
|
if (!_vertexCache.empty())
|
|
{
|
|
setVertexArray(_vertexCache.size(),&_vertexCache.front());
|
|
_treatVertexDataAsTemporary = true;
|
|
drawArrays(_modeCache,0,_vertexCache.size());
|
|
}
|
|
}
|
|
|
|
protected:
|
|
|
|
|
|
unsigned int _vertexArraySize;
|
|
const Vec3* _vertexArrayPtr;
|
|
|
|
GLenum _modeCache;
|
|
std::vector<Vec3> _vertexCache;
|
|
bool _treatVertexDataAsTemporary;
|
|
};
|
|
|
|
|
|
}
|
|
|
|
#endif
|