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);