Search code examples
pythonopenglpygame3dpyopengl

OpenGl incomplete formation of the 3d cuboid when i use Gl_lines


Top and bottom faces of a cuboid drawn in wireframe

from tokenize import Double
from OpenGL.GL import *
from OpenGL.GLU import *
import pygame
from pygame.locals import *
import serial

#ser = serial.Serial('/dev/tty.usbserial', 38400, timeout=1)
ser = serial.Serial('COM5', 38400, timeout=1)
ax = ay = az =0.0
dx = dy = dz =0.0
def resize(width, height):
    if height==0:
        height=1
    glViewport(0, 0, width, height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45, 1.0*width/height, 0.1, 100.0)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

def init():
    glShadeModel(GL_SMOOTH)
    glClearColor(0.0, 0.0, 0.0, 0.0)
    glClearDepth(1.0)
    glEnable(GL_DEPTH_TEST)
    glDepthFunc(GL_LEQUAL)
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)

def drawText(position, textString):     
    font = pygame.font.SysFont ("Courier", 18, True)
    textSurface = font.render(textString, True, (255,255,255,255), (0,0,0,255))     
    textData = pygame.image.tostring(textSurface, "RGBA", True)     
    glRasterPos3d(*position)     
    glDrawPixels(textSurface.get_width(), textSurface.get_height(), GL_RGBA, GL_UNSIGNED_BYTE, textData)

def draw():
    global rquad
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    
    glLoadIdentity()
    glTranslatef(0,0.0,-7.0)

    osd_text = "pitch: " + str("{0:.2f}".format(ay)) + ", roll: " + str("{0:.2f}".format(ax)) + ", yaw: " + str("{0:.2f}".format(az))

    drawText((-2,-2, 2), osd_text)
    drawText((-2,2, 0), "PRESS Z TO CALIBRATE OFFSETS")

    # the way I'm holding the IMU board, X and Y axis are switched 
    # with respect to the OpenGL coordinate system
    glRotatef((az-dz)*-1, 0.0, 1.0, 0.0)  # Yaw,   rotate around y-axis
    glRotatef(ay-dy ,1.0,0.0,0.0)        # Pitch, rotate around x-axis
    glRotatef((-1*ax)-dx ,0.0,0.0,1.0)     # Roll,  rotate around z-axis

    glBegin(GL_QUADS)   
    #glColor3f(0.0,1.0,0.0)
    glVertex3f( 1.0, 0.2,-1.0)
    glVertex3f(-1.0, 0.2,-1.0)      
    glVertex3f(-1.0, 0.2, 1.0)      
    glVertex3f( 1.0, 0.2, 1.0)      

    #glColor3f(1.0,0.5,0.0) 
    glVertex3f( 1.0,-0.2, 1.0)
    glVertex3f(-1.0,-0.2, 1.0)      
    glVertex3f(-1.0,-0.2,-1.0)      
    glVertex3f( 1.0,-0.2,-1.0)      

    #glColor3f(1.0,0.0,0.0)     
    glVertex3f( 1.0, 0.2, 1.0)
    glVertex3f(-1.0, 0.2, 1.0)      
    glVertex3f(-1.0,-0.2, 1.0)      
    glVertex3f( 1.0,-0.2, 1.0)      

    #glColor3f(1.0,1.0,0.0) 
    glVertex3f( 1.0,-0.2,-1.0)
    glVertex3f(-1.0,-0.2,-1.0)
    glVertex3f(-1.0, 0.2,-1.0)      
    glVertex3f( 1.0, 0.2,-1.0)      

    #glColor3f(0.0,0.0,1.0) 
    glVertex3f(-1.0, 0.2, 1.0)
    glVertex3f(-1.0, 0.2,-1.0)      
    glVertex3f(-1.0,-0.2,-1.0)      
    glVertex3f(-1.0,-0.2, 1.0)      

    #glColor3f(1.0,0.0,1.0) 
    glVertex3f( 1.0, 0.2,-1.0)
    glVertex3f( 1.0, 0.2, 1.0)
    glVertex3f( 1.0,-0.2, 1.0)      
    glVertex3f( 1.0,-0.2,-1.0)      
    glEnd() 
         
