OpenGL widget canvas rendering

1,161 views
Skip to first unread message

Pavel Kostelnik

unread,
Jun 28, 2012, 9:46:02 AM6/28/12
to kivy-...@googlegroups.com
Hi,

I started porting Dice3DS for kivy but I just CANT get OpenGL instructions working in Kivy. The rendering doesn't work I just get a black space where I expect my rendered result. This is my Widget code:

class ThreeDWidget(Widget):
def __init__(self):
Widget.__init__(self)
self.setup_Dice3DS()
self.cb.ask_update()
self.canvas.ask_update()

def setup_Dice3DS(self):
with self.canvas:
self.fbo = Fbo(size=(150150), clear_color=((.3, .3, .3, .2)))
self.size= self.fbo.size
with self.fbo:
self.cb = Callback(self.run_gl)
#parameter reset_context=True doesn't help :(
def run_gl(self, instr):
#direct openGL instructions don't work 
glClearColor(0.5,0.5,1.0,0)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
#neither does kivy instruction 
#ClearColor(0.5,0.5,1.0,0)


Or can somehow just please please give me a snippet of code that show how to render widget canvas with OpenGL ? Pleaaase ? I really have a hard time getting this and I can't find much valuable information anywhere…

thanks a lot

Mathieu Virbel

unread,
Jun 28, 2012, 10:02:12 AM6/28/12
to kivy-...@googlegroups.com
You're on the right way.

A/ What you're missing is to ask to refresh the fbo when it changed.
Remember, kivy don't display 60FPS like game. It refresh the screen only
when necessary. When a graphics instruction is changed, it ask for an
update to parent... until the root window got the refresh.
And then, a drawing is done.

In your case, you must trigger that behavior yourself, because we don't
know when the callback is changing the state. So you can add in init:

Clock.schedule_interval(self.ask_update, 1/60.)

And add a method:

def ask_update(self, dt):
self.fbo.ask_update()
# or self.cb is correct too. i'm just used to update the fbo
that way.


B/ FBO = all the rendering done when the FBO is binded is redirected to
a Texture. Look at your example, you didn't use the texture anywhere.
You can add a Rectangle instruction, with the texture from the FBO, and
then you'll draw the Fbo's texture on the screen:

with self.canvas:
self.fbo = Fbo(size=(150, 150), ...)
self.size = self.fbo.size
Rectangle(size=self.size, texture=self.fbo.texture)


That's all!

Note: Check kivy/examples/widgets/fbowidget.py if you want a clean usage
of FBO inside a widget, and take care of the size of the widget / update
of the texture etc.

Mathieu
> hard time getting this and I can't find much valuable information anywhere�
>
> thanks a lot
>

Pavel Kostelnik

unread,
Jun 28, 2012, 11:50:50 AM6/28/12
to kivy-...@googlegroups.com
I fixed those two issues in my widget but I still get a black screen - I guess the texture is still not updated somehow. Just try to add my widget to a simple kivy app and run it

class ThreeDWidget(Widget):

    

    def __init__(self):
        Widget.__init__(self)
        self.setup_Dice3DS()
        Clock.schedule_interval(self.ask_update,1/60.)

    def setup_Dice3DS(self):
        with self.canvas:
            self.fbo = Fbo(size=(150, 150), clear_color=((.3, .0, .3, .2)))
            self.size= self.fbo.size
            Rectangle(size=self.size, texture=self.fbo.texture)
        with self.fbo:
            Callback(self.run_gl)
            #parameter reset_context=True doesn't help :(
    def run_gl(self, instr):

        

        glClearColor(0.5,0.5,1.0,0)    # This Will Clear The Background Color to desired one

       

        glLoadIdentity()                                    # Reset The Projection Matrix
                                                                                    # Calculate The Aspect Ratio Of The Window

    

        glMatrixMode(GL_MODELVIEW)

    


        glClearColor(0.5,0.5,1.0,0)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        glBegin(GL_POLYGON)                 # Start drawing a polygon
        glVertex3f(0.0, 1.0, 0.0)           # Top
        glVertex3f(1.0, -1.0, 0.0)          # Bottom Right
        glVertex3f(-1.0, -1.0, 0.0)         # Bottom Left
        glEnd()                       
        #neither does kivy instruction 
        #ClearColor(0.5,0.5,1.0,0)

        

    def ask_update(self, dt):
        print "dt" + str(dt)
        self.fbo.ask_update()


