Okay, I figured this out. :) I've attached a file called "osgpickbug" if
you want to look at it, but this is a misnomer--it's not actually a bug.
At least, I don't think it is.

What is happening is that when the intersection occurs exactly on the
hypotenuses of the two triangles that form the quad (the Widget), both
are (naturally) being returned. I don't know if I should feel clever for
solving this or embarrassed that I even brought it up. :) At any rate,
perhaps people in the future will find this post archived if they run
into the same thing...

On Thu, 2008-03-20 at 14:36 +0000, Robert Osfield wrote:
> Hi Jeremy,
> 
> This "might" be an osgUtil bug, we'd need to recreate it on one of the
> core examples and go from there.
> 
> Robert.
> 
> On Thu, Mar 20, 2008 at 2:27 PM, Jeremy Moles <[EMAIL PROTECTED]> wrote:
> > While working through some strange picking problems in osgWidget (and,
> >  by the way, SVN osgWidget is _TOTALLY_ busted, so please don't even
> >  bother with it :)), I noticed that at some XY coordinates
> >  osgViewer::computeIntersections is returning an Intersection object for
> >  the same Drawable twice. I'm not quite sure what causes this, but I used
> >  the followed code (psuedo) to verify it:
> >
> >
> >
> >         for(x = 0; x < screenWidth; x++) {
> >                 for(y = 0; y < screenHeight; y++) {
> >                         v.computeIntr(x, y, i, MY_MASK)
> >                 }
> >         }
> >
> >
> >
> >  ...with only a single Drawable (Widget) on the screen at the time, which
> >  simulates a person moving their cursor over every pixel. There's no
> >  pattern that I can see to the times this occurs, and it isn't something
> >  I've been able to fix by changing the threading model or
> >  enabling/disabling vsync.
> >
> >  I can certainly add code to guarantee that my own internal PickResults
> >  object doesn't add the same Drawable more than once, but I wanted to
> >  throw this question out there before going down that path. Is it
> >  perfectly acceptable for computeIntersections to return the same
> >  Drawable twice?
> >
> >  _______________________________________________
> >  osg-users mailing list
> >  osg-users@lists.openscenegraph.org
> >  http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
> >
> 
#include <iostream>
#include <osg/Array>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/MatrixTransform>
#include <osg/BlendFunc>
#include <osgGA/StateSetManipulator>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

typedef osg::Vec2Array TexCoordArray;
typedef osg::Vec3Array PointArray;
typedef osg::Vec4Array ColorArray;

typedef TexCoordArray::value_type TexCoord;
typedef PointArray::value_type    Point;
typedef ColorArray::value_type    Color;

typedef TexCoord::value_type texcoord_type;
typedef Point::value_type    point_type;
typedef Color::value_type    color_type;

typedef osgUtil::LineSegmentIntersector::Intersections Intersections;

const unsigned int MASK_2D       = 0xF0000000;
const float        SCREEN_WIDTH  = 1280.0f;
const float        SCREEN_HEIGHT = 1024.0f;

class OSG_EXPORT Widget: public osg::Geometry {
	enum _POINT {
		LL = 0,
		LR = 1,
		UR = 2,
		UL = 3
	};

	static osg::ref_ptr<PointArray> _norms;

protected:
	PointArray* _verts() {
		return dynamic_cast<PointArray*>(getVertexArray());
	}

	ColorArray* _cols() {
		return dynamic_cast<ColorArray*>(getColorArray());
	}

public:
	Widget(point_type = 0.0f, point_type = 0.0f);

	void setDimensions(
		point_type = -1.0f,
		point_type = -1.0f,
		point_type = -1.0f,
		point_type = -1.0f,
		point_type = -1.0f
	);

	void setColor(color_type, color_type, color_type, color_type);
};

osg::ref_ptr<PointArray> Widget::_norms;

Widget::Widget(point_type w, point_type h) {
	if(!_norms.valid()) {
		_norms = new PointArray(1);

		(*_norms)[0].set(0.0f, 0.0f, 1.0f);
		(*_norms)[0].normalize();
	}

	TexCoordArray* texs = new TexCoordArray(4);

	std::fill(texs->begin(), texs->end(), osg::Vec2(0.0f, 0.0f));

	setUseDisplayList(false);
	setDataVariance(osg::Object::DYNAMIC);
	setVertexArray(new PointArray(4));
	setColorArray(new ColorArray(4));
	setNormalArray(_norms.get());
	setTexCoordArray(0, texs);
	setNormalBinding(osg::Geometry::BIND_OVERALL);
	setColorBinding(osg::Geometry::BIND_PER_VERTEX);
	addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

	setDimensions(0.0f, 0.0f, w, h);
	setColor(1.0f, 1.0f, 1.0f, 0.5f);

	getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
	getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
}

