I have a basic OpenGL square drawing code that I want to put another thread using Python. This is the normal code which is working well,
from OpenGL.GLUT import *
from OpenGL.GL import *
from OpenGL.GLU import *
class Drawer:
def drawQuad(self, x,y,width):
halfW=width/2
glBegin(GL_QUADS)
glVertex3f(x-halfW, y-halfW, 0)
glVertex3f(x-halfW, y+halfW, 0)
glVertex3f(x+halfW, y+halfW, 0)
glVertex3f(x+halfW, y-halfW, 0)
glEnd()
def display(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glColor3f(0, 0, 1)
self.drawQuad(0.0,0.0,0.6)
glutSwapBuffers( )
class Visualizer:
drawer = Drawer()
def __init__(self):
glutInit(sys.argv)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
glutInitWindowSize(250, 250)
glutInitWindowPosition(100, 100)
glutCreateWindow(sys.argv[0])
glutDisplayFunc( self.drawer.display )
glClearColor ( 0, 0, 0, 0 )
glShadeModel( GL_SMOOTH )
glutMainLoop()
visualizer = Visualizer()
This works on my machine flawlessly. Now, I want to put this on a thread. I did the following,
class Thread(threading.Thread):
visualizer = None
def run(self):
self.visualizer = Visualizer()
thread = Thread()
thread.start()
When I run the thread, instead of visualizer itself, it does not work. The OpenGL window does not appear. I cannot see what the problem is.
I tried the threading with some other examples, they seemed working well. I am confused a bit. What is the problem with my threading approach for OpenGL?
Related
Today I am trying to develop an UI using cefpython which allows me to embed a web browser and interacts with it with javascript bindings.
I'm using it to develop on Windows platform.
For this purpose, I am using the "multi_threaded_message_loop" flag which allows me to gain in performance.
I'm also using wxpython on python 3 to embed it.
The problem is when I resize my window, the use of WindowUtils.OnSize() freezes my app. 99% of the time, it happens when the browser is loading (but it also happens when it's done (rarely)).
Here is a sample code to reproduce :
import platform
import sys
import wx
from cefpython3 import cefpython
WindowUtils = cefpython.WindowUtils()
WIDTH = 800
HEIGHT = 600
import os
class MainFrame(wx.Frame):
browser = None
mainPanel = None
def createMainBrowser(self):
self.browser = self.createBrowser(self.mainPanel)
def createBrowser(self, parent):
browser = cefpython.CreateBrowserSync(
self.getWindowInfo(parent),
browserSettings={},
navigateUrl='http://www.google.com'
)
return browser
def getWindowInfo(self, parent):
windowInfo = cefpython.WindowInfo()
windowInfo.SetAsChild(parent.GetHandle(), [0, 0, WIDTH, HEIGHT])
return windowInfo
def __init__(self):
wx.Frame.__init__(
self, parent=None, id=wx.ID_ANY, title='wx', size=(WIDTH, HEIGHT)
)
self.mainPanel = wx.Panel(self)
self.mainPanel.SetBackgroundColour(wx.GREEN)
cefpython.PostTask(cefpython.TID_UI, self.createMainBrowser)
self.mainPanel.Bind(wx.EVT_SIZE, self.OnSize)
def OnSize(self, _):
if not self.browser:
return
WindowUtils.OnSize(self.mainPanel.GetHandle(), 0, 0, 0)
self.browser.NotifyMoveOrResizeStarted()
class App(wx.App):
def OnInit(self):
frame = MainFrame()
frame.Show()
return True
if __name__ == '__main__':
sys.excepthook = cefpython.ExceptHook # To shutdown all CEF processes on error
cefpython.Initialize({
"locales_dir_path": cefpython.GetModuleDirectory() + "/locales",
"browser_subprocess_path": cefpython.GetModuleDirectory() + "/subprocess",
"auto_zooming": "system_dpi",
"multi_threaded_message_loop": True,
})
app = App(False)
app.MainLoop()
cefpython.Shutdown()
Thank you a lot for your help !
Alann
Problem solved !
Instead of using
def OnSize(self, _):
if not self.browser:
return
WindowUtils.OnSize(self.mainPanel.GetHandle(), 0, 0, 0)
self.browser.NotifyMoveOrResizeStarted()
I use
def OnSize(self, sizeEvent):
if not self.browser:
return
w = sizeEvent.GetSize().GetWidth()
h = sizeEvent.GetSize().GetHeight()
win32gui.SetWindowPos(self.browser.GetWindowHandle(), 0, 0, 0, w, h, 0)
self.browser.NotifyMoveOrResizeStarted()
I don't know if this is because I'm on windows 10 but maybe WindowsUtils needs to be updated !
I would like to open and close a glut window several times in my program. I came up with this python code:
#!/usr/bin/python
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
#parameters for viewer
name = 'Viewer'
width, height = 500, 500
spheresize = 0.3
def display():
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
gluLookAt(0,0,10,0,0,0,0,1,0)
glPushMatrix()
color = [1.0,0.0,0.0,1.0]
glMaterialfv(GL_FRONT,GL_DIFFUSE,color)
glTranslatef(0.0,0.0,1.0)
glutSolidSphere(spheresize,20,20)
glPopMatrix()
glutSwapBuffers()
return
def closing():
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE,GLUT_ACTION_GLUTMAINLOOP_RETURNS) glutLeaveMainLoop()
return
#---------------BEGIN PROGRAM----------------
while 1:
glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowSize(width,height)
glutCreateWindow(name)
glClearColor(0.,1.0,0.,1.)
glShadeModel(GL_SMOOTH)
glEnable(GL_CULL_FACE)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glMatrixMode(GL_PROJECTION)
gluPerspective(40.,1.,1.,40.)
glMatrixMode(GL_MODELVIEW)
glPushMatrix()
glutDisplayFunc(display)
glutCloseFunc(closing)
glutMainLoop()
print "\n\nMAIN MENUE:"
print "p - print"
print "q - quit"
option = raw_input()
if option == "q":
raise SystemExit
elif option == "p":
print ("Hello World!")
When I try to run this, the window closes as I intended, but it crashes after using option 'p' with
freeglut ERROR: Function glutCreateWindow called without first calling 'glutInit'.
After I found some other posts about a similar problem, I assumed it might be a problem of my library linkage, so I tried to run it in a clean python environment on another computer. It gave the same error.
Does anyone have an idea what might be my mistake?
I'm using Python and OpenGL to make some calculations related to a physical system and then display them and be able to manipulate the image rotating it, translating it, ...
I'm not a professional programmer and I have little experience using OpenGL and I'm having some issues trying to get what I want. I would like to be able to save the window that I get as an output in a video file and to do so I've seen the possibility of using glReadPixels to capture each frame and then put them all together.
I am using right now something that looks like the following code and I want to be able to save the frames to images but, although I've been able to save to save the pixels to an array using glReadPixels, I don't know where nor how to call the function that I've defined as captureScreen. What should I do to get the output that I'm looking for?
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
from scipy import *
import numpy as np
import random as rnd
def captureScreen(file_):
glPixelStorei(GL_PACK_ALIGNMENT, 1)
data = glReadPixels(0, 0, 800, 800, GL_RGBA, GL_UNSIGNED_BYTE)
image = Image.fromstring("RGBA", (800, 800), data)
image.save(file_, 'png')
def main():
glutInit(sys.argv)
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowPosition(0, 0)
glutInitWindowSize(800, 800)
glutCreateWindow ("Test")
glEnable(GL_DEPTH_TEST)
glDepthMask(GL_TRUE)
glEnable(GL_BLEND)
glEnable(GL_TEXTURE_2D)
glEnable(GL_COLOR_MATERIAL)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glPointSize( 6.0 )
glLineWidth( 2.0 )
glEnable(GL_POINT_SMOOTH)
glEnable(GL_LINE_SMOOTH)
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
glEnable(GL_POLYGON_SMOOTH)
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST)
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
glClearColor(0.0, 0.0, 0.0, 0.0)
glutFullScreen()
glutKeyboardFunc(keyboard)
glutIdleFunc(dynamics)
glutDisplayFunc(display)
glutMouseFunc(mouse)
glutMainLoop()
if __name__ == '__main__':
main()
keyboard, display, dynamics and mouse are functions previously defined.
You can call glReadPixels() just after glutSwapBuffers():
glutSwapBuffers()
glReadBuffer(GL_FRONT)
glReadPixels(...)
Or just before:
glReadBuffer(GL_BACK)
glReadPixels(...)
glutSwapBuffers()
So captureScreen() should be called from your "display" function which is probably the one which calls glutSwapBuffers()
I have the example code below, simplified from a larger project. I have been trying to make alpha channels work i have enabled blending and written a similar example using pygame which works. How ever setting up opengl to work with a glx context seems to stop blending from working, i have a feeling i need to enabel some parameter to the gl context setup but have not been able to find out what that parameter is.
Any suggestions on why this is not working, i have tried on two different machines one with high end radeon and another with an intel graphics card both do the same however.
#blending is not working any ideas why ?
import sys
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL import GLX
from OpenGL.raw._GLX import struct__XDisplay
from OpenGL import GL
from ctypes import *
import Xlib
from Xlib.display import Display
from gi.repository import Gtk, GdkX11, Gdk
class gtkgl:
""" these method do not seem to exist in python x11 library lets exploit the c methods """
xlib = cdll.LoadLibrary('libX11.so')
xlib.XOpenDisplay.argtypes = [c_char_p]
xlib.XOpenDisplay.restype = POINTER(struct__XDisplay)
xdisplay = xlib.XOpenDisplay("")
display = Xlib.display.Display()
attrs = []
xwindow_id = None
width = height = 200
def __init__(self):
""" lets setup are opengl settings and create the context for our window """
self.add_attribute(GLX.GLX_RGBA, True)
self.add_attribute(GLX.GLX_RED_SIZE, 1)
self.add_attribute(GLX.GLX_GREEN_SIZE, 1)
self.add_attribute(GLX.GLX_BLUE_SIZE, 1)
self.add_attribute(GLX.GLX_ALPHA_SIZE, 1)
self.add_attribute(GLX.GLX_DOUBLEBUFFER, 0)
glClearDepth(1.0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glShadeModel(GL_SMOOTH)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glLight(GL_LIGHT0, GL_POSITION, (0, 1, 1, 0))
xvinfo = GLX.glXChooseVisual(self.xdisplay, self.display.get_default_screen(), self.get_attributes())
configs = GLX.glXChooseFBConfig(self.xdisplay, 0, None, byref(c_int()))
self.context = GLX.glXCreateContext(self.xdisplay, xvinfo, None, True)
def add_attribute(self, setting, value):
"""just to nicely add opengl parameters"""
self.attrs.append(setting)
self.attrs.append(value)
def get_attributes(self):
""" return our parameters in the expected structure"""
attrs = self.attrs + [0, 0]
return (c_int * len(attrs))(*attrs)
def configure(self, wid):
""" """
self.xwindow_id = GdkX11.X11Window.get_xid(wid)
if(not GLX.glXMakeCurrent(self.xdisplay, self.xwindow_id, self.context)):
print 'failed'
glViewport(0, 0, self.width, self.height)
def draw_start(self):
"""make cairo context current for drawing"""
if(not GLX.glXMakeCurrent(self.xdisplay, self.xwindow_id, self.context)):
print "failed"
def draw_finish(self):
"""swap buffer when we have finished drawing"""
GLX.glXSwapBuffers(self.xdisplay, self.xwindow_id)
def test(self):
"""Test method to draw something so we can make sure opengl is working and we can see something"""
self.draw_start()
glClearColor(0.0, 0.0, 0.0, 0.0)
glClear(GL_COLOR_BUFFER_BIT)
glBegin(GL_TRIANGLES)
glIndexi(0)
glColor4f(1.0, 0.0, 0.0, 0.2)
glVertex2i(0, 1)
glIndexi(0)
glColor4f(0.0, 1.0, 0.0, 0.2)
glVertex2i(-1, -1)
glIndexi(0)
glColor4f(0.0, 0.0, 1.0, 1.0)
glVertex2i(1, -1)
glEnd()
self.draw_finish()
class gui():
glwrap = gtkgl()
def __init__(self):
self.window = Gtk.Window()
self.window.realize()
self.window.resize(self.glwrap.width, self.glwrap.height)
self.window.set_resizable(True)
self.window.set_reallocate_redraws(True)
self.window.set_title("GTK3 with opengl")
self.window.connect('delete_event', Gtk.main_quit)
self.window.connect('destroy', lambda quit: Gtk.main_quit())
self.drawing_area = Gtk.DrawingArea()
self.drawing_area.connect('configure_event', self.on_configure_event)
self.drawing_area.connect('draw', self.on_draw)
self.drawing_area.set_double_buffered(False)
self.drawing_area.set_size_request(self.glwrap.width, self.glwrap.height)
self.window.add(self.drawing_area)
self.window.show_all()
def on_configure_event(self, widget, event):
self.glwrap.configure(widget.get_window())
return True
def on_draw(self, widget, context):
self.glwrap.test()
def main():
g = gui()
Gtk.main()
if __name__ == '__main__':
main()
It's not the OpenGL context missing something (at the point of creation I mean). You're simply not enabling blending. You need to add a glEnable(GL_BLEND); before drawing primitives that require blending.
BTW: Using 1 bit as minimum requirement for RGB channels can yield to undesired results. Use at least 5 bits (for 16 bit displays) or better yet 8 bits. Also you don't need an alpha channel on the main framebuffer for blending to work. So unless you want to create transparent windows on a compositor, then you should use 0 alpha bits on the window's framebuffer.
I can't get a basic shader program working in PyQt. I think this should at least compile the shader code correctly (I'm no expert here), but addShaderFromSourceFile() always returns false no matter what I try. The shader program log is always empty too.
I'm on Ubuntu 12.04, and I can compile and run GLSL shader programs in C++. So I don't think it's a system issue.
File shader.vert
void main(void)
{
gl_Position = ftransform();
}
File shader.frag
void main(void)
{
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
File test_shaders.py
from OpenGL.GL import *
from OpenGL.GLU import *
from PyQt4 import QtCore, QtGui
from PyQt4.QtOpenGL import *
class ExampleQGLWidget(QGLWidget):
def __init__(self, parent):
QGLWidget.__init__(self, parent)
self.shaderProgram = QGLShaderProgram()
print self.shaderProgram.addShaderFromSourceFile(QGLShader.Vertex, "shader.vert")
print self.shaderProgram.addShaderFromSourceFile(QGLShader.Fragment, "shader.frag")
print self.shaderProgram.log()
self.shaderProgram.link()
glViewport(0,0, 640, 480)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.shaderProgram.bind()
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
def initializeGL(self):
glClearColor(0.0, 0.0, 0.0, 1.0)
glClearDepth(1.0)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
class TestContainer(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
widget = ExampleQGLWidget(self)
self.setCentralWidget(widget)
if __name__ == '__main__':
app = QtGui.QApplication(['Shader Example'])
window = TestContainer()
window.show()
app.exec_()
The OpenGL context isn't setup inside the constructor, it's only valid and current inside the paintGL, resizeGL and initializeGL methods, so you should load and compile shaders inside the initializeGL method, and not anywhere else.
I believe that the other answer may be outdated now. There is, at least since PyQt5, a way to make the widgets OpenGL context current (and to clean up afterwards).
It can be achieved with the makeCurrent() and currentDone() methods on the QGlWidget.
A solution would look like:
...
class ExampleQGLWidget(QGLWidget):
def __init__(self, parent):
QGLWidget.__init__(self, parent)
self.shaderProgram = QGLShaderProgram()
self.makeCurrent()
print self.shaderProgram.addShaderFromSourceFile(QGLShader.Vertex, "shader.vert")
print self.shaderProgram.addShaderFromSourceFile(QGLShader.Fragment, "shader.frag")
print self.shaderProgram.log()
self.shaderProgram.link()
self.doneCurrent()
glViewport(0,0, 640, 480)
...