使用OpenSceneGraph生成3D数据格式文件

发布于:2025-04-07 ⋅ 阅读:(21) ⋅ 点赞:(0)

OpenSceneGraph (OSG) 提供了多种方式来生成和导出3D数据格式文件。以下是详细的生成方法和示例代码:

一、基本文件生成方法

1. 使用osgDB::writeNodeFile函数

这是最直接的生成方式,支持多种格式:

#include <osgDB/WriteFile>

osg::ref_ptr<osg::Node> scene = createScene(); // 创建你的场景图

// 导出为不同格式
bool success;
success = osgDB::writeNodeFile(*scene, "output.osgt");  // OSG文本格式
success = osgDB::writeNodeFile(*scene, "output.osgb");  // OSG二进制格式
success = osgDB::writeNodeFile(*scene, "output.obj");   // Wavefront OBJ
success = osgDB::writeNodeFile(*scene, "output.dae");   // COLLADA
success = osgDB::writeNodeFile(*scene, "output.fbx");   // FBX(需插件支持)

2. 支持的导出格式

格式类型 文件扩展名 说明
OSG原生 .osgt, .osgb, .osgx 文本/二进制/XML格式
通用3D .obj, .stl, .ply 静态网格格式
场景格式 .dae, .fbx, .3ds 支持完整场景
地形数据 .ive, .lwo, .txp 优化格式

二、编程生成场景并导出

1. 创建简单几何体并导出

#include <osg/Geode>
#include <osg/Geometry>
#include <osgDB/WriteFile>

osg::Geode* createCube() {
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
    
    // 定义8个顶点(立方体)
    osg::Vec3Array* vertices = new osg::Vec3Array;
    vertices->push_back(osg::Vec3(-1.0f, -1.0f,  1.0f)); // 前左下
    vertices->push_back(osg::Vec3( 1.0f, -1.0f,  1.0f)); // 前右下
    vertices->push_back(osg::Vec3( 1.0f,  1.0f,  1.0f)); // 前右上
    vertices->push_back(osg::Vec3(-1.0f,  1.0f,  1.0f)); // 前左上
    vertices->push_back(osg::Vec3(-1.0f, -1.0f, -1.0f)); // 后左下
    vertices->push_back(osg::Vec3( 1.0f, -1.0f, -1.0f)); // 后右下
    vertices->push_back(osg::Vec3( 1.0f,  1.0f, -1.0f)); // 后右上
    vertices->push_back(osg::Vec3(-1.0f,  1.0f, -1.0f)); // 后左上
    geometry->setVertexArray(vertices);
    
    // 定义法线
    osg::Vec3Array* normals = new osg::Vec3Array;
    normals->push_back(osg::Vec3( 0.0f,  0.0f,  1.0f)); // 前
    normals->push_back(osg::Vec3( 0.0f,  0.0f, -1.0f)); // 后
    normals->push_back(osg::Vec3( 1.0f,  0.0f,  0.0f)); // 右
    normals->push_back(osg::Vec3(-1.0f,  0.0f,  0.0f)); // 左
    normals->push_back(osg::Vec3( 0.0f,  1.0f,  0.0f)); // 上
    normals->push_back(osg::Vec3( 0.0f, -1.0f,  0.0f)); // 下
    geometry->setNormalArray(normals, osg::Array::BIND_PER_PRIMITIVE);
    
    // 定义6个面(12个三角形)
    osg::DrawElementsUInt* faces = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
    
    // 前面
    faces->push_back(0); faces->push_back(1); faces->push_back(2);
    faces->push_back(2); faces->push_back(3); faces->push_back(0);
    
    // 后面
    faces->push_back(5); faces->push_back(4); faces->push_back(7);
    faces->push_back(7); faces->push_back(6); faces->push_back(5);
    
    // 右面
    faces->push_back(1); faces->push_back(5); faces->push_back(6);
    faces->push_back(6); faces->push_back(2); faces->push_back(1);
    
    // 左面
    faces->push_back(4); faces->push_back(0); faces->push_back(3);
    faces->push_back(3); faces->push_back(7); faces->push_back(4);
    
    // 上面
    faces->push_back(3); faces->push_back(2); faces->push_back(6);
    faces->push_back(6); faces->push_back(7); faces->push_back(3);
    
    // 下面
    faces->push_back(4); faces->push_back(5); faces->push_back(1);
    faces->push_back(1); faces->push_back(0); faces->push_back(4);
    
    geometry->addPrimitiveSet(faces);
    geode->addDrawable(geometry);
    
    return geode.release();
}

int main() {
    osg::ref_ptr<osg::Node> scene = createCube();
    osgDB::writeNodeFile(*scene, "box.osgb");
    return 0;
}

 2. 生成带纹理的模型