This is the first step for me porting Dice3DS and I really need it to work… I need to make sure OpenGL graphics instructions work and after that convert them to kivy graphic instructions . 


thanks a lot
hard time getting this and I can't find much valuable information anywhere…

thanks a lot



Hwan-Wei Lin

unread,
Jun 28, 2012, 12:36:48 PM6/28/12
to kivy-...@googlegroups.com
 
Hi,
 
You can try this,
 
        glClearColor(0.5,0.5,1.0,1.0)    # This Will Clear The Background Color to desired one
 
Hope it is helpful.

Pavel Kostelnik

unread,
Jun 29, 2012, 5:24:20 AM6/29/12
to kivy-...@googlegroups.com
thanks that helped,

tho I am only able to draw a background, I can't draw a polygon on the background…My widget code is now like this:

class ThreeDWidget(Widget):

    

    def __init__(self):
        Widget.__init__(self)
        self.setup_Dice3DS()
        Clock.schedule_interval(self.ask_update,1/60.)

    def setup_Dice3DS(self):
        with self.canvas:
            self.fbo = Fbo(size=(300, 300), pos=self.pos)
            self.size= self.fbo.size
            self.r = Rectangle(size=self.size, texture=self.fbo.texture)
        with self.fbo:
            Callback(self.run_gl)
    
    def run_gl(self, instr):
        glClearColor(0.0, 0.2, 0.3, 1.0)    # This Will Clear The Background Color
        glClearDepth(1.0)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()                                    # Reset The Projection Matrix
        glMatrixMode(GL_MODELVIEW)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()                                        # Reset The View 

        # Move Left 1.5 units and into the screen 6.0 units.
        glTranslatef(-1.5, 0.0, -6.0)

        # Draw a triangle - THIS PART DOESNT WORK!!!
        glBegin(GL_POLYGON)                 # Start drawing a polygon
        glColor3f(1.0, 0.0, 0.0)            # Red
        glVertex3f(0.0, 1.0, 0.0)           # Top
        glColor3f(0.0, 1.0, 0.0)            # Green
        glVertex3f(1.0, -1.0, 0.0)          # Bottom Right
        glColor3f(0.0, 0.0, 1.0)            # Blue
        glVertex3f(-1.0, -1.0, 0.0)         # Bottom Left
        glEnd()                          
        
    def ask_update(self, dt):

        print "dt" + str(dt)

        self.fbo.ask_update()
        self.r.pos = self.pos
        self.r.size = self.size


So the problem is in the polygon drawing… I get background of the widget colored fine, but there is no triangle on it… How do I render other content on the fbo ? ( cause that seems to be the problem for me). I only have the background …

Christian Bergmann

unread,
Sep 26, 2012, 5:24:02 AM9/26/12
to kivy-...@googlegroups.com
Hi, 

I am faced with the same challenge.
have you solved it already?

thanks
chris

Mathieu Virbel

unread,
Sep 26, 2012, 7:07:43 AM9/26/12
to kivy-...@googlegroups.com
As i said, you are in the Kivy GL context, so you have a shader already
active. When a shader is active, you cannot use direct rendering such as
glBegin etc.

One start point would be to glUseProgram(0).
And same for texture, or any others values.

Mathieu

Le 29/06/2012 11:24, Pavel Kostelnik a �crit :
> thanks that helped,
>
> tho I am only able to draw a background, I can't draw a polygon on the
> background�My widget code is now like this:
> So the problem is in the polygon drawing� I get background of the widget
> colored fine, but there is no triangle on it� How do I render other
> content on the fbo ? ( cause that seems to be the problem for me). I
> only have the background �
>
>
> On Jun 28, 2012, at 6:36 PM, Hwan-Wei Lin wrote:
>
>>
>> Hi,
>>
>> You can try this,
>>
>> glClearColor(0.5,0.5,1.0,*1.**0*) # This Will Clear The
>> to work� I need to make sure OpenGL graphics instructions work and
>>>> information anywhere�
>>>>
>>>> thanks a lot
>>>>
>>>
>>
>>
>

Christian Bergmann

unread,
Sep 26, 2012, 9:27:45 AM9/26/12
to kivy-...@googlegroups.com
Hi Mathieu,

oh, I must have missed this! Sorry, Excuse me!!!

