BlueRoseNote/03-UnrealEngine/Rendering/AIGC/GaussianSplattingViewer.md

181 lines
7.5 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: GaussianSplattingViewer
date: 2023-12-29 19:35:16
excerpt:
tags:
rating: ⭐
---
# 前言
- https://github.com/limacv/GaussianSplattingViewer
使用GLFW创建的程序。
# main.py
主要逻辑位于main()中,大致逻辑如下:
1. 获取前文设置的全部变量。
2. 创建imgui用于控制变量。
3. 创建GLFW渲染窗口**windows**。
4. 调用**imgui.integrations.glfw**中的**GlfwRenderer**,并且将结果渲染到这个**windows**中。
5. 获取tk(tkinter)并且赋值给root之后调用withdraw()。应该是用于绘制选择文件窗口的。
6. 绑定glfw的set_cursor_pos_callback、set_mouse_button_callback、set_scroll_callback、set_key_callback、set_window_size_callback事件。
7. 创建**renderer_ogl**的**OpenGLRenderer**渲染器对象并将其加入g_renderer_list全局渲染器列表。
8. 创建**renderer_cuda**的**CUDARenderer**渲染器对象如果成功将其加入g_renderer_list全局渲染器列表。
9. 按照之前设置的渲染器index选择用于渲染的渲染器并赋值给**g_renderer**。
10. 高斯数据处理
1. gaussians = util_gau.naive_gaussian(),创建写死的高斯数据。
2. update_activated_renderer_state(gaussians)
11. 开始进入渲染循环
1. 调用glfw、GlfwRenderer、imgui循环相关函数。
2. 清屏。
3. 更新摄像机Location & Intrin。
4. imgui菜单控制逻辑。调整各种参数、打开Ply点云文件。**载入逻辑位于util_gau.py的load_ply()**
1. 文件载入之后会进行一次高斯数据更新update_gaussian_data()以及排序sort_and_update()
5. 摄像机更新。
6. 缩放更新。
7. 如果修改了Shading则更新渲染模式set_render_mod()
8. 如果点击了sort Gaussians按钮则进行一次排序sort_and_update()
9. 如果勾选了g_auto_sort则进行一次排序sort_and_update()
10. 保存图片按钮逻辑。
11. imgui、GlfwRenderer渲染函数调用glfw更换前后缓存。
## 渲染器函数
### renderer_ogl.py
> 渲染模式为:"Gaussian Ball", "Billboard", "Depth", "SH:0", "SH:0~1", "SH:0~2", "SH:0~3 (default)。
`_sort_gaussian`
```python
def _sort_gaussian(gaus: util_gau.GaussianData, view_mat):
xyz = gaus.xyz
xyz_view = view_mat[None, :3, :3] @ xyz[..., None] + view_mat[None, :3, 3, None]
depth = xyz_view[:, 2, 0]
index = np.argsort(depth)
index = index.astype(np.int32).reshape(-1, 1)
return index
```
`__init__`
1. 载入Shader。
2. 定义面片顶点数据。
3. 设置属性通道为Position并将顶点数据塞入VAO。
4. 设置渲染属性:
1. 禁用剔除。
2. 开启BlendModegl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA。也就是线性插值。
`update_gaussian_data`
1. 传入当前高斯数据。
2. 调用下面的flat函数赋值给gaussian_data。
3. 传递vao、buffer_id、gaussian_data、bind_idx到Shader中。
4. 调用 `util.set_uniform_1int(self.program, gaus.sh_dim, "sh_dim")`
`sort_and_update`排序并且更新Shader中的数据。
`draw`:绘制函数。
1. 传递VAO点云数据数组到VertexShader。
2. 取得点云数。
3. 绘制与点云数目一样多的面片Instance。
```python
def flat(self) -> np.ndarray:
ret = np.concatenate([self.xyz, self.rot, self.scale, self.opacity, self.sh], axis=-1)
return np.ascontiguousarray(ret)
```
#### VertexShader
1. 根据gl_InstanceID、total_dim计算当前面片Instance的点云数据开始index。
2. 根据开始index从g_data[]取得g_pos数据并且转换成屏幕空间坐标。
3. 执行early culling。将不在屏幕内的点云数据都塞到Vec4(-100, -100, -100,1)。
4. 根据开始index从g_data[]取得g_rot。
5. 根据开始index从g_data[]取得g_scale。
6. 根据开始index从g_data[]取得g_opacity。
7. 调用computeCov3D() => computeCov2D(),计算协方差矩阵。
```c++
mat3 cov3d = computeCov3D(g_scale * scale_modifier, g_rot);
vec2 wh = 2 * hfovxy_focal.xy * hfovxy_focal.z;
vec3 cov2d = computeCov2D(g_pos_view,
hfovxy_focal.z,
hfovxy_focal.z,
hfovxy_focal.x,
hfovxy_focal.y,
cov3d,
view_matrix);
// Invert covariance (EWA algorithm)
float det = (cov2d.x * cov2d.z - cov2d.y * cov2d.y);
if (det == 0.0f)
gl_Position = vec4(0.f, 0.f, 0.f, 0.f);
float det_inv = 1.f / det;
conic = vec3(cov2d.z * det_inv, -cov2d.y * det_inv, cov2d.x * det_inv);
vec2 quadwh_scr = vec2(3.f * sqrt(cov2d.x), 3.f * sqrt(cov2d.z)); // screen space half quad height and width
vec2 quadwh_ndc = quadwh_scr / wh * 2; // in ndc space
g_pos_screen.xy = g_pos_screen.xy + position * quadwh_ndc;
coordxy = position * quadwh_scr;
gl_Position = g_pos_screen;
```
8. alpha = g_opacity;
9. if (render_mod == -1)则计算深度最后输出color为1/Depth的灰度值。"Depth"渲染模式。
```c++
// Covert SH to color
int sh_start = start + SH_IDX;
vec3 dir = g_pos.xyz - cam_pos;
dir = normalize(dir);
color = SH_C0 * get_vec3(sh_start);
if (sh_dim > 3 && render_mod >= 1) // 1 * 3
{
float x = dir.x;
float y = dir.y;
float z = dir.z;
color = color - SH_C1 * y * get_vec3(sh_start + 1 * 3) + SH_C1 * z * get_vec3(sh_start + 2 * 3) - SH_C1 * x * get_vec3(sh_start + 3 * 3);
if (sh_dim > 12 && render_mod >= 2) // (1 + 3) * 3
{
float xx = x * x, yy = y * y, zz = z * z;
float xy = x * y, yz = y * z, xz = x * z;
color = color +
SH_C2_0 * xy * get_vec3(sh_start + 4 * 3) +
SH_C2_1 * yz * get_vec3(sh_start + 5 * 3) +
SH_C2_2 * (2.0f * zz - xx - yy) * get_vec3(sh_start + 6 * 3) +
SH_C2_3 * xz * get_vec3(sh_start + 7 * 3) +
SH_C2_4 * (xx - yy) * get_vec3(sh_start + 8 * 3);
if (sh_dim > 27 && render_mod >= 3) // (1 + 3 + 5) * 3
{
color = color +
SH_C3_0 * y * (3.0f * xx - yy) * get_vec3(sh_start + 9 * 3) +
SH_C3_1 * xy * z * get_vec3(sh_start + 10 * 3) +
SH_C3_2 * y * (4.0f * zz - xx - yy) * get_vec3(sh_start + 11 * 3) +
SH_C3_3 * z * (2.0f * zz - 3.0f * xx - 3.0f * yy) * get_vec3(sh_start + 12 * 3) +
SH_C3_4 * x * (4.0f * zz - xx - yy) * get_vec3(sh_start + 13 * 3) +
SH_C3_5 * z * (xx - yy) * get_vec3(sh_start + 14 * 3) +
SH_C3_6 * x * (xx - 3.0f * yy) * get_vec3(sh_start + 15 * 3);
}
}
}
color += 0.5f;
```
#### PixelShader
1.  if (render_mod == -2)则直接显示当前颜色,并且结束渲染。"Billboard"渲染模式
2. 计算`power = -0.5f * (conic.x * coordxy.x * coordxy.x + conic.z * coordxy.y * coordxy.y) - conic.y * coordxy.x * coordxy.y;`丢弃power大于0的像素。
3. 计算float opacity = `min(0.99f, alpha * exp(power))`;丢弃opacity小于1/255的像素。
4. FragColor = vec4(color, opacity);
5.  if (render_mod == -3)则将透明度低于0.22的像素都隐藏。"Gaussian Ball"渲染模式
"Depth", "SH:0", "SH:0~1", "SH:0~2", "SH:0~3 (default)。
### renderer_cuda.py
## 相关函数
**update_activated_renderer_state**:更新渲染器状态。包括更新**高斯数据**、**摄像机缩放&高斯点云排序**、摄像机位移、渲染比例、渲染Mode。
```python
def update_activated_renderer_state(gaus: util_gau.GaussianData):
    g_renderer.update_gaussian_data(gaus)
    g_renderer.sort_and_update(g_camera)
    g_renderer.set_scale_modifier(g_scale_modifier)
    g_renderer.set_render_mod(g_render_mode - 3)
    g_renderer.update_camera_pose(g_camera)
    g_renderer.update_camera_intrin(g_camera)
    g_renderer.set_render_reso(g_camera.w, g_camera.h)
```