首页/新闻资讯/正文详情

OsgEarth 加载CESIUM或ReadyMap 后,再加载模型,结果黑乎乎

发布时间:2026/9/24 11:42:57 来源:云帆数科 栏目:资讯中心
OsgEarth 加载CESIUM或ReadyMap 后,再加载模型,结果黑乎乎
最近做了一个有关地球的OsgEarth的项目发现OsgEarth 加载CESIUM或ReadyMap 后再加载模型结果黑乎乎。。。折腾数日发现了解决方法。。。原理就不说了直接贴代码/** * file ModelShaderLoader.h * brief 模型加载自建着色器工具类解决osgEarth ReadyMap / CesiumNative模型发黑问题 * details * 两套渲染环境二选一自动选择对应着色器 * 1. ReadyMap不启用GL3RealizeOperation使用osg_*别名版本shader屏幕微分法线漫反射 * 2. CesiumNative启用GL3RealizeOperation(Core Profile)不能使用osg_*别名 * 使用显式location顶点属性Node回调实时推送MVP矩阵uniform同样屏幕微分法线漫反射。 * 功能加载模型、挂载对应shader、全局缩放。 * author xxx * date 2026-09-23 * note * - 两套环境模型加载都正常着色器分支自动切换消除模型发黑 * - CesiumNative环境禁止调用setUseModelViewAndProjectionUniforms/setUseVertexAttributeAliasing会崩溃。 * warning * - CesiumNative使用NodeCallback实时更新矩阵uniform有极小额外开销 * - 着色器状态使用OVERRIDE子节点材质无法覆盖。 */ #pragma once #include QObject #include osg/ref_ptr #include osg/NodeCallback #include string class ModelShaderLoader : public QObject { Q_OBJECT public: enum class RenderEnv { ReadyMap, CesiumNative }; explicit ModelShaderLoader(QObject* parent nullptr); void setRenderEnv(RenderEnv env); /** * brief 加载模型并自动挂载对应环境的自建shader修复发黑 * param[in] filePath 模型路径 * param[in] scale 模型缩放系数 * return osg::ref_ptrosg::Node 组装完成节点失败返回nullptr */ osg::ref_ptrosg::Node loadModel(const std::string filePath, double scale); private: RenderEnv _renderEnv RenderEnv::ReadyMap; // ReadyMap 版本shader源码osg_*别名 static const char* vertSrcReadyMap; static const char* fragSrcReadyMap; // CesiumNative CoreProfile版本shader源码无osg_*别名 static const char* vertSrcCesium; static const char* fragSrcCesium; // Cesium环境回调遍历节点更新MVP uniform struct MatrixUpdateCallback; }; /** * file ModelShaderLoader.cpp * brief ModelShaderLoader实现自建shader解决osgEarth Cesium/ReadyMap模型发黑 * author xxx * date 2026-09-23 */ #include ModelShaderLoader.h #include osgViewer/Viewer #include osg/State #include osg/Texture #include osg/NodeVisitor #include osg/MatrixTransform #include osg/Uniform #include osg/Shader #include osg/Program #include osgDB/ReadFile #include iostream // ReadyMap Shaderosg_*别名 const char* ModelShaderLoader::vertSrcReadyMap R( #version 330 core in vec4 osg_Vertex; in vec4 osg_MultiTexCoord0; uniform mat4 osg_ModelViewProjectionMatrix; uniform mat4 osg_ModelViewMatrix; out vec2 vTexCoord; out vec3 vViewPos; void main() { gl_Position osg_ModelViewProjectionMatrix * osg_Vertex; vViewPos (osg_ModelViewMatrix * osg_Vertex).xyz; vTexCoord osg_MultiTexCoord0.xy; } ); const char* ModelShaderLoader::fragSrcReadyMap R( #version 330 core uniform sampler2D tex0; in vec2 vTexCoord; in vec3 vViewPos; out vec4 fragColor; void main() { vec3 dx dFdx(vViewPos); vec3 dy dFdy(vViewPos); vec3 normal normalize(cross(dx, dy)); vec3 lightDir normalize(vec3(0.6, 0.7, 0.4)); float diff max(dot(normal, lightDir),0.0); vec4 texColor texture(tex0, vTexCoord); vec3 rgb texColor.rgb * (0.3 0.7 * diff); fragColor vec4(rgb, texColor.a); } ); // CesiumNative ShaderCoreProfile无osg_* const char* ModelShaderLoader::vertSrcCesium R( #version 330 core layout(location 0) in vec3 aPos; layout(location 1) in vec2 aTexCoord; uniform mat4 uMVP; uniform mat4 uModelView; out vec2 vTexCoord; out vec3 vViewPos; void main() { gl_Position uMVP * vec4(aPos,1.0); vViewPos (uModelView * vec4(aPos,1.0)).xyz; vTexCoord aTexCoord; } ); const char* ModelShaderLoader::fragSrcCesium R( #version 330 core uniform sampler2D tex0; in vec2 vTexCoord; in vec3 vViewPos; out vec4 fragColor; void main() { vec3 dx dFdx(vViewPos); vec3 dy dFdy(vViewPos); vec3 normal normalize(cross(dx, dy)); vec3 lightDir normalize(vec3(0.6, 0.7, 0.4)); float diff max(dot(normal, lightDir),0.0); vec4 texColor texture(tex0, vTexCoord); vec3 rgb texColor.rgb * (0.3 0.7 * diff); fragColor vec4(rgb, texColor.a); } ); // Cesium 矩阵更新回调每帧遍历获取模型矩阵上传MVP struct ModelShaderLoader::MatrixUpdateCallback : public osg::NodeCallback { osg::ref_ptrosg::Uniform _uMVP; osg::ref_ptrosg::Uniform _uModelView; MatrixUpdateCallback() { _uMVP new osg::Uniform(uMVP, osg::Matrixf()); _uModelView new osg::Uniform(uModelView, osg::Matrixf()); } void operator()(osg::Node* node, osg::NodeVisitor* nv) override { osg::Matrixd MVP node-getMatrix() * nv-getViewMatrix() * nv-getProjectionMatrix(); osg::Matrixd MV node-getMatrix() * nv-getViewMatrix(); _uMVP-set(MVP); _uModelView-set(MV); traverse(node, nv); } }; ModelShaderLoader::ModelShaderLoader(QObject* parent) : QObject(parent) { } void ModelShaderLoader::setRenderEnv(RenderEnv env) { _renderEnv env; } osg::ref_ptrosg::Node ModelShaderLoader::loadModel(const std::string filePath, double scale) { osg::ref_ptrosg::Node modelNode osgDB::readNodeFile(filePath); if (!modelNode) { std::cerr [ModelShaderLoader] load model failed: filePath std::endl; return nullptr; } osg::ref_ptrosg::Program program new osg::Program; osg::ref_ptrMatrixUpdateCallback matrixCb; if (_renderEnv RenderEnv::ReadyMap) { std::cout [ModelShaderLoader] ReadyMap env, use osg_alias shader std::endl; program-addShader(new osg::Shader(osg::Shader::VERTEX, vertSrcReadyMap)); program-addShader(new osg::Shader(osg::Shader::FRAGMENT, fragSrcReadyMap)); program-addBindAttribLocation(osg_Vertex, 0); program-addBindAttribLocation(osg_MultiTexCoord0, 1); } else { std::cout [ModelShaderLoader] CesiumNative env, use core profile shader std::endl; program-addShader(new osg::Shader(osg::Shader::VERTEX, vertSrcCesium)); program-addShader(new osg::Shader(osg::Shader::FRAGMENT, fragSrcCesium)); matrixCb new MatrixUpdateCallback(); } // 遍历Geode挂载shader struct ApplyShaderVisitor : public osg::NodeVisitor { osg::Program* _prog; MatrixUpdateCallback* _mtxCb; ApplyShaderVisitor(osg::Program* p, MatrixUpdateCallback* cb) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), _prog(p), _mtxCb(cb) {} void apply(osg::Geode geode) override { for (unsigned int i 0; i geode.getNumDrawables(); i) { osg::Drawable* draw geode.getDrawable(i); osg::StateSet* ss draw-getOrCreateStateSet(); ss-setAttributeAndModes(_prog, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); ss-setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); ss-addUniform(new osg::Uniform(tex0, 0)); if (_mtxCb) { ss-addUniform(_mtxCb-_uMVP.get()); ss-addUniform(_mtxCb-_uModelView.get()); } } } }; ApplyShaderVisitor vis(program.get(), matrixCb.get()); modelNode-accept(vis); // 外层缩放节点 绑定矩阵回调Cesium环境 osg::ref_ptrosg::MatrixTransform scaleXform new osg::MatrixTransform; scaleXform-setMatrix(osg::Matrix::scale(osg::Vec3(scale, scale, scale))); scaleXform-addChild(modelNode.get()); if (matrixCb) { scaleXform-addUpdateCallback(matrixCb.get()); } return scaleXform; } // 1. CesiumNative开启GL3RealizeOperation auto loader new ModelShaderLoader(this); loader-setRenderEnv(ModelShaderLoader::RenderEnv::CesiumNative); auto modelNode loader-loadModel(xxx.obj, 1.0); // 2. ReadyMap不开启GL3RealizeOperation打开alias开关 auto loader new ModelShaderLoader(this); loader-setRenderEnv(ModelShaderLoader::RenderEnv::ReadyMap); auto modelNode loader-loadModel(xxx.obj, 1.0);

