如果你以前使用过python来处理图片的话,那你对PIL有一定的了解,PIL是python的一个第3方库,主要是用来做图片处理的,但从1.1.7版本开始就已经停止维护了。
而Pillow则是PIL的衍生分支,它支持PIL的API,使用方法都一样,到现在还在维护。
首先我们来创建一个QGLWidget
class MyGLWidget(QGLWidget):
添加一些buffer(内存)对象
# buffer object ids self.vaoID = None self.vboVerticesID = None self.vboIndicesID = None self.textureID = None self.sprogram = None
使用Pillow来加载图片
# chang this to load your image file self.loadImage('Lenna.png')
然后我们重写initializeGL方法来进行初始化
def initializeGL(self):
创建并编译shader
# create shader from file vshader = shaderFromFile(GL_VERTEX_SHADER, 'shader.vert') fshader = shaderFromFile(GL_FRAGMENT_SHADER, 'shader.frag') # compile shaders self.sprogram = shaders.compileProgram(vshader, fshader)
设置shader里的一些参数
# get attribute and set uniform for shaders glUseProgram(self.sprogram) self.vertexAL = glGetAttribLocation(self.sprogram, 'pos') self.tmUL = glGetUniformLocation(self.sprogram, 'textureMap') glUniform1i(self.tmUL, 0) glUseProgram(0)
设置平面的坐标和顶点循序
# two triangle to make a quad self.vertices = np.array((0.0, 0.0, 1.0, 0.1, 1.0, 0.9, 0.0, 1.0), dtype=np.float32) self.indices = np.array((0, 1, 2, 0, 2, 3), dtype=np.ushort)

然后将数据传送到显卡
# set up vertex array self.vaoID = glGenVertexArrays(1) self.vboVerticesID = glGenBuffers(1) self.vboIndicesID = glGenBuffers(1) glBindVertexArray(self.vaoID) glBindBuffer(GL_ARRAY_BUFFER, self.vboVerticesID) # copy vertices data from memery to gpu memery glBufferData(GL_ARRAY_BUFFER, self.vertices.nbytes, self.vertices, GL_STATIC_DRAW) # tell opengl how to procces the vertices data glEnableVertexAttribArray(self.vertexAL) glVertexAttribPointer(self.vertexAL, 2, GL_FLOAT, GL_FALSE, 0, None) # send the indice data too glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.vboIndicesID) glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.indices.nbytes, self.indices, GL_STATIC_DRAW)
在我们传送图片数据到显卡之前,我们需要从上向下反转图片,不然我们显示的图片就是上向下反转的图片
# flip the image in the Y axis im = self.im.transpose(Image.FLIP_TOP_BOTTOM)
然后传送图片数据到显卡
# set up texture self.textureID = glGenTextures(1) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_2D, self.textureID) # set filters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) # set uv coords mode glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP) # send the image data to gpu memery glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, self.im.size[0], self.im.size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, im.tostring())
这里你可以吧uv的坐标模式换一下
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT)
并把shader.vert里的uv坐标改成
uv = pos*2 - 1;
你将会得到

到这里我们就可以开始进行渲染绘制了
def paintGL(self, *args, **kwargs): # clear the buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # active shader glUseProgram(self.sprogram) # draw triangles glDrawElements(GL_TRIANGLES, self.indices.size, GL_UNSIGNED_SHORT, None) glUseProgram(0)
至于shader.vert和shader.frag,做的都是非常简单的事情
shader.vert负责接收顶点信息,并保存uv的坐标,最后把uv传递给shader.frag,然后它通过uv坐标来读取图片的像素并导出给硬件,最终硬件进行显示。

完整的代码可以从这里获取
https://github.com/mackst/opengl-samples/tree/master/displayImage
ps.图片需要你们自己添加