当前位置: 首页 > news >正文

CloudCompare-源码分析-绘制与 3D 场景分离的“前景”元素

文章目录

    • ⭐ 核心功能概述
    • 🧩 详细分析
      • 1. 设置 2D 模式
      • 2. 配置绘制上下文
      • 3. 绘制主数据库中的 2D 实体
      • 4. 绘制颜色条(标量场)
      • 5. 绘制比例尺 & 三维坐标系(Trihedron)
      • 6. 绘制 GL 滤波器横幅
      • 7. 绘制消息文本
      • 8. 绘制 Clickable 区域
      • 9. LOD 进度图标动画
      • 10. 错误检查
    • 🔚 小结:函数作用定位


void ccGLWindowInterface::drawForeground(CC_DRAW_CONTEXT& CONTEXT, RenderingParams& renderingParams)
{ccQOpenGLFunctions* glFunc = functions();assert(glFunc);/****************************************//****  PASS: 2D/FOREGROUND/NO LIGHT  ****//****************************************/setStandardOrthoCenter();glFunc->glDisable(GL_DEPTH_TEST);CONTEXT.drawingFlags = CC_DRAW_2D | CC_DRAW_FOREGROUND;if (m_interactionFlags & INTERACT_TRANSFORM_ENTITIES){CONTEXT.drawingFlags |= CC_VIRTUAL_TRANS_ENABLED;}//we draw 2D entitiesif (m_globalDBRoot)m_globalDBRoot->draw(CONTEXT);if (m_winDBRoot)m_winDBRoot->draw(CONTEXT);//current displayed scalar field color ramp (if any)ccRenderingTools::DrawColorRamp(CONTEXT);m_clickableItems.clear();/*** overlay entities ***/{//default overlay colorconst ccColor::Rgbub& textCol = getDisplayParameters().textDefaultCol;if (!m_captureMode.enabled || m_captureMode.renderOverlayItems){//scale: only in ortho modeif (m_showScale && !m_viewportParams.perspectiveView){drawScale(textCol);}if (m_showTrihedron){//trihedrondrawTrihedron();}}if (!m_captureMode.enabled){int yStart = 0;//transparent border at the top of the screenbool showGLFilterRibbon = renderingParams.useFBO && m_activeGLFilter;showGLFilterRibbon &= !exclusiveFullScreen(); //we hide it in fullscreen mode!if (showGLFilterRibbon){const float w = glWidth() / 2.0f;const float h = glHeight() / 2.0f;const int borderHeight = getGlFilterBannerHeight();glFunc->glPushAttrib(GL_COLOR_BUFFER_BIT);glFunc->glEnable(GL_BLEND);glFunc->glColor4f(1.0f, 1.0f, 0.0f, 0.6f);glFunc->glBegin(GL_QUADS);glFunc->glVertex2f(w, h);glFunc->glVertex2f(-w, h);glFunc->glVertex2f(-w, h - borderHeight);glFunc->glVertex2f(w, h - borderHeight);glFunc->glEnd();glFunc->glPopAttrib(); //GL_COLOR_BUFFER_BITauto devicePixelRatio = getDevicePixelRatio();QFont newFont;newFont.setPointSize(static_cast<int>(newFont.pointSizeF() * getDevicePixelRatio()));glColor4ubv_safe<ccQOpenGLFunctions>(glFunc, ccColor::black);renderText(	static_cast<int>(10 * devicePixelRatio),borderHeight - static_cast<int>((CC_GL_FILTER_BANNER_MARGIN - CC_GL_FILTER_BANNER_MARGIN / 2) * devicePixelRatio),QString("[GL filter] ") + m_activeGLFilter->getDescription(),static_cast<uint16_t>(RenderTextReservedIDs::GLFilterLabel),newFont);yStart += borderHeight;}//current messages (if valid)if (!m_messagesToDisplay.empty()){glColor3ubv_safe<ccQOpenGLFunctions>(glFunc, textCol);int ll_currentHeight = glHeight() - 10; //lower leftint uc_currentHeight = 10; //upper centerQFont font = getTextDisplayFont();for (const auto& message : m_messagesToDisplay){uint16_t textureID = 0;if (message.type != CUSTOM_MESSAGE){textureID = static_cast<uint16_t>(RenderTextReservedIDs::StandardMessagePrefix) + static_cast<uint16_t>(message.type);}switch (message.position){case LOWER_LEFT_MESSAGE:{renderText(10, ll_currentHeight, message.message, textureID, font);int messageHeight = QFontMetrics(font).height();ll_currentHeight -= (messageHeight * 5) / 4; //add a 25% margin}break;case UPPER_CENTER_MESSAGE:{QRect rect = QFontMetrics(font).boundingRect(message.message);//take the GL filter banner into account!int x = (glWidth() - rect.width()) / 2;int y = uc_currentHeight + rect.height();if (showGLFilterRibbon){y += getGlFilterBannerHeight();}renderText(x, y, message.message, textureID, font);uc_currentHeight += (rect.height() * 5) / 4; //add a 25% margin}break;case SCREEN_CENTER_MESSAGE:{QFont newFont(font); //no need to take zoom into account!newFont.setPointSize(static_cast<int>(12 * getDevicePixelRatio()));QRect rect = QFontMetrics(newFont).boundingRect(message.message);//only one message supported in the screen center (for the moment ;)renderText((glWidth() - rect.width()) / 2, (glHeight() - rect.height()) / 2, message.message, textureID, newFont);}break;}}}//hot-zone{drawClickableItems(0, yStart);}if (renderingParams.nextLODState.inProgress){renderingParams.nextLODState.progressIndicator++;//draw LOD in progress 'icon'static const int lodIconSize = 32;static const int margin = 6;static const unsigned lodIconParts = 12;static const float lodPartsRadius = 3.0f;int x = margin;yStart += margin;static const float radius = lodIconSize / 2.0f - lodPartsRadius;static const float alpha = static_cast<float>((2 * M_PI) / lodIconParts);int cx = x + lodIconSize / 2 - glWidth() / 2;int cy = glHeight() / 2 - (yStart + lodIconSize / 2);glFunc->glPushAttrib(GL_POINT_BIT | GL_DEPTH_BUFFER_BIT);glFunc->glPointSize(lodPartsRadius);glFunc->glEnable(GL_POINT_SMOOTH);glFunc->glDisable(GL_DEPTH_TEST);//draw spinning circlesglFunc->glBegin(GL_POINTS);for (unsigned i = 0; i < lodIconParts; ++i){float intensity = static_cast<float>((i + renderingParams.nextLODState.progressIndicator) % lodIconParts) / (lodIconParts - 1);intensity /= ccColor::MAX;float col[3] = { textCol.rgb[0] * intensity,textCol.rgb[1] * intensity,textCol.rgb[2] * intensity };glFunc->glColor3fv(col);glFunc->glVertex3f(cx + radius * std::cos(i*alpha), cy + radius * std::sin(i*alpha), 0);}glFunc->glEnd();glFunc->glPopAttrib(); //GL_POINT_BIT | GL_DEPTH_BUFFER_BITyStart += lodIconSize + margin;}}}logGLError("ccGLWindow::drawForeground");
}