相关推荐

千兆以太网实际吞吐为何达不到125MB/s?帧结构与IFG开销深度解析
千兆以太网实际吞吐为何达不到125MB/s?帧结构与IFG开销深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 11:42:48

晶振相位噪声如何影响5G光模块误码率?原理、选型与布局实战
晶振相位噪声如何影响5G光模块误码率?原理、选型与布局实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 11:42:41

基于计算机视觉的交互式电子沙盘:激光定位与坐标转换实战解析
基于计算机视觉的交互式电子沙盘:激光定位与坐标转换实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 11:42:41

Python招聘数据分析与岗位推荐系统实战指南
Python招聘数据分析与岗位推荐系统实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:20:59

STM32串口控制张大头步进电机:从UART到角度误差的避坑指南
STM32串口控制张大头步进电机:从UART到角度误差的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:20:46

K3s+Helm构建企业数字人平台的工程化部署实践
K3s+Helm构建企业数字人平台的工程化部署实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:20:46

告别Modelsim命令行:VSCode+HDL Checker实现Verilog实时语法检查
告别Modelsim命令行:VSCode+HDL Checker实现Verilog实时语法检查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:20:46

边缘计算控制器如何解决工业现场传统方案的三大痛点
边缘计算控制器如何解决工业现场传统方案的三大痛点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:20:46

STM32H743+LVGL实战:MPU与SDRAM协同配置避坑指南
STM32H743+LVGL实战:MPU与SDRAM协同配置避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:20:46

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码