我正在尝试编写一些代码,将单个图像显示为wxGLCanvas
容器中的简单2D纹理矩形。
这是迄今为止我所得到的一个可运行的例子:
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()
这成功绘制了一个矩形,但无法对其进行纹理化 - 我看到的只是一个白色矩形。知道我做错了吗?
答案 0 :(得分:7)
嗯,我犯的重要错误是没有将输入数据的浮点值缩放到0和1之间 - 我的所有像素都是> 1,所以四边形呈现为白色!我在查找如何使用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()