2012-09-20 14 views
2

我試圖編寫一些代碼,它將在一個容器中顯示一個圖像作爲簡單的2D紋理矩形。使用PyOpenGL在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

您確定您的頂點有正確的收尾順序嗎? – Aesthete

+0

嗯,除非我犯了一個非常根本的錯誤 - 他們只是左下角,右下角,右上角,左上角? –

+0

你試過扭轉它們嗎?這只是一個想法,我沒有真正的時間來正確地閱讀你的代碼。 – Aesthete

回答

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()