osgEarth对Shaders.cpp.in的处理

本文探讨了在项目中使用Shaders.cpp.in等文件管理shader代码的优势,通过CMake的configure_shaders宏,实现shader代码从独立文件到cpp文件的自动化集成。此方法避免了硬编码,提高了代码的维护性和可读性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么要使用Shaders.cpp.in(还有MPShaders.cpp.in SimpleSkyShaders.cpp.in  SplatShaders.cpp.in DetailShaders.cpp.in)?主要是为了实现shader的单独成文件,不用硬编码到cpp文件中。

借助CMake对Shaders.cpp.in进行处理,重新生成cpp文件,从而将shader文件编码到这个新cpp中。

CMake的处理过程如下:

1、在CMakeLists.txt中添加

configure_shaders(
    Shaders.cpp.in
    ${SHADERS_CPP}
    ${TARGET_GLSL} )

2、OsgEarthMacroUtils.cmake中定义了configure_shaders

对shaders.cpp.in的处理由此宏完成,最终会将shader代码编码进一个新生成的cpp文件AutoGenShaders.cpp中

configure_file(
    ${source_dir}/${template_file}
    ${output_cpp_file}
    @ONLY )

以上主要完成着色器代码的替换

3、替换shader中的版本号和精度

osgEarth/ShaderLoader.cpp
std::string
ShaderLoader::load(const std::string&    filename,
                   const ShaderPackage&  package,
                   const osgDB::Options* dbOptions)
{
    osgEarth::replaceIn(output, "$GLSL_VERSION_STR", GLSL_VERSION_STR);
    osgEarth::replaceIn(output, "$GLSL_DEFAULT_PRECISION_FLOAT", GLSL_DEFAULT_PRECISION_FLOAT);
}

 

 

 

 

