In 3D scenes, you often encounter the problem of interacting with the model in the scene. The most common way is to select the model and perform various movements and highlights on the model. These operations generally require the intersection provided in osg. To implement, the following intersector is provided in OSG (OSG 3.4.0 version)
OSG Intersector (1) Plane Intersector
Including: IntersectorGroup, LineSegmentIntersector, PlaneIntersector, PolytopeINtersector, RayIntersector, this article focuses on the plane intersector (RayIntersector) PlaneIntersector) to make some introductions, and follow-up will add other content
The use scene of the plane intersector A common use scene of the plane intersector is to find the intersection line with some models, including contour lines, section lines (cross sections, longitudinal sections, etc.), as shown in the figure below. Terrain intersection:
OSG Intersector (1) Plane Intersector
How to use Before using the plane intersector, you need to use a plane to construct the intersector, and check its constructor: OSG Intersector (1) Plane Intersector PlaneIntersector
There are many ways to construct osg :: Plane. In simple terms, the plane can be constructed in three-dimensional analytical geometry (such as the general formula of a plane, point method, three-point method, etc.), and then the second parameter boundingPolytope can be passed in. This parameter is used to put some constraints on the plane. The plane we construct is actually infinite. Using this parameter, we can constrain the plane to intersect with objects in the scene only in a certain area. The construction of this parameter is also composed of many faces. When the construction is complete, it can be done using the most common way of intersection, as shown below:
osg :: ref_ptr <osgUtil :: PlaneIntersector> intersector = new osgUtil :: PlaneIntersector (plane, boundingPolytope);
osgUtil :: IntersectionVisitor intersectionVisitor;
intersectionVisitor.reset ();
intersectionVisitor.setIntersector (intersector.get ());
sceneNode-> accept (intersectionVisitor);
After completion, you can get the delivered content from the intersector object.
osgUtil :: PlaneIntersector :: Intersections & intersections = intersector-> getIntersections ();
The node polyline can be obtained from many Intersections. In general, the point coordinates obtained from the intersection are below the local coordinates, which need to be transformed to obtain the values in world coordinates. Matrix, so you can transfer all coordinates to the world coordinate system with the following changes:
osgUtil :: PlaneIntersector :: Intersections :: iterator itr;
for (itr = intersections.begin ();
itr! = intersections.end ();
++ itr)
{
osgUtil :: PlaneIntersector :: Intersection & intersection = * itr;
if (intersection.matrix.valid ())
{
// OSG_NOTICE << "transforming" << std :: endl;
// transform points on polyline
for (auto pitr = intersection.polyline.begin ();
pitr! = intersection.polyline.end ();
++ pitr)
{
* pitr = (* pitr) * (* intersection.matrix);
}
// matrix no longer needed.
intersection.matrix = 0;
}
}
Another point to note: the coordinates of the polyline are actually chaotic. If you directly train these points into a LINES_STRIP, you will find that these lines are intertwined. Therefore, after the intersection is completed, we need to check the The results are processed. As for the specific processing method depends on the actual application, the method of finding the intersection with the ground provided in this article is very simple. You can arrange these intersections according to the x value from small to large or from large to small, and eliminate the duplicate The value of x can be used (just use std :: set). Example This article provides an example to simply find the intersection of a plane and a terrain generated by VPB. The main code is as follows:
// Used to sort the vertices
bool compareVec3 (const osg :: Vec3d & p1, const osg :: Vec3d & p2)
{
return p1.x () <p2.x ();
}
void computeIntersection ()
{
if (_controlPoints.size () <1)
{
// Get the first point of the intersection plane
_firstPointX = x;
_firstPointY = y;
_firstPointZ = z;
}
else
{
// Draw the intersection line
osg :: ref_ptr <osg :: Geometry> geometry = new osg :: Geometry;
osg :: ref_ptr <osg :: Vec3Array> vertexArray = new osg :: Vec3Array;
Ranch
Ranch
osg :: Plane plane;
osg :: Polytope boundingPolytope;
// Terrain normal (the terrain generated by VPB, if it is the earth's surface, it needs to be calculated)
osg :: Vec3d upVector (0.0, 0.0, 1.0);
Ranch
// Find the start and end points of the intersection plane
osg :: Vec3d endPoint = osg :: Vec3 (x, y, z);
osg :: Vec3d startPoint = osg :: Vec3 (_firstPointX, _firstPointY, _firstPointZ);
// Construct the intersection plane (point method)
osg :: Vec3d planeNormal = (endPoint-startPoint) ^ upVector;
planeNormal.normalize ();
plane.set (planeNormal, startPoint);
// first constraint surface
osg :: Vec3d startPlaneNormal = upVector ^ planeNormal;
startPlaneNormal.normalize ();
boundingPolytope.add (osg :: Plane (startPlaneNormal, startPoint));
// second constraint surface
osg :: Vec3d endPlaneNormal = planeNormal ^ upVector;
endPlaneNormal.normalize ();
boundingPolytope.add (osg :: Plane (endPlaneNormal, endPoint));
Ranch
// Construct plane intersector
osg :: ref_ptr <osgUtil :: PlaneIntersector> intersector = new osgUtil :: PlaneIntersector (plane, boundingPolytope);
osgUtil :: IntersectionVisitor intersectionVisitor;
intersector-> setRecordHeightsAsAttributes (true);
intersectionVisitor.reset ();
intersectionVisitor.setIntersector (intersector.get ());
_viewer-> getCamera ()-> accept (intersectionVisitor);
osgUtil :: PlaneIntersector :: Intersections & intersections = intersector-> getIntersections ();
// Transform the result (local coordinates go to world coordinates)
osgUtil :: PlaneIntersector :: Intersections :: iterator itr;
for (itr = intersections.begin ();
itr! = intersections.end ();
++ itr)
{
osgUtil :: PlaneIntersector :: Intersection & intersection = * itr;
if (intersection.matrix.valid ())
{
for (auto pitr = intersection.polyline.begin ();
pitr! = intersection.polyline.end ();
++ pitr)
{
* pitr = (* pitr) * (* intersection.matrix);
}
// matrix no longer needed.
intersection.matrix = 0;
}
}
// Remove duplicate x values and sort intersections by x value
std :: set <osg :: Vec3d, decltype (compareVec3) *>
myVec3Array (compareVec3);
osgUtil :: PlaneIntersector :: Intersections :: iterator itrs;
for (itrs = intersections.begin ();
itrs! = intersections.end ();
++ itrs)
{
osgUtil :: PlaneIntersector :: Intersection & intersection = * itrs;
for (auto pitr = intersection.polyline.begin ();
pitr! = intersection.polyline.end ();
++ pitr)
{
myVec3Array.insert (* pitr);
}
}
Ranch
for (auto pitr = myVec3Array.begin (); pitr! = myVec3Array.end (); ++ pitr)
{
vertexArray-> push_back (* pitr));
}
osg :: ref_ptr <osg :: Vec4Array> colorArray = new osg :: Vec4Array ();
colorArray-> push_back (osg :: Vec4 (255,0,0,0));
geometry-> setColorArray (colorArray, osg :: Array :: BIND_OVERALL);
osg :: ref_ptr <osg :: LineWidth> lineWidth = new osg :: LineWidth ();
lineWidth-> setWidth (2.0f);
geometry-> getOrCreateStateSet ()-> setAttributeAndModes (
lineWidth, osg::StateAttribute::ON);
geometry->setVertexArray(vertexArray);
osg::ref_ptr<osg::DrawArrays> drawArray = new osg::DrawArrays(osg::DrawArrays::LINE_STRIP, 0, vertexArray->size());
geometry->addPrimitiveSet(drawArray);
_geode->addChild(geometry);
_geode->dirtyBound();
}
}