Added support for primitive functor into the new osg::ProceduralGeometry class

This commit is contained in:
Robert Osfield 2002-11-01 15:12:51 +00:00
parent 92895370f7
commit bba03297a7
4 changed files with 581 additions and 72 deletions

View File

@ -457,9 +457,7 @@ class SG_EXPORT Grid : public HeightField
META_Shape(osg,Grid)
void allocGrid(unsigned int numColumns,unsigned int numRows, float value=0.0f);
void populateGrid(float minValue,float maxValue);
void allocateGrid(unsigned int numColumns,unsigned int numRows);
void setHeight(unsigned int c,unsigned int r,float value)
{
@ -486,7 +484,7 @@ class CompositeShape : public Shape
typedef std::vector< ref_ptr<Shape> > ChildList;
CompositeShape();
CompositeShape() {}
CompositeShape(const CompositeShape& cs,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
Shape(cs,copyop),

View File

@ -43,7 +43,7 @@ osg::Geode* createShapes()
geode->addDrawable(new osg::ProceduralGeometry(osgNew osg::Cylinder(osg::Vec3(6.0f,0.0f,0.0f),radius,height)));
osg::Grid* grid = new osg::Grid;
grid->allocGrid(38,39);
grid->allocateGrid(38,39);
grid->setXInterval(0.28f);
grid->setYInterval(0.28f);
@ -58,22 +58,27 @@ osg::Geode* createShapes()
osg::ConvexHull* mesh = new osg::ConvexHull;
osg::Vec3Array* vertices = new osg::Vec3Array(4);
(*vertices)[0].set(0.0f,0.0f,4.0f);
(*vertices)[1].set(0.0f,0.0f,0.0f);
(*vertices)[2].set(4.0f,0.0f,0.0f);
(*vertices)[3].set(4.0f,0.0f,4.0f);
osg::UByteArray* indices = new osg::UByteArray(6);
(*vertices)[0].set(7.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)[2].set(7.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);
osg::UByteArray* indices = new osg::UByteArray(12);
(*indices)[0]=0;
(*indices)[1]=1;
(*indices)[2]=2;
(*indices)[1]=2;
(*indices)[2]=1;
(*indices)[3]=0;
(*indices)[4]=2;
(*indices)[4]=1;
(*indices)[5]=3;
(*indices)[6]=1;
(*indices)[7]=2;
(*indices)[8]=3;
(*indices)[9]=2;
(*indices)[10]=0;
(*indices)[11]=3;
mesh->setVertices(vertices);
mesh->setIndices(indices);
geode->addDrawable(new osg::ProceduralGeometry(mesh));
return geode;
}

View File

@ -478,12 +478,29 @@ void DrawShapeVisitor::apply(const TriangleMesh& mesh)
const Vec3Array* vertices = mesh.getVertices();
const IndexArray* indices = mesh.getIndices();
if (vertices && indices)
{
glNormal3f(0.0f,0.0f,1.0f);
_state.setVertexPointer(3,GL_FLOAT,0,vertices->getDataPointer());
glDrawElements(GL_TRIANGLES,indices->getNumElements(),indices->getDataType(),indices->getDataPointer());
}
if (vertices && indices)
{
glBegin(GL_TRIANGLES);
for(unsigned int i=0;i<indices->getNumElements();i+=3)
{
const osg::Vec3& v1=(*vertices)[indices->index(i)];
const osg::Vec3& v2=(*vertices)[indices->index(i+1)];
const osg::Vec3& v3=(*vertices)[indices->index(i+2)];
Vec3 normal = (v2-v1)^(v3-v2);
normal.normalize();
glNormal3fv(normal.ptr());
glVertex3fv(v1.ptr());
glVertex3fv(v2.ptr());
glVertex3fv(v3.ptr());
}
glEnd();
}
}
void DrawShapeVisitor::apply(const ConvexHull& hull)
@ -546,12 +563,17 @@ void DrawShapeVisitor::apply(const HeightField& field)
}
void DrawShapeVisitor::apply(const CompositeShape& composite)
void DrawShapeVisitor::apply(const CompositeShape& group)
{
std::cout << "draw a composite "<<&composite<<std::endl;
for(unsigned int i=0;i<group.getNumChildren();++i)
{
group.getChild(i)->accept(*this);
}
}
///////////////////////////////////////////////////////////////////////////////
//
// Compute bounding of shape
@ -582,14 +604,16 @@ class ComputeBoundShapeVisitor : public ConstShapeVisitor
void ComputeBoundShapeVisitor::apply(const Sphere& sphere)
{
Vec3 halfLengths(sphere.getRadius(),sphere.getRadius(),sphere.getRadius());
_bb.set(sphere.getCenter()-halfLengths,sphere.getCenter()+halfLengths);
_bb.expandBy(sphere.getCenter()-halfLengths);
_bb.expandBy(sphere.getCenter()+halfLengths);
}
void ComputeBoundShapeVisitor::apply(const Box& box)
{
if (box.zeroRotation())
{
_bb.set(box.getCenter()-box.getHalfLengths(),box.getCenter()+box.getHalfLengths());
_bb.expandBy(box.getCenter()-box.getHalfLengths());
_bb.expandBy(box.getCenter()+box.getHalfLengths());
}
else
{
@ -624,9 +648,8 @@ void ComputeBoundShapeVisitor::apply(const Cone& cone)
{
if (cone.zeroRotation())
{
Vec3 halfLengths(cone.getRadius(),cone.getRadius(),cone.getHeight()*0.5f);
_bb.set(cone.getCenter()+Vec3(-cone.getRadius(),-cone.getRadius(),cone.getBaseOffset()),
cone.getCenter()+Vec3(cone.getRadius(),cone.getRadius(),cone.getHeight()+cone.getBaseOffset()));
_bb.expandBy(cone.getCenter()+Vec3(-cone.getRadius(),-cone.getRadius(),cone.getBaseOffset()));
_bb.expandBy(cone.getCenter()+Vec3(cone.getRadius(),cone.getRadius(),cone.getHeight()+cone.getBaseOffset()));
}
else
@ -651,7 +674,8 @@ void ComputeBoundShapeVisitor::apply(const Cylinder& cylinder)
if (cylinder.zeroRotation())
{
Vec3 halfLengths(cylinder.getRadius(),cylinder.getRadius(),cylinder.getHeight()*0.5f);
_bb.set(cylinder.getCenter()-halfLengths,cylinder.getCenter()+halfLengths);
_bb.expandBy(cylinder.getCenter()-halfLengths);
_bb.expandBy(cylinder.getCenter()+halfLengths);
}
else
@ -684,10 +708,22 @@ void ComputeBoundShapeVisitor::apply(const Cylinder& cylinder)
void ComputeBoundShapeVisitor::apply(const InfinitePlane&)
{
// can't compute the bounding box of an infinite plane!!! :-)
}
void ComputeBoundShapeVisitor::apply(const TriangleMesh&)
void ComputeBoundShapeVisitor::apply(const TriangleMesh& mesh)
{
const Vec3Array* vertices = mesh.getVertices();
const IndexArray* indices = mesh.getIndices();
if (vertices && indices)
{
for(unsigned int i=0;i<indices->getNumElements();++i)
{
const osg::Vec3& v=(*vertices)[indices->index(i)];
_bb.expandBy(v);
}
}
}
void ComputeBoundShapeVisitor::apply(const ConvexHull& hull)
@ -711,17 +747,496 @@ void ComputeBoundShapeVisitor::apply(const HeightField& field)
}
}
_bb.set(field.getOrigin()+osg::Vec3(0.0f,0.0f,zMin),
field.getOrigin()+osg::Vec3(field.getXInterval()*field.getNumColumns(),field.getYInterval()*field.getNumRows(),zMax));
if (field.zeroRotation())
{
_bb.expandBy(field.getOrigin()+osg::Vec3(0.0f,0.0f,zMin));
_bb.expandBy(field.getOrigin()+osg::Vec3(field.getXInterval()*field.getNumColumns(),field.getYInterval()*field.getNumRows(),zMax));
}
else
{
float x = field.getXInterval()*field.getNumColumns();
float y = field.getYInterval()*field.getNumRows();
Vec3 base_1(field.getOrigin()+Vec3(0,0,zMin));
Vec3 base_2(field.getOrigin()+Vec3(x,0,zMin));
Vec3 base_3(field.getOrigin()+Vec3(x,y,zMin));
Vec3 base_4(field.getOrigin()+Vec3(0,y,zMin));
Vec3 top_1(field.getOrigin()+Vec3(0,0,zMax));
Vec3 top_2(field.getOrigin()+Vec3(x,0,zMax));
Vec3 top_3(field.getOrigin()+Vec3(x,y,zMax));
Vec3 top_4(field.getOrigin()+Vec3(0,y,zMax));
Matrix matrix = field.getRotationMatrix();
_bb.expandBy(base_1*matrix);
_bb.expandBy(base_2*matrix);
_bb.expandBy(base_3*matrix);
_bb.expandBy(base_4*matrix);
_bb.expandBy(top_1*matrix);
_bb.expandBy(top_2*matrix);
_bb.expandBy(top_3*matrix);
_bb.expandBy(top_4*matrix);
}
}
void ComputeBoundShapeVisitor::apply(const CompositeShape&)
void ComputeBoundShapeVisitor::apply(const CompositeShape& group)
{
for(unsigned int i=0;i<group.getNumChildren();++i)
{
group.getChild(i)->accept(*this);
}
}
///////////////////////////////////////////////////////////////////////////////
//
// Accept a primtive functor for each of the shapes.
//
class PrimitiveShapeVisitor : public ConstShapeVisitor
{
public:
PrimitiveShapeVisitor(Drawable::PrimitiveFunctor& functor,TessellationHints* hints):
_functor(functor),
_hints(hints) {}
virtual void apply(const Sphere&);
virtual void apply(const Box&);
virtual void apply(const Cone&);
virtual void apply(const Cylinder&);
virtual void apply(const InfinitePlane&);
virtual void apply(const TriangleMesh&);
virtual void apply(const ConvexHull&);
virtual void apply(const HeightField&);
virtual void apply(const CompositeShape&);
Drawable::PrimitiveFunctor& _functor;
TessellationHints* _hints;
};
void PrimitiveShapeVisitor::apply(const Sphere& sphere)
{
float tx = sphere.getCenter().x();
float ty = sphere.getCenter().y();
float tz = sphere.getCenter().z();
unsigned int numSegments = 40;
unsigned int numRows = 20;
float lDelta = osg::PI/(float)numRows;
float vDelta = 1.0f/(float)numRows;
float angleDelta = osg::PI*2.0f/(float)numSegments;
float texCoordHorzDelta = 1.0f/(float)numSegments;
float lBase=-osg::PI*0.5f;
float rBase=0.0f;
float zBase=-sphere.getRadius();
float vBase=0.0f;
float nzBase=-1.0f;
float nRatioBase=0.0f;
for(unsigned int rowi=0;
rowi<numRows;
++rowi)
{
float lTop = lBase+lDelta;
float rTop = cosf(lTop)*sphere.getRadius();
float zTop = sinf(lTop)*sphere.getRadius();
float vTop = vBase+vDelta;
float nzTop= sinf(lTop);
float nRatioTop= cosf(lTop);
_functor.begin(GL_QUAD_STRIP);
float angle = 0.0f;
float texCoord = 0.0f;
for(unsigned int topi=0;
topi<numSegments;
++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
{
float c = cosf(angle);
float s = sinf(angle);
_functor.vertex(tx+c*rTop,ty+s*rTop,tz+zTop);
_functor.vertex(tx+c*rBase,ty+s*rBase,tz+zBase);
}
// do last point by hand to ensure no round off errors.
_functor.vertex(tx+rTop,ty,tz+zTop);
_functor.vertex(ty+rBase,ty,tz+zBase);
_functor.end();
lBase=lTop;
rBase=rTop;
zBase=zTop;
vBase=vTop;
nzBase=nzTop;
nRatioBase=nRatioTop;
}
}
void PrimitiveShapeVisitor::apply(const Box& box)
{
float x = box.getHalfLengths().x();
float y = box.getHalfLengths().y();
float z = box.getHalfLengths().z();
Vec3 base_1(-x,-y,-z);
Vec3 base_2(x,-y,-z);
Vec3 base_3(x,y,-z);
Vec3 base_4(-x,y,-z);
Vec3 top_1(-x,-y,z);
Vec3 top_2(x,-y,z);
Vec3 top_3(x,y,z);
Vec3 top_4(-x,y,z);
if (box.zeroRotation())
{
base_1 += box.getCenter();
base_2 += box.getCenter();
base_3 += box.getCenter();
base_4 += box.getCenter();
top_1 += box.getCenter();
top_2 += box.getCenter();
top_3 += box.getCenter();
top_4 += box.getCenter();
}
else
{
Matrix matrix = box.getRotationMatrix();
matrix.setTrans(box.getCenter());
base_1 = base_1*matrix;
base_2 = base_2*matrix;
base_3 = base_3*matrix;
base_4 = base_4*matrix;
top_1 = top_1*matrix;
top_2 = top_2*matrix;
top_3 = top_3*matrix;
top_4 = top_4*matrix;
}
_functor.begin(GL_QUADS);
_functor.vertex(top_1);
_functor.vertex(base_1);
_functor.vertex(base_2);
_functor.vertex(top_2);
_functor.vertex(top_2);
_functor.vertex(base_2);
_functor.vertex(base_3);
_functor.vertex(top_3);
_functor.vertex(top_3);
_functor.vertex(base_3);
_functor.vertex(base_4);
_functor.vertex(top_4);
_functor.vertex(top_4);
_functor.vertex(base_4);
_functor.vertex(base_1);
_functor.vertex(top_1);
_functor.vertex(top_4);
_functor.vertex(top_1);
_functor.vertex(top_2);
_functor.vertex(top_3);
_functor.vertex(base_2);
_functor.vertex(base_3);
_functor.vertex(base_4);
_functor.vertex(base_1);
_functor.end();
}
void PrimitiveShapeVisitor::apply(const Cone& cone)
{
Matrix matrix = cone.getRotationMatrix();
matrix.setTrans(cone.getCenter());
unsigned int numSegments = 40;
unsigned int numRows = 10;
float r = cone.getRadius();
float h = cone.getHeight();
float normalz = r/(sqrtf(r*r+h*h));
float normalRatio = 1.0f/(sqrtf(1.0f+normalz*normalz));
normalz *= normalRatio;
float angleDelta = 2.0f*osg::PI/(float)numSegments;
float texCoordHorzDelta = 1.0/(float)numSegments;
float texCoordRowDelta = 1.0/(float)numRows;
float hDelta = cone.getHeight()/(float)numRows;
float rDelta = cone.getRadius()/(float)numRows;
float topz=cone.getHeight()+cone.getBaseOffset();
float topr=0.0f;
float topv=1.0f;
float basez=topz-hDelta;
float baser=rDelta;
float basev=topv-texCoordRowDelta;
float angle;
float texCoord;
for(unsigned int rowi=0;
rowi<numRows;
++rowi,topz=basez, basez-=hDelta, topr=baser, baser+=rDelta, topv=basev, basev-=texCoordRowDelta)
{
// we can't use a fan for the cone top
// since we need different normals at the top
// for each face..
_functor.begin(GL_QUAD_STRIP);
angle = 0.0f;
texCoord = 0.0f;
for(unsigned int topi=0;
topi<numSegments;
++topi,angle+=angleDelta,texCoord+=texCoordHorzDelta)
{
float c = cosf(angle);
float s = sinf(angle);
_functor.vertex(Vec3(c*topr,s*topr,topz)*matrix);
_functor.vertex(Vec3(c*baser,s*baser,basez)*matrix);
}
// do last point by hand to ensure no round off errors.
_functor.vertex(Vec3(topr,0.0f,topz)*matrix);
_functor.vertex(Vec3(baser,0.0f,basez)*matrix);
_functor.end();
}
// we can't use a fan for the cone top
// since we need different normals at the top
// for each face..
_functor.begin(GL_TRIANGLE_FAN);
angle = osg::PI*2.0f;
texCoord = 1.0f;
basez = cone.getBaseOffset();
_functor.vertex(Vec3(0.0f,0.0f,basez)*matrix);
for(unsigned int bottomi=0;
bottomi<numSegments;
++bottomi,angle-=angleDelta,texCoord-=texCoordHorzDelta)
{
float c = cosf(angle);
float s = sinf(angle);
_functor.vertex(Vec3(c*r,s*r,basez)*matrix);
}
_functor.vertex(Vec3(r,0.0f,basez)*matrix);
_functor.end();
}
void PrimitiveShapeVisitor::apply(const Cylinder& cylinder)
{
Matrix matrix = cylinder.getRotationMatrix();
matrix.setTrans(cylinder.getCenter());
unsigned int numSegments = 40;
float angleDelta = 2.0f*osg::PI/(float)numSegments;
float texCoordDelta = 1.0/(float)numSegments;
float r = cylinder.getRadius();
float h = cylinder.getHeight();
float basez = -h*0.5f;
float topz = h*0.5f;
// cylinder body
_functor.begin(GL_QUAD_STRIP);
float angle = 0.0f;
float texCoord = 0.0f;
for(unsigned int bodyi=0;
bodyi<numSegments;
++bodyi,angle+=angleDelta,texCoord+=texCoordDelta)
{
float c = cosf(angle);
float s = sinf(angle);
_functor.vertex(Vec3(c*r,s*r,topz)*matrix);
_functor.vertex(Vec3(c*r,s*r,basez)*matrix);
}
// do last point by hand to ensure no round off errors.
_functor.vertex(Vec3(r,0.0f,topz)*matrix);
_functor.vertex(Vec3(r,0.0f,basez)*matrix);
_functor.end();
// cylinder top
_functor.begin(GL_TRIANGLE_FAN);
_functor.vertex(Vec3(0.0f,0.0f,topz)*matrix);
angle = 0.0f;
texCoord = 0.0f;
for(unsigned int topi=0;
topi<numSegments;
++topi,angle+=angleDelta,texCoord+=texCoordDelta)
{
float c = cosf(angle);
float s = sinf(angle);
_functor.vertex(Vec3(c*r,s*r,topz)*matrix);
}
_functor.vertex(Vec3(r,0.0f,topz)*matrix);
_functor.end();
// cylinder bottom
_functor.begin(GL_TRIANGLE_FAN);
_functor.vertex(Vec3(0.0f,0.0f,basez)*matrix);
angle = osg::PI*2.0f;
texCoord = 1.0f;
for(unsigned int bottomi=0;
bottomi<numSegments;
++bottomi,angle-=angleDelta,texCoord-=texCoordDelta)
{
float c = cosf(angle);
float s = sinf(angle);
_functor.vertex(Vec3(c*r,s*r,basez)*matrix);
}
_functor.vertex(Vec3(r,0.0f,basez)*matrix);
_functor.end();
}
void PrimitiveShapeVisitor::apply(const InfinitePlane& plane)
{
std::cout << "Primitive a Plane ("<<plane<<") "<<std::endl;
}
void PrimitiveShapeVisitor::apply(const TriangleMesh& mesh)
{
const Vec3Array* vertices = mesh.getVertices();
const IndexArray* indices = mesh.getIndices();
if (vertices && indices)
{
_functor.begin(GL_TRIANGLES);
for(unsigned int i=0;i<indices->getNumElements();i+=3)
{
_functor.vertex((*vertices)[indices->index(i)]);
_functor.vertex((*vertices)[indices->index(i+1)]);
_functor.vertex((*vertices)[indices->index(i+2)]);
}
_functor.end();
}
}
void PrimitiveShapeVisitor::apply(const ConvexHull& hull)
{
apply((const TriangleMesh&)hull);
}
void PrimitiveShapeVisitor::apply(const HeightField& field)
{
if (field.getNumColumns()==0 || field.getNumRows()==0) return;
Matrix matrix = field.getRotationMatrix();
matrix.setTrans(field.getOrigin());
float dx = field.getXInterval();
float dy = field.getYInterval();
float du = 1.0f/((float)field.getNumColumns()-1.0f);
float dv = 1.0f/((float)field.getNumRows()-1.0f);
float vBase = 0.0f;
for(unsigned int row=0;row<field.getNumRows()-1;++row)
{
_functor.begin(GL_QUAD_STRIP);
for(unsigned int col=0;col<field.getNumColumns();++col)
{
Vec3 vertTop(dx*(float)col,dy*(float)row+dy,field.getHeight(col,row+1));
Vec3 vertBase(dx*(float)col,dy*(float)row,field.getHeight(col,row));
_functor.vertex(vertTop*matrix);
_functor.vertex(vertBase*matrix);
}
_functor.end();
}
}
void PrimitiveShapeVisitor::apply(const CompositeShape& group)
{
for(unsigned int i=0;i<group.getNumChildren();++i)
{
group.getChild(i)->accept(*this);
}
}
///////////////////////////////////////////////////////////////////////////////
//
// ProceduralGeometry itself..
//
ProceduralGeometry::ProceduralGeometry()
{
}
@ -749,12 +1264,17 @@ void ProceduralGeometry::drawImmediateMode(State& state)
}
}
void ProceduralGeometry::accept(AttributeFunctor& af)
void ProceduralGeometry::accept(AttributeFunctor&)
{
}
void ProceduralGeometry::accept(PrimitiveFunctor& pf)
{
if (_shape.valid())
{
PrimitiveShapeVisitor psv(pf,_tessellationHints.get());
_shape->accept(psv);
}
}

