Hi,
I was trying to generate a textured halo around a flat (2D) geometric
shape that is supposed to fade with distance without using any GLSL.
The shape is a convex polygon.
My approach is to create a polygon with a hole, where the vertices on
the outer ring has alpha transparency 0 and those on the inner ring
have alpha transparency 1. The hole is exactly centered and has half
the size of the outer shape.
The polygon is run through the osg tesselator and then displayed, but
the result is unexpected and seems to hint at some weird behavior of
the tesselator when alpha values are present.
I am attaching a self contained example, maybe someone can point out
whether I am doing something wrong, or whether the osg tesselator
cannot really handle per-vertex colors. Is anyone aware of an approach
that will produce the result I expect?
Christian
#include <limits>
#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osgViewer/Viewer>
#include <osg/Projection>
#include <osg/MatrixTransform>
#include <osgUtil/Tessellator>
#define SQRT3 1.732050807f
#define SQRT3_2 0.866025403f
class HoleGeometry: public osg::Geometry
{
public:
HoleGeometry(osg::Vec2Array &outer, osg::Vec2Array &inner, char *filename, float insidealpha, float outsidealpha);
};
HoleGeometry::HoleGeometry(osg::Vec2Array &outer, osg::Vec2Array &inner, char *filename, float insidealpha, float outsidealpha)
{
int i, nstart = 0;
osg::Vec3Array *coords = new osg::Vec3Array;
osg::Vec3Array *nrms = new osg::Vec3Array;
osg::Vec2Array *tcs = new osg::Vec2Array;
osg::Vec4Array *colors = new osg::Vec4Array;
osg::Vec3 nrm(0,-1,0);
setVertexArray(coords);
setNormalArray(nrms);
setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
setTexCoordArray(0,tcs);
setColorArray(colors);
setColorBinding(osg::Geometry::BIND_PER_VERTEX);
// compute the bounds of outer shape
osg::Vec2 minpos(+std::numeric_limits<double>::infinity(),+std::numeric_limits<double>::infinity());
osg::Vec2 maxpos(-std::numeric_limits<double>::infinity(),-std::numeric_limits<double>::infinity());
for (int i = 0; i < outer.getNumElements(); i++) {
if (outer[i].x() < minpos.x()) minpos.x() = outer[i].x();
if (outer[i].x() > maxpos.x()) maxpos.x() = outer[i].x();
if (outer[i].y() < minpos.y()) minpos.y() = outer[i].y();
if (outer[i].y() > maxpos.y()) maxpos.y() = outer[i].y();
}
// get the original outer shape
osg::Vec2 texscale(1.0/(maxpos.x()-minpos.x()), 1.0/(maxpos.y()-minpos.y()));
for (i = 0; i < outer.size(); i++) {
coords->push_back(osg::Vec3(outer[i].x(), 0, outer[i].y()));
tcs->push_back( osg::Vec2((outer[i].x()-minpos.x())*texscale.x(), (outer[i].y()-minpos.y())*texscale.y()) );
nrms->push_back(nrm);
colors->push_back(osg::Vec4(1.0,1.0,1.0,outsidealpha));
}
addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nstart, outer.size()));nstart+=outer.size();
// now add an inner ring shape
for (i = 0; i < inner.size(); i++) {
coords->push_back(osg::Vec3(inner[i].x(), 0, inner[i].y()));
tcs->push_back( osg::Vec2((inner[i].x()-minpos.x())*texscale.x(), (inner[i].y()-minpos.y())*texscale.y()) );
nrms->push_back(nrm);
colors->push_back(osg::Vec4(1.0,1.0,1.0,insidealpha));
}
addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON,nstart, inner.size()));nstart+=inner.size();
// set texture and enable blending
osg::StateSet* stateset = getOrCreateStateSet();
osg::Image* image = osgDB::readImageFile(filename);
if (image) {
osg::Texture2D* texture = new osg::Texture2D;
texture->setImage(image);
stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
}
stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
// We use a Tessellator to produce the tessellation required
osg::ref_ptr<osgUtil::Tessellator> tscx=new osgUtil::Tessellator; // the v1.2 multi-contour Tessellator.
tscx->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
tscx->setBoundaryOnly(false);
tscx->setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD); // so that first change in wind type makes the commonest tessellation - ODD.
tscx->retessellatePolygons(*this);
}
int main( int argc, char **argv )
{
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc,argv);
// construct the viewer.
osgViewer::Viewer viewer;
// read the scene from the list of file specified commandline args.
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
// if no model has been successfully loaded report failure.
if (!loadedModel)
{
osg::Vec2Array *outer = new osg::Vec2Array();
osg::Vec2Array *inner = new osg::Vec2Array();
// some concave shape consisting of 3 hexagons
float R = 100.0;
float o = 1.5*R / 2;
outer->push_back(osg::Vec2f(o +1.0f*R, 0.0f));
outer->push_back(osg::Vec2f(o +0.5f*R, 1.0f*R*SQRT3_2));
outer->push_back(osg::Vec2f(o -0.5f*R, 1.0f*R*SQRT3_2));
outer->push_back(osg::Vec2f(o -1.0f*R, 2.0f*R*SQRT3_2));
outer->push_back(osg::Vec2f(o -2.0f*R, 2.0f*R*SQRT3_2));
outer->push_back(osg::Vec2f(o -2.5f*R, 1.0f*R*SQRT3_2));
outer->push_back(osg::Vec2f(o -2.0f*R, 0.0f));
outer->push_back(osg::Vec2f(o -2.5f*R,-1.0f*R*SQRT3_2));
outer->push_back(osg::Vec2f(o -2.0f*R,-2.0f*R*SQRT3_2));
outer->push_back(osg::Vec2f(o -1.0f*R,-2.0f*R*SQRT3_2));
outer->push_back(osg::Vec2f(o -0.5f*R,-1.0f*R*SQRT3_2));
outer->push_back(osg::Vec2f(o +0.5f*R,-1.0f*R*SQRT3_2));
// some concave shape consisting of 3 hexagons
R = 50.0;
o = 1.5*R / 2;
inner->push_back(osg::Vec2f(o +1.0f*R, 0.0f));
inner->push_back(osg::Vec2f(o +0.5f*R, 1.0f*R*SQRT3_2));
inner->push_back(osg::Vec2f(o -0.5f*R, 1.0f*R*SQRT3_2));
inner->push_back(osg::Vec2f(o -1.0f*R, 2.0f*R*SQRT3_2));
inner->push_back(osg::Vec2f(o -2.0f*R, 2.0f*R*SQRT3_2));
inner->push_back(osg::Vec2f(o -2.5f*R, 1.0f*R*SQRT3_2));
inner->push_back(osg::Vec2f(o -2.0f*R, 0.0f));
inner->push_back(osg::Vec2f(o -2.5f*R,-1.0f*R*SQRT3_2));
inner->push_back(osg::Vec2f(o -2.0f*R,-2.0f*R*SQRT3_2));
inner->push_back(osg::Vec2f(o -1.0f*R,-2.0f*R*SQRT3_2));
inner->push_back(osg::Vec2f(o -0.5f*R,-1.0f*R*SQRT3_2));
inner->push_back(osg::Vec2f(o +0.5f*R,-1.0f*R*SQRT3_2));
osg::Geode *gd=new osg::Geode;
HoleGeometry *ggeom = new HoleGeometry(*outer, *inner, "Cubemap_snow/posy.jpg", 1.0f, 0.0f);
gd->addDrawable( ggeom );
loadedModel=gd;
}
// osgUtil::Optimizer optimizer;
// optimizer.optimize(loadedModel.get() );
// set the scene to render
viewer.setSceneData(loadedModel.get());
return viewer.run();
}
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org