這個問題其實涉及到OSG中的兩個問題:多邊形分格化和幾何圖元遍歷。ios
在OpenGL/OSG中,因爲效率的緣由,默認是直接顯示的簡單的凸多邊形。若是直接強行顯示凹多邊形,渲染結果是不肯定的。因此對於複雜的凹多邊形,須要將其分解成簡單的凸多邊形,這個過程就是多邊形分格化。在OSG中是經過osgUtil::Tessellator類來實現多邊形分格化的。數組
對於二維的凹多邊形,能夠有辦法計算其面積。可是對於三維空間的凹多邊形,計算其面積卻很困難。這是由於三維空間凹多邊形甚至都有可能不是共面的。而咱們知道,任何複雜的圖形都是經過分解成三角形進行繪製的,只要獲取分解成的三角形,計算其面積並相加(空間三角形的面積計算比較簡單),就能夠獲得凹多邊形的總面積。
在OSG中提供了一個用來訪問圖元的類:osg::PrimitiveFunctor,其繼承類osg::TriangleFunctor能夠獲取其三角面圖元。幾何體類osg::Geometry提供了遍歷幾何圖元的訪問器接口。ide
其具體實現以下。注意在查找多邊形分格化的資料的時候,提到了環繞數和環繞規則的概念。在OSG裏面也有相應的參數設置。惋惜這一段沒有看明白,只能根據仿照例子來設置了。學習
#include <iostream> #include <Windows.h> #include <osgViewer/Viewer> #include <osgDB/ReadFile> #include <osgUtil/Tessellator> #include <osg/TriangleFunctor> using namespace std; using namespace osg; osg::ref_ptr<osg::Geometry> redPolygon; //計算空間三角形的面積 double CalTriangleArea(const osg::Vec3& a, const osg::Vec3& b, const osg::Vec3& c) { double area = 0; double side[3];//存儲三條邊的長度; side[0] = sqrt(pow(a.x() - b.x(), 2) + pow(a.y() - b.y(), 2) + pow(a.z() - b.z(), 2)); side[1] = sqrt(pow(a.x() - c.x(), 2) + pow(a.y() - c.y(), 2) + pow(a.z() - c.z(), 2)); side[2] = sqrt(pow(c.x() - b.x(), 2) + pow(c.y() - b.y(), 2) + pow(c.z() - b.z(), 2)); //不能構成三角形; if (side[0] + side[1] <= side[2] || side[0] + side[2] <= side[1] || side[1] + side[2] <= side[0]) return area; //利用海倫公式。s=sqr(p*(p-a)(p-b)(p-c)); double p = (side[0] + side[1] + side[2]) / 2; //半周長; area = sqrt(p*(p - side[0])*(p - side[1])*(p - side[2])); return area; } //三角面片訪問器 struct TriangleAreaFunctor { TriangleAreaFunctor() { sumArea = new double; } ~TriangleAreaFunctor() { if (sumArea) { delete sumArea; sumArea = nullptr; } } void operator() (const osg::Vec3& v1, const osg::Vec3& v2, const osg::Vec3& v3) const { *sumArea = *sumArea + CalTriangleArea(v1, v2, v3); } double GetSumArea() { return *sumArea; } protected: double *sumArea = nullptr; }; // ref_ptr<Geode> createPolygon() { const float wall[6][3] = { { -115.54f, 70.873f, -118.952f}, { -111.516f, 70.7189f, -71.8492f }, { -88.5345f, 70.8667f, -86.3565f }, { -64.9495f, 71.8231f, -53.6525f }, { -52.9755f, 69.028f, -129.093f }, { -89.2272f, 71.1478f, -105.434f } }; // ref_ptr<Geode> geode = new Geode(); redPolygon = new osg::Geometry; // osg::ref_ptr<osg::Vec3Array> redVex = new osg::Vec3Array; redPolygon->setVertexArray(redVex); for (int i = 0; i< 6; i++) { redVex->push_back(osg::Vec3(wall[i][0], wall[i][1], wall[i][2])); } redPolygon->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, 6)); //設置顏色數組 osg::ref_ptr<osg::Vec4Array> redColors = new osg::Vec4Array; redColors->push_back(osg::Vec4(1.0, 0.0, 0.0, 0.5)); redPolygon->setColorArray(redColors); redColors->setBinding(osg::Array::BIND_PER_PRIMITIVE_SET); //若是須要透明,則加入這個 redPolygon->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); redPolygon->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); //建立分格化對象(支持凹多邊形) osg::ref_ptr<osgUtil::Tessellator> tscx = new osgUtil::Tessellator; //設置分格類型爲幾何體 tscx->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY); //設置只顯示輪廓線爲false。設置環繞規則,這裏不太懂 tscx->setWindingType(osgUtil::Tessellator::TESS_WINDING_ODD); //使用分格化 tscx->retessellatePolygons(*(redPolygon.get())); geode->addDrawable(redPolygon); return geode; } int main() { // ref_ptr<Group> root = new Group(); root->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); //關閉默認光照 root->addChild(createPolygon()); // osgViewer::Viewer viewer; viewer.setSceneData(root); viewer.setUpViewInWindow(100, 100, 800, 600); viewer.run(); osg::TriangleFunctor<TriangleAreaFunctor> tf; redPolygon->accept(tf); cout << "面積:" << tf.GetSumArea() << endl; return 0; }
渲染結果以下:
ui