osg::Node* createTexturedQuad() {
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
    
    // 顶点
    osg::Vec3Array* vertices = new osg::Vec3Array;
    vertices->push_back(osg::Vec3(-1,0,-1));
    vertices->push_back(osg::Vec3(1,0,-1));
    vertices->push_back(osg::Vec3(1,0,1));
    vertices->push_back(osg::Vec3(-1,0,1));
    geom->setVertexArray(vertices);
    
    // 纹理坐标
    osg::Vec2Array* texcoords = new osg::Vec2Array;
    texcoords->push_back(osg::Vec2(0,0));
    texcoords->push_back(osg::Vec2(1,0));
    texcoords->push_back(osg::Vec2(1,1));
    texcoords->push_back(osg::Vec2(0,1));
    geom->setTexCoordArray(0, texcoords);
    
    // 加载纹理
    osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
    texture->setImage(osgDB::readImageFile("texture.jpg"));
    
    // 创建状态集
    osg::ref_ptr<osg::StateSet> stateset = geom->getOrCreateStateSet();
    stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
    
    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
    geode->addDrawable(geom);
    
    return geode.release();
}

三、高级导出选项

1. 使用osg::Options控制导出

osg::ref_ptr<osgDB::Options> options = new osgDB::Options;
options->setOptionString("WriteImageHint=IncludeFile");  // 包含纹理引用

osgDB::writeNodeFile(*scene, "textured_model.osgt", options.get());

2. 常用导出选项

选项字符串 功能描述
"WriteImageHint=IncludeFile" 包含纹理文件引用
"Compressor=zlib" 使用压缩格式
"Precision=15" 设置浮点精度
"OutputTextureFiles" 导出纹理文件

3. 批量导出多个LOD级别

void exportLODs(osg::Node* model, const std::string& basename) {
    osg::ref_ptr<osg::LOD> lod = new osg::LOD;
    
    // 创建不同细节级别的模型
    osg::Node* highRes = createSimplifiedModel(model, 1.0f);
    osg::Node* medRes = createSimplifiedModel(model, 0.5f);
    osg::Node* lowRes = createSimplifiedModel(model, 0.2f);
    
    lod->addChild(highRes, 0, 50);
    lod->addChild(medRes, 50, 200);
    lod->addChild(lowRes, 200, FLT_MAX);
    
    osgDB::writeNodeFile(*lod, basename + "_lod.osgb");
}

// 辅助函数:创建简化模型
osg::Node* createSimplifiedModel(osg::Node* original, float ratio) {
    osgUtil::Simplifier simplifier(ratio);
    osg::ref_ptr<osg::Node> copy = dynamic_cast<osg::Node*>(original->clone(osg::CopyOp::DEEP_COPY_ALL));
    copy->accept(simplifier);
    return copy.release();
}

四、处理导出问题

1. 检查插件支持

// 列出所有支持的写入格式
osgDB::Registry::instance()->getWriterExtensions();

// 检查特定格式是否支持
if (osgDB::Registry::instance()->getReaderWriterForExtension("fbx")) {
    // FBX导出可用
}

2. 错误处理

bool result = osgDB::writeNodeFile(*node, "output.fbx");
if (!result) {
    OSG_WARN << "Failed to export FBX file. Make sure FBX plugin is installed." << std::endl;
    
    // 尝试回退格式
    osgDB::writeNodeFile(*node, "output.obj");
}

五、实际应用示例

1. 生成地形并导出

osg::Node* createTerrain() {
    osg::ref_ptr<osg::HeightField> hf = new osg::HeightField;
    hf->allocate(64, 64); // 64x64网格
    
    // 填充高度数据
    for (unsigned int r=0; r<hf->getNumRows(); ++r) {
        for (unsigned int c=0; c<hf->getNumColumns(); ++c) {
            float height = sin(c/10.0f) * cos(r/10.0f) * 10.0f;
            hf->setHeight(c, r, height);
        }
    }
    
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    geode->addDrawable(new osg::ShapeDrawable(hf.get()));
    
    return geode.release();
}

// 导出为OpenFlight格式
osgDB::writeNodeFile(*createTerrain(), "terrain.flt");

2. 动画模型导出

osg::AnimationPath* createAnimationPath() {
    osg::ref_ptr<osg::AnimationPath> path = new osg::AnimationPath;
    path->setLoopMode(osg::AnimationPath::LOOP);
    
    float time = 0.0f;
    float delta = 1.0f/30.0f; // 30fps
    
    for (unsigned int i=0; i<60; ++i) {
        osg::Vec3 pos(sin(time), cos(time), 0.0f);
        path->insert(time, osg::AnimationPath::ControlPoint(pos));
        time += delta;
    }
    
    return path.release();
}

osg::Node* createAnimatedModel() {
    osg::ref_ptr<osg::MatrixTransform> animNode = new osg::MatrixTransform;
    animNode->setUpdateCallback(new osg::AnimationPathCallback(createAnimationPath()));
    
    // 添加你的模型
    animNode->addChild(createSimpleBox());
    
    return animNode.release();
}

// 导出动画模型
osgDB::writeNodeFile(*createAnimatedModel(), "animated.dae");

 

 


网站公告

今日签到

点亮在社区的每一天
去签到