osgEarth Version (required): 3.8.0
Description of the problem: Polygon filling anomaly
What you have tried: I have tried three methods to fill the semi transparent space
Under the 2D plan view (-180/90 in the lower left and right corners, 180/90 in the upper right corner), the following effect should be drawn:
I have encountered an issue where the semi transparent color filling is abnormal when drawing polygons.
I have tried the following three methods:
void OSGWidget::addLargeConcavePolygonBase(osgEarth::MapNode* mapNode)
{
QPolygonF qPoly;
std::vector<osg::Vec3d> ctrlPoints;
ctrlPoints.push_back(osg::Vec3d(90.0, 30.0, 0));
ctrlPoints.push_back(osg::Vec3d(120.0, 13.0, 0));
ctrlPoints.push_back(osg::Vec3d(140.0, 1.0, 0));
ctrlPoints.push_back(osg::Vec3d(95.0, -4.0, 0));
ctrlPoints.push_back(osg::Vec3d(85.0, -5.0, 0));
ctrlPoints.push_back(osg::Vec3d(75.0, -6.0, 0));
ctrlPoints.push_back(osg::Vec3d(45.0, -7.0, 0));
ctrlPoints.push_back(osg::Vec3d(15.0, -10.0, 0));
ctrlPoints.push_back(osg::Vec3d(0.0, -8.0, 0));
ctrlPoints.push_back(osg::Vec3d(-8.0, -20.0, 0));
ctrlPoints.push_back(osg::Vec3d(-15.0, -45.0, 0));
ctrlPoints.push_back(osg::Vec3d(-90.0, -70.0, 0));
ctrlPoints.push_back(osg::Vec3d(-135.0, -45.0, 0));
ctrlPoints.push_back(osg::Vec3d(-160.0, -0.0, 0));
ctrlPoints.push_back(osg::Vec3d(-90.0, 28.0, 0));
ctrlPoints.push_back(osg::Vec3d(-5.0, 6.0, 0));
for (size_t i = 0; i < ctrlPoints.size() - 1; ++i)
qPoly.push_back(QPointF(ctrlPoints.at(i).x(), ctrlPoints.at(i).y()));
static osg::observer_ptr<osg::Group> m_polygonGroup;
if (m_polygonGroup.valid()) m_root->removeChild(m_polygonGroup.get());
osg::ref_ptr<osg::Group> newGroup = new osg::Group();
m_root->addChild(newGroup.get());
m_polygonGroup = newGroup.get();
const osgEarth::SpatialReference *srs = mapNode->getMap()->getSRS();
osgEarth::Style style;
style.getOrCreate<osgEarth::PolygonSymbol>()->fill()->color() = osgEarth::Color(osg::Vec4(1.0, 0.65, 0.0, 0.4));
//style.getOrCreate<osgEarth::LineSymbol>()->stroke()->color() = osgEarth::Color(osg::Vec4(1.0, 0.65, 0.0, 0.4));
//style.getOrCreate<osgEarth::LineSymbol>()->stroke()->width() = osgEarth::Distance(0.001, osgEarth::Units::PIXELS);
//style.getOrCreate<osgEarth::LineSymbol>()->tessellationSize() = osgEarth::Distance(1000, osgEarth::Units::METERS);
osgEarth::AltitudeSymbol* as = style.getOrCreate<osgEarth::AltitudeSymbol>();
as->clamping() = osgEarth::AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN;
as->technique() = osgEarth::AltitudeSymbol::TECHNIQUE_DRAPE;
as->verticalOffset() = osgEarth::Distance(0.5, osgEarth::Units::METERS);
osg::ref_ptr<osgEarth::Polygon> poly = new osgEarth::Polygon();
for (const QPointF& pt : qPoly)
{
poly->push_back(osg::Vec3d(pt.x(), pt.y(), 0.0));
}
if (poly->front() != poly->back())
poly->push_back(poly->front());
poly->rewind(osgEarth::Geometry::ORIENTATION_CCW);
osg::ref_ptr<osgEarth::FeatureNode> fn = new osgEarth::FeatureNode(new osgEarth::Feature(poly.get(), srs, style));
fn->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin");
newGroup->addChild(fn.get());
}
this type can't show any polygon and fill color
- 2. use TessellateOperator::tessellateGeo
// Using TessellateOperator to segment and draw functions
void OSGWidget::addLargeConcavePolygonTess(osgEarth::MapNode* mapNode)
{
std::vector<osg::Vec3d> ctrlPoints;
ctrlPoints.push_back(osg::Vec3d(90.0, 30.0, 0));
ctrlPoints.push_back(osg::Vec3d(120.0, 13.0, 0));
ctrlPoints.push_back(osg::Vec3d(140.0, 1.0, 0));
ctrlPoints.push_back(osg::Vec3d(95.0, -4.0, 0));
ctrlPoints.push_back(osg::Vec3d(85.0, -5.0, 0));
ctrlPoints.push_back(osg::Vec3d(75.0, -6.0, 0));
ctrlPoints.push_back(osg::Vec3d(45.0, -7.0, 0));
ctrlPoints.push_back(osg::Vec3d(15.0, -10.0, 0));
ctrlPoints.push_back(osg::Vec3d(0.0, -8.0, 0));
ctrlPoints.push_back(osg::Vec3d(-8.0, -20.0, 0));
ctrlPoints.push_back(osg::Vec3d(-15.0, -45.0, 0));
ctrlPoints.push_back(osg::Vec3d(-90.0, -70.0, 0));
ctrlPoints.push_back(osg::Vec3d(-135.0, -45.0, 0));
ctrlPoints.push_back(osg::Vec3d(-160.0, -0.0, 0));
ctrlPoints.push_back(osg::Vec3d(-90.0, 28.0, 0));
ctrlPoints.push_back(osg::Vec3d(-5.0, 6.0, 0));
osg::ref_ptr<osgEarth::Polygon> finalPoly = new osgEarth::Polygon();
int numPoints = ctrlPoints.size();
for (int i = 0; i < numPoints; ++i)
{
std::vector<osg::Vec3d> segmentPoints;
// Calculate the index of the next point, and if it reaches the end, take the remainder to return to 0
int nextIdx = (i + 1) % numPoints;
// Split the long side into multiple segments
osgEarth::Util::TessellateOperator::tessellateGeo(
ctrlPoints[i],
ctrlPoints[nextIdx],
100,
osgEarth::GEOINTERP_GREAT_CIRCLE, // Interpolation of large circular flight path
segmentPoints
);
// Discard the last point of each paragraph
// This not only avoids repeating the beginning and end, but also perfectly closes the entire polygon
for (size_t j = 0; j < segmentPoints.size() - 1; ++j) {
finalPoly->push_back(segmentPoints[j]);
}
}
osg::ref_ptr<osgEarth::Feature> feature = new osgEarth::Feature(finalPoly.get(), osgEarth::SpatialReference::get("wgs84"));
osgEarth::Style style;
osgEarth::PolygonSymbol* fill = style.getOrCreate<osgEarth::PolygonSymbol>();
fill->fill()->color() = osgEarth::Color(osgEarth::Color::Red, 0.5);
osgEarth::LineSymbol* ls = style.getOrCreate<osgEarth::LineSymbol>();
ls->stroke()->color() = osgEarth::Color::Green;
ls->stroke()->width() = osgEarth::Distance(1.0, osgEarth::Units::PIXELS);
osgEarth::AltitudeSymbol* alt = style.getOrCreate<osgEarth::AltitudeSymbol>();
alt->clamping() = osgEarth::AltitudeSymbol::CLAMP_TO_TERRAIN;
alt->technique() = osgEarth::AltitudeSymbol::TECHNIQUE_DRAPE;//TECHNIQUE_GPU;
feature->setStyle(style);
osg::ref_ptr<osgEarth::FeatureNode> node = new osgEarth::FeatureNode(feature.get());
node->setMapNode(mapNode);
mapNode->addChild(node.get());
}
TessellateOperator's type can show the green bordline, but fill failed.
- 3. split the East and West Hemispheres
// Forcefully insert a necessary point passing through the Y-axis in a polygon
QPolygonF insertYAxisIntersections(const QPolygonF& poly)
{
QPolygonF newPoly;
int n = poly.size();
if (n < 2) return poly;
for (int i = 0; i < n; ++i)
{
const QPointF& p1 = poly[i];
const QPointF& p2 = poly[(i+1) % n]; // Next points, wrap around the polygon
newPoly.push_back(p1); // First add the current point
// Determine whether two points span both sides (x < 0 and x > 0)
if ((p1.x() < 0 && p2.x() > 0) || (p1.x() > 0 && p2.x() < 0))
{
double t = (0.0 - p1.x()) / (p2.x() - p1.x()); // linear interpolation
double yIntersect = p1.y() + t * (p2.y() - p1.y());
QPointF interPoint(0.0, yIntersect);
newPoly.push_back(interPoint); // Insert Intersection Point
}
}
return newPoly;
}
void OSGWidget::addLargeConcavePolygonEastWest(osgEarth::MapNode* mapNode)
{
QPolygonF qPoly;
std::vector<osg::Vec3d> ctrlPoints;
ctrlPoints.push_back(osg::Vec3d(90.0, 30.0, 0));
ctrlPoints.push_back(osg::Vec3d(120.0, 13.0, 0));
ctrlPoints.push_back(osg::Vec3d(140.0, 1.0, 0));
ctrlPoints.push_back(osg::Vec3d(95.0, -4.0, 0));
ctrlPoints.push_back(osg::Vec3d(85.0, -5.0, 0));
ctrlPoints.push_back(osg::Vec3d(75.0, -6.0, 0));
ctrlPoints.push_back(osg::Vec3d(45.0, -7.0, 0));
ctrlPoints.push_back(osg::Vec3d(15.0, -10.0, 0));
ctrlPoints.push_back(osg::Vec3d(0.0, -8.0, 0));
ctrlPoints.push_back(osg::Vec3d(-8.0, -20.0, 0));
ctrlPoints.push_back(osg::Vec3d(-15.0, -45.0, 0));
ctrlPoints.push_back(osg::Vec3d(-90.0, -70.0, 0));
ctrlPoints.push_back(osg::Vec3d(-135.0, -45.0, 0));
ctrlPoints.push_back(osg::Vec3d(-160.0, -0.0, 0));
ctrlPoints.push_back(osg::Vec3d(-90.0, 28.0, 0));
ctrlPoints.push_back(osg::Vec3d(-5.0, 6.0, 0));
for (size_t i = 0; i < ctrlPoints.size() - 1; ++i)
qPoly.push_back(QPointF(ctrlPoints.at(i).x(), ctrlPoints.at(i).y()));
// If two points of the original shape pass through the Y-axis, insert a point that passes through the Y-axis
QPolygonF modifiedPoly = insertYAxisIntersections(qPoly);
osg::ref_ptr<osg::Group> newGroup = new osg::Group();
mapNode->addChild(newGroup.get());
const osgEarth::SpatialReference* srs = mapNode->getMap()->getSRS();
osgEarth::Style style;
style.getOrCreate<osgEarth::PolygonSymbol>()->fill()->color() = osgEarth::Color(osg::Vec4(1.0, 0.65, 0.0, 0.4));
style.getOrCreate<osgEarth::LineSymbol>()->tessellationSize() = osgEarth::Distance(500, osgEarth::Units::METERS);
style.getOrCreate<osgEarth::LineSymbol>()->stroke()->color() = osgEarth::Color(osg::Vec4(1.0, 0.65, 0.0, 0.4));
style.getOrCreate<osgEarth::LineSymbol>()->stroke()->width() = osgEarth::Distance(0.01, osgEarth::Units::METERS);
osgEarth::AltitudeSymbol* as = style.getOrCreate<osgEarth::AltitudeSymbol>();
as->clamping() = osgEarth::AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN;
as->technique() = osgEarth::AltitudeSymbol::TECHNIQUE_DRAPE;
as->verticalOffset() = osgEarth::Distance(0.5, osgEarth::Units::METERS);
// Draw separately from the east and west hemispheres
osg::ref_ptr<osgEarth::Polygon> westPoly = new osgEarth::Polygon();
osg::ref_ptr<osgEarth::Polygon> eastPoly = new osgEarth::Polygon();
for (const QPointF& pt : modifiedPoly) {
double lon = pt.x();
if (lon <= 0) westPoly->push_back(osg::Vec3d(lon, pt.y(), 0));
if (lon >= 0) eastPoly->push_back(osg::Vec3d(lon, pt.y(), 0));
}
// Process polygons of two hemispheres separately
auto processSubPoly = [&](osg::ref_ptr<osgEarth::Polygon> sub) {
if (sub->size() < 3) return;
sub->rewind(osgEarth::Geometry::ORIENTATION_CCW);
osg::ref_ptr<osgEarth::FeatureNode> fn = new osgEarth::FeatureNode(new osgEarth::Feature(sub.get(), srs, style));
fn->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin");
newGroup->addChild(fn.get());
};
if(westPoly->size()) processSubPoly(westPoly);
if(eastPoly->size()) processSubPoly(eastPoly);
}
If the border lines of the segmented polygon are colored, there will be a vertical line in the middle.
At present, I am not sure if this is due to an error in my usage method or a rendering error myself?
Best Regards!
osgEarth Version (required): 3.8.0
Description of the problem: Polygon filling anomaly
What you have tried: I have tried three methods to fill the semi transparent space
Under the 2D plan view (-180/90 in the lower left and right corners, 180/90 in the upper right corner), the following effect should be drawn:
I have encountered an issue where the semi transparent color filling is abnormal when drawing polygons.
I have tried the following three methods:
this type can't show any polygon and fill color
TessellateOperator's type can show the green bordline, but fill failed.
If the border lines of the segmented polygon are colored, there will be a vertical line in the middle.
At present, I am not sure if this is due to an error in my usage method or a rendering error myself?
Best Regards!