From David Jung, added support for osg::Capsule shape

This commit is contained in:
Robert Osfield 2004-03-02 20:33:00 +00:00
parent 13d5b50bcf
commit e2469aece9
3 changed files with 374 additions and 37 deletions

View File

@ -41,6 +41,7 @@ osg::Geode* createShapes()
geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(2.0f,0.0f,0.0f),2*radius),hints)); geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(2.0f,0.0f,0.0f),2*radius),hints));
geode->addDrawable(new osg::ShapeDrawable(new osg::Cone(osg::Vec3(4.0f,0.0f,0.0f),radius,height),hints)); geode->addDrawable(new osg::ShapeDrawable(new osg::Cone(osg::Vec3(4.0f,0.0f,0.0f),radius,height),hints));
geode->addDrawable(new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(6.0f,0.0f,0.0f),radius,height),hints)); geode->addDrawable(new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(6.0f,0.0f,0.0f),radius,height),hints));
geode->addDrawable(new osg::ShapeDrawable(new osg::Capsule(osg::Vec3(8.0f,0.0f,0.0f),radius,height),hints));
osg::HeightField* grid = new osg::HeightField; osg::HeightField* grid = new osg::HeightField;
grid->allocateGrid(38,39); grid->allocateGrid(38,39);
@ -58,10 +59,10 @@ osg::Geode* createShapes()
osg::ConvexHull* mesh = new osg::ConvexHull; osg::ConvexHull* mesh = new osg::ConvexHull;
osg::Vec3Array* vertices = new osg::Vec3Array(4); osg::Vec3Array* vertices = new osg::Vec3Array(4);
(*vertices)[0].set(7.0+0.0f,-1.0f+2.0f,-1.0f+0.0f); (*vertices)[0].set(9.0+0.0f,-1.0f+2.0f,-1.0f+0.0f);
(*vertices)[1].set(7.0+1.0f,-1.0f+0.0f,-1.0f+0.0f); (*vertices)[1].set(9.0+1.0f,-1.0f+0.0f,-1.0f+0.0f);
(*vertices)[2].set(7.0+2.0f,-1.0f+2.0f,-1.0f+0.0f); (*vertices)[2].set(9.0+2.0f,-1.0f+2.0f,-1.0f+0.0f);
(*vertices)[3].set(7.0+1.0f,-1.0f+1.0f,-1.0f+2.0f); (*vertices)[3].set(9.0+1.0f,-1.0f+1.0f,-1.0f+2.0f);
osg::UByteArray* indices = new osg::UByteArray(12); osg::UByteArray* indices = new osg::UByteArray(12);
(*indices)[0]=0; (*indices)[0]=0;
(*indices)[1]=2; (*indices)[1]=2;

View File