solved! :)

        #glTranslatef(-1.5, 0.0, -6.0)
        glUseProgram(0)
        glBegin(GL_POLYGON)                 # Start drawing a polygon
        glColor3f(1.0, 0.0, 0.0)            # Red
        glVertex3f(0.0, 1.0, 0.0)           # Top
        glColor3f(0.0, 1.0, 0.0)            # Green
        glVertex3f(1.0, -1.0, 0.0)          # Bottom Right
        glColor3f(0.0, 0.0, 1.0)            # Blue
        glVertex3f(-1.0, -1.0, 0.0)         # Bottom Left
        glEnd()   

thanks a lot
chris

Christian Bergmann

unread,
Oct 8, 2012, 4:29:57 PM10/8/12
to kivy-...@googlegroups.com
Hi,

hope someone could help me again, please.
I want to activate my own shader... using "glUseProgram(program)"
however, my triangle, which I drawed not displayed
the shader func "compile_program" works very well on pure pygame...

program = compile_program('''
// sample Vertex program
varying vec3 pos;
void main() {
    pos = gl_Vertex.xyz;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
''', '''
// sample Fragment program
varying vec3 pos;
void main() {
    gl_FragColor.rgb = pos.xyz;
}
''')

    def _drawTriangle(self):
        """ """
        glUseProgram(program)
        glBegin(GL_TRIANGLES)
        glColor3f(1.0, 0.0, 0.0) 
        glVertex3f(-1,-1, 0);  
        glVertex3f( 1,-1, 0);
        glVertex3f( 0, .5, 0);     
        glEnd()


------------------------------------------
code:
#comments removed
class ThreeDWidget(Widget):
    """ """
    
    def __init__(self, **kwargs):
        """ """
        super(ThreeDWidget, self).__init__(**kwargs)
        glShadeModel(GL_SMOOTH)
        glClearColor(0.0, 0.0, 0.0, 0.0)
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LEQUAL)
        
    def drawTriangle(self, pos, size, color, z=1):
        """ """
        self.pos = pos
        self.size = size
        self.color = color
        self.z = z

        self._init_fbo()
        Clock.schedule_interval(self._ask_update,1/60)      

    def _init_fbo(self):
        """ """
        with self.canvas:
            self._fbo = Fbo(size=self.size, pos=self.pos)
            self.rect = Rectangle(size=self.size, texture=self._fbo.texture)
        
        with self._fbo:
            Color(0, 0, 0)
            Rectangle(size=Window.size)            
            Callback(self._display)
        
    def _display(self, instr):
        """ """
        glClearColor(0, 0, 0, 0)    
        glClearDepth(1.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        self._drawScene()
        glFlush()
   
    def _drawScene(self, sel=0):
        """ """
        #view = glGetIntegerv(GL_VIEWPORT)
        #(x,y) = pygame.mouse.get_pos()
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        #if sel: gluPickMatrix(x, view[3]-y, 1, 1, view)
        gluPerspective(60, view[2]/view[3], 1, 1000)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        glTranslatef(0, 0.0, -1.8)
        self._drawTriangle()
        
    def _drawTriangle(self):
        """ """
        glUseProgram(program)
        glBegin(GL_TRIANGLES)
        glColor3f(1.0, 0.0, 0.0) 
        glVertex3f(-1,-1, 0);  
        glVertex3f( 1,-1, 0);
        glVertex3f( 0, .5, 0);     
        glEnd()

    def _ask_update(self, dt):
        """ """
        self._fbo.ask_update()     
        self.rect.pos = self.pos
        self.rect.size = self.size
    ...

-----------------------------------------------
#shader.py
#!/usr/bin/env python

from ctypes import *
import sys
 
from pygame.locals import *
 
try:
    # For OpenGL-ctypes
    from OpenGL import platform
    gl = platform.OpenGL
except ImportError:
    try:
        # For PyOpenGL
        gl = cdll.LoadLibrary('libGL.so')
    except OSError:
        # Load for Mac
        from ctypes.util import find_library
        # finds the absolute path to the framework
        path = find_library('OpenGL')
        gl = cdll.LoadLibrary(path)
 
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
 
glShaderSource = gl.glShaderSource
glShaderSource.argtypes = [c_int, c_int, POINTER(c_char_p), POINTER(c_int)]
glGetShaderiv = gl.glGetShaderiv
glGetShaderiv.argtypes = [c_int, c_int, POINTER(c_int)]
glGetShaderInfoLog = gl.glGetShaderInfoLog
glGetShaderInfoLog.argtypes = [c_int, c_int, POINTER(c_int), c_char_p]

 
GL_FRAGMENT_SHADER = 0x8B30
GL_VERTEX_SHADER = 0x8B31
GL_COMPILE_STATUS = 0x8B81
GL_LINK_STATUS = 0x8B82
GL_INFO_LOG_LENGTH = 0x8B84
 
def compile_shader(source, shader_type):
    shader = glCreateShader(shader_type)
    source = c_char_p(source)
    length = c_int(-1)
    glShaderSource(shader, 1, byref(source), byref(length))
    glCompileShader(shader)
    
    status = c_int()
    glGetShaderiv(shader, GL_COMPILE_STATUS, byref(status))
    if not status.value:
        print_log(shader)
        glDeleteShader(shader)
        raise ValueError, 'Shader compilation failed'
    return shader
 
def compile_program(vertex_source, fragment_source):
    vertex_shader = None
    fragment_shader = None
    program = glCreateProgram()
 
    if vertex_source:
        vertex_shader = compile_shader(vertex_source, GL_VERTEX_SHADER)
        glAttachShader(program, vertex_shader)
    if fragment_source:
        fragment_shader = compile_shader(fragment_source, GL_FRAGMENT_SHADER)
        glAttachShader(program, fragment_shader)
    glLinkProgram(program)
 
    if vertex_shader:
        glDeleteShader(vertex_shader)
    if fragment_shader:
        glDeleteShader(fragment_shader)
    return program
 
def print_log(shader):
    length = c_int()
    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, byref(length))
 
    if length.value > 0:
        log = create_string_buffer(length.value)
        glGetShaderInfoLog(shader, length, byref(length), log)
        print >> sys.stderr, log.value

