summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralonrubintec <alonrubintech@gmail.com>2023-01-31 23:45:31 +0200
committeralonrubintec <alonrubintech@gmail.com>2023-01-31 23:45:31 +0200
commitb982a82f137f3cf2184bf44d12e18fcc91f1c1ee (patch)
tree7dd3fa8f401562a9954b017da45d1bb8541eccfe
Initial commit
-rw-r--r--README.md39
-rw-r--r--arcball.py105
-rw-r--r--engine.py220
-rw-r--r--functions.py155
-rw-r--r--main.py67
-rw-r--r--resource/3DView02.ui1612
-rw-r--r--resource/app_preview.PNGbin0 -> 264211 bytes
-rw-r--r--resource/load.pngbin0 -> 1582 bytes
-rw-r--r--resource/shaders.py47
9 files changed, 2245 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7870222
--- /dev/null
+++ b/README.md
@@ -0,0 +1,39 @@
+## Qt 3DViewer
+### Qt 3DViewer is a compact tool for viewing 3D models in a user friendly way.
+
+<br>This project is a compact and user-friendly application designed to showcase
+<br>3D models in a visually appealing manner. With support for a wide range of
+<br>file formats including .obj, .stl, .ply, .off, and .om.
+
+Powered by Python the PyQt framework, the app use OpenGL, in combination
+<br>with ModernGL to render the 3D models and scenes in a interactive experience.
+<br>Designed and developed by Alon Rubin.
+
+
+
+### Movement:
+
+- Rotate: click and drag the <b>left mouse</b> button.
+- Pan: click and drag the <b>right mouse</b> button.
+- Zoom: use the <b>mouse wheel</b> to zoom in or out.
+
+### Watch a video demo:
+
+<a href="https://www.youtube.com/watch?v=ZwK2B9AODtw&ab_channel=ALONZUBINA" target="_blank">
+<img src="https://i.ytimg.com/an_webp/ZwK2B9AODtw/mqdefault_6s.webp?du=3000&sqp=CPzh5Z4G&rs=AOn4CLCFIgJwRNM3GbouU5iCmgl1I0AuDw" alt="Watch the series" width="340" height="180" border="10" />
+</a>
+
+### App preview:
+![Alt text](resource/app_preview.png "app_preview.png")
+
+### How to install:
+
+1. Install Python 3.9
+2. Install PyQt 5
+3. Import all the Libraries
+
+## Like this project?
+
+Check out other stuff that i make:
+<br>https://github.com/alonrubintec
+<br>https://www.artstation.com/alonzu
diff --git a/arcball.py b/arcball.py
new file mode 100644
index 0000000..be6759e
--- /dev/null
+++ b/arcball.py
@@ -0,0 +1,105 @@
+import numpy as np
+from scipy.spatial.transform import Rotation as R
+
+
+class ArcBall:
+ def __init__(self, NewWidth: float, NewHeight: float):
+ self.StVec = np.zeros(3, 'f4') # Saved click vector
+ self.EnVec = np.zeros(3, 'f4') # Saved drag vector
+ self.AdjustWidth = 0. # Mouse bounds width
+ self.AdjustHeight = 0. # Mouse bounds height
+ self.setBounds(NewWidth, NewHeight)
+ self.Epsilon = 1.0e-5
+
+ def setBounds(self, NewWidth: float, NewHeight: float):
+ assert((NewWidth > 1.0) and (NewHeight > 1.0))
+ # Set adjustment factor for width/height
+ self.AdjustWidth = 1.0 / ((NewWidth - 1.0) * 0.5)
+ self.AdjustHeight = 1.0 / ((NewHeight - 1.0) * 0.5)
+
+ def click(self, NewPt):
+ # Map the point to the sphere
+ self._mapToSphere(NewPt, self.StVec)
+
+ def drag(self, NewPt):
+ NewRot = np.zeros((4,), 'f4')
+ # Map the point to the sphere
+ self._mapToSphere(NewPt, self.EnVec)
+ Perp = np.cross(self.StVec, self.EnVec)
+ # Compute the length of the perpendicular vector
+ if np.linalg.norm(Perp) > self.Epsilon: # if its non-zero
+ NewRot[:3] = Perp[:3]
+ NewRot[3] = np.dot(self.StVec, self.EnVec)
+ else:
+ pass
+ return NewRot
+
+ def _mapToSphere(self, NewPt, NewVec):
+ TempPt = NewPt.copy()
+ TempPt[0] = (TempPt[0] * self.AdjustWidth) - 1.0
+ TempPt[1] = 1.0 - (TempPt[1] * self.AdjustHeight)
+ # center
+ length2 = np.dot(TempPt, TempPt)
+ if length2 > 1.0:
+ # Compute a normalizing factor
+ norm = 1.0 / np.sqrt(length2)
+ NewVec[0] = TempPt[0] * norm
+ NewVec[1] = TempPt[1] * norm
+ NewVec[2] = 0.0
+ else:
+ # Return a vector to a point mapped inside the sphere
+ NewVec[0] = TempPt[0]
+ NewVec[1] = TempPt[1]
+ NewVec[2] = np.sqrt(1.0 - length2)
+
+
+class ArcBallUtil(ArcBall):
+ def __init__(self, NewWidth: float, NewHeight: float):
+ self.Transform = np.identity(4, 'f4')
+ self.LastRot = np.identity(3, 'f4')
+ self.ThisRot = np.identity(3, 'f4')
+ self.isDragging = False
+ super().__init__(NewWidth, NewHeight)
+
+ def onDrag(self, cursor_x, cursor_y):
+ if self.isDragging:
+ mouse_pt = np.array([cursor_x, cursor_y], 'f4')
+ # Update End Vector And Get Rotation As Quaternion
+ self.ThisQuat = self.drag(mouse_pt)
+ self.ThisQuat[0] *= 0.5 # Reduce the influence of the vertical axis
+ self.ThisRot = self.Matrix3fSetRotationFromQuat4f(self.ThisQuat)
+ self.ThisRot = np.matmul(self.LastRot, self.ThisRot)
+ self.Transform = self.Matrix4fSetRotationFromMatrix3f(
+ self.Transform, self.ThisRot)
+ return
+
+ def resetRotation(self):
+ self.isDragging = False
+ self.LastRot = np.identity(3, 'f4')
+ self.ThisRot = np.identity(3, 'f4')
+ self.Transform = self.Matrix4fSetRotationFromMatrix3f(self.Transform,
+ self.ThisRot)
+
+ def onClickLeftUp(self):
+ self.isDragging = False
+ # Set Last Static Rotation To Last Dynamic One
+ self.LastRot = self.ThisRot.copy()
+
+ def onClickLeftDown(self, cursor_x: float, cursor_y: float):
+ self.LastRot = self.ThisRot.copy()
+ self.isDragging = True
+ mouse_pt = np.array([cursor_x, cursor_y], 'f4')
+ self.click(mouse_pt)
+ return
+
+ def Matrix4fSetRotationFromMatrix3f(self, NewObj, m3x3):
+ scale = np.linalg.norm(NewObj[:3, :3], ord='fro') / np.sqrt(3)
+ NewObj[0:3, 0:3] = m3x3 * scale
+ scaled_NewObj = NewObj
+ return scaled_NewObj
+
+ def Matrix3fSetRotationFromQuat4f(self, q1):
+ if np.sum(np.dot(q1, q1)) < self.Epsilon:
+ return np.identity(3, 'f4')
+ r = R.from_quat(q1)
+ return r.as_matrix().T
diff --git a/engine.py b/engine.py
new file mode 100644
index 0000000..4ffb1c9
--- /dev/null
+++ b/engine.py
@@ -0,0 +1,220 @@
+import numpy
+import moderngl
+import math
+
+from PyQt5 import QtOpenGL, QtCore
+from arcball import ArcBallUtil
+from pyrr import Matrix44
+from resource import shaders
+
+
+def grid(size, steps):
+ # Create grid parameters
+ u = numpy.repeat(numpy.linspace(-size, size, steps), 2)
+ v = numpy.tile([-size, size], steps)
+ w = numpy.zeros(steps * 2)
+ new_grid = numpy.concatenate([numpy.dstack([u, v, w]), numpy.dstack([v, u, w])])
+
+ # Rotate grid
+ lower_grid = 0.135
+ rotation_matrix = numpy.array([
+ [0, 0, 1],
+ [1, 0, 0],
+ [0, lower_grid, 0]
+ ])
+ return numpy.dot(new_grid, rotation_matrix)
+
+
+class QGLControllerWidget(QtOpenGL.QGLWidget):
+ def __init__(self, parent=None):
+ self.parent = parent
+ super(QGLControllerWidget, self).__init__(parent)
+
+ # Initialize OpenGL parameters
+ self.bg_color = (0.1, 0.1, 0.1, 0.1)
+ self.color_alpha = 1.0
+ self.new_color = (1.0, 1.0, 1.0, self.color_alpha)
+ self.fov = 60.0
+ self.camera_zoom = 2.0
+ self.setMouseTracking(True)
+ self.wheelEvent = self.update_zoom
+ self.is_wireframe = False
+ self.texture = None
+ self.cell = 50
+ self.size = 20
+ self.grid = grid(self.size, self.cell)
+ self.grid_alpha_value = 1.0
+
+ def initializeGL(self):
+ # Create a new OpenGL context
+ self.ctx = moderngl.create_context()
+
+ # Create the shader program
+ self.prog = self.ctx.program(
+ vertex_shader=shaders.vertex_shader,
+ fragment_shader=shaders.fragment_shader
+ )
+ self.set_scene()
+
+ def set_scene(self):
+ # Setting shader parameters
+ self.light = self.prog['Light']
+ self.color = self.prog['Color']
+ self.mvp = self.prog['Mvp']
+ self.prog["Texture"].value = 0
+ self.light.value = (1.0, 1.0, 1.0)
+ self.color.value = (1.0, 1.0, 1.0, 1.0)
+
+ # Setting mesh parameters
+ self.mesh = None
+ self.vbo = self.ctx.buffer(self.grid.astype('f4'))
+ self.vao2 = self.ctx.simple_vertex_array(self.prog, self.vbo, 'in_position')
+
+ # Setting ArcBall parameters
+ self.arc_ball = ArcBallUtil(self.width(), self.height())
+ self.center = numpy.zeros(3)
+ self.scale = 1.0
+
+ def paintGL(self):
+ # OpenGL loop
+ self.ctx.clear(*self.bg_color)
+ self.ctx.enable(moderngl.BLEND)
+ self.ctx.enable(moderngl.DEPTH_TEST | moderngl.CULL_FACE)
+ self.ctx.wireframe = self.is_wireframe
+ if self.mesh is None:
+ return
+
+ # Update projection matrix loop
+ self.aspect_ratio = self.width() / max(1.0, self.height())
+ proj = Matrix44.perspective_projection(self.fov, self.aspect_ratio, 0.1, 1000.0)
+ lookat = Matrix44.look_at(
+ (0.0, 0.0, self.camera_zoom),
+ (0.0, 0.0, 0.0),
+ (0.0, 1.0, 0.0),
+ )
+ self.arc_ball.Transform[3, :3] = -self.arc_ball.Transform[:3, :3].T @ self.center
+ self.mvp.write((proj * lookat * self.arc_ball.Transform).astype('f4'))
+
+ # Render mesh loop
+ self.color.value = self.new_color
+ self.vao.render()
+
+ # Render grid loop
+ self.color.value = (1.0, 1.0, 1.0, self.grid_alpha_value)
+ self.vao2.render(moderngl.LINES)
+ self.color.value = self.new_color
+
+ def set_mesh(self, new_mesh):
+ if new_mesh is None:
+ self.set_scene()
+ return
+ self.mesh = new_mesh
+ self.mesh.update_normals()
+
+ # Creates an index buffer
+ index_buffer = self.ctx.buffer(numpy.array(self.mesh.face_vertex_indices(), dtype="u4").tobytes())
+
+ # Creates a list of vertex buffer objects (VBOs)
+ vao_content = [(self.ctx.buffer(numpy.array(self.mesh.points(), dtype="f4").tobytes()), '3f', 'in_position'),
+ (self.ctx.buffer(numpy.array(self.mesh.vertex_normals(), dtype="f4").tobytes()), '3f', 'in_normal')]
+ self.vao = self.ctx.vertex_array(self.prog, vao_content, index_buffer, 4)
+ self.init_arcball()
+
+ def init_arcball(self):
+ # Create ArcBall
+ self.arc_ball = ArcBallUtil(self.width(), self.height())
+ mesh_points = self.mesh.points()
+ bounding_box_min = numpy.min(mesh_points, axis=0)
+ bounding_box_max = numpy.max(mesh_points, axis=0)
+ self.center = 0.5*(bounding_box_max+bounding_box_min)
+ self.scale = numpy.linalg.norm(bounding_box_max-self.center)
+ self.arc_ball.Transform[:3, :3] /= self.scale
+ self.arc_ball.Transform[3, :3] = -self.center/self.scale
+
+ # -------------- GUI interface --------------
+ def change_light_color(self, color, alpha=1):
+ color = color + (alpha,)
+ print(color)
+ self.color.value = color
+ self.new_color = color
+
+ def update_alpha(self, alpha):
+ self.color_alpha = (alpha*0.01)
+ color_list = list(self.new_color)
+ color_list[-1] = self.color_alpha
+ self.new_color = tuple(color_list)
+
+ def update_grid_alpha(self, alpha):
+ self.grid_alpha_value = (alpha*0.01)
+
+ def background_color(self, color):
+ self.bg_color = color = color
+
+ def update_fov(self, num):
+ self.fov = num
+ self.camera_zoom = self.camera_distance(num)
+ self.update()
+
+ def camera_distance(self, num):
+ return 1 / (math.tan(math.radians(num / 2)))
+
+ def update_grid_cell(self, cells):
+ self.cell = cells
+ self.grid = grid(self.size, self.cell)
+ self.update_grid()
+
+ def update_grid_size(self, size):
+ self.size = size
+ self.grid = grid(self.size, self.cell)
+ self.update_grid()
+
+ def update_grid(self):
+ self.vbo = self.ctx.buffer(self.grid.astype('f4'))
+ self.vao2 = self.ctx.simple_vertex_array(self.prog, self.vbo, 'in_position')
+
+ def resizeGL(self, width, height):
+ width = max(2, width)
+ height = max(2, height)
+ self.ctx.viewport = (0, 0, width, height)
+ self.arc_ball.setBounds(width, height)
+ return
+
+ def make_wireframe(self):
+ self.is_wireframe = True
+
+ def make_solid(self):
+ self.is_wireframe = False
+
+ # Input handling
+ def mousePressEvent(self, event):
+ if event.buttons() & QtCore.Qt.LeftButton:
+ self.arc_ball.onClickLeftDown(event.x(), event.y())
+ elif event.buttons() & QtCore.Qt.RightButton:
+ self.prev_x = event.x()
+ self.prev_y = event.y()
+
+ def mouseReleaseEvent(self, event):
+ if event.buttons() & QtCore.Qt.LeftButton:
+ self.arc_ball.onClickLeftUp()
+
+ def mouseMoveEvent(self, event):
+ if event.buttons() & QtCore.Qt.LeftButton:
+ self.arc_ball.onDrag(event.x(), event.y())
+
+ def update_zoom(self, event):
+ self.camera_zoom += event.angleDelta().y() * 0.001
+ if self.camera_zoom < 0.1:
+ self.camera_zoom = 0.1
+ self.update()
+
+ def mouseMoveEvent(self, event):
+ if event.buttons() & QtCore.Qt.LeftButton:
+ self.arc_ball.onDrag(event.x(), event.y())
+ elif event.buttons() & QtCore.Qt.RightButton:
+ x_movement = event.x() - self.prev_x
+ y_movement = event.y() - self.prev_y
+ self.center[0] -= x_movement * 0.01
+ self.center[1] += y_movement * 0.01
+ self.update()
+ self.prev_x = event.x()
+ self.prev_y = event.y() \ No newline at end of file
diff --git a/functions.py b/functions.py
new file mode 100644
index 0000000..043bc16
--- /dev/null
+++ b/functions.py
@@ -0,0 +1,155 @@
+from PyQt5.QtWidgets import QColorDialog, QMessageBox
+from PyQt5 import QtWidgets
+from OpenGL.GLUT import *
+import openmesh
+import re
+
+
+def open_file( opengl_obj, obj_path, obj_name, uv_label, material_label, drawcalls_label, vertices_label, triangles_label, edges_label):
+ file_name = QtWidgets.QFileDialog.getOpenFileName(
+ None, 'Open file', '', "Mesh files (*.obj *.stl *.ply *.off *.om)")
+ if not file_name[0]:
+ return
+ mesh = openmesh.read_trimesh(file_name[0])
+ opengl_obj.set_mesh(mesh)
+ set_name(file_name, obj_path, obj_name)
+ set_file_info(mesh, vertices_label, triangles_label, edges_label)
+
+ _, file_extension = os.path.splitext(file_name[0])
+ file_format = file_extension.replace(".", "")
+ if file_format == "obj":
+ has_uv(file_name[0], uv_label)
+ materials(file_name[0], material_label)
+ draw_calls(file_name[0], drawcalls_label)
+
+
+def set_name(file_name, obj_path, obj_name):
+ file_path = os.path.normpath(file_name[0])
+ ob_name = os.path.basename(file_name[0])
+ obj_path.setText(file_path)
+ obj_name.setText(ob_name)
+
+
+def set_file_info(mesh, vertices_label, triangles_label, edges_label):
+ vertex_count = mesh.n_vertices()
+ triangle_count = mesh.n_faces()
+ edges_count = mesh.n_edges()
+ vertices_label.setText(str(vertex_count))
+ triangles_label.setText(str(triangle_count))
+ edges_label.setText(str(edges_count))
+
+
+def has_uv(file_path, has_label):
+ with open(file_path, "r") as file:
+ contents = file.read()
+ if "vt" in contents:
+ has_label.setText(str("Yes"))
+ else:
+ has_label.setText(str("No"))
+
+
+def materials(file_path, material_label):
+ with open(file_path, "r") as file:
+ contents = file.read()
+ num = set(re.findall(r'usemtl (\S+)', contents))
+ material_label.setText(str(len(num)))
+
+
+def draw_calls(file_path, drawcalls_label):
+ with open(file_path, "r") as file:
+ contents = file.read()
+ draw = tuple(re.findall(r'usemtl (\S+)', contents))
+ if len(draw)>1:
+ drawcalls_label.setText(str(len(draw)))
+ else:
+ drawcalls_label.setText(str(1))
+
+
+def get_color(button, button_color, btn_name, openGL):
+ color_dialog = QColorDialog()
+ color = color_dialog.getColor()
+ if color.isValid():
+ r, g, b, a = color.getRgb()
+ color = f"rgb({r}, {g}, {b})"
+ button_color(button, color)
+ if btn_name == "background":
+ openGL.background_color((r / 255, g / 255, b / 255))
+ if btn_name == "wire":
+ openGL.change_light_color((r/255, g/255, b/255))
+
+
+def set_button_color(button, color):
+ button.setStyleSheet(f"background-color: {color};"
+ f"border-radius: 2px"
+ )
+
+
+def change_slider(slider, line, openGL, btn_name=""):
+ value = slider.value()
+ line.setText(str(value))
+ if btn_name == "fov":
+ value = slider.value()
+ openGL.update_fov(value)
+
+ if btn_name == "wireframe":
+ value = slider.value()
+ openGL.update_alpha(value)
+
+ if btn_name == "grid":
+ value = slider.value()
+ openGL.update_grid_alpha(value)
+
+
+def updateSlider(slider, line):
+ value = int(line.text())
+ slider.setValue(value)
+
+
+def update_grid_size(text, openGL, btn_name):
+ value = int(text.text())
+ if btn_name == "cell":
+ openGL.update_grid_cell(value)
+ if btn_name == "size":
+ openGL.update_grid_size(value)
+
+
+def close_file(openGL, obj_path, obj_name):
+ openGL.set_mesh(None)
+ obj_path.setText("")
+ obj_name.setText("")
+
+
+def show_message_box():
+ title = "About Qt 3DViewer"
+ message = "Qt 3DViewer is a compact tool for \n" \
+ "viewing 3D models in a user friendly way\n" \
+ "Designed and Developed by Alon Rubin.\n\n" \
+ "Powered by: Python 3.9, Qt Designer,\n " \
+ "PyQt5, OpenGL, OpenMesh and ModernGL.\n\n" \
+ "Movement:\n" \
+ "• Left mouse button to rotate\n" \
+ "• Mouse wheel to zoom\n" \
+ "• Right mouse button to pan."
+ msg = QMessageBox()
+ msg.setStyleSheet("""
+ QMessageBox {
+ background-color: rgb(56, 56, 56);
+ letter-spacing: 0.4cm;
+ font-size: 14px;
+ color: rgb(145, 145, 145);
+ }
+ width: 60px;
+ color: rgb(200, 200, 200);
+ background-color: rgb(56, 56, 56);
+ padding: 10px;
+ width: 60px;
+ """
+ )
+ msg.setWindowTitle(title)
+ msg.setText(message)
+ msg.setStandardButtons(QMessageBox.Close)
+ msg.exec_()
+
+
+def exit_app():
+ sys.exit() \ No newline at end of file
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..6d99a3c
--- /dev/null
+++ b/main.py
@@ -0,0 +1,67 @@
+from PyQt5 import QtWidgets, QtCore, uic
+from PyQt5.QtGui import QIcon
+from OpenGL.GLUT import *
+from engine import QGLControllerWidget
+import functions as f
+
+
+class MainWindow(QtWidgets.QMainWindow):
+ def __init__(self):
+ # Load UI file
+ QtWidgets.QMainWindow.__init__(self)
+ uic.loadUi("resource/3DView02.ui", self)
+
+ # Create openGL context
+ self.openGL = QGLControllerWidget(self)
+ self.openGL.setGeometry(0, 37, 870, 731)
+ timer = QtCore.QTimer(self)
+ timer.setInterval(20) # refresh speed in milliseconds
+ timer.timeout.connect(self.openGL.updateGL)
+ timer.start()
+
+ # Load button
+ load_icon = QIcon("resource/load.png")
+ self.load_button.setIcon(load_icon)
+
+ def load_file():
+ f.open_file(self.openGL, self.obj_path_label, self.obj_name_label, self.uv2_label, self.material_label,
+ self.drawcalls_label, self.vertices_label, self.triangles_label, self.edges_label)
+
+ self.load_button.clicked.connect(load_file)
+ self.actionLoad.triggered.connect(load_file)
+
+ # Menubar Buttons
+ self.actionQuit.triggered.connect(lambda: f.exit_app())
+ self.actionClose.triggered.connect(lambda: f.close_file(self.openGL, self.obj_path_label, self.obj_name_label))
+ self.actionAbout.triggered.connect(lambda: f.show_message_box())
+
+ # Buttons
+ self.wireframe_color.clicked.connect(lambda: f.get_color(self.wireframe_color, f.set_button_color, "wire", self.openGL))
+ self.background_color.clicked.connect(lambda: f.get_color(self.background_color, f.set_button_color, "background", self.openGL))
+
+ # Settings Sliders
+ self.fov_slider.valueChanged.connect(lambda: f.change_slider(self.fov_slider, self.fov_slider_value, self.openGL, "fov"))
+ self.fov_slider_value.textChanged.connect(lambda: f.updateSlider(self.fov_slider, self.fov_slider_value))
+ self.grid_slider.valueChanged.connect(lambda: f.change_slider(self.grid_slider, self.grid_slider_value, self.openGL, "na"))
+ self.grid_slider_value.textChanged.connect(lambda: f.updateSlider(self.grid_slider, self.grid_slider_value))
+
+ # Settings Sliders
+ self.wireframe_slider.valueChanged.connect(lambda: f.change_slider(self.wireframe_slider, self.wireframe_slider_value, self.openGL, "wireframe"))
+ self.wireframe_slider_value.textChanged.connect(lambda: f.updateSlider(self.wireframe_slider, self.wireframe_slider_value))
+
+ # Settings radio buttons
+ self.wireframe_radio.toggled.connect(lambda: self.openGL.make_wireframe())
+ self.solid_radio.toggled.connect(lambda: self.openGL.make_solid())
+
+ # Grid settings
+ self.grid_cell.textChanged.connect(lambda: f.update_grid_size(self.grid_cell, self.openGL, "cell"))
+ self.grid_size.textChanged.connect(lambda: f.update_grid_size(self.grid_size, self.openGL, "size"))
+ self.grid_slider.valueChanged.connect(lambda: f.change_slider(self.grid_slider, self.grid_slider_value, self.openGL, "grid"))
+ self.grid_slider_value.textChanged.connect(lambda: f.updateSlider(self.grid_slider, self.grid_slider_value))
+
+
+if __name__ == '__main__':
+ app = QtWidgets.QApplication(sys.argv)
+ win = MainWindow()
+ win.show()
+ sys.exit(app.exec_()) \ No newline at end of file
diff --git a/resource/3DView02.ui b/resource/3DView02.ui
new file mode 100644
index 0000000..68658a6
--- /dev/null
+++ b/resource/3DView02.ui
@@ -0,0 +1,1612 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1150</width>
+ <height>800</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>1150</width>
+ <height>800</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>1150</width>
+ <height>800</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Qt 3DViewer</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <widget class="QFrame" name="frame">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1150</width>
+ <height>800</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>1150</width>
+ <height>800</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(38, 38, 38);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <widget class="QOpenGLWidget" name="openGLWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>870</width>
+ <height>731</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QFrame" name="frame_2">
+ <property name="geometry">
+ <rect>
+ <x>871</x>
+ <y>0</y>
+ <width>275</width>
+ <height>50</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(45, 45, 45);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <widget class="QLabel" name="obj_name_label">
+ <property name="geometry">
+ <rect>
+ <x>50</x>
+ <y>10</y>
+ <width>211</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(210, 210, 210);</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="load_button">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>30</width>
+ <height>30</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>6</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QPushButton {
+background-color: rgb(56, 56, 56);
+border-radius: 2px
+}
+
+QPushButton:hover {
+background-color: rgb(65, 65, 65);
+border-radius: 2px
+}
+
+QPushButton:pressed {
+ background-color: rgb(50,50,50);
+}</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QTabWidget" name="tabWidget_2">
+ <property name="geometry">
+ <rect>
+ <x>870</x>
+ <y>50</y>
+ <width>279</width>
+ <height>681</height>
+ </rect>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>8</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QTabWidget::pane {
+ border: 1px solid lightgray;
+ border-color: rgb(38, 38, 38);
+ top:-1px;
+ background: rgb(245, 245, 245);
+}
+
+QTabBar::tab {
+ background: rgb(45, 45, 45);
+ color: rgb(128, 128, 128);
+ border: 1px solid lightgray;
+ border-color: rgb(38, 38, 38);
+ padding: 8px;
+ padding-left:49px;
+ padding-right: 49px;
+}
+QTabBar::tab:hover {
+ background: rgb(51, 51, 51);
+}
+QTabBar::tab:selected {
+ background: rgb(56, 56, 56);
+ color: rgb(210, 210, 210);
+}
+
+QTabWidget QStackedWidget &gt; QWidget {
+ background-color: rgb(56, 56, 56);
+}
+QTabBar {
+ font: 10pt &quot;Microsoft YaHei UI&quot;;
+ }</string>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab_1">
+ <attribute name="title">
+ <string>Data</string>
+ </attribute>
+ <widget class="QLabel" name="mesh_label">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>10</y>
+ <width>71</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(175, 175, 175);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Mesh</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_2">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>40</y>
+ <width>71</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Triangles</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="triangles_label">
+ <property name="geometry">
+ <rect>
+ <x>150</x>
+ <y>40</y>
+ <width>91</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="vertices_label">
+ <property name="geometry">
+ <rect>
+ <x>150</x>
+ <y>70</y>
+ <width>91</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_5">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>70</y>
+ <width>71</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Vertices</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="edges_label">
+ <property name="geometry">
+ <rect>
+ <x>150</x>
+ <y>100</y>
+ <width>91</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_7">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>130</y>
+ <width>101</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>UV coordinates</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="uv2_label">
+ <property name="geometry">
+ <rect>
+ <x>150</x>
+ <y>130</y>
+ <width>91</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>No</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="edges_label_test">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>100</y>
+ <width>71</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Edges</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="drawcalls_label">
+ <property name="geometry">
+ <rect>
+ <x>150</x>
+ <y>190</y>
+ <width>91</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>1</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_11">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>160</y>
+ <width>101</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Material IDS</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="material_label">
+ <property name="geometry">
+ <rect>
+ <x>150</x>
+ <y>160</y>
+ <width>91</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_13">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>190</y>
+ <width>101</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Draw Calls</string>
+ </property>
+ </widget>
+ <widget class="QFrame" name="frame_3">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>230</y>
+ <width>280</width>
+ <height>1</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(38, 38, 38);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ <widget class="QFrame" name="frame_4">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>330</y>
+ <width>280</width>
+ <height>1</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(38, 38, 38);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ <widget class="QFrame" name="frame_10">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>480</y>
+ <width>280</width>
+ <height>201</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(38, 38, 38);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_18">
+ <property name="geometry">
+ <rect>
+ <x>70</x>
+ <y>290</y>
+ <width>91</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(175, 175, 175);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Solid</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" name="solid_radio">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>290</y>
+ <width>20</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QRadioButton::indicator {
+ width: 20px;
+ height: 20px;
+ border-radius: 2px
+}
+QRadioButton::indicator::unchecked {
+ background-color: rgb(45, 45, 45);
+}
+QRadioButton::indicator:unchecked:hover {
+ background-color: rgb(50, 50, 50);
+}
+QRadioButton::indicator::checked {
+ background-color: rgb(30, 150, 220);
+}</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_30">
+ <property name="geometry">
+ <rect>
+ <x>50</x>
+ <y>433</y>
+ <width>51</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Opacity</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_24">
+ <property name="geometry">
+ <rect>
+ <x>160</x>
+ <y>290</y>
+ <width>91</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(175, 175, 175);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Wireframe</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" name="wireframe_radio">
+ <property name="geometry">
+ <rect>
+ <x>130</x>
+ <y>290</y>
+ <width>20</width>
+ <height>20</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QRadioButton::indicator {
+ width: 20px;
+ height: 20px;
+ border-radius: 2px
+}
+QRadioButton::indicator::unchecked {
+ background-color: rgb(45, 45, 45);
+}
+QRadioButton::indicator:unchecked:hover {
+ background-color: rgb(50, 50, 50);
+}
+QRadioButton::indicator::checked {
+ background-color: rgb(30, 150, 220);
+}</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_10">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>250</y>
+ <width>71</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(175, 175, 175);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>View</string>
+ </property>
+ </widget>
+ <widget class="QFrame" name="frame_11">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>390</y>
+ <width>151</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(45, 45, 45);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <widget class="QLabel" name="mesh_label_19">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>0</y>
+ <width>71</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Color</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QToolButton" name="wireframe_color">
+ <property name="geometry">
+ <rect>
+ <x>210</x>
+ <y>390</y>
+ <width>60</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"> QToolButton{
+ background-color: rgb(160, 160, 160);
+ color: rgb(145, 145, 145);
+ border-radius: 2px
+}
+QToolButton:hover {
+background:rgba(160, 160, 160,.8);
+}</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ <widget class="QSlider" name="wireframe_slider">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>430</y>
+ <width>151</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QSlider {
+ background-color: rgb(45, 45, 45);
+}
+
+QSlider::groove:horizontal {
+background: rgb(45, 45, 45);
+}
+
+QSlider::handle:horizontal {
+ background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);
+ width: 10px;
+ background: rgb(30, 150, 220);
+}</string>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="wireframe_slider_value">
+ <property name="geometry">
+ <rect>
+ <x>210</x>
+ <y>430</y>
+ <width>60</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLineEdit {
+ border: 2px solid gray;
+ color: rgb(145, 145, 145);
+ border-color: rgb(45, 45, 45);
+ background-color: rgb(45, 45, 45);
+}</string>
+ </property>
+ <property name="text">
+ <string>100</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_15">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>350</y>
+ <width>71</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(175, 175, 175);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Model</string>
+ </property>
+ </widget>
+ <zorder>mesh_label</zorder>
+ <zorder>mesh_label_2</zorder>
+ <zorder>triangles_label</zorder>
+ <zorder>vertices_label</zorder>
+ <zorder>mesh_label_5</zorder>
+ <zorder>edges_label</zorder>
+ <zorder>mesh_label_7</zorder>
+ <zorder>uv2_label</zorder>
+ <zorder>edges_label_test</zorder>
+ <zorder>drawcalls_label</zorder>
+ <zorder>mesh_label_11</zorder>
+ <zorder>material_label</zorder>
+ <zorder>mesh_label_13</zorder>
+ <zorder>frame_3</zorder>
+ <zorder>frame_4</zorder>
+ <zorder>frame_10</zorder>
+ <zorder>mesh_label_18</zorder>
+ <zorder>solid_radio</zorder>
+ <zorder>mesh_label_24</zorder>
+ <zorder>wireframe_radio</zorder>
+ <zorder>mesh_label_10</zorder>
+ <zorder>frame_11</zorder>
+ <zorder>wireframe_color</zorder>
+ <zorder>wireframe_slider</zorder>
+ <zorder>wireframe_slider_value</zorder>
+ <zorder>mesh_label_15</zorder>
+ <zorder>mesh_label_30</zorder>
+ </widget>
+ <widget class="QWidget" name="tab_2">
+ <attribute name="title">
+ <string>Settings</string>
+ </attribute>
+ <widget class="QLabel" name="mesh_label_14">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>245</y>
+ <width>51</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;
+selectByMouse: false</string>
+ </property>
+ <property name="text">
+ <string>Opacity</string>
+ </property>
+ </widget>
+ <widget class="QFrame" name="frame_8">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>280</y>
+ <width>170</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(45, 45, 45);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <widget class="QLabel" name="mesh_label_12">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>0</y>
+ <width>91</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Cells amount</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QToolButton" name="background_color">
+ <property name="geometry">
+ <rect>
+ <x>200</x>
+ <y>40</y>
+ <width>60</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"> QToolButton{
+ background-color: rgb(200, 200, 200);
+ color: rgb(145, 145, 145);
+ border-radius: 2px
+}
+QToolButton:hover {
+ background-color: rgb(220, 220, 220);
+}</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ <widget class="QFrame" name="frame_6">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>90</y>
+ <width>280</width>
+ <height>1</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(38, 38, 38);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ <widget class="QSlider" name="grid_slider">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>240</y>
+ <width>170</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QSlider {
+ background-color: rgb(45, 45, 45);
+}
+
+QSlider::groove:horizontal {
+background: rgb(45, 45, 45);
+}
+
+QSlider::handle:horizontal {
+ background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);
+ width: 10px;
+ background: rgb(30, 150, 220);
+}</string>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QSlider" name="fov_slider">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>140</y>
+ <width>170</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QSlider {
+ background-color: rgb(45, 45, 45);
+}
+
+QSlider::groove:horizontal {
+background: rgb(45, 45, 45);
+}
+
+QSlider::handle:horizontal {
+ background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);
+ width: 10px;
+ background: rgb(30, 150, 220);
+}</string>
+ </property>
+ <property name="minimum">
+ <number>10</number>
+ </property>
+ <property name="maximum">
+ <number>120</number>
+ </property>
+ <property name="sliderPosition">
+ <number>60</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="fov_slider_value">
+ <property name="geometry">
+ <rect>
+ <x>200</x>
+ <y>140</y>
+ <width>60</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLineEdit {
+ border: 2px solid gray;
+ color: rgb(145, 145, 145);
+ border-color: rgb(45, 45, 45);
+ background-color: rgb(45, 45, 45);
+}</string>
+ </property>
+ <property name="text">
+ <string>60</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QFrame" name="frame_7">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>190</y>
+ <width>280</width>
+ <height>1</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(38, 38, 38);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="grid_slider_value">
+ <property name="geometry">
+ <rect>
+ <x>200</x>
+ <y>240</y>
+ <width>60</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLineEdit {
+ border: 2px solid gray;
+ color: rgb(145, 145, 145);
+ border-color: rgb(45, 45, 45);
+ background-color: rgb(45, 45, 45);
+}</string>
+ </property>
+ <property name="text">
+ <string>100</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_3">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>10</y>
+ <width>91</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(175, 175, 175);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Background</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_8">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>210</y>
+ <width>91</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(175, 175, 175);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Grid</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="mesh_label_6">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>110</y>
+ <width>91</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(175, 175, 175);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Field of view</string>
+ </property>
+ </widget>
+ <widget class="QFrame" name="frame_5">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>40</y>
+ <width>170</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(45, 45, 45);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <widget class="QLabel" name="mesh_label_4">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>0</y>
+ <width>71</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Color</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QFrame" name="frame_9">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>370</y>
+ <width>280</width>
+ <height>311</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(38, 38, 38);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="grid_cell">
+ <property name="geometry">
+ <rect>
+ <x>200</x>
+ <y>280</y>
+ <width>60</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLineEdit {
+ border: 2px solid gray;
+ color: rgb(145, 145, 145);
+ border-color: rgb(45, 45, 45);
+ background-color: rgb(45, 45, 45);
+}</string>
+ </property>
+ <property name="text">
+ <string>50</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLineEdit" name="grid_size">
+ <property name="geometry">
+ <rect>
+ <x>200</x>
+ <y>320</y>
+ <width>60</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLineEdit {
+ border: 2px solid gray;
+ color: rgb(145, 145, 145);
+ border-color: rgb(45, 45, 45);
+ background-color: rgb(45, 45, 45);
+}</string>
+ </property>
+ <property name="text">
+ <string>20</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QFrame" name="frame_12">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>320</y>
+ <width>170</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background-color: rgb(45, 45, 45);</string>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <widget class="QLabel" name="mesh_label_16">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>0</y>
+ <width>71</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>10</pointsize>
+ <weight>50</weight>
+ <bold>false</bold>
+ <kerning>true</kerning>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string>Size</string>
+ </property>
+ </widget>
+ </widget>
+ <zorder>frame_8</zorder>
+ <zorder>background_color</zorder>
+ <zorder>frame_6</zorder>
+ <zorder>grid_slider</zorder>
+ <zorder>fov_slider</zorder>
+ <zorder>fov_slider_value</zorder>
+ <zorder>frame_7</zorder>
+ <zorder>grid_slider_value</zorder>
+ <zorder>mesh_label_3</zorder>
+ <zorder>mesh_label_8</zorder>
+ <zorder>mesh_label_6</zorder>
+ <zorder>frame_5</zorder>
+ <zorder>frame_9</zorder>
+ <zorder>grid_cell</zorder>
+ <zorder>mesh_label_14</zorder>
+ <zorder>grid_size</zorder>
+ <zorder>frame_12</zorder>
+ </widget>
+ </widget>
+ <widget class="QLabel" name="obj_path_label">
+ <property name="geometry">
+ <rect>
+ <x>14</x>
+ <y>731</y>
+ <width>1131</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <property name="font">
+ <font>
+ <family>Microsoft YaHei UI</family>
+ <pointsize>9</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">color: rgb(145, 145, 145);
+background: transparent;</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </widget>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1150</width>
+ <height>37</height>
+ </rect>
+ </property>
+ <property name="statusTip">
+ <string/>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QMenuBar {
+background: rgb(38, 38, 38);
+ padding: 8px;
+ color: rgb(210, 210, 210);
+}
+
+QMenuBar::item {
+ background: transparent;
+}
+
+QMenuBar::item:selected {
+ background: rgb(56, 56, 56);
+ padding: 20px;
+ spacing: 20px;
+}
+
+QMenuBar::item:pressed {
+ background: rgb(56, 56, 56);
+ padding: 20px;
+ spacing: 20px;
+}
+
+QMenu {
+ background: rgb(38, 38, 38);
+ padding: 10px;
+ color: rgb(210, 210, 210);
+
+}
+
+QMenu::item {
+ background-color: transparent;
+ padding: 5px;
+padding-left: 10px;
+padding-right: 150px;
+}
+
+QMenu::item:selected {
+ background: rgb(56, 56, 56);
+ spacing: 20px;
+}</string>
+ </property>
+ <widget class="QMenu" name="menuFile">
+ <property name="title">
+ <string>File</string>
+ </property>
+ <addaction name="actionLoad"/>
+ <addaction name="actionClose"/>
+ <addaction name="separator"/>
+ <addaction name="actionQuit"/>
+ </widget>
+ <widget class="QMenu" name="menuAbout">
+ <property name="title">
+ <string>About</string>
+ </property>
+ <addaction name="actionAbout"/>
+ </widget>
+ <addaction name="menuFile"/>
+ <addaction name="menuAbout"/>
+ </widget>
+ <action name="actionLoad">
+ <property name="text">
+ <string>Load</string>
+ </property>
+ </action>
+ <action name="actionClose">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </action>
+ <action name="actionQuit">
+ <property name="text">
+ <string>Quit</string>
+ </property>
+ </action>
+ <action name="actionAbout">
+ <property name="text">
+ <string>About</string>
+ </property>
+ </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/resource/app_preview.PNG b/resource/app_preview.PNG
new file mode 100644
index 0000000..d26f68c
--- /dev/null
+++ b/resource/app_preview.PNG
Binary files differ
diff --git a/resource/load.png b/resource/load.png
new file mode 100644
index 0000000..2c5a34c
--- /dev/null
+++ b/resource/load.png
Binary files differ
diff --git a/resource/shaders.py b/resource/shaders.py
new file mode 100644
index 0000000..7fce7ca
--- /dev/null
+++ b/resource/shaders.py
@@ -0,0 +1,47 @@
+vertex_shader='''
+ #version 330
+
+ uniform mat4 Mvp;
+
+ in vec3 in_position;
+ in vec3 in_normal;
+ in vec2 in_texcoord_0;
+
+ out vec3 v_vert;
+ out vec3 v_norm;
+ out vec2 v_text;
+
+ void main() {
+ v_vert = in_position;
+ v_norm = in_normal;
+ v_text = in_texcoord_0;
+ gl_Position = Mvp * vec4(in_position, 1.0);
+ }
+ '''
+fragment_shader='''
+ #version 330
+
+ uniform sampler2D Texture;
+ uniform vec4 Color;
+ uniform vec3 Light;
+
+ in vec3 v_vert;
+ in vec3 v_norm;
+ in vec2 v_text;
+
+ out vec4 f_color;
+
+ void main() {
+ float lum = -dot(normalize(v_norm), normalize(v_vert + Light));
+ lum = acos(lum) / 3.14159265;
+ lum = clamp(lum, 0.0, 1.0);
+ lum = lum * lum;
+ lum = smoothstep(0.0, 1.0, lum);
+ lum *= smoothstep(0.0, 80.0, v_vert.z) * 0.3 + 0.7;
+ lum = lum * 0.8 + 0.2;
+
+ vec3 color = texture(Texture, v_text).rgb;
+ color = color * (1.0 - Color.a) + Color.rgb * Color.a;
+ f_color = vec4(color * lum, Color.a);
+ }
+ '''