Я использую Mac OS X Mavericks, iMac с NVIDIA GeForce GTX 660M, поэтому он должен поддерживать OpenGL версии 4.1 и GLSL версии 4.1.0. Но когда я использую это:
print("OpenGL: " + str(glGetString(GL_VERSION)))
print("GLSL: " + str(glGetString(GL_SHADING_LANGUAGE_VERSION)))
Я получаю это:
OpenGL: b'2.1 NVIDIA-8.26.26 310.40.45f01'
GLSL: b'1.20'
Я узнал, что я должен включить основной профиль
class TestWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
super(TestWindow, self).__init__(parent)
# generate random data points
self.data = np.array([
[ -0.90, -0.90 ], [ 0.85, -0.90 ], [ -0.90, 0.85 ],
[ 0.90, -0.85 ], [ 0.90, 0.90 ], [ -0.85, 0.90 ]
], dtype = np.float32)
# core profile
glformat = QtOpenGL.QGLFormat()
glformat.setVersion(4, 1)
glformat.setProfile(QtOpenGL.QGLFormat.CoreProfile)
glformat.setSampleBuffers( True )
# initialize the GL widget
self.widget = GLPlotWidget(glformat)
self.widget.set_data(self.data)
# put the window at the screen position (100, 100)
self.setGeometry(100, 100, self.widget.width, self.widget.height)
self.setCentralWidget(self.widget)
self.show()
Но это не решило проблему. Теперь я нашел этот Вопрос, где решается эта проблема для C ++:
// Add this in initializeGL before m_shader.setAttributeBuffer:
uint vao;
typedef void (APIENTRY *_glGenVertexArrays) (GLsizei, GLuint*);
typedef void (APIENTRY *_glBindVertexArray) (GLuint);
_glGenVertexArrays glGenVertexArrays;
_glBindVertexArray glBindVertexArray;
glGenVertexArrays = (_glGenVertexArrays) QGLWidget::context()->getProcAddress("glGenVertexArrays");
glBindVertexArray = (_glBindVertexArray) QGLWidget::context()->getProcAddress("glBindVertexArray");
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
но как я могу сделать то же самое в python3?
Вот мой полный исходный код:
# PyQT4 imports
from PyQt4 import QtGui, QtCore, QtOpenGL
from PyQt4.QtOpenGL import QGLWidget
# PyOpenGL imports
from OpenGL.GL import *
from OpenGL.GL.shaders import *
class GLPlotWidget(QGLWidget):
# default window size
width, height = 600, 600
def __init__(self, format = None):
super(GLPlotWidget, self).__init__(format, None)
def set_data(self, data):
self.data = data
self.count = data.shape[0]
self.numVAOs = 2
self.VAOs = [0] * self.numVAOs
self.numVBOs = 2
self.VBOs = [0] * self.numVBOs
self.shader = None
self.vPositionLocation = 0
def initializeGL(self):
glGenVertexArrays(self.numVAOs, self.VAOs)
glBindVertexArray(self.VAOs[0])
glGenBuffers(self.numVBOs, self.VBOs)
glBindBuffer(GL_ARRAY_BUFFER, self.VBOs[0])
glBufferData(GL_ARRAY_BUFFER, self.count, self.data, GL_STATIC_DRAW)
VERTEX_SHADER = compileShader("""#version 410 core
layout(location = 0) in vec4 vPosition;
void main() {
gl_Position = vPosition;
}
""", GL_VERTEX_SHADER)
FRAGMENT_SHADER = compileShader("""#version 410 core
out vec4 fColor;
void main() {
fColor = vec4(0.0, 0.0, 1.0, 1.0);
}
""", GL_FRAGMENT_SHADER)
self.shader = compileProgram(VERTEX_SHADER, FRAGMENT_SHADER)
glUseProgram(self.shader)
glVertexAttribPointer(self.vPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, 0)
glEnableVertexAttribArray(self.vPositionLocation)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT)
glBindVertexArray(self.VAOs[0])
glDrawArrays(GL_TRIANGLES, 0, self.count)
glFlush()
def resizeGL(self, width, height):
# update the window size
self.width, self.height = width, height
# paint within the whole window
glViewport(0, 0, width, height)
# set orthographic projection (2D only)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# the window corner OpenGL coordinates are (-+1, -+1)
glOrtho(-1, 1, -1, 1, -1, 1)
if __name__ == '__main__':
# import numpy for generating random data points
import sys
import numpy as np
import numpy.random as rnd
# define a QT window with an OpenGL widget inside it
class TestWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
super(TestWindow, self).__init__(parent)
# generate random data points
self.data = np.array([
[ -0.90, -0.90 ], [ 0.85, -0.90 ], [ -0.90, 0.85 ],
[ 0.90, -0.85 ], [ 0.90, 0.90 ], [ -0.85, 0.90 ]
], dtype = np.float32)
# core profile
glformat = QtOpenGL.QGLFormat()
glformat.setVersion(4, 1)
glformat.setProfile(QtOpenGL.QGLFormat.CoreProfile)
glformat.setSampleBuffers( True )
# initialize the GL widget
self.widget = GLPlotWidget(glformat)
self.widget.set_data(self.data)
# put the window at the screen position (100, 100)
self.setGeometry(100, 100, self.widget.width, self.widget.height)
self.setCentralWidget(self.widget)
self.show()
# create the QT App and window
app = QtGui.QApplication(sys.argv)
window = TestWindow()
window.show()
app.exec_()
В случае, если у кого-то еще были подобные проблемы, критической ошибкой в исходном коде является вызов glVertexAttribPointer
,
Обязательно используйте c_void_p(0)
от ctypes
для последнего параметра, в противном случае вызов будет недействительным, и VAO ничего не будет рисовать.
Переход с PyQt4 на PyQt5 решает проблему
Полный исходный код:
# PyQT5 imports
from PyQt5 import QtGui, QtCore, QtOpenGL, QtWidgets
from PyQt5.QtOpenGL import QGLWidget
from ctypes import *
# PyOpenGL imports
from OpenGL.GL import *
from OpenGL.GL.shaders import *
from OpenGL.GLUT import *
class GLPlotWidget(QGLWidget):
# default window size
width, height = 600, 600
def __init__(self, format = None):
super(GLPlotWidget, self).__init__(format, None)
def set_data(self, data):
self.data = data
self.count = self.data.nbytes
self.numVAOs = 2
self.VAOs = [0] * self.numVAOs
self.numVBOs = 2
self.VBOs = [0] * self.numVBOs
self.shader = None
self.vPositionLocation = 0
def initializeGL(self):
glClearColor(0.0, 0.0, 0.0, 1.0)
self.VAOs = glGenVertexArrays(self.numVAOs)
glBindVertexArray(self.VAOs[0])
self.VBOs = glGenBuffers(self.numVBOs)
glBindBuffer(GL_ARRAY_BUFFER, self.VBOs[0])
glBufferData(GL_ARRAY_BUFFER, self.count, self.data, GL_STATIC_DRAW)
VERTEX_SHADER = compileShader("""#version 410 core
layout(location = 0) in vec4 vPosition;
void main() {
gl_Position = vPosition;
}
""", GL_VERTEX_SHADER)
FRAGMENT_SHADER = compileShader("""#version 410 core
out vec4 fColor;
void main() {
fColor = vec4(1.0, 1.0, 0.0, 1.0);
}
""", GL_FRAGMENT_SHADER)
self.shader = compileProgram(VERTEX_SHADER, FRAGMENT_SHADER)
glUseProgram(self.shader)
glVertexAttribPointer(self.vPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, c_void_p(0))
glEnableVertexAttribArray(self.vPositionLocation)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT)
glBindVertexArray(self.VAOs[0])
glDrawArrays(GL_TRIANGLES, 0, self.count)
glFlush()
if __name__ == '__main__':
# import numpy for generating random data points
import sys
import numpy as np
import numpy.random as rnd
# define a QT window with an OpenGL widget inside it
class TestWindow(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super(TestWindow, self).__init__(parent)
self.data = np.array([
[ -0.90, -0.90 ],
[ 0.85, -0.90 ],
[ -0.90, 0.85 ],
[ 0.90, -0.85 ],
[ 0.90, 0.90 ],
[ -0.85, 0.90 ]
], dtype = np.float32)
# initialize the GL widget
glformat = QtOpenGL.QGLFormat()
glformat.setVersion(4, 1)
glformat.setProfile(QtOpenGL.QGLFormat.CoreProfile)
glformat.setSampleBuffers( True )
self.widget = GLPlotWidget(glformat)
self.widget.set_data(self.data)
# put the window at the screen position (100, 100)
self.setGeometry(100, 100, self.widget.width, self.widget.height)
self.setCentralWidget(self.widget)
self.show()
# create the QT App and window
app = QtWidgets.QApplication(sys.argv)
window = TestWindow()
window.show()
app.exec_()