thanks

Mathieu Virbel

unread,
Oct 8, 2012, 5:04:31 PM10/8/12
to kivy-...@googlegroups.com
Hi Christian,

You cannot act like you did, because you're breaking all the pipeline.
We are doing the OpenGL stuff, and then, you must not do it yourself
except if you understand what you need to do exactly within the pipeline.

Now, concerning the Shader itself, we have 2 examples in the project
that demonstrate how you can write your own shader (like plasma.py), or
how to write a shader that will be applied for all children (like
shadertree.py). Start from thoses one, then extend.

https://github.com/kivy/kivy/tree/master/examples/shader

For each frame, we are traversing the graphics tree, remove redundant
instructions, and emit opengl instructions. If you want to plug your own
GL instructions while we are doing it, use Callback instruction.

http://kivy.org/docs/api-kivy.graphics.html#kivy.graphics.Callback

I see you're trying to do some 3d stuff. We have started a branch about
it to support 3d in our pipeline and instructions.
(graphics-customvertex if i remember well), partially usable, need more
love before merge :)

Regards,

Mathieu


Le 08/10/2012 22:29, Christian Bergmann a �crit :
> --
>
>
>

Christian Bergmann

unread,
Oct 9, 2012, 3:17:24 PM10/9/12
to kivy-...@googlegroups.com
Hi Mathieu ,

thanks for your answer and comments!

First I tried exactly this procedure as. 
I've used your shader widget example and added the 3d widget, which draws via opengl.
Once I've added the widget, all GL instructions were marked as invalid.
Because it did not work, I wanted to try this way. ;o)

Right, i'm trying to do some 3d stuff. My challenge is to create a interactive charting widget. But for that I need to use the opengl selection...
I see, I need more time to understand opengl/kivy and try your way again.

thanks a lot
chris

Christian Bergmann

unread,
Oct 9, 2012, 3:36:34 PM10/9/12
to kivy-...@googlegroups.com
i've forgotten to say...
because i'll use the opengl selection in order to pick a drawed element

glLoadName(1);
  glBegin(gl_triangles);
    ...
  glEnd;

 i just need to draw on opengl.

With shader i'll apply several effects as for example blur etc.

chris

Thomas Hansen

unread,
Oct 9, 2012, 3:41:53 PM10/9/12
to kivy-...@googlegroups.com
Is slection available in OpenGL ES ? I ususally end up writing a
shader to draw elements in unique colors for picking...

--
Thomas
> --
>
>

Christian Bergmann

unread,
Oct 9, 2012, 4:39:15 PM10/9/12
to kivy-...@googlegroups.com
...! :( you right.
It seems to be that the selection is not available in OpenGL ES 
Reply all
Reply to author
Forward
0 new messages