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

Reply via email to