这个函数 ccGLWindowInterface::drawForeground 是 CloudCompare 中用于在 OpenGL 窗口前景层绘制 2D 图形、提示、比例尺、轴、进度指示器等 UI 元素的重要函数之一。它通常在每帧渲染后执行,用于绘制与 3D 场景分离的“前景”元素,如 HUD 信息。


⭐ 核心功能概述

该函数的主要职责是:

  1. 设置 2D 正交投影和禁用深度测试

  2. 绘制前景中的 2D 实体(如数据库实体、颜色条、点击区域等)。

  3. 绘制辅助 UI 元素

    • 比例尺 drawScale
    • 三维坐标系 drawTrihedron
    • 消息提示文字(底部左侧/顶部中间/屏幕中心)
    • 当前激活的 GL 滤波器横幅
    • LOD(多层细节)加载图标动画
    • Clickable 热区

🧩 详细分析

1. 设置 2D 模式

setStandardOrthoCenter();
glFunc->glDisable(GL_DEPTH_TEST);
  • 设置正交投影,使后续绘制在屏幕空间(2D 层)进行。
  • 关闭深度测试,避免 UI 被 3D 对象遮挡。

2. 配置绘制上下文

CONTEXT.drawingFlags = CC_DRAW_2D | CC_DRAW_FOREGROUND;
if (m_interactionFlags & INTERACT_TRANSFORM_ENTITIES)
{CONTEXT.drawingFlags |= CC_VIRTUAL_TRANS_ENABLED;
}
  • 设置绘制标志,指示当前是“前景层 2D 绘制”。
  • 如果当前处于实体变换交互模式,则启用虚拟变换标志。