<think>我们已经在使用osgEarth的GDALElevationLayer加载高程TIFF文件。为了显示高程颜色图(即根据高程值着色),我们需要添加一个颜色映射层(ColorRamp)。在osgEarth中,我们可以通过创建一个自定义的着色器(Shader)或者使用内置的ElevationLayer的渲染技术来实现。一种简单的方法是使用osgEarth的Util::TopographicMapTechnique,它提供了高程颜色映射。但是,这里我们将采用另一种方法:使用osgEarth的ColorRamp类创建一个颜色渐变,然后将其应用到高程图层上。步骤:1.创建并添加高程图层(GDALElevationLayer)。2.创建一个颜色渐变(ColorRamp)并生成一个纹理(Texture)。3.创建一个地形效果(TerrainEffect)来应用这个颜色渐变纹理。4.将地形效果添加到地图(Map)中。以下是如何在已有的代码基础上(即已经加载了高程图层)实现高程颜色图的显示:注意:我们假设已经有一个Map对象,并且已经将高程图层添加到Map中。我们将创建一个自定义的TerrainEffect,它会在渲染地形时使用颜色渐变纹理。具体步骤如下:1.创建颜色渐变纹理。2.编写一个着色器程序,该程序将高程值映射到颜色渐变纹理上。3.创建一个TerrainEffect,将着色器程序应用到地形上。由于osgEarth的TerrainEffect需要添加到Map的TerrainEngine中,我们可以在MapNode创建之后添加这个效果。示例代码:首先,在创建MapNode之后,我们添加以下代码:```cpp#include<osgEarth/MapNode>#include <osgEarth/Color>#include <osgEarth/ShaderLoader> #include<osgEarth/TerrainEngineNode> #include<osgEarth/TextureCompositor> #include<osgEarth/ColorRamp> #include<osgEarth/Shaders>#include <osgEarth/Registry>#include <osgEarth/Capabilities> #include<osgEarth/VirtualProgram> //创建颜色渐变纹理osg::Texture2D* createColorRampTexture() {osgEarth::ColorRampramp;//设置颜色渐变:从低到高,例如:蓝色->绿色->黄色->红色ramp.add(osgEarth::Color(0,0,1,1),0.0f);//蓝色,低高程ramp.add(osgEarth::Color(0,1,0,1),0.5f);//绿色ramp.add(osgEarth::Color(1,1,0,1),0.75f);//黄色ramp.add(osgEarth::Color(1,0,0,1),1.0f);//红色,高高程osg::Image*image =ramp.createImage(256);osg::Texture2D*texture =new osg::Texture2D();texture->setImage(image);texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);return texture; }//创建并添加高程颜色映射效果void addElevationColorRampEffect(osgEarth::MapNode* mapNode){//创建颜色渐变纹理osg::Texture2D* colorRampTex= createColorRampTexture();//创建一个虚拟程序(着色器程序)osgEarth::VirtualProgram*vp= newosgEarth::VirtualProgram();vp->setName("elevation_color_ramp");//加载着色器代码std::stringvs=osgEarth::ShaderLoader::load(osgEarth::ShaderPackage("elevation_color_ramp"),"elevation_color_ramp.vert",osgEarth::Registry::instance()->shaderGenerator());std::string fs= osgEarth::ShaderLoader::load(osgEarth::ShaderPackage("elevation_color_ramp"),"elevation_color_ramp.frag",osgEarth::Registry::instance()->shaderGenerator());vp->setShader("elevation_color_ramp_vert",newosg::Shader(osg::Shader::VERTEX,vs));vp->setShader("elevation_color_ramp_frag", newosg::Shader(osg::Shader::FRAGMENT, fs));//将纹理作为uniform传递给着色器osg::StateSet*ss =mapNode->getOrCreateStateSet();ss->setTextureAttributeAndModes(1, colorRampTex,osg::StateAttribute::ON);ss->addUniform(newosg::Uniform("oe_elevation_ramp",1)); //纹理单元1//添加虚拟程序到状态集ss->setAttributeAndModes(vp,osg::StateAttribute::ON);//获取地形引擎节点osgEarth::TerrainEngineNode*terrainEngine= mapNode->getTerrainEngine();terrainEngine->getStateSet()->setAttributeAndModes(vp, osg::StateAttribute::ON); }//在创建MapNode后调用osg::Node*createScene() {//创建Map对象osgEarth::Map*map =new osgEarth::Map();//添加高程图层(如之前代码)osgEarth::GDALElevationLayer::Options elevationOptions;elevationOptions.url()= ".././elevation/dem_90m.tif";osgEarth::GDALElevationLayer* elevLayer =new osgEarth::GDALElevationLayer(elevationOptions);map->addLayer(elevLayer);//创建MapNodeosgEarth::MapNode* mapNode =new osgEarth::MapNode(map);//添加高程颜色映射效果addElevationColorRampEffect(mapNode);return mapNode;}```着色器代码:我们需要两个着色器文件:`elevation_color_ramp.vert`和`elevation_color_ramp.frag`。我们将它们放在与代码相同的目录,或者通过osgEarth的shader包机制加载。 **elevation_color_ramp.vert**: ```glsl//osgEarth内置的顶点着色器已经计算了高程,我们只需要传递高程值到片段着色器varying floatoe_elevation;void main() {//调用内置的顶点处理函数vec4 vertex= gl_Vertex;vec3normal =gl_Normal;//计算世界坐标(使用osgEarth的模型矩阵)vec4 vertex_view= gl_ModelViewMatrix* vertex;//传递高程值(假设在模型坐标中,顶点的高度即为高程)oe_elevation =vertex.z;//注意:这里假设地形在模型坐标中,z轴表示高程。实际中可能需要转换。gl_Position =gl_ModelViewProjectionMatrix *vertex;} ```**elevation_color_ramp.frag**:```glsluniform sampler2Doe_elevation_ramp;varyingfloat oe_elevation;void main() {//归一化高程值(假设高程范围0~1000,这里需要根据实际调整)float minElevation=0.0;floatmaxElevation =1000.0;floatnormalizedElevation =(oe_elevation -minElevation)/ (maxElevation -minElevation);normalizedElevation= clamp(normalizedElevation,0.0,1.0);//从颜色渐变纹理中采样vec4 color= texture2D(oe_elevation_ramp, vec2(normalizedElevation,0.0));gl_FragColor =color;} ```注意:上面的着色器是一个简化的例子。实际中,高程值需要从地形中获取,并且可能需要通过统一变量(uniform)传递高程范围。此外,顶点着色器中的高程计算可能需要根据实际地形进行调整。为了更精确地控制高程范围,我们可以通过uniform变量传递最小和最大高程值。改进的片段着色器:```glsluniform sampler2Doe_elevation_ramp;uniform floatoe_min_elevation; uniformfloat oe_max_elevation; varying floatoe_elevation; voidmain(){//归一化高程值float normalizedElevation= (oe_elevation- oe_min_elevation) /(oe_max_elevation- oe_min_elevation);normalizedElevation =clamp(normalizedElevation,0.0,1.0);//从颜色渐变纹理中采样vec4 color= texture2D(oe_elevation_ramp, vec2(normalizedElevation,0.0));gl_FragColor =color;} ```然后在C++代码中设置这两个uniform:```cpp//在addElevationColorRampEffect函数中,添加:ss->addUniform(newosg::Uniform("oe_min_elevation",0.0f));ss->addUniform(new osg::Uniform("oe_max_elevation",1000.0f)); ```这样,我们就实现了在osgEarth中加载高程TIFF文件并显示高程颜色图。注意:实际的高程范围需要根据你的数据来设定,可以通过GDALElevationLayer获取实际的高程范围。获取高程范围:```cpposgEarth::ElevationLayer::ElevationMinMaxminmax= elevLayer->getMinMaxElevation();floatminElev=minmax.minElevation();float maxElev =minmax.maxElevation();```然后设置uniform:```cppss->addUniform(newosg::Uniform("oe_min_elevation", minElev));ss->addUniform(new osg::Uniform("oe_max_elevation",maxElev)); ```这样,颜色映射就会根据实际的高程范围进行归一化。总结:我们通过创建自定义的着色器程序,将高程值映射到颜色渐变纹理上,实现了高程颜色图的显示。注意:如果地形有多个图层,可能需要考虑如何合并高程值。这里我们只使用了一个高程图层。如果遇到问题,可以检查着色器是否编译成功,以及纹理单元是否正确绑定。最后,将createScene返回的节点设置为场景根节点即可。以上就是在已有高程图层基础上显示高程颜色图的方法。 §§相关问题§§:1.如何动态改变高程颜色映射的渐变颜色? 2.如何在osgEarth中同时显示高程颜色图和卫星影像?3.如何优化着色器以处理非常大的高程范围? 4.如何将高程颜色图与地形光照效果结合?</think>在已有代码基础上使用 `osgEarth::GDALElevationLayer` 加载高程 TIFF 文件后,要显示高程颜色图(高程渐变着色),需要添加一个颜色映射效果。以下是完整的解决方案: ### ✅ 解决方案:添加高程颜色映射 ```cpp #include <osgEarth/MapNode> #include <osgEarth/Color> #include <osgEarth/ShaderLoader> #include <osgEarth/TerrainEngineNode> #include <osgEarth/TextureCompositor> #include <osgEarth/ColorRamp> #include <osgEarth/Shaders> #include <osgEarth/Registry> #include <osgEarth/Capabilities> // 创建高程颜色映射效果 osg::Node* createElevationColorMap(osgEarth::MapNode* mapNode) { // 1. 创建颜色渐变 osgEarth::ColorRamp ramp; ramp.add(osgEarth::Color::Blue, 0.0f); // 低高程 - 蓝色 ramp.add(osgEarth::Color::Green, 0.3f); // 中高程 - 绿色 ramp.add(osgEarth::Color::Yellow, 0.6f); // 中高程 - 黄色 ramp.add(osgEarth::Color::Red, 1.0f); // 高高程 - 红色 // 2. 创建着色器程序 osgEarth::VirtualProgram* vp = new osgEarth::VirtualProgram(); vp->setName("elevation_colormap"); // 3. 添加着色器代码 std::string vs = R"( #version 330 in vec3 osg_Vertex; out float oe_terrain_elev; void main() { gl_Position = gl_ModelViewProjectionMatrix * vec4(osg_Vertex, 1.0); oe_terrain_elev = osg_Vertex.z; } )"; std::string fs = R"( #version 330 uniform sampler2D oe_elevation_ramp; uniform float oe_min_elev; uniform float oe_max_elev; in float oe_terrain_elev; out vec4 fragColor; void main() { // 归一化高程值 (0.0-1.0) float normalizedElev = (oe_terrain_elev - oe_min_elev) / (oe_max_elev - oe_min_elev); normalizedElev = clamp(normalizedElev, 0.0, 1.0); // 从渐变纹理采样颜色 vec4 color = texture(oe_elevation_ramp, vec2(normalizedElev, 0.0)); fragColor = color; } )"; vp->setShader("elevation_colormap_vert", new osg::Shader(osg::Shader::VERTEX, vs)); vp->setShader("elevation_colormap_frag", new osg::Shader(osg::Shader::FRAGMENT, fs)); // 4. 创建渐变纹理 osg::Image* image = ramp.createImage(256); osg::Texture2D* rampTex = new osg::Texture2D(); rampTex->setImage(image); rampTex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); rampTex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); // 5. 添加到状态集 osg::StateSet* ss = mapNode->getOrCreateStateSet(); ss->setTextureAttributeAndModes(0, rampTex, osg::StateAttribute::ON); ss->addUniform(new osg::Uniform("oe_elevation_ramp", 0)); // 纹理单元0 ss->addUniform(new osg::Uniform("oe_min_elev", 0.0f)); // 最小高程值 ss->addUniform(new osg::Uniform("oe_max_elev", 1000.0f)); // 最大高程值 ss->setAttributeAndModes(vp, osg::StateAttribute::ON); return mapNode; } // 在您的主代码中使用 osg::Group* root = new osg::Group(); // 创建地图节点 osgEarth::Map* map = new osgEarth::Map(); osgEarth::MapNode* mapNode = new osgEarth::MapNode(map); root->addChild(mapNode); // 添加高程层(您的代码) osgEarth::GDALElevationLayer::Options elevationOptions; elevationOptions.url() = ".././elevation/dem_90m.tif"; osgEarth::GDALElevationLayer* elevLayer = new osgEarth::GDALElevationLayer(elevationOptions); map->addLayer(elevLayer); // 添加颜色映射效果 root->addChild(createElevationColorMap(mapNode)); // 添加到查看器 osgViewer::Viewer viewer; viewer.setSceneData(root); ``` ### 🔍 代码解释: 1. **颜色渐变创建**: - 使用 `osgEarth::ColorRamp` 定义从低到高的颜色渐变 - 添加了蓝→绿→黄→红的颜色过渡 2. **着色器程序**: - **顶点着色器**:传递地形高程值 - **片段着色器**:根据高程值从渐变纹理采样颜色 - 使用 `normalizedElev` 将高程值归一化到 0-1 范围 3. **渐变纹理**: - 将颜色渐变转换为 256×1 的纹理 - 设置纹理过滤模式为线性插值 4. **状态设置**: - 将渐变纹理绑定到纹理单元0 - 设置高程范围统一变量(需根据实际数据调整) - 启用着色器程序 ### ⚙️ 高程范围调整: 要获取实际高程范围,可在加载高程层后添加: ```cpp // 获取实际高程范围 osgEarth::ElevationLayer::ElevationMinMax minmax = elevLayer->getMinMaxElevation(); float minElev = minmax.minElevation(); float maxElev = minmax.maxElevation(); // 更新统一变量 ss->getUniform("oe_min_elev")->set(minElev); ss->getUniform("oe_max_elev")->set(maxElev); ``` ### 🌈 自定义颜色方案: 修改 `ColorRamp` 创建不同颜色方案: ```cpp // 冰川方案 ramp.add(osgEarth::Color(0.8, 0.9, 1.0), 0.0f); // 淡蓝 ramp.add(osgEarth::Color(0.6, 0.8, 1.0), 0.3f); // 中蓝 ramp.add(osgEarth::Color(0.9, 0.95, 1.0), 0.7f); // 淡青 ramp.add(osgEarth::Color::White, 1.0f); // 白色 // 沙漠方案 ramp.add(osgEarth::Color(0.9, 0.8, 0.5), 0.0f); // 沙色 ramp.add(osgEarth::Color(0.7, 0.5, 0.3), 0.5f); // 棕色 ramp.add(osgEarth::Color(0.5, 0.3, 0.2), 1.0f); // 深棕 ``` ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值