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

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)

http://www.xdnf.cn/news/10191.html

相关文章:

  • 【harbor】--harbor仓库部署
  • win32相关(临界区)
  • 免费且好用的PDF水印添加工具
  • 【图像处理入门】2. Python中OpenCV与Matplotlib的图像操作指南
  • 第304个Vulnhub靶场演练攻略:digital world.local:FALL
  • 考研系列—操作系统:第四章、文件管理(part.1)
  • 软件工程方法论:在确定性与不确定性的永恒之舞中寻找平衡
  • CSS专题之水平垂直居中
  • Unity3D仿星露谷物语开发58之保存时钟信息到文件
  • java 微服务中,微服务相互调用 feign 和flux 如何选择
  • 在 RK3588 上通过 VSCode 远程开发配置指南
  • 基础补充(扩展方法/协变)
  • 设计模式——建造者设计模式(创建型)
  • Spring Boot 自动参数校验
  • 基于大模型预测带状疱疹(无并发症)诊疗方案的研究报告
  • 基于图神经网络的自然语言处理:融合LangGraph与大型概念模型的情感分析实践
  • 每日c/c++题 备战蓝桥杯(P2240 【深基12.例1】部分背包问题)
  • Photoshop智能图层 vs 普通图层:核心差异与适用场景对比
  • 进程间通信(消息队列)
  • 11.21 LangGraph多轮对话系统实战:三步构建高效信息整理引擎,效率提升300%!
  • [9-3] 串口发送串口发送+接收 江协科技学习笔记(26个知识点)
  • STM32 串口通信①:USART 全面理解 + 代码详解
  • STL之vector
  • 前端面经 协商缓存和强缓存
  • 《数据结构初阶》【番外篇:二路归并的外排史诗】
  • Asp.Net Core SignalR的分布式部署
  • 力扣刷题(第四十三天)
  • AI书签管理工具开发全记录(七):页面编写与接口对接
  • 混沌映射(Chaotic Map)
  • MAC上怎么进入隐藏目录