3. 绘制主数据库中的 2D 实体

if (m_globalDBRoot)m_globalDBRoot->draw(CONTEXT);
if (m_winDBRoot)m_winDBRoot->draw(CONTEXT);
  • 对全局和窗口级别的数据库根节点调用 draw,让其以 2D 模式绘制相关 UI(如注释、文本等)。

4. 绘制颜色条(标量场)

ccRenderingTools::DrawColorRamp(CONTEXT);
  • 如果启用了标量场(Scalar Field),则绘制颜色条 UI。

5. 绘制比例尺 & 三维坐标系(Trihedron)

if (m_showScale && !m_viewportParams.perspectiveView)drawScale(textCol);if (m_showTrihedron)drawTrihedron();
  • 比例尺只在正交视图下绘制。
  • 三维坐标系三棱锥在所有模式下都可以绘制。

6. 绘制 GL 滤波器横幅

if (showGLFilterRibbon)
{// 黄色半透明矩形横幅 + 黑色文字renderText(..., "[GL filter] " + m_activeGLFilter->getDescription());
}
  • 用于提示当前启用的 OpenGL 滤波器,如 SSAO、模糊等。
  • 支持 Retina/高分屏的像素比处理(getDevicePixelRatio)。

7. 绘制消息文本

for (const auto& message : m_messagesToDisplay)
{switch (message.position){case LOWER_LEFT_MESSAGE:case UPPER_CENTER_MESSAGE:case SCREEN_CENTER_MESSAGE:}
}
  • 支持三类位置:

    • 左下角:多条消息垂直堆叠。
    • 顶部居中:考虑 GL 滤波器横幅的高度。
    • 屏幕中央:一般只允许显示一条提示,字体更大。

8. 绘制 Clickable 区域

drawClickableItems(0, yStart);
  • 为 UI 热区做准备,例如右键菜单、拾取区域、图标等。

9. LOD 进度图标动画

if (renderingParams.nextLODState.inProgress)
{// 动态圆圈指示器(转圈)
}
  • 当 LOD 加载进行中,绘制一个 12 个点组成的动态转圈效果。
  • 每次调用自增 progressIndicator 实现动画帧切换。
  • 使用 glBegin(GL_POINTS) 绘制。

10. 错误检查

logGLError("ccGLWindow::drawForeground");
  • 输出 OpenGL 错误(如有),便于调试。

🔚 小结:函数作用定位

这个函数是 CloudCompare 渲染架构中一个典型的“前景层渲染”函数:

类别内容
📌 作用绘制与主渲染内容(3D)分离的 2D UI 元素
🔁 调用频率每帧调用
🔧 接口类型内部私有/受控调用(非直接外部接口)
🧱 渲染内容比例尺、坐标系、标量条、状态消息、交互提示、LOD 图标等
📐 投影模式正交(2D)

相关文章:

  • Remote Sensing投稿记录(投稿邮箱写错、申请大修延期...)风雨波折投稿路
  • 澄清 STM32 NVIC 中断优先级
  • simulink mask的使用技巧
  • SQL进阶之旅 Day 9:高级索引策略
  • C++ 命令模式:设计与实现详解
  • SOC-ESP32S3部分:22-分区表
  • AutoML详解:自动化机器学习的未来
  • GitHub 汉化插件,GitHub 中文化界面安装全教程
  • Git -> Git Stash临时保存当前工程分支修改
  • 计算机组成原理第5章 中央处理器 (CPU)(竟成)
  • LG P4119 [Ynoi2018] 未来日记 Solution
  • Spring Boot 自动参数校验
  • Mistral 推出全新开发者平台Agents API
  • AE 脚本表达式错误 Default ColorSelectionwhile (true){ break;} }
  • 10000+套PPT模版合集和简历模版 【多种系列风格】免费下载
  • Java对象克隆:从浅到深的奥秘
  • 最卸载器——Geek Uninstaller 使用指南
  • [SC]SystemC在CPU/GPU验证中的应用(三)
  • 79. 单词搜索-极致优化,可行性剪枝和顺序剪枝
  • L56.【LeetCode题解】 电话号码的字母组合
  • 中国建设银行网站密码/小说网站排名前十
  • 网页制作与网站建设期末考试/大型网站建设平台
  • 网站不同/江苏网站seo
  • 微信网站可以免费做么/广州百度关键词排名
  • 商务网站的主要存在形式/商丘seo教程
  • 哪个网站可以做加工代理的/太原网站制作推广