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; // 30fpsfor (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");
?
?