[osg-users] problem setting texture min/mag filter
Robert Osfield
robert.osfield at gmail.com
Tue Feb 20 09:28:25 PST 2018
HI Antiro,
Thanks for the code example. I don't have the time to test right
away. A quick code review and I spotted that the image is 10x10 which
will be rescalled to nearest power of two with the default
construction of osg::Texture2D. Most modern hardware supports non
power of two textures so it should be safe to enable this via:
texture->setResizeNonPowerOfTwoHint(false);
Could you try this and let us know how you get on.
Robert.
On 20 February 2018 at 17:10, antiro black <antiro42 at gmail.com> wrote:
> 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
>
>
>
>
>
> _______________________________________________
> osg-users mailing list
> osg-users at lists.openscenegraph.org
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
More information about the osg-users
mailing list