graphics.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. """Generate OpenGL graphics for visualizing polyhedra."""
  2. # Third-party imports
  3. import moderngl
  4. import numpy as np
  5. from pyrr import Matrix44, matrix44
  6. from PySide6 import QtGui, QtOpenGLWidgets
  7. class ModernGLWidget(QtOpenGLWidgets.QOpenGLWidget):
  8. def __init__(self, parent):
  9. super().__init__(parent)
  10. self.parent = parent
  11. fmt = QtGui.QSurfaceFormat()
  12. fmt.setVersion(3, 3)
  13. fmt.setProfile(QtGui.QSurfaceFormat.CoreProfile)
  14. self.setFormat(fmt)
  15. self.resize(512, 512)
  16. def initializeGL(self):
  17. pass
  18. def resizeGL(self, width, height):
  19. #print(self.ctx.viewport)
  20. #self.ctx.viewport = (0, 0, width, height)
  21. pass
  22. def paintGL(self):
  23. # Set up context and shaders
  24. self.ctx = moderngl.create_context()
  25. self.ctx.clear(0.2, 0, 0.2, 0)
  26. self.prog = self.ctx.program(vertex_shader="""
  27. #version 330
  28. uniform mat4 rotation;
  29. uniform mat4 zoom;
  30. in vec3 color;
  31. in vec3 in_vert;
  32. out vec3 v_color;
  33. void main() {
  34. gl_Position = zoom * rotation * vec4(in_vert, 1.0);
  35. v_color = color;
  36. }
  37. """,
  38. fragment_shader="""
  39. #version 330
  40. in vec3 v_color;
  41. out vec4 f_color;
  42. void main() {
  43. f_color = vec4(v_color, 1.0);
  44. }"""
  45. )
  46. self.edges_prog = self.ctx.program(vertex_shader="""
  47. #version 330
  48. uniform mat4 rotation;
  49. uniform mat4 zoom;
  50. uniform vec3 color;
  51. in vec3 in_vert;
  52. out vec3 v_color;
  53. void main() {
  54. gl_Position = zoom * rotation * vec4(in_vert, 1.0);
  55. v_color = color;
  56. }
  57. """,
  58. fragment_shader="""
  59. #version 330
  60. in vec3 v_color;
  61. out vec4 f_color;
  62. void main() {
  63. f_color = vec4(v_color, 1.0);
  64. }"""
  65. )
  66. if self.parent.show_edges_only.isChecked():
  67. draw_func = self.draw_edges
  68. else:
  69. draw_func = self.draw_polyhedron
  70. if self.parent.show_prior_polyhedra_checkbox.isChecked():
  71. # Draw all created polyhedra
  72. for model in self.parent.polytope_models:
  73. draw_func(model)
  74. else:
  75. # Draw last created polyhedron
  76. try:
  77. draw_func(self.parent.polytope_models[-1])
  78. # For when no created polyhedron exists
  79. except IndexError:
  80. pass
  81. def draw_polyhedron(self, model):
  82. """Draw polyhedron."""
  83. # Create VAOs for each face
  84. vaos = []
  85. for idx, face in enumerate(model.polytope.faces):
  86. positions = self.ctx.buffer(np.array([vertex.coordinates for vertex in face.vertices], dtype="f4").flatten())
  87. color = self.ctx.buffer(np.array(np.tile(model.color[idx], len(face)).flatten(), dtype="f4"))
  88. vao = self.ctx.vertex_array(
  89. self.prog,
  90. [
  91. (positions, "3f", "in_vert"),
  92. (color, "3f", "color")
  93. ]
  94. )
  95. vaos.append(vao)
  96. # Set uniforms
  97. x = self.parent.x_slider.value() / 20
  98. y = self.parent.y_slider.value() / 20
  99. z = self.parent.z_slider.value() / 20
  100. zoom = self.parent.zoom_slider.value() / 20
  101. self.prog["rotation"].write(Matrix44.from_eulers((x, y, z), dtype="f4"))
  102. self.prog["zoom"].write(matrix44.create_from_scale([zoom, zoom, zoom], dtype="f4"))
  103. # Render
  104. self.ctx.enable(moderngl.DEPTH_TEST)
  105. for vao in vaos:
  106. vao.render(moderngl.TRIANGLE_FAN)
  107. def draw_edges(self, model):
  108. vaos = []
  109. for face in model.polytope.faces:
  110. positions = self.ctx.buffer(np.array([vertex.coordinates for vertex in face.vertices], dtype="f4").flatten())
  111. vao = self.ctx.vertex_array(
  112. self.edges_prog,
  113. [
  114. (positions, "3f", "in_vert"),
  115. ]
  116. )
  117. vaos.append(vao)
  118. # Set uniforms
  119. x = self.parent.x_slider.value() / 20
  120. y = self.parent.y_slider.value() / 20
  121. z = self.parent.z_slider.value() / 20
  122. zoom = self.parent.zoom_slider.value() / 20
  123. self.edges_prog["color"].value = model.color[0]
  124. self.edges_prog["rotation"].write(Matrix44.from_eulers((x, y, z), dtype="f4"))
  125. self.edges_prog["zoom"].write(matrix44.create_from_scale([zoom, zoom, zoom], dtype="f4"))
  126. # Render
  127. self.ctx.enable(moderngl.DEPTH_TEST)
  128. for vao in vaos:
  129. vao.render(moderngl.LINE_LOOP)
  130. def draw_faces(self):
  131. pass