181 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			181 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								---
							 | 
						|||
| 
								 | 
							
								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. 开启BlendMode,gl.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)
							 | 
						|||
| 
								 | 
							
								```
							 |