void Widget::setDimensions(
	point_type x,
	point_type y,
	point_type w,
	point_type h,
	point_type z
) {
	PointArray* verts = _verts();

	if(x == -1.0f) x = (*verts)[LL].x();
	
	if(y == -1.0f) y = (*verts)[LL].y();
	
	if(w == -1.0f) w = (*verts)[LR].x() - (*verts)[LL].x();

	if(h == -1.0f) h = (*verts)[UL].y() - (*verts)[LL].y();

	if(z == -1.0f) z = 0.0f;

	(*verts)[LL].set(x,     y,     z);
	(*verts)[LR].set(x + w, y,     z);
	(*verts)[UR].set(x + w, y + h, z);
	(*verts)[UL].set(x,     y + h, z);
}

void Widget::setColor(color_type r, color_type g, color_type b, color_type a) {
	ColorArray* cols = _cols();

	(*cols)[LL].set(r, g, b, a);
	(*cols)[LR].set(r, g, b, a);
	(*cols)[UR].set(r, g, b, a);
	(*cols)[UL].set(r, g, b, a);
}

class OSG_EXPORT MouseHandler: public osgGA::GUIEventHandler {
	osgViewer::Viewer& _viewer;

public:
	MouseHandler(osgViewer::Viewer& v):
	_viewer(v) {
	}
	
	virtual bool handle(
		const osgGA::GUIEventAdapter&,
		osgGA::GUIActionAdapter&,
		osg::Object*,
		osg::NodeVisitor*
	);

	void pickAtXY(float, float);
};

bool MouseHandler::handle(
	const osgGA::GUIEventAdapter& gea,
	osgGA::GUIActionAdapter&      gaa,
	osg::Object*                  obj,
	osg::NodeVisitor*             nv
) {
	osgGA::GUIEventAdapter::EventType ev = gea.getEventType();

	if(ev == osgGA::GUIEventAdapter::MOVE) pickAtXY(gea.getX(), gea.getY());

	// Simulate a mouse movement over every pixel in the active region...
	else if(ev == osgGA::GUIEventAdapter::PUSH) {
		for(float x = 0.0f; x < 300.0f; x++) {
			for(float y = SCREEN_HEIGHT - 100.0f; y < SCREEN_HEIGHT; y++) {
				pickAtXY(x, y);
			}
		}

		return true;
	}

	return false;
}

void MouseHandler::pickAtXY(float x, float y) {
	Intersections intr;

	if(_viewer.computeIntersections(x, y, intr, MASK_2D)) {
		if(intr.size() > 1) osg::notify(osg::NOTICE) << "Got doubles at: " << x << " " << y << std::endl;

		for(Intersections::iterator i = intr.begin(); i != intr.end(); i++) {
			osg::MatrixTransform* win = dynamic_cast<osg::MatrixTransform*>(
				i->nodePath.back()->getParent(0)
			);

			if(!win) continue;

			Widget* widget = dynamic_cast<Widget*>(i->drawable.get());

			if(!widget) continue;
		}
	}
}

osg::Camera* createOrthoCamera(double width, double height) {
	osg::Camera* camera = new osg::Camera();

	camera->getOrCreateStateSet()->setMode(
		GL_LIGHTING,
		osg::StateAttribute::PROTECTED | osg::StateAttribute::OFF
	);

	osg::Matrix m = osg::Matrix::ortho2D(0.0f, width, 0.0f, height);
	osg::Matrix s = osg::Matrix::scale(1.0f, -1.0f, 1.0f);
	osg::Matrix t = osg::Matrix::translate(0.0f, -height, 0.0f);

	camera->setProjectionMatrix(t * s * m);
	camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
	camera->setViewMatrix(osg::Matrix::identity());
	camera->setClearMask(GL_DEPTH_BUFFER_BIT);
	camera->setRenderOrder(osg::Camera::POST_RENDER);
	
	return camera;
}

int main(int, char**) {
	osgViewer::Viewer viewer;

	Widget* widget = new Widget(300.0f, 100.0f);

	widget->setColor(0.5f, 0.1f, 0.5f, 0.5f);

	MouseHandler* mh = new MouseHandler(viewer);

	viewer.addEventHandler(mh);
	viewer.addEventHandler(new osgViewer::StatsHandler());
	viewer.addEventHandler(new osgViewer::WindowSizeHandler());
	viewer.addEventHandler(new osgGA::StateSetManipulator(
		viewer.getCamera()->getOrCreateStateSet()
	));

	osg::Switch*          wm     = new osg::Switch();
	osg::MatrixTransform* window = new osg::MatrixTransform();
	osg::Geode*           geode  = new osg::Geode();
	osg::Group*           group  = new osg::Group();
	osg::Camera*          camera = createOrthoCamera(SCREEN_WIDTH, SCREEN_HEIGHT);

	geode->addDrawable(widget);

	window->addChild(geode);

	wm->addChild(window);

	camera->addChild(wm);

	geode->setNodeMask(MASK_2D);

	group->addChild(camera);

	viewer.setSceneData(group);

	/*
	This doesn't work here! For some reason, you have to move the mouse at least
	once before picking works properly?
	for(float x = 0.0f; x < 300.0f; x++) {
		for(float y = SCREEN_HEIGHT - 100.0f; y < SCREEN_HEIGHT; y++) {
			mh->pickAtXY(x, y);
		}
	}
	*/

	return viewer.run();
}
_______________________________________________
osg-users mailing list
osg-users@lists.openscenegraph.org
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to