详解osgb的顶点,纹理,索引,UV读取与存储

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)

for (int i = 0; i < node.getNumDrawables(); i++)

遍历Geode中所有的Drawable(通常是osg::Geometry类型)

处理每个Geometry

osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(node.getDrawable(i));

尝试将 Drawable 转为 osg::Geometry 类型,如果转换成功,表示该对象是几何体。

解析顶点信息

osg::Array* vertexArray = geometry->getVertexArray();
osg::Vec3Array* verts = dynamic_cast<osg::Vec3Array*>(vertexArray);

获取顶点数组并强制转换为三维坐标数组(Vec3Array)

vert存储所有顶点坐标

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::Image* image = tex2D->getImage();
osgDB::writeImageFile(*image, "abc.jpg");

获取贴在模型上的纹理(Texture2D)

提取出其中的图像(osg::Image)

保存图像为JPG文件(调试用途)

读取UV坐标+获取纹理颜色

osg::Array* uvArry = geometry->getTexCoordArray(0);
osg::Vec2Array* vertsUV = dynamic_cast<osg::Vec2Array*>(uvArry);

获取纹理坐标(UV)数组

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(即为暗色或黑色点)

if (r < 100 && g < 100 && b < 100)
    greenPointIndices.push_back(i);

这些“暗黑点”会被记录到greenPointIndices中

处理索引,剔除包含暗黑点的三角面

osg::DrawElementsUInt* drawElemUInt = new osg::DrawElementsUInt(GL_TRIANGLES);

新建一个DrawElementsUInt类型的三角形集合,保存有效三角面索引。

for (ipr ...)
{
    for (ic ...)
    {
        unsigned int iIndex0 = prset->index(ic * 3);
        ...
        if (任意一个顶点是暗色点)
            continue;
        else
            drawElemUInt->push_back(三个顶点索引);
    }
}

遍历所有原始三角形

若三角形中有任意一个顶点在greenPointIndices中(即暗点),跳过不加入新网格。

其他三角面则加入drawElemUInt

构建新Geometry并导出为OSGB文件

osg::Geometry* geometry_new = new osg::Geometry();
geometry_new->setVertexArray(verts);
...
geometry_new->addPrimitiveSet(drawElemUInt);

构建一个新几何体,复用原始顶点和纹理坐标,仅替换三角面为“亮色区域”

osg::Geode* pGeode_new = new osg::Geode;
pGeode_new->addDrawable(geometry_new);
osgDB::writeNodeFile(*pGeode_new, "test.osgb", ...);

将新的几何体写入.osgb文件(OpenSceneGraph二进制模式格式)

### 如何使用 OpenSceneGraph (OSG) 读取 OSGB 文件中的顶点和法向量数据 在 OpenSceneGraph 中,`osgb` 是一种二进制文件格式,用于存储场景图及其相关几何数据。要解析 `osgb` 文件并提取其中的顶点和法向量数据,可以利用 OSG 提供的核心 API 来遍历节点树,并访问具体的几何对象。 以下是实现这一功能的关键步骤以及示例代码: #### 使用 OSG 遍历场景图并获取几何数据 通过加载 `.osgb` 文件,可以获得一个根节点 (`osg::Node`) 对象。随后可以通过递归方式遍历该节点树,找到所有的几何体 (`osg::Geometry`) 并从中提取顶点数组和法向量数组。 ```cpp #include <osg/Geode> #include <osg/Geometry> #include <osgViewer/Viewer> #include <osgDB/ReadFile> void extractVertexAndNormalData(osg::Node* node) { // 定义回调函数来处理几何体 class GeometryVisitor : public osg::NodeVisitor { public: GeometryVisitor() : osg::NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN) {} void apply(osg::Geode& geode) override { for (unsigned int i = 0; i < geode.getNumDrawables(); ++i) { osg::Drawable* drawable = geode.getDrawable(i); if (!drawable) continue; osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(drawable); if (!geometry) continue; // 获取顶点数组 osg::Vec3Array* vertices = static_cast<osg::Vec3Array*>(geometry->getVertexArray()); if (vertices) { std::cout << "Vertices:" << std::endl; for (const auto& vertex : *vertices) { std::cout << " Vertex: (" << vertex.x() << ", " << vertex.y() << ", " << vertex.z() << ")" << std::endl; } } // 获取法向量数组 osg::Vec3Array* normals = static_cast<osg::Vec3Array*>(geometry->getNormalArray()); if (normals) { std::cout << "Normals:" << std::endl; for (const auto& normal : *normals) { std::cout << " Normal: (" << normal.x() << ", " << normal.y() << ", " << normal.z() << ")" << std::endl; } } } traverse(geode); // 继续遍历子节点 } }; GeometryVisitor visitor; node->accept(visitor); } int main(int argc, char** argv) { // 加载 .osgb 文件 osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFile("example.osgb"); if (!loadedModel) { std::cerr << "Failed to load model." << std::endl; return -1; } // 调用方法提取顶点和法向量数据 extractVertexAndNormalData(loadedModel.get()); return 0; } ``` 上述代码展示了如何加载一个 `.osgb` 文件,并通过递归遍历其节点结构来提取顶点和法向量的数据[^2]。 --- ### 关键说明 1. **加载模型**: 使用 `osgDB::readNodeFile()` 函数可以从指定路径加载 `.osgb` 或其他支持的文件格式。 2. **遍历节点树**: 自定义了一个基于 `osg::NodeVisitor` 的类 `GeometryVisitor`,它能够自动遍历整个场景图,并针对每个 `osg::Geode` 节点内的可绘制对象执行操作。 3. **访问几何属性**: 利用 `osg::Geometry` 类提供的接口(如 `getVertexArray()` 和 `getNormalArray()`),可以直接获取顶点和法向量的相关数据。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值