first commit
This commit is contained in:
134
BACKGROUND_GRID.md
Normal file
134
BACKGROUND_GRID.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# 屏幕空间背景(白底 + 灰色网格线)说明
|
||||
|
||||
这份文档解释项目里新增的“3D 软件常见的白色背景 + 灰色分割线网格”是怎么实现的,以及如何调整效果。
|
||||
|
||||
需求点:
|
||||
|
||||
- 背景看起来更“科技感”(轻微渐变 + 网格线 + vignette)
|
||||
- **背景不随相机旋转**(不受 yaw/pitch/zoom 影响)
|
||||
|
||||
---
|
||||
|
||||
## 实现方式概览(为什么它不会旋转)
|
||||
|
||||
我们采用“屏幕空间(screen-space)”绘制方式:
|
||||
|
||||
1. **画一个全屏 quad**(两个三角形),顶点坐标直接写在裁剪空间 NDC([-1,1])
|
||||
2. fragment shader 使用 `gl_FragCoord`(屏幕像素坐标)生成网格线
|
||||
|
||||
由于整个背景是直接画在屏幕坐标系里,不使用 `uMVP`,所以它不会跟着相机旋转或移动。
|
||||
|
||||
---
|
||||
|
||||
## 关键文件
|
||||
|
||||
- 资源注册:`resources.qrc`
|
||||
- 新增:`shaders/bg.vert`、`shaders/bg.frag`
|
||||
- Shader:
|
||||
- `shaders/bg.vert`:全屏 quad 的顶点 shader(裁剪空间直出)
|
||||
- `shaders/bg.frag`:背景颜色 + 抗锯齿网格线(基于 `gl_FragCoord`)
|
||||
- C++(OpenGLWidget):
|
||||
- `src/glwidget.h`:新增 `m_bgProg`、`m_bgVao/m_bgVbo`、`initBackgroundGeometry_()`
|
||||
- `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)
|
||||
- 顶点 shader(`shaders/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” 的淡淡雾化效果
|
||||
|
||||
Reference in New Issue
Block a user