View File

@ -3,45 +3,6 @@
using namespace osg;
Grid::Grid()
{
}
Grid::Grid(const Grid& mesh,const CopyOp& copyop):
HeightField(mesh,copyop)
{
_heights = mesh._heights;
}
Grid::~Grid()
{
}
void Grid::allocGrid(unsigned int numColumns,unsigned int numRows, float value)
{
if (_columns!=numColumns || _rows!=numRows)
{
_heights.resize(numColumns*numRows);
}
_columns=numColumns;
_rows=numRows;
//_heights.fill(value);
}
void Grid::populateGrid(float minValue,float maxValue)
{
float offset=minValue;
float gain=(maxValue-minValue)/(float)RAND_MAX;
for(unsigned int row=0;row<_rows;++row)
{
for(unsigned int col=0;col<_columns;++col)
{
setHeight(col,row,rand()*gain+offset);
}
}
}
Vec3 HeightField::getNormal(unsigned int c,unsigned int r) const
{
// four point normal generation.
@ -79,3 +40,28 @@ Vec3 HeightField::getNormal(unsigned int c,unsigned int r) const
return normal;
}
Grid::Grid()
{
}
Grid::Grid(const Grid& mesh,const CopyOp& copyop):
HeightField(mesh,copyop)
{
_heights = mesh._heights;
}
Grid::~Grid()
{
}
void Grid::allocateGrid(unsigned int numColumns,unsigned int numRows)
{
if (_columns!=numColumns || _rows!=numRows)
{
_heights.resize(numColumns*numRows);
}
_columns=numColumns;
_rows=numRows;
}