@ -90,6 +90,7 @@ class Sphere;
class Box; class Box;
class Cone; class Cone;
class Cylinder; class Cylinder;
class Capsule;
class InfinitePlane; class InfinitePlane;
class TriangleMesh; class TriangleMesh;
@ -108,6 +109,7 @@ class ShapeVisitor
virtual void apply(Box&) {} virtual void apply(Box&) {}
virtual void apply(Cone&) {} virtual void apply(Cone&) {}
virtual void apply(Cylinder&) {} virtual void apply(Cylinder&) {}
virtual void apply(Capsule&) {}
virtual void apply(InfinitePlane&) {} virtual void apply(InfinitePlane&) {}
virtual void apply(TriangleMesh&) {} virtual void apply(TriangleMesh&) {}
@ -127,6 +129,7 @@ class ConstShapeVisitor
virtual void apply(const Box&) {} virtual void apply(const Box&) {}
virtual void apply(const Cone&) {} virtual void apply(const Cone&) {}
virtual void apply(const Cylinder&) {} virtual void apply(const Cylinder&) {}
virtual void apply(const Capsule&) {}
virtual void apply(const InfinitePlane&) {} virtual void apply(const InfinitePlane&) {}
virtual void apply(const TriangleMesh&) {} virtual void apply(const TriangleMesh&) {}
@ -350,6 +353,63 @@ class Cylinder : public Shape
Quat _rotation; Quat _rotation;
}; };
class Capsule : public Shape
{
public:
Capsule():
_center(0.0f,0.0f,0.0f),
_radius(1.0f),
_height(1.0f) {}
Capsule(const osg::Vec3& center,float radius,float height):
_center(center),
_radius(radius),
_height(height) {}
Capsule(const Capsule& capsule,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
Shape(capsule,copyop),
_center(capsule._center),
_radius(capsule._radius),
_height(capsule._height),
_rotation(capsule._rotation) {}
META_Shape(osg, Capsule);
inline bool valid() const { return _radius>=0.0f; }
inline void set(const Vec3& center,float radius, float height)
{
_center = center;
_radius = radius;
_height = height;
}
inline void setCenter(const Vec3& center) { _center = center; }
inline const Vec3& getCenter() const { return _center; }
inline void setRadius(float radius) { _radius = radius; }
inline float getRadius() const { return _radius; }
inline void setHeight(float height) { _height = height; }
inline float getHeight() const { return _height; }
inline void setRotation(const Quat& quat) { _rotation = quat; }
inline const Quat& getRotation() const { return _rotation; }
inline Matrix getRotationMatrix() const { return Matrix(_rotation); }
bool zeroRotation() const { return _rotation.zeroRotation(); }
protected:
virtual ~Capsule() {}
Vec3 _center;
float _radius;
float _height;
Quat _rotation;
};
class InfinitePlane : public Shape, public Plane class InfinitePlane : public Shape, public Plane
{ {
public: public:

View File

@ -46,6 +46,7 @@ class DrawShapeVisitor : public ConstShapeVisitor
virtual void apply(const Box&); virtual void apply(const Box&);
virtual void apply(const Cone&); virtual void apply(const Cone&);
virtual void apply(const Cylinder&); virtual void apply(const Cylinder&);
virtual void apply(const Capsule&);
virtual void apply(const InfinitePlane&); virtual void apply(const InfinitePlane&);
virtual void apply(const TriangleMesh&); virtual void apply(const TriangleMesh&);
@ -56,12 +57,223 @@ class DrawShapeVisitor : public ConstShapeVisitor
State& _state; State& _state;
const TessellationHints* _hints; const TessellationHints* _hints;
protected:
enum SphereHalf { SphereTopHalf, SphereBottomHalf };
// helpers for apply( Cylinder | Sphere | Capsule )
void drawCylinderBody(unsigned int numSegments, float radius, float height);
void drawHalfSphere(unsigned int numSegments, unsigned int numRows, float radius, SphereHalf which, float zOffset = 0.0f);
}; };
void DrawShapeVisitor::drawCylinderBody(unsigned int numSegments, float radius, float height)
{
const float angleDelta = 2.0f*osg::PI/(float)numSegments;
const float texCoordDelta = 1.0f/(float)numSegments;
const float r = radius;
const float h = height;
float basez = -h*0.5f;
float topz = h*0.5f;
float angle = 0.0f;
float texCoord = 0.0f;
bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true;
bool drawBackFace = _hints ? _hints->getCreateBackFace() : false;
// The only difference between the font & back face loops is that the
// normals are inverted and the order of the vertex pairs is reversed.
// The code is mostly duplicated in order to hoist the back/front face
// test out of the loop for efficiency
glBegin(GL_QUAD_STRIP);
if (drawFrontFace) {
for(unsigned int bodyi=0;
bodyi<numSegments;
++bodyi,angle+=angleDelta,texCoord+=texCoordDelta)
{
float c = cosf(angle);
float s = sinf(angle);
glNormal3f(c,s,0.0f);
glTexCoord2f(texCoord,1.0f);
glVertex3f(c*r,s*r,topz);
glTexCoord2f(texCoord,0.0f);
glVertex3f(c*r,s*r,basez);
}
// do last point by hand to ensure no round off errors.
glNormal3f(1.0f,0.0f,0.0f);
glTexCoord2f(1.0f,1.0f);
glVertex3f(r,0.0f,topz);
glTexCoord2f(1.0f,0.0f);
glVertex3f(r,0.0f,basez);
}
if (drawBackFace) {
for(unsigned int bodyi=0;
bodyi<numSegments;
++bodyi,angle+=angleDelta,texCoord+=texCoordDelta)
{
float c = cosf(angle);
float s = sinf(angle);
glNormal3f(-c,-s,0.0f);
glTexCoord2f(texCoord,0.0f);
glVertex3f(c*r,s*r,basez);
glTexCoord2f(texCoord,1.0f);
glVertex3f(c*r,s*r,topz);
}
// do last point by hand to ensure no round off errors.
glNormal3f(-1.0f,0.0f,0.0f);
glTexCoord2f(1.0f,0.0f);
glVertex3f(r,0.0f,basez);
glTexCoord2f(1.0f,1.0f);
glVertex3f(r,0.0f,topz);
}
glEnd();
}
void DrawShapeVisitor::drawHalfSphere(unsigned int numSegments, unsigned int numRows, float radius, SphereHalf which, float zOffset)
{
float lDelta = osg::PI/(float)numRows;
float vDelta = 1.0f/(float)numRows;
bool top = (which==SphereTopHalf);
bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true;
bool drawBackFace = _hints ? _hints->getCreateBackFace() : false;
float angleDelta = osg::PI*2.0f/(float)numSegments;
float texCoordHorzDelta = 1.0f/(float)numSegments;
float lBase=-osg::PI*0.5f + (top?(lDelta*(numRows/2)):0.0f);
float rBase=(top?(cosf(lBase)*radius):0.0f);
float zBase=(top?(sinf(lBase)*radius):-radius);
float vBase=(top?(vDelta*(numRows/2)):0.0f);
float nzBase=(top?(sinf(lBase)):-1.0f);
float nRatioBase=(top?(cosf(lBase)):0.0f);
unsigned int rowbegin = top?numRows/2:0;
unsigned int rowend = top?numRows:numRows/2;
for(unsigned int rowi=rowbegin; rowi<rowend; ++rowi)
{
float lTop = lBase+lDelta;
float rTop = cosf(lTop)*radius;
float zTop = sinf(lTop)*radius;
float vTop = vBase+vDelta;
float nzTop= sinf(lTop);
float nRatioTop= cosf(lTop);
glBegin(GL_QUAD_STRIP);
float angle = 0.0f;
float texCoord = 0.0f;
// The only difference between the font & back face loops is that the
// normals are inverted and the order of the vertex pairs is reversed.
// The code is mostly duplicated in order to hoist the back/front face
// test out of the loop for efficiency
if (drawFrontFace) {
for(unsigned int topi=0; topi<numSegments;
++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
{
float c = cosf(angle);
float s = sinf(angle);
glNormal3f(c*nRatioTop,s*nRatioTop,nzTop);
glTexCoord2f(texCoord,vTop);
glVertex3f(c*rTop,s*rTop,zTop+zOffset);
glNormal3f(c*nRatioBase,s*nRatioBase,nzBase);
glTexCoord2f(texCoord,vBase);
glVertex3f(c*rBase,s*rBase,zBase+zOffset);
}
// do last point by hand to ensure no round off errors.
glNormal3f(nRatioTop,0.0f,nzTop);
glTexCoord2f(1.0f,vTop);
glVertex3f(rTop,0.0f,zTop+zOffset);
glNormal3f(nRatioBase,0.0f,nzBase);
glTexCoord2f(1.0f,vBase);
glVertex3f(rBase,0.0f,zBase+zOffset);
}
if (drawBackFace) {
for(unsigned int topi=0; topi<numSegments;
++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
{
float c = cosf(angle);
float s = sinf(angle);
glNormal3f(-c*nRatioBase,-s*nRatioBase,-nzBase);
glTexCoord2f(texCoord,vBase);
glVertex3f(c*rBase,s*rBase,zBase+zOffset);
glNormal3f(-c*nRatioTop,-s*nRatioTop,-nzTop);
glTexCoord2f(texCoord,vTop);
glVertex3f(c*rTop,s*rTop,zTop+zOffset);
}
// do last point by hand to ensure no round off errors.
glNormal3f(-nRatioBase,0.0f,-nzBase);
glTexCoord2f(1.0f,vBase);
glVertex3f(rBase,0.0f,zBase+zOffset);
glNormal3f(-nRatioTop,0.0f,-nzTop);
glTexCoord2f(1.0f,vTop);
glVertex3f(rTop,0.0f,zTop+zOffset);
}
glEnd();
lBase=lTop;
rBase=rTop;
zBase=zTop;
vBase=vTop;
nzBase=nzTop;
nRatioBase=nRatioTop;
}
}
void DrawShapeVisitor::apply(const Sphere& sphere) void DrawShapeVisitor::apply(const Sphere& sphere)
{ {
glPushMatrix(); glPushMatrix();
glTranslatef(sphere.getCenter().x(),sphere.getCenter().y(),sphere.getCenter().z()); glTranslatef(sphere.getCenter().x(),sphere.getCenter().y(),sphere.getCenter().z());
@ -496,6 +708,11 @@ void DrawShapeVisitor::apply(const Cylinder& cylinder)
numSegments = MIN_NUM_SEGMENTS; numSegments = MIN_NUM_SEGMENTS;
} }
// cylinder body
if (createBody)
drawCylinderBody(numSegments, cylinder.getRadius(), cylinder.getHeight());
float angleDelta = 2.0f*osg::PI/(float)numSegments; float angleDelta = 2.0f*osg::PI/(float)numSegments;
float texCoordDelta = 1.0f/(float)numSegments; float texCoordDelta = 1.0f/(float)numSegments;
@ -508,38 +725,6 @@ void DrawShapeVisitor::apply(const Cylinder& cylinder)
float angle = 0.0f; float angle = 0.0f;
float texCoord = 0.0f; float texCoord = 0.0f;
// cylinder body
if (createBody) {
glBegin(GL_QUAD_STRIP);
for(unsigned int bodyi=0;
bodyi<numSegments;
++bodyi,angle+=angleDelta,texCoord+=texCoordDelta)
{
float c = cosf(angle);
float s = sinf(angle);
glNormal3f(c,s,0.0f);
glTexCoord2f(texCoord,1.0f);
glVertex3f(c*r,s*r,topz);
glTexCoord2f(texCoord,0.0f);
glVertex3f(c*r,s*r,basez);
}
// do last point by hand to ensure no round off errors.
glNormal3f(1.0f,0.0f,0.0f);
glTexCoord2f(1.0f,1.0f);
glVertex3f(r,0.0f,topz);
glTexCoord2f(1.0f,0.0f);
glVertex3f(r,0.0f,basez);
glEnd();
}
// cylinder top // cylinder top
if (createTop) { if (createTop) {
glBegin(GL_TRIANGLE_FAN); glBegin(GL_TRIANGLE_FAN);
@ -597,6 +782,51 @@ void DrawShapeVisitor::apply(const Cylinder& cylinder)
glPopMatrix(); glPopMatrix();
} }
void DrawShapeVisitor::apply(const Capsule& capsule)
{
glPushMatrix();
glTranslatef(capsule.getCenter().x(),capsule.getCenter().y(),capsule.getCenter().z());
if (!capsule.zeroRotation())
{
Matrix rotation(capsule.getRotationMatrix());
glMultMatrix(rotation.ptr());
}
// evaluate hints
bool createBody = (_hints ? _hints->getCreateBody() : true);
bool createTop = (_hints ? _hints->getCreateTop() : true);
bool createBottom = (_hints ? _hints->getCreateBottom() : true);
unsigned int numSegments = 40;
unsigned int numRows = 20;
if (_hints && _hints->getDetailRatio() != 1.0f) {
float ratio = _hints->getDetailRatio();
numSegments = (unsigned int) (numSegments * ratio);
if (numSegments < MIN_NUM_SEGMENTS)
numSegments = MIN_NUM_SEGMENTS;
numRows = (unsigned int) (numRows * ratio);
if (numRows < MIN_NUM_ROWS)
numRows = MIN_NUM_ROWS;
}
// capsule cylindrical body
if (createBody)
drawCylinderBody(numSegments, capsule.getRadius(), capsule.getHeight());
// capsule top cap
if (createTop)
drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereTopHalf, capsule.getHeight()/2.0f);
// capsule bottom cap
if (createBottom)
drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereBottomHalf, -capsule.getHeight()/2.0f);
glPopMatrix();
}
void DrawShapeVisitor::apply(const InfinitePlane& plane) void DrawShapeVisitor::apply(const InfinitePlane& plane)
{ {
std::cout << "draw a Plane ("<<plane<<") "<<std::endl; std::cout << "draw a Plane ("<<plane<<") "<<std::endl;
@ -814,6 +1044,7 @@ class ComputeBoundShapeVisitor : public ConstShapeVisitor
virtual void apply(const Box&); virtual void apply(const Box&);
virtual void apply(const Cone&); virtual void apply(const Cone&);
virtual void apply(const Cylinder&); virtual void apply(const Cylinder&);
virtual void apply(const Capsule&);
virtual void apply(const InfinitePlane&); virtual void apply(const InfinitePlane&);
virtual void apply(const TriangleMesh&); virtual void apply(const TriangleMesh&);
@ -931,6 +1162,43 @@ void ComputeBoundShapeVisitor::apply(const Cylinder& cylinder)
} }
} }
void ComputeBoundShapeVisitor::apply(const Capsule& capsule)
{
if (capsule.zeroRotation())
{
Vec3 halfLengths(capsule.getRadius(),capsule.getRadius(),capsule.getHeight()*0.5f + capsule.getRadius());
_bb.expandBy(capsule.getCenter()-halfLengths);
_bb.expandBy(capsule.getCenter()+halfLengths);
}
else
{
float r = capsule.getRadius();
float z = capsule.getHeight()*0.5f + capsule.getRadius();
Vec3 base_1(Vec3(-r,-r,-z));
Vec3 base_2(Vec3(r,-r,-z));
Vec3 base_3(Vec3(r,r,-z));
Vec3 base_4(Vec3(-r,r,-z));
Vec3 top_1(Vec3(-r,-r,z));
Vec3 top_2(Vec3(r,-r,z));
Vec3 top_3(Vec3(r,r,z));
Vec3 top_4(Vec3(-r,r,z));
Matrix matrix = capsule.getRotationMatrix();
_bb.expandBy(capsule.getCenter()+base_1*matrix);
_bb.expandBy(capsule.getCenter()+base_2*matrix);
_bb.expandBy(capsule.getCenter()+base_3*matrix);
_bb.expandBy(capsule.getCenter()+base_4*matrix);
_bb.expandBy(capsule.getCenter()+top_1*matrix);
_bb.expandBy(capsule.getCenter()+top_2*matrix);
_bb.expandBy(capsule.getCenter()+top_3*matrix);
_bb.expandBy(capsule.getCenter()+top_4*matrix);
}
}
void ComputeBoundShapeVisitor::apply(const InfinitePlane&) void ComputeBoundShapeVisitor::apply(const InfinitePlane&)
{ {
// can't compute the bounding box of an infinite plane!!! :-) // can't compute the bounding box of an infinite plane!!! :-)
@ -1043,6 +1311,7 @@ class PrimitiveShapeVisitor : public ConstShapeVisitor
virtual void apply(const Box&); virtual void apply(const Box&);
virtual void apply(const Cone&); virtual void apply(const Cone&);
virtual void apply(const Cylinder&); virtual void apply(const Cylinder&);
virtual void apply(const Capsule&);
virtual void apply(const InfinitePlane&); virtual void apply(const InfinitePlane&);
virtual void apply(const TriangleMesh&); virtual void apply(const TriangleMesh&);
@ -1385,6 +1654,13 @@ void PrimitiveShapeVisitor::apply(const Cylinder& cylinder)
_functor.end(); _functor.end();
} }
void PrimitiveShapeVisitor::apply(const Capsule& /*capsule*/)
{
#if 0
notify(NOTICE)<<"Warning: PrimitiveShapeVisitor doesn't implement apply(Capsule&) (yet)."<<std::endl;
#endif
}
void PrimitiveShapeVisitor::apply(const InfinitePlane& plane) void PrimitiveShapeVisitor::apply(const InfinitePlane& plane)
{ {
std::cout << "Primitive a Plane ("<<plane<<") "<<std::endl; std::cout << "Primitive a Plane ("<<plane<<") "<<std::endl;