[osg-users] problem setting texture min/mag filter

antiro black antiro42 at gmail.com
Tue Feb 20 09:10:18 PST 2018


Hi,

I made an executable example based on the osgtexture2D example. I removed the code to render the different walls of the cube with the exception of the filter wall. I kept the rest as close to the original as possible. changes to the code have been marked using comments.

Essentially all I'm doing is generating an input image instead of loading one.


Code:

#include <osg/Node>
#include <osg/Geometry>
#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/Texture2D>
#include <osg/DrawPixels>
#include <osg/PolygonOffset>
#include <osg/Geode>

#include <osgDB/Registry>
#include <osgDB/ReadFile>

#include <osgText/Text>

#include <osgViewer/Viewer>

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// filter wall and animation callback.
//

class FilterCallback : public osg::NodeCallback
{
public:

    FilterCallback(osg::Texture2D* texture,osgText::Text* text,double delay=1.0):
        _texture(texture),
        _text(text),
        _delay(delay),
        _currPos(0),
        _prevTime(0.0)
    {
        // start with a mip mapped mode to ensure that
        _minFilterList.push_back(osg::Texture2D::LINEAR_MIPMAP_LINEAR);
        _magFilterList.push_back(osg::Texture2D::LINEAR);
        _textList.push_back("Tri-linear mip mapping (default filtering)\nsetFilter(MIN_FILTER,LINEAR_MIP_LINEAR)\nsetFilter(MAG_FILTER,LINEAR)");

        _minFilterList.push_back(osg::Texture2D::NEAREST);
        _magFilterList.push_back(osg::Texture2D::NEAREST);
        _textList.push_back("Nearest filtering\nsetFilter(MIN_FILTER,NEAREST)\nsetFilter(MAG_FILTER,NEAREST)");

        _minFilterList.push_back(osg::Texture2D::LINEAR);
        _magFilterList.push_back(osg::Texture2D::LINEAR);
        _textList.push_back("Linear filtering\nsetFilter(MIN_FILTER,LINEAR)\nsetFilter(MAG_FILTER,LINEAR)");

        _minFilterList.push_back(osg::Texture2D::NEAREST_MIPMAP_NEAREST);
        _magFilterList.push_back(osg::Texture2D::LINEAR);
        _textList.push_back("nearest mip mapping (default filtering)\nsetFilter(MIN_FILTER,)\nsetFilter(MAG_FILTER,LINEAR)");

        _minFilterList.push_back(osg::Texture2D::LINEAR_MIPMAP_NEAREST);
        _magFilterList.push_back(osg::Texture2D::LINEAR);
        _textList.push_back("bi-linear mip mapping\nsetFilter(MIN_FILTER,LINEAR_MIPMAP_NEAREST)\nsetFilter(MAG_FILTER,LINEAR)");

        _minFilterList.push_back(osg::Texture2D::NEAREST_MIPMAP_LINEAR);
        _magFilterList.push_back(osg::Texture2D::LINEAR);
        _textList.push_back("bi-linear mip mapping\nsetFilter(MIN_FILTER,NEAREST_MIPMAP_LINEAR)\nsetFilter(MAG_FILTER,LINEAR)");


        setValues();
    }

    virtual void operator()(osg::Node*, osg::NodeVisitor* nv)
    {
        if (nv->getFrameStamp())
        {
            double currTime = nv->getFrameStamp()->getSimulationTime();
            if (currTime-_prevTime>_delay)
            {
                // update filter modes and text.
                setValues();

                // advance the current position, wrap round if required.
                _currPos++;
                if (_currPos>=_minFilterList.size()) _currPos=0;

                // record time
                _prevTime = currTime;
            }
        }
    }

    void setValues()
    {
        _texture->setFilter(osg::Texture2D::MIN_FILTER,_minFilterList[_currPos]);
        _texture->setFilter(osg::Texture2D::MAG_FILTER,_magFilterList[_currPos]);

        _text->setText(_textList[_currPos]);
    }

protected:

    typedef std::vector<osg::Texture2D::FilterMode> FilterList;
    typedef std::vector<std::string>                TextList;

    osg::ref_ptr<osg::Texture2D>    _texture;
    osg::ref_ptr<osgText::Text>     _text;
    double                          _delay;

    FilterList                      _minFilterList;
    FilterList                      _magFilterList;
    TextList                        _textList;

    unsigned int                    _currPos;
    double                          _prevTime;

};

