То, что вы видите в окне просмотра, является проекцией трехмерного объема просмотра. Матрица проекции определяет область (объем) относительно наблюдателя (зрителя), который проецируется на область просмотра.
В вашем случае вы используете проекцию Orthographi c . В проекции orthographi c эта область (объем) определяется 6 расстояниями (слева, справа, снизу, сверху, близко и далеко) к позиции зрителя. Все объекты (точки), находящиеся в пространстве (объеме), «видны» в области просмотра. Все объекты (точки), находящиеся вне этого пространства, обрезаются по границам объема.
[...], но единственный способ увидеть точки - нормализовать их координаты до -0,5. - 0,5 значения [...]
На самом деле вы делаете это неправильно. Вы изменяете масштаб координат вершин (точек), а не расширяете объем просмотра.
Проекция orthographi c может быть установлена с помощью glOrtho
:
gl.glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0)
Эта настройка определяет кубоидный объем с левым, нижним, около od (-0,5, -0,5, 4,0) и правым, верхним, далеко (0,5, 0,5, 15,0).
Увеличение этот объем, а не масштабирование координат:
gl.glOrtho(min_x, max_x, max_y, min_y, min_z, max_z)
Я рекомендую сделать следующее:
Вычислить ограничивающий прямоугольник, ограниченный осью облака точек, из (self.min_x
, self._min_y
, self.min_z
) до (self.max_x
, self._max_y
, self.max_z
) и определите проекцию orthgrphi c, которая определяет объем кубоида, достаточно большой, чтобы охватить все точки независимо от его ориентации ( Евклидово расстояние ):
ef resizeGL(self, width, height):
side = min(width, height)
if side < 0:
return
gl.glViewport((width - side) // 2, (height - side) // 2, side, side)
dx = self.max_x - self.min_x
dy = self.max_y - self.min_y
dz = self.max_z - self.min_z
dia = math.sqrt(dx*dx + dy*dy + dz*dz)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
gl.glOrtho(-dia/2, dia/2, dia/2, -dia/2, -dia/2, dia/2)
gl.glMatrixMode(gl.GL_MODELVIEW)
Вычислить центр ограничительной рамки и определить начальный перевод в противоположном направлении. Перевод должен «переместить» центр облака точек к источнику мира:
self.center_x = (self.min_x + self.max_x) / 2
self.center_y = (self.min_y + self.max_y) / 2
self.center_z = (self.min_z + self.max_z) / 2
self.xPos = 0
self.yPos = 0
self.zPos = 0
Объем просмотра достаточно велик, поэтому нет необходимости масштабировать точки (self.zoomScale = 1
). Важно сначала масштабировать облако точек, затем перевести его и окончательно повернуть, поэтому ось вращения является центром облака точек:
modelview = translate * rotation * scale * translateToOrigin
Операции преобразования матрицы, такие как glRotate
, glScale
и glTranslate
, определяют новую матрицу и умножают текущую матрицу на новую матрицу. Следовательно, порядок операций должен быть 1. glTranslate
2. glRotate
, 3. glScale
, 4. glTranslate(-center)
,:
def paintGL(self):
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
gl.glLoadIdentity()
gl.glTranslated(self.xPos, self.yPos, self.zPos)
gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0)
gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0)
gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0)
gl.glScaled(self.zoomScale, self.zoomScale, self.zoomScale)
gl.glTranslated(-self.center_x, -self.center_y, -self.center_z)
# [...]