I’m using OpenGL to create an application that draws “billboards” with different images. The user can step though the billboards and look at the images on the different ones. The problem is that the billboards are displaying in the wrong order. The front row is in the back. In other words, if there are n rows, the order in which they are displayed is 1, 2, 3, . . ., n-1, 0. I’ve looked at the coordinates and changed the camera and lots of other things, and I have no idea what is wrong. The code that draws the billboards is below; the class that draws the billboards is called Gallery. (I can provide the rest of the application upon request.) If anyone has any ideas for me at all, even for what might be wrong or something else to help me diagnose the problem, I would be very grateful!
Thank you,
Shari
#!/usr/binh/env python2.5
import wx
import Image
from wx import glcanvas
import wx.lib.scrolledpanel as scrolled
import wx.lib.statbmp as statbmp
import wx.lib.buttons as buttons
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from vtk.wx.wxVTKRenderWindow import *
import appData.appData
import vizGenerator.vizEngine
MAP_FILE_NAME = “/home/shari/thesisFiles/testSet.cod”
DATA_FILE_NAME = “/home/shari/thesisFiles/schoolData.vtk”
MAX_HISTORY_SIZE = 1000
class MyGlCanvas(glcanvas.GLCanvas):
def init(self, parent):
glcanvas.GLCanvas.init(self, parent, -1)
self.init = False
# initial mouse position
self.lastx = self.x = 30
self.lasty = self.y = 30
self.size = None
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
def OnEraseBackground(self, event):
pass # Do nothing, to avoid flashing on MSW.
def OnSize(self, event):
size = self.size = self.GetClientSize()
if self.GetContext():
self.SetCurrent()
glViewport(0, 0, size.width, size.height)
event.Skip()
def OnPaint(self, event):
dc = wx.PaintDC(self)
self.SetCurrent()
if not self.init:
self.InitGL()
self.init = True
self.OnDraw()
def OnMouseDown(self, evt):
self.CaptureMouse()
self.x, self.y = self.lastx, self.lasty = evt.GetPosition()
def OnMouseUp(self, evt):
self.ReleaseMouse()
def OnMouseMotion(self, evt):
if evt.Dragging() and evt.LeftIsDown():
self.lastx, self.lasty = self.x, self.y
self.x, self.y = evt.GetPosition()
self.Refresh(False)
class Gallery(MyGlCanvas):
vizImageIds = []
xMapSize = 0
yMapSize = 0
width = 0.1 # Length of a billboard
height = 0.1 # Height of a billboard
distX = 0.1 # Distance between billboards in the x direction
distZ = 0.15 # Distance between billboards in the z direction
myVizEngine = vizGenerator.vizEngine.vizEngine(MAP_FILE_NAME, DATA_FILE_NAME)
# TODO: Put these back!
#xMapSize = int(myVizEngine.mapMatrix.sizeX)
#yMapSize = int(myVizEngine.mapMatrix.sizeY)
xMapSize = 3
yMapSize = 3
billboardList = 0
def InitGL(self):
print "In Gallery.InitGL"
self.SetCurrent()
glClearColor(0.7, 0.7, 0.7, 0.0)
glShadeModel(GL_FLAT)
glEnable(GL_DEPTH_TEST)
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
self.vizImageIds = glGenTextures(self.xMapSize * self.yMapSize + 1)
self.CreateDisplayList()
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# Calculate the aspect ratio of the window
size = self.size = self.GetClientSize()
gluPerspective(80.0, float(size.width) / float(size.height),
0.01, 20.0)
print "GL Error after gluPerspective: ", glGetError()
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glClearColor(0.7, 0.7, 0.7, 0.0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
self.LookAt(0, 0)
def OnDraw(self):
self.SetCurrent()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glCallList(self.billboardList)
glFlush()
self.SwapBuffers()
def DrawBillboard(self, x, y, z, filename, textureCount):
self.textureId = self.LoadImage(filename, textureCount)
self.SetupTexture(textureCount)
glBindTexture(GL_TEXTURE_2D, self.vizImageIds[textureCount])
#glMatrixMode(GL_MODELVIEW)
#glLoadIdentity()
glBegin(GL_QUADS)
coords = self.GetBillboardCoordinates(x, z)
leftX = coords[0]
rightX = coords[1]
bottomY = coords[2]
topY = coords[3]
z = coords[4]
#print "Drawing billboard at ", x, y, z
print "Billboard position: ", leftX, rightX, bottomY, topY, z
glNormal3f(0.0, 0.0, -1.0)
glTexCoord2f(0.0, 0.0); glVertex3f(leftX, bottomY, z)
glTexCoord2f(1.0, 0.0); glVertex3f(rightX, bottomY, z)
glTexCoord2f(1.0, 1.0); glVertex3f(rightX, topY, z)
glTexCoord2f(0.0, 1.0); glVertex3f(leftX, topY, z)
#glTexCoord2f(0.0, 0.0); glVertex3f(leftX, bottomY, z)
#glTexCoord2f(0.0, 1.0); glVertex3f(leftX, topY, z)
#glTexCoord2f(1.0, 1.0); glVertex3f(rightX, topY, z)
#glTexCoord2f(1.0, 0.0); glVertex3f(rightX, bottomY, z)
glEnd()
def GetBillboardCoordinates(self, x, z):
#leftX = (self.xMapSize * self.distX) - (x * self.distX) + (self.xMapSize * self.width) - (x * self.width)
leftX = -x * (self.distX + self.width) - self.width
rightX = leftX + self.width
bottomY = 0
topY = bottomY + self.height
zCoord = (self.distZ * self.yMapSize) - (z + 1) * self.distZ
print "In GetBillboardCoordinates, zCoord is ", zCoord
return leftX, rightX, bottomY, topY, zCoord
def SetupTexture(self, textureId):
glEnable(GL_TEXTURE_2D)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
glBindTexture(GL_TEXTURE_2D, self.vizImageIds[textureId]) # Added 20061003
def LoadImage(self, filename, id):
#print "In LoadImage, filename is ", filename
# First, load bitmap
if filename == None:
return None
textureImageFile = None
textureImageFile = open(filename, 'r')
if textureImageFile:
textureImageFile.close()
im = Image.open(filename)
# The images are mirrored, so flip it so they look the same
#im = im.transpose(Image.FLIP_LEFT_RIGHT)
try:
ix, iy, image = im.size[0], im.size[1], im.tostring("raw", "RGBA", 0, -1)
except SystemError:
ix, iy, image = im.size[0], im.size[1], im.tostring("raw", "RGBX", 0, -1)
else:
print "ERROR - Image File not found"
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image)
return self.vizImageIds[id]
def CreateDisplayList(self):
self.billboardList = glGenLists(1)
glNewList(self.billboardList, GL_COMPILE)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
# Draw a matrix of billboards
textureCount = 0
for x in range(0, self.xMapSize):
for z in range(0, self.yMapSize):
textureFilename = self.myVizEngine.getViz([x, z])
y = 0
print "Drawing billboard for filename", textureFilename
self.DrawBillboard(x, y, z, textureFilename, textureCount)
textureCount += 1
gluLookAt(0.2, 0.05, 0.01,
0.2, 0.05, 0.1,
0, 1, 0)
glColor3f(0.0, 1.0, 0.0) # green for x axis
glBegin(GL_LINES)
#glLineStipple(1, 0x0101) # dotted
glVertex3f(0.0, 0.0, 0.0)
glVertex3f(-2.0, 0.0, 0.0)
glEnd()
glColor3f(1.0, 0.0, 0.0) # red for z axis
glBegin(GL_LINES)
#glLineStipple(1, 0x00FF) # dashed
glVertex3f(0.0, 0.0, 0.0)
glVertex3f(0.0, 0.0, 2.0)
glEnd()
glFlush()
glEndList()
def SetPosition(self, camX, camY, camZ, viewX, viewY, viewZ):
"""Sets the viewpoint at which to look
Called when the user moves from one location to another"""
print "In Gallery.SetPosition"
self.SetCurrent()
# Viewing transformation
print "Camera: ", camX, camY, camZ
print "View: ", viewX, viewY, viewZ
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(camX, camY, camZ, # camera position
viewX, viewY, viewZ , # camera aimed at
0.0, 1.0, 0.0) # view-up matrix
self.OnDraw()
#self.SwapBuffers()
def LookAt(self, x, z):
"""Positions the camera and viewpoint to look at the billboard
at array position (x, z)"""
print "Looking at position: ", x, z
#self.SetCurrent()
coords = self.GetBillboardCoordinates(x, z)
leftX = coords[0]
rightX = coords[1]
bottomY = coords[2]
topY = coords[3]
z = coords[4]
billboardX = (leftX + rightX) / 2
billboardY = (bottomY + topY) / 2
billboardZ = z
print "In LookAt, billboard position = ", billboardX, billboardY, billboardZ
#billboardZ = (z - 1) * self.distZ
camX = billboardX
camY = billboardY
#camZ = billboardZ - (self.distZ / 5.0)
#camZ = billboardZ - ((self.distZ / 4.0) * 3) # Step back 3/4 of the way to the next billboard
camZ = billboardZ + (self.distZ * 0.8) #- self.distZ / 4.0
self.SetPosition(camX, camY, camZ,
billboardX, billboardY, billboardZ)
#self.SwapBuffers()
def getVizEngine(self):
return self.myVizEngine
class CubeCanvas(MyGlCanvas):
def InitGL(self):
print “In CubeCanvas.InitGL”
# set viewing projection
glMatrixMode(GL_PROJECTION)
glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0)
# position viewer
glMatrixMode(GL_MODELVIEW)
glTranslatef(0.0, 0.0, -2.0)
# position object
glRotatef(self.y, 1.0, 0.0, 0.0)
glRotatef(self.x, 0.0, 1.0, 0.0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
def OnDraw(self):
print "In CubeCanvas.OnDraw"
# clear color and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# draw six faces of a cube
glBegin(GL_QUADS)
glNormal3f( 0.0, 0.0, 1.0)
glVertex3f( 0.5, 0.5, 0.5)
glVertex3f(-0.5, 0.5, 0.5)
glVertex3f(-0.5,-0.5, 0.5)
glVertex3f( 0.5,-0.5, 0.5)
glNormal3f( 0.0, 0.0,-1.0)
glVertex3f(-0.5,-0.5,-0.5)
glVertex3f(-0.5, 0.5,-0.5)
glVertex3f( 0.5, 0.5,-0.5)
glVertex3f( 0.5,-0.5,-0.5)
glNormal3f( 0.0, 1.0, 0.0)
glVertex3f( 0.5, 0.5, 0.5)
glVertex3f( 0.5, 0.5,-0.5)
glVertex3f(-0.5, 0.5,-0.5)
glVertex3f(-0.5, 0.5, 0.5)
glNormal3f( 0.0,-1.0, 0.0)
glVertex3f(-0.5,-0.5,-0.5)
glVertex3f( 0.5,-0.5,-0.5)
glVertex3f( 0.5,-0.5, 0.5)
glVertex3f(-0.5,-0.5, 0.5)
glNormal3f( 1.0, 0.0, 0.0)
glVertex3f( 0.5, 0.5, 0.5)
glVertex3f( 0.5,-0.5, 0.5)
glVertex3f( 0.5,-0.5,-0.5)
glVertex3f( 0.5, 0.5,-0.5)
glNormal3f(-1.0, 0.0, 0.0)
glVertex3f(-0.5,-0.5,-0.5)
glVertex3f(-0.5,-0.5, 0.5)
glVertex3f(-0.5, 0.5, 0.5)
glVertex3f(-0.5, 0.5,-0.5)
glEnd()
if self.size is None:
self.size = self.GetClientSize()
w, h = self.size
w = max(w, 1.0)
h = max(h, 1.0)
xScale = 180.0 / w
yScale = 180.0 / h
glRotatef((self.y - self.lasty) * yScale, 1.0, 0.0, 0.0);
glRotatef((self.x - self.lastx) * xScale, 0.0, 1.0, 0.0);
self.SwapBuffers()
class CurrentView(wx.Panel):
def init(self, parent):
print “Entering CurrentView.init”
self.parent = parent
self.position = [self.parent.currAppData.position.x,
self.parent.currAppData.position.z]
wx.Panel.__init__(self, self.parent, style=wx.BORDER_SUNKEN, size=(60, 200))
box = wx.BoxSizer(wx.VERTICAL)
self.widget = wxVTKRenderWindow(self, -1, pos=(100, 100), size=(170, 170))
self.myVizEngine = vizGenerator.vizEngine.vizEngine(MAP_FILE_NAME, DATA_FILE_NAME)
#ren = self.myVizEngine.getVtkViz(self.position)
#self.widget.GetRenderWindow().AddRenderer(ren)
self.OnDraw()
box.Add(self.widget, 0, wx.ALIGN_RIGHT)
self.SetSizer(box)
print "CurrentView.__init__ has completed"
def SetPosition(self, position):
self.position = position
def OnDraw(self):
print "In CurrentView.OnDraw"
self.position = [self.parent.currAppData.position.x,
self.parent.currAppData.position.z]
print "Position is ", self.position
self.widget = wxVTKRenderWindow(self, -1, pos=(100, 100), size=(170, 170))
#myVizEngine = vizGenerator.vizEngine.vizEngine(MAP_FILE_NAME, DATA_FILE_NAME)
ren = self.myVizEngine.getVtkViz(self.position)
#renWin = self.widget.GetRenderWindow()
#renWin.AddRenderer(ren)
self.widget.GetRenderWindow().AddRenderer(ren)
self.widget.GetRenderWindow().Render()
#self.widget.Render()
renWin.Render()
camera = ren.GetActiveCamera()
camera.SetViewUp(1, 0, 0)
ren.SetActiveCamera(camera)
#self.widget.Render()
#self.widget.GetRenderWindow().Render()
print "Finished CurrentView.OnDraw"
class HistoryView(scrolled.ScrolledPanel):
#class HistoryView(wx.ScrolledWindow):
SPACING = 1
def __init__(self, parent):
wx.ScrolledWindow.init(self, parent, id=-1, pos=wx.DefaultPosition,
size=(700, 100), style=wx.HSCROLL,
name=“History View”)
scrolled.ScrolledPanel.__init__(self, parent, -1, size=(840, 300))
#self.SetSize((700, 100))
#self.panel = wx.Panel(self, style=wx.BORDER_SUNKEN, size=(700, 100))
#self.navigationWin = navigationWin
self.parent = parent
self.history = self.parent.currAppData.history
self.boxSizer = wx.BoxSizer(wx.HORIZONTAL)
self.boxSizer.SetMinSize((600, 200))
self.myVizEngine = vizGenerator.vizEngine.vizEngine(MAP_FILE_NAME, DATA_FILE_NAME)
# Add initial position to history
print "Adding initial position: ", self.parent.currAppData.position
self.AddPosition(self.parent.currAppData.position)
#self.OnDraw()
self.SetSizerAndFit(self.boxSizer)
#self.SetSizer(self.boxSizer)
self.SetupScrolling(scroll_x=True, scroll_y=False)
self.boxSizer.Fit(self)
def AddPosition(self, position):
print "In HistoryView.AddPosition, adding position ", position
historyButton = HistoryButton(self, position, self.myVizEngine)
self.boxSizer.Add(historyButton, 0, wx.ALL, self.SPACING)
self.boxSizer.Layout()
self.boxSizer.FitInside(self)
class HistoryButton(buttons.GenBitmapButton):
SCALE_FACTOR = 0.75
def __init__(self, parent, position, vizEngine):
self.position = position
print "Button created with position: ", self.position.toString()
self.parent = parent
textureFilename = vizEngine.getViz([position.x, position.z])
image = wx.Image(textureFilename, wx.BITMAP_TYPE_BMP)
#image = wx.Bitmap(textureFilename)
width = image.GetWidth()
height = image.GetHeight()
#print "Image Size: ", width, height
scaledImage = image.Scale(width * self.SCALE_FACTOR, height * self.SCALE_FACTOR)
bitmapImage = scaledImage.ConvertToBitmap()
buttons.GenBitmapButton.__init__(self, parent, -1, bitmapImage, pos=(0, 0), style=0)
self.Bind(wx.EVT_BUTTON, self.OnClick, self)
def OnClick(self, event):
print "Button Position: ", self.position.toString()
self.parent.parent.navigationPanel.OnStep(self.position)
#class CurrentView(wx.Panel):
def init(self, parent):
print “Entering CurrentView.init”
self.parent = parent
self.position = [self.parent.currAppData.position.x,
self.parent.currAppData.position.z]
wx.Panel.init(self, parent, style=wx.BORDER_SUNKEN)
box = wx.BoxSizer(wx.VERTICAL)
self.widget = wxVTKRenderWindow(self, -1, pos=(100, 100), size=(170, 170))
myVizEngine = vizGenerator.vizEngine.vizEngine(MAP_FILE_NAME, DATA_FILE_NAME)
ren = myVizEngine.getVtkViz(self.position)
self.widget.GetRenderWindow().AddRenderer(ren)
box.Add(self)
self.SetSizer(box)
print “Leaving CurrentView.init”
def OnDraw(self):
print “In CurrentView.OnDraw”
self.position = [self.parent.currAppData.position.x,
self.parent.currAppData.position.z]
myVizEngine = vizGenerator.vizEngine.vizEngine(MAP_FILE_NAME, DATA_FILE_NAME)
ren = myVizEngine.getVtkViz(self.position)
#class CurrentView(wx.Panel):