osg::Node* createFilterWall(osg::BoundingBox& bb,osg::Image *img)
{
    osg::Group* group = new osg::Group;

    // left hand side of bounding box.
    osg::Vec3 top_left(bb.xMin(),bb.yMin(),bb.zMax());
    osg::Vec3 bottom_left(bb.xMin(),bb.yMin(),bb.zMin());
    osg::Vec3 bottom_right(bb.xMin(),bb.yMax(),bb.zMin());
    osg::Vec3 top_right(bb.xMin(),bb.yMax(),bb.zMax());
    osg::Vec3 center(bb.xMin(),(bb.yMin()+bb.yMax())*0.5f,(bb.zMin()+bb.zMax())*0.5f);
    float height = bb.zMax()-bb.zMin();

    // create the geometry for the wall.
    osg::Geometry* geom = new osg::Geometry;

    osg::Vec3Array* vertices = new osg::Vec3Array(4);
    (*vertices)[0] = top_left;
    (*vertices)[1] = bottom_left;
    (*vertices)[2] = bottom_right;
    (*vertices)[3] = top_right;
    geom->setVertexArray(vertices);

    osg::Vec2Array* texcoords = new osg::Vec2Array(4);
    (*texcoords)[0].set(0.0f,1.0f);
    (*texcoords)[1].set(0.0f,0.0f);
    (*texcoords)[2].set(1.0f,0.0f);
    (*texcoords)[3].set(1.0f,1.0f);
    geom->setTexCoordArray(0,texcoords);

    osg::Vec3Array* normals = new osg::Vec3Array(1);
    (*normals)[0].set(1.0f,0.0f,0.0f);
    geom->setNormalArray(normals, osg::Array::BIND_OVERALL);

    osg::Vec4Array* colors = new osg::Vec4Array(1);
    (*colors)[0].set(1.0f,1.0f,1.0f,1.0f);
    geom->setColorArray(colors, osg::Array::BIND_OVERALL);

    geom->addPrimitiveSet(new osg::DrawArrays(GL_QUADS,0,4));

    osg::Geode* geom_geode = new osg::Geode;
    geom_geode->addDrawable(geom);
    group->addChild(geom_geode);


    // set up the texture state.
    osg::Texture2D* texture = new osg::Texture2D;
    texture->setDataVariance(osg::Object::DYNAMIC); // protect from being optimized away as static state.
    texture->setImage(img); //////<-- setting image directly from ptr (original used osgDB::readImageFile() )

    osg::StateSet* stateset = geom->getOrCreateStateSet();
    stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);

    // create the text label.

    osgText::Text* text = new osgText::Text;
    text->setDataVariance(osg::Object::DYNAMIC);

    text->setFont("fonts/arial.ttf");
    text->setPosition(center);
    text->setCharacterSize(height*0.03f);
    text->setAlignment(osgText::Text::CENTER_CENTER);
    text->setAxisAlignment(osgText::Text::YZ_PLANE);

    osg::Geode* text_geode = new osg::Geode;
    text_geode->addDrawable(text);

    osg::StateSet* text_stateset = text_geode->getOrCreateStateSet();
    text_stateset->setAttributeAndModes(new osg::PolygonOffset(-1.0f,-1.0f),osg::StateAttribute::ON);

    group->addChild(text_geode);

    // set the update callback to cycle through the various min and mag filter modes.
    group->setUpdateCallback(new FilterCallback(texture,text));

    return group;

}


osg::Node* createModel()
{

    // create the root node which will hold the model.
    osg::Group* root = new osg::Group();

    // turn off lighting
    root->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);

    osg::BoundingBox bb(0.0f,0.0f,0.0f,1.0f,1.0f,1.0f);

/////////// NEW CODE: ///////////////
		int w=10,h=10;
		GLubyte * pixels=(GLubyte*)calloc(w*h*3,sizeof(GLubyte));
	int pixelCount=0;

	for(int i=0;i<100;i++){
		int x=pixelCount%w;
		int y=int(pixelCount/w);

		int xy = y*w + x;
		//pixels[xy*3]=GLubyte(stoi(tile->ToConstScalarToken()->GetRawData()));
		pixels[xy*3]=GLubyte(unsigned(x<6?180:10));
		pixels[xy*3+1]=0;
		pixels[xy*3+2]=0;

		pixelCount++;
	}
	osg::Image* m_tileDataImg = new osg::Image;
	m_tileDataImg->setImage(w,h,1,GL_RGB,GL_RGB,GL_UNSIGNED_BYTE,pixels,osg::Image::NO_DELETE); 
/////////// END NEW CODE: ///////////////

    root->addChild(createFilterWall(bb,m_tileDataImg)); ///// <-- passing image ptr (original code used image filename)

    return root;
}

int main(int , char **)
{
    // construct the viewer.
    osgViewer::Viewer viewer;

    // add model to viewer.
    viewer.setSceneData( createModel() );

    return viewer.run();
}




Note that the filter wall is on the side of the cube, so you have to rotate it before you see anything.

The input image which I am generating is the following (verified by using osgDB::writeImageFile() to output it):

[Image: https://i.imgur.com/8YUX0UD.png ]
It might be too small to see, but the important part is that it contains only two colors.


The result I get with nearest filtering:
[Image: https://i.imgur.com/h6MIpI9.png ]
Suddenly there is a band with an intermediate color which is not present in the input.


The expected result (created by editing the screenshot):
[Image: https://i.imgur.com/Plew0gD.png ]

I'm not sure how the images translate to the mailing list, so just in case: this is the imgur album containing the three images: https://imgur.com/a/rNFu0

Thank you!

Cheers,
antiro[img][/img]

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=72972#72972







More information about the osg-users mailing list