osgEarth
// 创建天空选项osgEarth::Util::SkyOptions skyOptions;// 设置天空的坐标系统(可选)skyOptions.coordinateSystem() = osgEarth::Util::SkyOptions::COORDSYS_ECEF;// 设置一天中的小时数(可选)skyOptions.hours() = 12.0f; // 中午// 设置环境光级别(可选)skyOptions.ambient() = 0.5f; // 50%的环境光// 使用选项创建天空节点osg::ref_ptr<osgEarth::Util::SkyNode> skyNode = osgEarth::Util::SkyNode::create(skyOptions);// 设置天空节点的日期和时间osgEarth::DateTime dateTime(2024, 6, 5, 12); // 2024年6月5日中午skyNode->setDateTime(dateTime);osgEarth::Util::Ephemeris* ephemeris = new osgEarth::Util::Ephemeris;skyNode->setEphemeris(ephemeris);// 设置天空节点的参考点(对于投影地图)osgEarth::GeoPoint refPoint(getMapNode()->getMapSRS(), 0, 0, 0); // 地球中心skyNode->setReferencePoint(refPoint);skyNode->setLighting(true);_root->addChild(skyNode);skyNode->attach(_viewer,0);//运行了 osgEarth 中的着色器生成器,通过对 _root 中的节点进行分析和处理,生成对应的着色器代码。着色器生成器根据节点的材质、光照、纹理等属性,自动生成相应的顶点着色器和片段着色器代码,以实现渲染效果。osgEarth::Registry::shaderGenerator().run(_root.get());
// 对根节点 _root 及其子节点中的所有状态集合进行优化。这个优化过程尝试将相同的状态合并为一个,以减少OpenGL状态切换次数,从而提高渲染性能。StateSetCache *cache = osgEarth::Registry::stateSetCache();cache->optimize(_root.get());// 添加场景数据_viewer->setSceneData(_root.get());``````cpp
class MoveEarthySkyWithEyePointTransform : public osg::Transform {
public:virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const override {osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);if (cv) {osg::Vec3 eyePointLocal = cv->getEyeLocal();matrix.preMult(osg::Matrix::translate(eyePointLocal));}return true;}virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const override {osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);if (cv) {osg::Vec3 eyePointLocal = cv->getEyeLocal();matrix.postMult(osg::Matrix::translate(-eyePointLocal));}return true;}
};// Update texture matrix for cubemaps
struct TexMatCallback : public osg::NodeCallback {
public:TexMatCallback(osg::TexMat& tm) : _texMat(tm) {}virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) override {osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);if (cv) {const osg::Matrix& MV = *(cv->getModelViewMatrix());const osg::Matrix R = osg::Matrix::rotate(osg::DegreesToRadians(112.0f), 0.0f, 0.0f, 1.0f) *osg::Matrix::rotate(osg::DegreesToRadians(90.0f), 1.0f, 0.0f, 0.0f);osg::Quat q = MV.getRotate();const osg::Matrix C = osg::Matrix::rotate(q.inverse());_texMat.setMatrix(C * R);}traverse(node, nv);}osg::TexMat& _texMat;
};class CSkyLight {
public:osg::TextureCubeMap* readCubeMap(const std::string& path) {osg::TextureCubeMap* cubemap = new osg::TextureCubeMap;osg::Image* images[6];
// std::string faces[6] = {"front3", "back3", "right3", "left3", "bottom3", "top3"};
// std::string faces[6] = {"front3", "back3", "top3", "bottom3", "left3", "right3"};std::string faces[6] = {"front3", "back3", "bottom3", "top3", "left3", "right3"};osg::TextureCubeMap::Face faceEnums[6] = {osg::TextureCubeMap::POSITIVE_X,osg::TextureCubeMap::NEGATIVE_X,osg::TextureCubeMap::POSITIVE_Y,osg::TextureCubeMap::NEGATIVE_Y,osg::TextureCubeMap::POSITIVE_Z,osg::TextureCubeMap::NEGATIVE_Z};for (int i = 0; i < 6; ++i) {images[i] = osgDB::readImageFile(path + faces[i] + ".png");if (!images[i]) return nullptr;cubemap->setImage(faceEnums[i], images[i]);}cubemap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);cubemap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);cubemap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);cubemap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);cubemap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);return cubemap;}osg::Node* createSkyBox(const std::string& path) {osg::StateSet* stateset = new osg::StateSet();osg::TexEnv* te = new osg::TexEnv;te->setMode(osg::TexEnv::REPLACE);stateset->setTextureAttributeAndModes(0, te, osg::StateAttribute::ON);osg::TexGen* tg = new osg::TexGen;tg->setMode(osg::TexGen::NORMAL_MAP);stateset->setTextureAttributeAndModes(0, tg, osg::StateAttribute::ON);osg::TexMat* tm = new osg::TexMat;stateset->setTextureAttribute(0, tm);osg::TextureCubeMap* skymap = readCubeMap(path);stateset->setTextureAttributeAndModes(0, skymap, osg::StateAttribute::ON);stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);osg::Depth* depth = new osg::Depth;depth->setFunction(osg::Depth::ALWAYS);depth->setRange(1.0, 1.0);stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);stateset->setRenderBinDetails(-1, "RenderBin");osg::Drawable* drawable = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f, 0.0f, 0.0f), 1));osg::Geode* geode = new osg::Geode;geode->setCullingActive(false);geode->setStateSet(stateset);geode->addDrawable(drawable);osg::Transform* transform = new MoveEarthySkyWithEyePointTransform;transform->setCullingActive(false);transform->addChild(geode);osg::ClearNode* clearNode = new osg::ClearNode;clearNode->setCullCallback(new TexMatCallback(*tm));clearNode->addChild(transform);return clearNode;}
};
int main() {osgViewer::Viewer viewer;viewer.setUpViewInWindow(100, 100, 800, 600);osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("./osgb/Tractor.OSGB");if (!model){std::cout << "无法加载模型" << std::endl;return 1;}osg::ref_ptr<osg::Group> geode = new osg::Group;geode->addChild(model);CSkyLight c;geode->addChild(c.createSkyBox("./osgb/"));viewer.setSceneData(geode);