Files
tactileipc3d/BACKGROUND_GRID.md
2025-12-18 09:19:39 +08:00

4.0 KiB
Raw Blame History

屏幕空间背景(白底 + 灰色网格线)说明

这份文档解释项目里新增的“3D 软件常见的白色背景 + 灰色分割线网格”是怎么实现的,以及如何调整效果。

需求点:

  • 背景看起来更“科技感”(轻微渐变 + 网格线 + vignette
  • 背景不随相机旋转(不受 yaw/pitch/zoom 影响)

实现方式概览(为什么它不会旋转)

我们采用“屏幕空间screen-space”绘制方式

  1. 画一个全屏 quad(两个三角形),顶点坐标直接写在裁剪空间 NDC[-1,1]
  2. fragment shader 使用 gl_FragCoord(屏幕像素坐标)生成网格线

由于整个背景是直接画在屏幕坐标系里,不使用 uMVP,所以它不会跟着相机旋转或移动。


关键文件

  • 资源注册:resources.qrc
    • 新增:shaders/bg.vertshaders/bg.frag
  • Shader
    • shaders/bg.vert:全屏 quad 的顶点 shader裁剪空间直出
    • shaders/bg.frag:背景颜色 + 抗锯齿网格线(基于 gl_FragCoord
  • C++OpenGLWidget
    • src/glwidget.h:新增 m_bgProgm_bgVao/m_bgVboinitBackgroundGeometry_()
    • src/glwidget.cpp
      • GLWidget::initPrograms_():编译/链接背景 program
      • GLWidget::initBackgroundGeometry_():创建全屏 quad VAO/VBO
      • GLWidget::paintGL():先画背景(关闭深度写入),再画 3D 内容

渲染顺序(为什么不会影响 3D 深度)

背景绘制发生在 GLWidget::paintGL() 的最前面:

  1. glClear(...) 清空颜色/深度
  2. 绘制背景(屏幕空间)
    • glDisable(GL_DEPTH_TEST);
    • glDepthMask(GL_FALSE);(不写深度)
  3. 恢复深度状态
    • glDepthMask(GL_TRUE);
    • glEnable(GL_DEPTH_TEST);
  4. 再绘制 panel / dots正常 3D 深度测试)

因此:背景永远在最底层,而且不会把深度缓冲弄脏。


全屏 quad背景几何

GLWidget::initBackgroundGeometry_() 创建一个覆盖整个屏幕的矩形(两个三角形):

  • 顶点坐标是 NDC裁剪空间
    • (-1,-1) 到 (1,1)
  • 顶点 shadershaders/bg.vert)仅仅把它输出到 gl_Position

这样不需要任何相机矩阵,也不会“跟着相机”动。


网格线怎么画出来的bg.frag

shaders/bg.frag 主要做了三件事:

1) 背景渐变底色

  • 使用 uv = gl_FragCoord.xy / uViewport 得到 0..1 的屏幕坐标
  • 在 y 方向做一个轻微渐变(上更亮、下稍灰)

2) 细网格 + 粗网格(分割线)

uMinorStep / uMajorStep(单位:像素)控制网格间距:

  • uMinorStep:细分格子(更淡)
  • uMajorStep:粗分格子(更明显)

网格线本质是对 fract(coord / step) 做“距离最近线”的计算,然后用 fwidth 做抗锯齿:

  • fwidth 会随着屏幕像素密度和视角变化自动调整边缘过渡,避免锯齿

3) 轻微 vignette

四角略暗、中心略亮,让画面更聚焦、更像 3D 软件视口。


HiDPI 注意点(为什么要乘 devicePixelRatio

Qt 的 width()/height() 是“逻辑像素”;而 gl_FragCoord 是“物理像素”。

所以背景在 C++ 里传入:

  • uViewport = (width * dpr, height * dpr)
  • 网格 step 也乘 dpr

否则在高 DPI 屏幕上网格会显得“变密/变粗”。


如何调整外观(常用参数)

调整网格密度

src/glwidget.cpp 里设置了:

  • uMinorStep = 24 px(细线间距)
  • uMajorStep = 120 px(粗线间距)

改这两个值就能让网格更密/更稀。

调整颜色/强度/科技感

shaders/bg.frag 里可以改:

  • topCol/botCol:背景渐变颜色
  • minorCol/majorCol:网格线颜色
  • mix(...) 的系数:线条深浅
  • vignette 强度:dot(p,p) 前面的系数

可选增强(如果你想更像 Blender/Unity

  • 加“坐标轴线”X 红、Z 蓝或灰色加深)并在中心画十字
  • 增加 UI 开关:显示/隐藏网格、调 step、调强度
  • 增加“地平线”或 “ground plane” 的淡淡雾化效果