[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