[英]Displaying a simple 2D textured rectangle inside a wxGLCanvas using PyOpenGL
I'm trying to write some code that will display a single image as a simple 2D textured rectangle within a wxGLCanvas
container. 我正在尝试编写一些代码,将一个图像显示为
wxGLCanvas
容器中的简单2D纹理矩形。
Here's a runnable example of what I've got so far: 这是我到目前为止所获得的一个可运行的例子:
import wx
from wxPython.glcanvas import wxGLCanvas
from OpenGL.GLU import *
from OpenGL.GL import *
import numpy as np
from scipy.misc import ascent
def run():
imarray = np.float32(ascent())
imarray = np.repeat(imarray[..., np.newaxis], 3, axis=2)
app = wx.PySimpleApp()
frame = wx.Frame(None, title='Simple 2D texture')
canvas = myGLCanvas(frame, imarray)
frame.Show(True)
app.MainLoop()
class myGLCanvas(wxGLCanvas):
def __init__(self, parent, image):
attribList = [wx.glcanvas.WX_GL_DOUBLEBUFFER]
wxGLCanvas.__init__(self, parent, -1, attribList=attribList)
wx.EVT_PAINT(self, self.OnPaint)
self.image = np.float32(image)
self.InitProjection()
self.InitTexture()
pass
def OnPaint(self, event):
"""Called whenever the window gets resized, uncovered etc."""
self.SetCurrent()
dc = wx.PaintDC(self)
self.OnDraw()
self.SwapBuffers()
pass
def InitProjection(self):
"""Enable the depth buffer and initialize the viewport and
projection matrix"""
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
width = self.image.shape[1]
height = self.image.shape[0]
glViewport(0, 0, width, height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, width, height, 0, -1, 1)
pass
def InitTexture(self):
"""Initializes the texture from a numpy array"""
self.texture = glGenTextures(1)
glEnable(GL_TEXTURE_2D)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glBindTexture(GL_TEXTURE_2D, self.texture)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGB,
self.image.shape[1], self.image.shape[0], 0,
GL_RGB,
GL_FLOAT,
self.image)
glDisable(GL_TEXTURE_2D)
pass
def OnDraw(self):
"""Draw a textured rectangle slightly smaller than the viewport"""
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glClearColor(0., 0., 0., 0.)
glClearDepth(1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glBindTexture(GL_TEXTURE_2D, self.texture)
glEnable(GL_TEXTURE_2D)
# draw a textured quad, shrink it a bit so the edge is clear
glBegin(GL_QUADS)
glTexCoord2f(0., 0.)
glVertex3f(-0.9, -0.9, 0.)
glTexCoord2f(1., 0.)
glVertex3f(0.9, -0.9, 0.)
glTexCoord2f(1., 1.)
glVertex3f(0.9, 0.9, 0.)
glTexCoord2f(0., 1.)
glVertex3f(-0.9, 0.9, 0.)
glEnd()
glDisable(GL_TEXTURE_2D)
pass
if __name__ == '__main__':
run()
This draws a rectangle successfully, but fails to texture it - all I see is a white rectangle. 这会成功绘制一个矩形,但无法对其进行纹理化 - 我看到的只是一个白色矩形。 Any idea what I'm doing wrong?
知道我做错了什么吗?
Well, the critical mistake I was making was not scaling the float values of my input data to between 0 and 1 - all my pixels were >1 so the quad rendered as white! 好吧,我犯的重要错误是没有将输入数据的浮点值缩放到0和1之间 - 我的所有像素都是> 1,所以四边形呈现为白色! I had a bit of trouble finding good examples of how to use
wxGLCanvas
es, so here's a simple texture rendered in a wxGLCanvas
for anyone who might find it useful. 我在找到如何使用
wxGLCanvas
es的好例子时遇到了一些麻烦,所以这里是一个在wxGLCanvas
呈现的简单纹理,适合任何可能发现它有用的人。
import numpy as np
from scipy.misc import ascent
import OpenGL.GL as gl
import wx
from wx.glcanvas import GLCanvas
class Canvas(GLCanvas):
def __init__(self, parent):
"""create the canvas """
super(Canvas, self).__init__(parent)
self.texture = None
# execute self.onPaint whenever the parent frame is repainted
wx.EVT_PAINT(self, self.onPaint)
def initTexture(self):
"""init the texture - this has to happen after an OpenGL context
has been created
"""
# make the OpenGL context associated with this canvas the current one
self.SetCurrent()
data = np.uint8(np.flipud(ascent()))
w, h = data.shape
# generate a texture id, make it current
self.texture = gl.glGenTextures(1)
gl.glBindTexture(gl.GL_TEXTURE_2D, self.texture)
# texture mode and parameters controlling wrapping and scaling
gl.glTexEnvf(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_MODULATE)
gl.glTexParameterf(
gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_REPEAT)
gl.glTexParameterf(
gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_REPEAT)
gl.glTexParameterf(
gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
gl.glTexParameterf(
gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
# map the image data to the texture. note that if the input
# type is GL_FLOAT, the values must be in the range [0..1]
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, w, h, 0,
gl.GL_LUMINANCE, gl.GL_UNSIGNED_BYTE, data)
def onPaint(self, event):
"""called when window is repainted """
# make sure we have a texture to draw
if not self.texture:
self.initTexture()
self.onDraw()
def onDraw(self):
"""draw function """
# make the OpenGL context associated with this canvas the current one
self.SetCurrent()
# set the viewport and projection
w, h = self.GetSize()
gl.glViewport(0, 0, w, h)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
gl.glOrtho(0, 1, 0, 1, 0, 1)
gl.glMatrixMode(gl.GL_MODELVIEW)
gl.glLoadIdentity()
gl.glClear(gl.GL_COLOR_BUFFER_BIT)
# enable textures, bind to our texture
gl.glEnable(gl.GL_TEXTURE_2D)
gl.glBindTexture(gl.GL_TEXTURE_2D, self.texture)
gl.glColor3f(1, 1, 1)
# draw a quad
gl.glBegin(gl.GL_QUADS)
gl.glTexCoord2f(0, 1)
gl.glVertex2f(0, 1)
gl.glTexCoord2f(0, 0)
gl.glVertex2f(0, 0)
gl.glTexCoord2f(1, 0)
gl.glVertex2f(1, 0)
gl.glTexCoord2f(1, 1)
gl.glVertex2f(1, 1)
gl.glEnd()
gl.glDisable(gl.GL_TEXTURE_2D)
# swap the front and back buffers so that the texture is visible
self.SwapBuffers()
def run():
app = wx.App()
fr = wx.Frame(None, size=(512, 512), title='wxPython texture demo')
canv = Canvas(fr)
fr.Show()
app.MainLoop()
if __name__ == "__main__":
run()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.