cpp
virtual void apply(osg::Geode& node)
{
for (int i = 0; i < node.getNumDrawables(); i++)
{
osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(node.getDrawable(i));
if (geometry)
{
//apply(*g);
//***********************************************
//解析顶点
osg::Array* vertexArray = geometry->getVertexArray();
if (vertexArray == NULL)
return;
//顶点数组
osg::Vec3Array* verts = dynamic_cast<osg::Vec3Array*>(vertexArray);
long lVertNum = verts->size();
std::vector<osg::Vec3 >::iterator iter_ver = verts->begin();
//遍历顶点值
for (; iter_ver != verts->end(); iter_ver++)
{
double x = iter_ver->x();
double y = iter_ver->y();
double z = iter_ver->z();
}
//纹理
osg::Texture2D* tex2D = dynamic_cast<osg::Texture2D*>(geometry->getStateSet()->getTextureAttribute(0, osg::StateAttribute::TEXTURE));
osg::Image* image = tex2D->getImage();
osgDB::writeImageFile(*image, "abc.jpg");
int width = image->s();
int height = image->t();
/*osg::Vec2 color;
osg::Vec4 c = image->getColor(color);*/
//UV
osg::Array* uvArry = geometry->getTexCoordArray(0);
osg::Vec2Array* vertsUV = dynamic_cast<osg::Vec2Array*>(uvArry);
std::vector<osg::Vec2 >::iterator iter_verUV = vertsUV->begin();
std::vector<int> greenPointIndices;
int i = 0;
for (; iter_verUV != vertsUV->end(); iter_verUV++)
{
double u = iter_verUV->x();
double v = iter_verUV->y();
osg::Vec2 color(u, v);
osg::Vec4 c = image->getColor(color);
float r = c.r() * 255;
float g = c.g() * 255;
float b = c.b() * 255;
if (r < 100 && g < 100 && b < 100 )
greenPointIndices.push_back(i);
i++;
}
//索引
int numP = geometry->getNumPrimitiveSets();
osg::ref_ptr<osg::DrawElementsUInt> drawElemUInt = new osg::DrawElementsUInt(GL_TRIANGLES);
for (unsigned int ipr = 0; ipr < numP; ipr++)
{
osg::PrimitiveSet* prset = geometry->getPrimitiveSet(ipr);
unsigned int ncnt = prset->getNumIndices();
for (unsigned int ic = 0; ic * 3 < prset->getNumIndices(); ic++)
{
unsigned int iIndex0 = prset->index(ic * 3);
unsigned int iIndex1 = prset->index(ic * 3 + 1);
unsigned int iIndex2 = prset->index(ic * 3 + 2);
bool find = false;
for (int i = 0; i < greenPointIndices.size(); i++)
{
if (greenPointIndices[i] == iIndex0 || greenPointIndices[i] == iIndex1 || greenPointIndices[i] == iIndex2)
{
find = true;
break;
}
}
if (find)
continue;
else
{
drawElemUInt->push_back(prset->index(ic * 3));
drawElemUInt->push_back(prset->index(ic * 3 + 1));
drawElemUInt->push_back(prset->index(ic * 3 + 2));
}
}
}
osg::ref_ptr<osg::Geometry> geometry_new = new osg::Geometry();
geometry_new->setVertexArray(verts);
geometry_new->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex2D, osg::StateAttribute::ON);
geometry_new->setTexCoordArray(0, uvArry);
geometry_new->addPrimitiveSet(drawElemUInt);
osg::Geode* pGeode_new = new osg::Geode;
pGeode_new->removeDrawables(0, pGeode_new->getNumDrawables());
pGeode_new->addDrawable(geometry_new);
osgDB::writeNodeFile(*pGeode_new, "test.osgb", new osgDB::Options("WriteImageHint=IncludeData Compressor=zlib"));
//***********************************************
}
}
}
参考博主:osgb的顶点,纹理,索引,UV读取与存储_osgb获取顶点-CSDN博客
作为C++小白看这段代码的详细解读
这段代码是用 C++ 编写的,并使用了 OpenSceneGraph (OSG) ------ 一个开源的高性能 3D 图形引擎,广泛用于地理信息系统、仿真、可视化等领域。
这段代码定义了一个虚函数 apply(osg::Geode& node),该函数的作用是:遍历一个三维模型,识别纹理上颜色较暗的区域,剔除那些区域对应的三角形网格,然后将剩余的"亮色"区域导出为一个新的 3D 模型文件**。**
一、逐行详细解析
开始遍历Geode下的Drawable对象(通常是Geometry)
cpp
for (int i = 0; i < node.getNumDrawables(); i++)
遍历Geode中所有的Drawable(通常是osg::Geometry类型)
处理每个Geometry
cpp
osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(node.getDrawable(i));
尝试将 Drawable 转为 osg::Geometry 类型,如果转换成功,表示该对象是几何体。
解析顶点信息
cpp
osg::Array* vertexArray = geometry->getVertexArray();
osg::Vec3Array* verts = dynamic_cast<osg::Vec3Array*>(vertexArray);
获取顶点数组并强制转换为三维坐标数组(Vec3Array)
vert存储所有顶点坐标
cpp
for (; iter_ver != verts->end(); iter_ver++)
{
double x = iter_ver->x();
double y = iter_ver->y();
double z = iter_ver->z();
}
遍历每个顶点,获取其三维坐标(这里没做实际操作)
提取纹理图像
cpp
osg::Texture2D* tex2D = dynamic_cast<osg::Texture2D*>(geometry->getStateSet()->getTextureAttribute(0, ...));
osg::Image* image = tex2D->getImage();
osgDB::writeImageFile(*image, "abc.jpg");
获取贴在模型上的纹理(Texture2D)
提取出其中的图像(osg::Image)
保存图像为JPG文件(调试用途)
读取UV坐标+获取纹理颜色
cpp
osg::Array* uvArry = geometry->getTexCoordArray(0);
osg::Vec2Array* vertsUV = dynamic_cast<osg::Vec2Array*>(uvArry);
获取纹理坐标(UV)数组
cpp
for (; iter_verUV != vertsUV->end(); iter_verUV++)
{
double u = iter_verUV->x();
double v = iter_verUV->y();
osg::Vec2 color(u, v);
osg::Vec4 c = image->getColor(color);
...
}
遍历每个顶点对应的纹理坐标(u,v)
从image图像中获取对应像素颜色c
判断颜色是否"偏暗",若R、G、B分量都小于100(即为暗色或黑色点)
cpp
if (r < 100 && g < 100 && b < 100)
greenPointIndices.push_back(i);
这些"暗黑点"会被记录到greenPointIndices中
处理索引,剔除包含暗黑点的三角面
cpp
osg::DrawElementsUInt* drawElemUInt = new osg::DrawElementsUInt(GL_TRIANGLES);
新建一个DrawElementsUInt类型的三角形集合,保存有效三角面索引。
cpp
for (ipr ...)
{
for (ic ...)
{
unsigned int iIndex0 = prset->index(ic * 3);
...
if (任意一个顶点是暗色点)
continue;
else
drawElemUInt->push_back(三个顶点索引);
}
}
遍历所有原始三角形
若三角形中有任意一个顶点在greenPointIndices中(即暗点),跳过不加入新网格。
其他三角面则加入drawElemUInt
构建新Geometry并导出为OSGB文件
cpp
osg::Geometry* geometry_new = new osg::Geometry();
geometry_new->setVertexArray(verts);
...
geometry_new->addPrimitiveSet(drawElemUInt);
构建一个新几何体,复用原始顶点和纹理坐标,仅替换三角面为"亮色区域"
cpp
osg::Geode* pGeode_new = new osg::Geode;
pGeode_new->addDrawable(geometry_new);
osgDB::writeNodeFile(*pGeode_new, "test.osgb", ...);
将新的几何体写入.osgb文件(OpenSceneGraph二进制模式格式)