Hi Jen, I'll not dive into the details of how you are going about things as I suspect it might be best to tackle things in a different way.
So.. could you explain from a higher level what you need to do and for what purpose. Please explain what exactly you mean by visible - just in the view frustum or do you mean just contributes pixels to the final on screen? Are you away of the OpenGL occlusion querry feature? Robert. On 5 December 2012 11:28, Jen Hunter <[email protected]> wrote: > Dear osg community, > > currently I need to find out which lines were visible in last drawn frame. > > My current approach is the following: > > (1) I use a NodeVisitor to check the loaded model for lines. I store the > vertices of each line in a class LineData. Every LineData object is stored > in a vector. > > (2) Knowing the lines I want to determine which of them were visible in > the last view. I calculate the screen coordinates for each vertex of a line > (vec = V * modelViewMatrix * projectionMatrix * windowMatrix). > > (3) Then I convert the z values of the screen coordinates to depth values > using Znear*Zfar / (Zfar - vec.z()*(Zfar-Znear)). > > (4) After that I check the depth buffer of the last frame at the position > of the screen coordinates and also extract the depth value using the > formula from (3). > > (5) Then I substract both depth values and for the start and the end point > of the line and if both results are under a specified threshold i count the > line as visible. > > However, I think in theory it should be working this way, but the > calculated number of visible lines is almost always wrong. I found out that > for some calculated screen coordinates one dimension is one pixel off, so > that I do not access the correct pixel in the depth buffer which is why the > returned value of these is the zfar value and not the wanted depth. > > > I attached some code and a model to show my problem. When you click at a > point on the model the visible lines are calculated. While the camera is in > home position the output of the visible lines on the command line is 4 > which is correct. When you move the camera and try different poses the > number of calculated visible lines changes but almost never to the desired > number which can be counted on the rendered image. > > > Code: > > #include <windows.h> > > #include <osg/Group> > #include <osgViewer/Viewer> > #include <osgViewer/ViewerEventHandlers> > #include <osg/MatrixTransform> > #include <osgDB/ReadFile> > #include <osgDB/WriteFile> > #include <osgGA/TrackballManipulator> > #include <osg/io_utils> > > #include <sstream> > #include <vector> > #include <iostream> > #include <fstream> > > osg::Matrix lastViewMatrix; > > struct CaptureCB : public osg::Camera::DrawCallback{ > > CaptureCB(osg::ref_ptr<osg::Image>img1){ > image3D = img1; > } > virtual void operator()( osg::RenderInfo& ri ) const{ > > image3D->readPixels( 0, 0, > ri.getCurrentCamera()->getViewport()->width(), > ri.getCurrentCamera()->getViewport()->height(), GL_DEPTH_COMPONENT, > GL_FLOAT ); > osg::ref_ptr<osg::Camera> osgCam = ri.getCurrentCamera(); > osgCam->attach(osg::Camera::DEPTH_BUFFER,image3D.get()); > lastViewMatrix = ri.getCurrentCamera()->getViewMatrix(); > } > protected: > osg::ref_ptr<osg::Image> image3D; > > }; > > class LineData{ > > public: > LineData(){}; > ~LineData(){}; > > osg::Vec3 start; > osg::Vec3 end; > > void setLine(osg::Vec3 s, osg::Vec3 e){ > start = s; > end = e; > > for(int i = 1; i < samplePointNr; i++){ > double t = (double)i/samplePointNr; > osg::Vec3 p(start.x() * (1-t) + end.x() * t, start.y() * > (1-t) + end.y() * t, start.z() * (1-t) + end.z() * t); > samplePoints.push_back(p); > } > } > > bool operator == (const LineData& line2) const{ > > if > ((!start.valid())||(!end.valid())||(!line2.start.valid())||(!line2.end.valid())) > return false; > > return ((start.x() == line2.start.x()) && > (start.y() == line2.start.y()) && > (start.z() == line2.start.z()) && > (end.x() == line2.end.x()) && > (end.y() == line2.end.y()) && > (end.z() == line2.end.z())); > } > > void printValues(){ > std::cout<<"start: "<<start.x()<<", "<<start.y()<<", > "<<start.z()<<" end: "<<end.x()<<", "<<end.y()<<", "<<end.z()<<std::endl; > > } > > double getEuclideanDistance(osg::Vec3 s,osg::Vec3 e){ > double dist = sqrt( pow(s.x() - e.x(), 2) + pow(s.y() - e.y(), 2) > + pow(s.z() - e.z(), 2) ); > return dist; > } > > private: > int samplePointNr; > std::vector<osg::Vec3>samplePoints; > > > }; > > std::vector<LineData>lines; > osg::ref_ptr<osg::Image> image = new osg::Image; > > //Determine lines in the model > class GetLinesVisitor : public osg::NodeVisitor{ > > public: > > GetLinesVisitor(): > osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN){ > numberOfLines = 0; > numberOfLinesDeleted = 0; > } > > std::vector<LineData> getLineVector(){ > return lines; > } > > virtual void apply(osg::Geode& geode){ > > for (unsigned int i = 0; i < geode.getNumDrawables(); i++) > { > > osg::Geometry* geometry = > geode.getDrawable(i)->asGeometry(); > if (geometry){ > > unsigned int nprim = > geometry->getNumPrimitiveSets() ; > for (unsigned int ipr = 0; ipr < nprim; > ipr++) { > > osg::PrimitiveSet* prset = > geometry->getPrimitiveSet(ipr); > osg::notify(osg::WARN) << > "Primitive Set "<< ipr << std::endl; > > const osg::Vec3Array *verts = > dynamic_cast<const osg::Vec3Array*>(geometry->getVertexArray()); > > if(prset->getMode() == > osg::PrimitiveSet::LINES){ > > unsigned int numIndices = > prset->getNumIndices(); > if(numIndices % 2 == 0){ > > for (unsigned int > ic = 0; ic<prset->getNumIndices(); ic+=2) { > > LineData > ldata; > > ldata.setLine((* verts)[prset->index(ic)],(* verts)[prset->index(ic+1)]); > > //Only add > if line isn't already in lines vector > bool > hasLineAlready = false; > > for(unsigned int l = 0; l < lines.size(); l++){ > > > if(ldata == lines.at(l)){ > > hasLineAlready = true; > > numberOfLinesDeleted++; > } > } > > > if(!hasLineAlready){ > > numberOfLines++; > > lines.push_back(ldata); > } > } > } > else > std::cout<<"Error: > Number of line points must be even."<<std::endl; > } > } > } > } > > std::cout<<"number of lines: "<<numberOfLines<<std::endl; > std::cout<<"number of deleted lines: > "<<numberOfLinesDeleted<<std::endl; > > osg::NodeVisitor::apply(geode); > } > > private: > unsigned int numberOfLines; > unsigned int numberOfLinesDeleted; > std::vector<LineData>lines; > }; > > > > class PickHandler : public osgGA::GUIEventHandler { > public: > > PickHandler() {} > ~PickHandler() {} > bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& > aa); > virtual void pick(osgViewer::View* view, const > osgGA::GUIEventAdapter& ea); > > }; > > bool PickHandler::handle(const osgGA::GUIEventAdapter& > ea,osgGA::GUIActionAdapter& aa) > { > switch(ea.getEventType()) > { > case(osgGA::GUIEventAdapter::PUSH): > { > if(ea.getButton()==osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) { > osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa); > if (view) pick(view,ea); > } > return false; > } > default: > return false; > } > } > > void PickHandler::pick(osgViewer::View* view, const > osgGA::GUIEventAdapter& ea) > { > osgUtil::LineSegmentIntersector::Intersections intersections; > > const osg::Viewport* viewport = view->getCamera()->getViewport(); > int width = viewport->width(); > int height = viewport->height(); > double fovy, aspectRatio, Zn, Zf; > view->getCamera()->getProjectionMatrixAsPerspective(fovy, > aspectRatio, Zn, Zf ); > > float x = ea.getX(); > float y = ea.getY(); > > if (view->computeIntersections(x,y,intersections)) { > > osg::Camera * viewCam = view->getCamera(); > float* z = (float*)image->data(); > > osg::Matrix MVPW = lastViewMatrix * > viewCam->getProjectionMatrix() * > view->getCamera()->getViewport()->computeWindowMatrix(); > int visLine = 0; > for(unsigned i = 0; i < lines.size(); i++){ > > //Calculate screen coordinates > osg::Vec3 start = lines.at(i).start*MVPW; > osg::Vec3 end = lines.at(i).end*MVPW; > > //Get the distance (depth) of each line coordinate > to the camera > double startZDistance = Zn*Zf / (Zf - > start.z()*(Zf-Zn)); > double endZDistance = Zn*Zf / (Zf - > end.z()*(Zf-Zn)); > > //Get the distance (depth) from the depth buffer > at the position of the calculated screen coordinates > double startZBufferDistance = Zn*Zf / (Zf - > z[(int)start.y()*width + (int)start.x() ]*(Zf-Zn)); > double endZBufferDistance = Zn*Zf / (Zf - > z[(int)end.y()*width + (int)end.x()]*(Zf-Zn)); > > //check if line is visible; If the line is visible > the subtraction of the depth values should be equal to 0. > bool startVisible = false; > bool endVisible = false; > double visibleThresh = 0.5; > > if > ((abs(startZBufferDistance-startZDistance))<visibleThresh) startVisible = > true; > if > ((abs(endZBufferDistance-endZDistance))<visibleThresh) endVisible = true; > > //Output > std::cout<<"start 3D coord: > ("<<lines.at(i).start.x()<<", > "<<lines.at(i).start.y()<<", "<<lines.at(i).start.z()<<")"<<std::endl; > std::cout<<"start projected screen coord: > ("<<start.x()<<", "<<start.y()<<", "<<start.z()<<")"<<std::endl; > std::cout<<"start depth buffer depth: > "<<startZBufferDistance<<" start depth projected: "<<startZDistance<<" > Dis: "<<(float)abs(startZBufferDistance-startZDistance)<<" -> "; > if (startVisible) printf("true\n"); > else printf("false\n"); > printf("---\n"); > std::cout<<"end 3D coord: ("<<lines.at(i).end.x()<<", > "<<lines.at(i).end.y()<<", "<<lines.at(i).end.z()<<")"<<std::endl; > std::cout<<"end projected screen Coord: > ("<<end.x()<<", "<<end.y()<<", "<<end.z()<<")"<<std::endl; > std::cout<<"end depth buffer depth: > "<<endZBufferDistance<<" end depth projected: "<<endZDistance<<" Dis: > "<<(float)abs(endZBufferDistance-endZDistance)<<" -> "; > if (endVisible) printf("true\n"); > else printf("false\n"); > > > printf("-----------------------------------------------------------\n"); > if(startVisible && endVisible) visLine++; > > } > std::cout<<"Number of visible: lines: "<<visLine<<std::endl; > } > } > > int main( int argc, char** argv ) > { > int width = 640; > int height = 480; > > osgViewer::Viewer viewer; > osg::ref_ptr<osg::Camera> camera = new osg::Camera; > camera->setClearColor(osg::Vec4(1.0, 1.0, 1.0, 0.0)); > camera->setViewport( new osg::Viewport(0, 0, width, height) ); > camera->setProjectionMatrixAsPerspective(30.0f, > static_cast<double>(width)/static_cast<double>(height), 1.0f, 10000.0f ); > viewer.setCamera(camera); > > osg::Node* scene = osgDB::readNodeFile("box.dae"); > > if (!scene){ > osg::notify(osg::NOTICE)<<"Please specifiy a model filename on the > command line."<<std::endl; > return 1; > } > > osg::Group* rootnode = new osg::Group; > > rootnode->addChild(scene); > viewer.setSceneData(rootnode); > viewer.addEventHandler(new osgViewer::StatsHandler); > > viewer.setUpViewInWindow(200, 200, 640, 480); > viewer.addEventHandler(new PickHandler()); > viewer.setCameraManipulator( new osgGA::TrackballManipulator ); > > GetLinesVisitor lineFinder; > scene->accept(lineFinder); > lines = lineFinder.getLineVector(); > > //update depth buffer image each frame > viewer.getCamera()->setPostDrawCallback(new CaptureCB(image)); > > return viewer.run(); > } > > > > > > What am I doing wrong? Is the calculation of the screen coordinates so > imprecise that it cannot be used for that? I can't imagine that. I guess I > have an error somewhere in my thinking, I'm not sure where the problem is. > > I would try another way finding visible lines, but as far as I found every > other vertex visibility investigation is far more complex than this way. > > > > > Cheers, > Dakota > > ------------------ > Read this topic online here: > http://forum.openscenegraph.org/viewtopic.php?p=51362#51362 > > > > > _______________________________________________ > osg-users mailing list > [email protected] > http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org > >
_______________________________________________ osg-users mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

