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

Reply via email to