def read_data():
    global ax, ay, az
    ax = ay = az = 0

    line = ser.readline().decode('utf-8')
    line = line.strip()
    imu = line.split(',')    
    ax = float(imu[0])
    ay = float(imu[1])
    az = float(imu[2])

def main():

    video_flags = OPENGL|DOUBLEBUF
    global dx, dy, dz
    pygame.init()
    screen = pygame.display.set_mode((640,480), video_flags)
    pygame.display.set_caption("Press Esc to quit")
    resize(640,480)
    init()
    frames = 0
    ticks = pygame.time.get_ticks()
    while 1:
        event = pygame.event.poll()
        if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
            pygame.quit()  #* quit pygame properly
            break       
        
        if event.type == KEYDOWN and event.key == K_z:
            dx=ax
            dy=ay
            dz=az

        read_data()
        draw()
      
        pygame.display.flip()
        frames = frames+1

    print ("fps:  %d" % ((frames*1000)/(pygame.time.get_ticks()-ticks)))
    ser.close()

if __name__ == '__main__': main()

I want to build an IMU visualization tool, this code works fine but as I am a complete beginner I am facing difficulties in building a custom model using GL_QUADS, even when i tried to display the cuboid(previously GL_Quads method) in GL_Lines there were a few portions missing as shown in the image, please guide me on how to build a model in OpenGL, I want to draw a 3D bi-copter in it. Summary: please guide me on building any type of 3D polygon in OpenGL.


Solution

  • The vertex order of line primitives differs from the vertex order of quads. See GL_LINES not showing up on top of cube?. However, you can draw GL_QUADS and change the rasterization mode with glPolygonMode:

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
    glBegin(GL_QUADS) 
    #[...]
    glEnd()
    

    Minimal example:

    import pygame
    from OpenGL.GL import *
    from OpenGL.GLU import *
    
    class Cube:
      
        def __init__(self):
            self.v = [(-1,-1,-1), ( 1,-1,-1), ( 1, 1,-1), (-1, 1,-1), (-1,-1, 1), ( 1,-1, 1), ( 1, 1, 1), (-1, 1, 1)]
            self.surfaces = [(0,1,2,3), (5,4,7,6), (4,0,3,7),(1,5,6,2), (4,5,1,0), (3,2,6,7)]
    
        def draw(self):
            glEnable(GL_DEPTH_TEST)
    
            glLineWidth(5)
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
    
            glBegin(GL_QUADS)
            for i, quad in enumerate(self.surfaces):
                for iv in quad:
                    glVertex3fv(self.v[iv])
            glEnd()
    
            glDisable( GL_POLYGON_OFFSET_FILL )
    
    def set_projection(w, h):
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45, w / h, 0.1, 50.0)
        glMatrixMode(GL_MODELVIEW)
    
    pygame.init()
    window = pygame.display.set_mode((400, 300), pygame.DOUBLEBUF | pygame.OPENGL | pygame.RESIZABLE)
    clock = pygame.time.Clock()
    
    set_projection(*window.get_size())
    cube = Cube()
    angle_x, angle_y = 0, 0
    
    run = True
    while run:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            elif event.type == pygame.VIDEORESIZE:
                glViewport(0, 0, event.w, event.h)
                set_projection(event.w, event.h)
    
        glLoadIdentity()
        glTranslatef(0, 0, -5)
        glRotatef(angle_y, 0, 1, 0)
        glRotatef(angle_x, 1, 0, 0)
        angle_x += 1
        angle_y += 0.4
    
        glClearColor(0.5, 0.5, 0.5, 1)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        cube.draw()    
        pygame.display.flip()
        
    pygame.quit()
    exit()