diff --git a/xml_editor/view/opengl_view.py b/xml_editor/view/opengl_view.py index 6416c24..b9b53b5 100644 --- a/xml_editor/view/opengl_view.py +++ b/xml_editor/view/opengl_view.py @@ -5,7 +5,7 @@ """ from PyQt5.QtWidgets import QOpenGLWidget, QSizePolicy -from PyQt5.QtCore import Qt, QSize, QPoint, pyqtSignal +from PyQt5.QtCore import Qt, QSize, QPoint, pyqtSignal, QTimer from PyQt5.QtGui import QMouseEvent, QWheelEvent, QKeyEvent import numpy as np @@ -28,6 +28,14 @@ print(f"警告: 无法初始化GLUT: {e}") raise e +# yc +# 添加 DISCOVERSE 项目的根目录到 sys.path +sys.path.append(os.path.abspath('/root/DISCOVERSE')) +# 导入 GSRenderer +from discoverse.gaussian_renderer.gsRenderer import GSRenderer +# import cv2 as cv +# import os + class OpenGLView(QOpenGLWidget): """ OpenGL视图类 @@ -66,6 +74,10 @@ def __init__(self, scene_viewmodel: SceneViewModel, parent=None): self._camera_rotation_x = 30.0 # 俯仰角 self._camera_rotation_y = -45.0 # 偏航角 self._camera_target = np.array([0.0, 0.0, 0.0]) + # self._camera_distance = 9.0 + # self._camera_rotation_x = 10.0 # 俯仰角 + # self._camera_rotation_y = -24.0 # 偏航角 + # self._camera_target = np.array([2.12316528 ,4.76870729 ,-0.36]) # 连接信号 self._scene_viewmodel.geometriesChanged.connect(self.update) @@ -99,6 +111,23 @@ def __init__(self, scene_viewmodel: SceneViewModel, parent=None): # 拖拽预览数据 self.drag_preview = {'active': False, 'position': None, 'type': None} + # yc 初始化gaussian renderer, 设置高斯背景ply + self.model_dict = {"background":"lobby2kfc.ply"} + self.gs_renderer = GSRenderer(self.model_dict, self.width(), self.height()) + self.index = 0 + + # # 为了动画效果 + # self.animation_dir = "/home/yuchi/renders" + # self.mask_dir = "/home/yuchi/renders_mask" + # self.target_fps = 30 + # self.num_frames = 150 + # self.frame_index = 0 + # self.animation = False + # self.animation_imgs = [] + # self.masks = [] + # self._timer = QTimer(self) + # self._timer.timeout.connect(self._on_click) + def minimumSizeHint(self): """返回建议的最小尺寸""" return QSize(200, 150) @@ -128,8 +157,62 @@ def initializeGL(self): def resizeGL(self, width, height): """处理窗口大小变化事件""" glViewport(0, 0, width, height) + # yc 高斯渲染的分辨率跟GL保持一致 + self.gs_renderer.set_camera_resolution(height,width) self._update_projection(width, height) + + + # yc 得到高斯渲染结果 numpy数组 + def get_gs_result(self): + self.gs_renderer.renderer.update_camera_pose(self.gs_renderer.camera) + return self.gs_renderer.render() + def initialize_gs_texture(self, width, height): + """初始化 gs 纹理(或重新分配尺寸)""" + if not hasattr(self, "gs_texture"): + # 第一次创建 + self.gs_texture = glGenTextures(1) + + glBindTexture(GL_TEXTURE_2D, self.gs_texture) + glPixelStorei(GL_UNPACK_ALIGNMENT, 1) # 关键:解决 RGB 对齐问题 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + # 分配新的纹理内存(RGB, uint8) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, + GL_RGB, GL_UNSIGNED_BYTE, None) + glBindTexture(GL_TEXTURE_2D, 0) + + # 记录当前纹理尺寸 + self.gs_tex_width = width + self.gs_tex_height = height + + # def start_animation(self): + # """点击按钮后调用:预加载图片并以30FPS播放150帧""" + # self.animation_imgs.clear() + # self.masks.clear() + # for i in range(self.num_frames): + # image = cv.imread(os.path.join(self.animation_dir, f"frame_{int(i):06d}.png")) + # image = cv.cvtColor(image, cv.COLOR_BGR2RGB) + # mask = cv.imread(os.path.join(self.mask_dir, f"frame_{int(i):06d}_mask.png")) + # self.animation_imgs.append(image) + # self.masks.append(mask) + # self.animation = True + # self.frame_index = 0 + # self._timer.start(round(1000 / self.target_fps)) + # self.update() + + # def _on_click(self): + # """定时器回调:只负责触发重绘和收尾""" + # if not self.animation: + # self._timer.stop() + # return + # if self.frame_index >= self.num_frames: + # self.animation = False + # self._timer.stop() + # # self.finished.emit() + # return + # self.update() + def paintGL(self): """渲染场景""" # 清除缓冲区 @@ -175,11 +258,74 @@ def paintGL(self): glDisable(GL_DEPTH_TEST) self._draw_drag_preview() glEnable(GL_DEPTH_TEST) + + # ---- 2. 获取高斯渲染结果 ---- + gs_result = self.get_gs_result() + # cv.imwrite(f'./test.png', gs_result) + # if self.animation: + # img = self.animation_imgs[self.frame_index] + # mask = self.masks[self.frame_index] + # self.frame_index += 1 + # gs_result = np.where(mask.astype(bool), gs_result, img) + # if self.frame_index > self.num_frames-1: + # self.animation = False + # 垂直翻转,需要的话(openGL以左下角为原点) + gs_result = np.flipud(gs_result) + + + height,width,_ = gs_result.shape + print("gs shape",gs_result.shape) + + # ---- 3. 初始化/检查纹理尺寸 ---- + if (not hasattr(self, "gs_texture") or + width != getattr(self, "gs_tex_width", None) or + height != getattr(self, "gs_tex_height", None)): + self.initialize_gs_texture(width, height) + + # ---- 4. 更新纹理内容 ---- + glBindTexture(GL_TEXTURE_2D, self.gs_texture) + glPixelStorei(GL_UNPACK_ALIGNMENT, 1) # 确保对齐 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, + GL_RGB, GL_UNSIGNED_BYTE, gs_result) + + # ---- 5. 绘制全屏 Quad ---- + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + + glMatrixMode(GL_PROJECTION) + glPushMatrix() + glLoadIdentity() + glOrtho(0, 1, 0, 1, -1, 1) + + glMatrixMode(GL_MODELVIEW) + glPushMatrix() + glLoadIdentity() + + glEnable(GL_TEXTURE_2D) + glBindTexture(GL_TEXTURE_2D, self.gs_texture) + glColor4f(1, 1, 1, 0.6) # 半透明叠加 + + glBegin(GL_QUADS) + glTexCoord2f(0, 0); glVertex2f(0, 0) + glTexCoord2f(1, 0); glVertex2f(1, 0) + glTexCoord2f(1, 1); glVertex2f(1, 1) + glTexCoord2f(0, 1); glVertex2f(0, 1) + glEnd() + + glDisable(GL_TEXTURE_2D) + glDisable(GL_BLEND) + + glMatrixMode(GL_PROJECTION) + glPopMatrix() + glMatrixMode(GL_MODELVIEW) + glPopMatrix() + + glBindTexture(GL_TEXTURE_2D, 0) def _update_projection(self, width, height): """更新投影矩阵""" aspect = width / height if height > 0 else 1.0 - gluPerspective(45.0, aspect, 0.1, 100.0) + gluPerspective(60.17, aspect, 0.1, 100.0) def _update_camera_config(self): """更新摄像机配置到场景视图模型(基于Z轴向上的坐标系)""" @@ -209,6 +355,16 @@ def _update_camera_config(self): 'projection_matrix': projection_matrix, 'view_matrix': modelview_matrix }) + + # yc + # 更新高斯渲染的相机视角 + self.gs_renderer.camera.position = camera_position + self.gs_renderer.camera.target = self._camera_target + print("camera_position", camera_position) + print('target position',self._camera_target) + print('camera distance',self._camera_distance) + print('camera rotation x',self._camera_rotation_x) # 俯仰角 + print('camera_rotation_y',self._camera_rotation_y) # 偏航角 def _draw_grid(self): """绘制地面网格"""