Using textures in orthographic projection in OpenGL - python
I'm currently programming a primary flight display using Python and OpenGL. As I have zero experience with OpenGL (and little experience with coding in general) I followed a simple tutorial giving an introduction to OpenGL for 2D applications. With this basic knowledge, I just started to make everything out of polygons (GL_QUADS) and some copied code to draw text. Which gave me this:
The visual result is satisfactory but the performance of ~450 iterations/second is questionable with one core of a Ryzen 1700x at 100% and a GTX1080 at 75% while only running this little program (which is supposed to run on a RaspberryPI 3).
So I want to try out using textures for the whole artificial horizon and inanimate objects like the scale of the speedometer, separation lines or "crosshair".
I've made a .png file that would replace the artificial horizon (see bottom) but I have no idea how to render it. All the tutorials I've found are for C++ and add a lot of complexity to the overall program so I want to ask if there is an "easy" way to implement a movable texture for my application.
Here is a mockup of how I'm currently calculating the position of the horizon and how I draw it (full runnable code at the end):
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from math import tan, radians
window_width = 800
window_height = 480
class Numbers:
mp = 0 #vertical middle point of horizon in pixels
rp = 0 #vertical right point of horizon in pixels
lp = 0 #vertical left point of horizon in pixels
def calc():
# mp- (pitch*(pixels/degree))
Numbers.mp = 240 - (Data.pitch * 8)
#offset is the vertical distance in pixels from mp
#offset =tan(roll) * pixels from horizontal middle point of screen to edge of artifical horizon
offset = tan(radians(Data.roll)) * 300
Numbers.rp = Numbers.mp - offset
Numbers.lp = Numbers.mp + offset
def horizon():
#sky
glBegin(GL_QUADS)
glColor3f(58/255, 109/255, 171/255)
glVertex2f(100, Numbers.lp)
glVertex2f(700, Numbers.rp)
glColor3f(0/255, 83/255, 165/255)
glVertex2f(700, 480)
glVertex2f(100, 480)
glEnd()
#ground
glColor3f(150/255, 70/255, 0/255)
glBegin(GL_QUADS)
glVertex2f(100, 0)
glVertex2f(700, 0)
glColor3f(140/255, 90/255, 0/255)
glVertex2f(700, Numbers.rp)
glVertex2f(100, Numbers.lp)
glEnd()
#devider line
glColor3f(255/255, 255/255, 255/255)
glBegin(GL_QUADS)
glVertex2f(100, Numbers.lp-1)
glVertex2f(700, Numbers.rp-1)
glVertex2f(700, Numbers.rp+1)
glVertex2f(100, Numbers.lp+1)
glEnd()
def iterate():
glViewport(0, 0, window_width, window_height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0.0, window_width, 0.0, window_height, 0.0, 1.0)
glMatrixMode (GL_MODELVIEW)
glLoadIdentity()
def showScreen():
#glutFullScreen()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
iterate()
calc()
horizon()
glutSwapBuffers()
if __name__ == "__main__":
glutInit()
glutInitDisplayMode(GLUT_RGBA)
glutInitWindowSize(window_width, window_height)
glutInitWindowPosition(10, 10)
wind = glutCreateWindow(b"Pi2Fly")
glutDisplayFunc(showScreen)
glutIdleFunc(showScreen)
glutMainLoop()
The real image goes from 180 to 180 to but that would be too big for SO
full code:
from OpenGL.GL import glVertex2f, glColor3f, glBegin, glEnd, GL_QUADS, GL_TRIANGLES
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from time import sleep, perf_counter, time
from math import tan, radians
import pygame
window_width = 800
window_height = 480
pygame.font.init()
font1 = pygame.font.Font (None, 40)
font2 = pygame.font.Font (None, 20)
font3 = pygame.font.Font (None, 25)
font4 = pygame.font.Font (None, 45)
class Numbers:
mp = 0
rp = 0
lp = 0
class Data:
roll = 20
pitch = 0
airspeed = 160
altitude = 4500
altitude_last = 0
altitude_now = 0
altitude_delta = 0
altitude_delta_table = 30 * [0]
time_last = 0
time_now = 0
c1 = True
c2 = True
c3 = 0
class FPS:
c = 0
fps = 0
def fps():
FPS.c += 1
try: FPS.last_clock = FPS.this_clock
except:FPS.last_clock = perf_counter()
FPS.this_clock = perf_counter()
if round(FPS.this_clock) > round(FPS.last_clock):
FPS.fps = FPS.c
FPS.c = 0
color = (255,198,0, 255)
drawText(5, 9, str(FPS.fps), color, font1)
drawText(55, 10, "FPS", color, font2)
def get_data():
#dummy data for artifical horizon
#pitch
if Data.pitch < 20 and Data.c1: Data.pitch += 0.03
if Data.pitch >= 20 and Data.c1: Data.c1 = False
if Data.pitch < 21 and not Data.c1: Data.pitch = Data.pitch - 0.03
if Data.pitch < -20: Data.c1 = True
#roll
if Data.roll < 20 and Data.c2: Data.roll += 0.02
if Data.roll >= 20 and Data.c2: Data.c2 = False
if Data.roll < 21 and not Data.c2: Data.roll = Data.roll - 0.02
if Data.roll < -20: Data.c2 = True
#airspeed
if Data.pitch > 0: Data.airspeed = Data.airspeed - 0.004 * Data.pitch
elif Data.pitch < 0: Data.airspeed = Data.airspeed + 0.004 * abs(Data.pitch)
#altitude
if Data.pitch > 0: Data.altitude = Data.altitude + 0.01 * Data.pitch
elif Data.pitch < 0: Data.altitude = Data.altitude - 0.01 * abs(Data.pitch)
#altitude_delta
Data.time_now = perf_counter()
if Data.time_now >= Data.time_last + 0.01:
if Data.c3 == 30: Data.c3 = 0
Data.time_last = Data.time_now
Data.altitude_last = Data.altitude_now
Data.altitude_now = Data.altitude
Data.altitude_delta_table[Data.c3] = Data.altitude_now - Data.altitude_last
Data.c3 +=1
Data.altitude_delta = (sum(Data.altitude_delta_table)/len(Data.altitude_delta_table))
def calc():
Numbers.mp = 240 - (Data.pitch * 8)
offset = tan(radians(Data.roll)) * 300
Numbers.rp = Numbers.mp - offset
Numbers.lp = Numbers.mp + offset
def frame():
#frame color = grey
glColor3f(100/255, 100/255, 100/255)
#horizon right line
glBegin(GL_QUADS)
glVertex2f(99, 0)
glVertex2f(100, 0)
glVertex2f(100, window_height)
glVertex2f(99, window_height)
glEnd()
#horizon left line
glBegin(GL_QUADS)
glVertex2f(700, 0)
glVertex2f(701, 0)
glVertex2f(701, window_height)
glVertex2f(700, window_height)
glEnd()
#right upper divider
glBegin(GL_QUADS)
glVertex2f(0, 430)
glVertex2f(100, 430)
glVertex2f(100, 431)
glVertex2f(0, 431)
glEnd()
#left upper divider
glBegin(GL_QUADS)
glVertex2f(700, 430)
glVertex2f(800, 430)
glVertex2f(800, 431)
glVertex2f(700, 431)
glEnd()
#right lower divider
glBegin(GL_QUADS)
glVertex2f(0, 50)
glVertex2f(100, 50)
glVertex2f(100, 51)
glVertex2f(0, 51)
glEnd()
#left lower divider
glBegin(GL_QUADS)
glVertex2f(700, 50)
glVertex2f(800, 50)
glVertex2f(800, 51)
glVertex2f(700, 51)
glEnd()
def horizon():
#sky
glBegin(GL_QUADS)
glColor3f(58/255, 109/255, 171/255)
glVertex2f(100, Numbers.lp)
glVertex2f(700, Numbers.rp)
glColor3f(0/255, 83/255, 165/255)
glVertex2f(700, 480)
glVertex2f(100, 480)
glEnd()
#ground
glColor3f(150/255, 70/255, 0/255)
glBegin(GL_QUADS)
glVertex2f(100, 0)
glVertex2f(700, 0)
glColor3f(140/255, 90/255, 0/255)
glVertex2f(700, Numbers.rp)
glVertex2f(100, Numbers.lp)
glEnd()
#devider line
glColor3f(255/255, 255/255, 255/255)
glBegin(GL_QUADS)
glVertex2f(100, Numbers.lp-1)
glVertex2f(700, Numbers.rp-1)
glVertex2f(700, Numbers.rp+1)
glVertex2f(100, Numbers.lp+1)
glEnd()
#crosshair
#indicator triangle shadow
glColor3f(187/255, 107/255, 1/255)
glBegin(GL_QUADS)
glVertex2f(400, 230)
glVertex2f(365, 215)
glVertex2f(400, 227)
glVertex2f(435, 215)
glEnd()
# indicator triangle
glColor3f(255/255, 198/255, 0/255)
glBegin(GL_QUADS)
glVertex2f(400, 240)
glVertex2f(365, 215)
glVertex2f(400, 230)
glVertex2f(435, 215)
glEnd()
#yellow indicator line
glColor3f(255/255, 198/255, 0/255)
glBegin(GL_QUADS)
glVertex2f(320, 241)
glVertex2f(320, 239)
glVertex2f(350, 239)
glVertex2f(350, 241)
glEnd()
glBegin(GL_QUADS)
glVertex2f(450, 241)
glVertex2f(450, 239)
glVertex2f(480, 239)
glVertex2f(480, 241)
glEnd()
color = (255, 255, 255, 0)
drawText(110, 10, str("roll: "+str(round(Data.roll))), color, font3)
drawText(620, 10, str("pitch: "+str(round(Data.pitch))), color, font3)
def speedometer():
#dial
ssp = 55 #start spacer
sp = 27 #spacer
color = (255,255,255,100)
drawText(14, ssp+sp*0, "0", color, font3)
drawText(10, ssp+sp*1, "20", color, font3)
drawText(10, ssp+sp*2, "40", color, font3)
drawText(10, ssp+sp*3, "60", color, font3)
drawText(10, ssp+sp*4, "80", color, font3)
drawText(5, ssp+sp*5, "100", color, font3)
drawText(5, ssp+sp*6, "120", color, font3)
drawText(5, ssp+sp*7, "140", color, font3)
drawText(5, ssp+sp*8, "160", color, font3)
drawText(5, ssp+sp*9, "180", color, font3)
drawText(5, ssp+sp*10, "200", color, font3)
drawText(5, ssp+sp*11, "220", color, font3)
drawText(5, ssp+sp*12, "240", color, font3)
drawText(5, ssp+sp*13, "260", color, font3)
#green area
glBegin(GL_QUADS)
glColor3f(35/255, 150/255, 29/255)
glVertex2f(40, 142)
glVertex2f(99, 142)
glVertex2f(99, 287)
glVertex2f(40, 287)
glEnd()
#yellow area
glBegin(GL_QUADS)
glColor3f(150/255, 100/255, 27/255)
glVertex2f(40, 287)
glVertex2f(99, 287)
glVertex2f(99, 360)
glVertex2f(40, 360)
glEnd()
#red area
glBegin(GL_QUADS)
glColor3f(151/255, 43/255, 29/255)
glVertex2f(40, 360)
glVertex2f(99, 360)
glVertex2f(99, 374)
glVertex2f(40, 374)
glEnd()
ll=35
l=15
w=1
ssp=64
glColor3f(255/255, 255/255, 255/255)
for x in range(0, 14):
ind_lines(ll, l, w, ssp+sp*x)
#knots
color = (0, 241, 250, 255)
drawText(60, 435, "kn", color, font4)
def speedometer_indicator():
ypos = 63 + round(Data.airspeed) * 1.35
glColor3f(0/255, 241/255, 250/255)
ind_lines(40, 59, 3, ypos)
color = (0, 241, 250, 255)
drawText(5, 435, str(round(Data.airspeed)), color, font4)
def altimeter():
color = (0, 241, 250, 255)
drawText(705, 435, str(round(Data.altitude)), color, font4)
drawText(784, 435, "m", color, font3)
def variometer():
color = (0, 241, 250, 255)
drawText(710, 10, str(round((abs(Data.altitude_delta*10)), 1)), color, font4)
drawText(765, 10, "m/s", color, font3)
if Data.altitude_delta*10 > 0:
glBegin(GL_TRIANGLES)
glVertex2f(767, 30)
glVertex2f(793, 30)
glVertex2f(780, 45)
glEnd()
if Data.altitude_delta*10 < 0:
glBegin(GL_TRIANGLES)
glVertex2f(765, 45)
glVertex2f(795, 45)
glVertex2f(780, 30)
glEnd()
def ind_lines(ll, l, w, sp): #ll=left limit,l=lenght, w=width, sp=spacer
#indicator lines
glBegin(GL_QUADS)
glVertex2f(ll, sp)
glVertex2f(ll+l, sp)
glVertex2f(ll+l, sp+w)
glVertex2f(ll, sp+w)
glEnd()
def drawText(xpos, ypos, textString, color, font):
textSurface = font.render(textString, True, color, (0,0,0,1))
textData = pygame.image.tostring(textSurface, "RGBA", True)
glRasterPos2d(xpos,ypos)
glDrawPixels(textSurface.get_width(), textSurface.get_height(), GL_RGBA, GL_UNSIGNED_BYTE, textData)
def draw_once():
speedometer()
frame()
def draw():
horizon()
speedometer_indicator()
altimeter()
variometer()
def iterate():
glViewport(0, 0, window_width, window_height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0.0, window_width, 0.0, window_height, 0.0, 1.0)
glMatrixMode (GL_MODELVIEW)
glLoadIdentity()
def showScreen():
#glutFullScreen()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
iterate()
try:get_data()
except Exception as e:print("get_data:\t", e)
try:calc()
except Exception as e:print("calc:\t", e)
try:draw_once()
except Exception as e:print("draw_once:\t", e)
try:draw()
except Exception as e:print("draw:\t", e)
try:fps()
except Exception as e:print("fps:\t", e)
glutSwapBuffers()
if __name__ == "__main__":
glutInit()
glutInitDisplayMode(GLUT_RGBA)
glutInitWindowSize(window_width, window_height)
glutInitWindowPosition(10, 10)
wind = glutCreateWindow(b"Pi2Fly")
glutDisplayFunc(showScreen)
glutIdleFunc(showScreen)
glutMainLoop()
You can use pygame to load an texture image:
def LoadTexture(filename):
image = pygame.image.load(filename)
datas = pygame.image.tostring(image, 'RGBA')
texID = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texID)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.get_width(), image.get_height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, datas)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glGenerateMipmap(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, 0)
return texID
Alternatively you can use Pillow and Numpy, to load a texture image, too:
from PIL import Image
import numpy
image = Image.open(filename)
imageData = numpy.array(list(image.getdata()), numpy.uint8)
texID = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texID)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.size[0], image.size[1],
0, GL_RGBA, GL_UNSIGNED_BYTE, imageData)
# [...]
When you want to dare the texture in Legacy OpenGL, then you have to:
set the texture coordinates by glTexCoord2f, before glVertex
bind the texture by glBindTexture
enable 2 dimensional textureing by glEnable(GL_TEXTURE_2D)
The following example, draws a quad on the entire viewport and wraps a texture on it. e.g.:
def DrawTexture(texID, x, y, w, h):
glBindTexture(GL_TEXTURE_2D, texID)
glEnable(GL_TEXTURE_2D)
glColor4f(1, 1, 1, 1)
glBegin(GL_QUADS)
glTexCoord2f(0, 1); glVertex2f(x, y)
glTexCoord2f(0, 0); glVertex2f(x, y+h)
glTexCoord2f(1, 0); glVertex2f(x+w, y+h)
glTexCoord2f(1, 1); glVertex2f(x+w, y)
glEnd()
glDisable(GL_TEXTURE_2D)
Note, if texturing is enabled, then by default the color of the texel is multiplied by the current color, because by default the texture environment mode (GL_TEXTURE_ENV_MODE) is GL_MODULATE. See glTexEnv.
This causes that the color of the texels of the texture is "mixed" by the last color which you have set by glColor4f.
Set a "white" color before you render the texture, to solve your issue:
glColor4f(1, 1, 1, 1)
Likewise you can change the environment mode to GL_REPLACE, instead:
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Furthermore, if the texture is partially transparent, you have to enable Blending before drawing the texture:
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
DrawTexture(....)
glDisable(GL_BLEND)
Related
How can I rotate rectangles in OpenGL?
Rectangles become distorted when I use glRotatef. I know that it's important to bring images to the center of the screen before rotating. I'm pretty sure I'm doing that: import os import pygame from PIL import Image from pathlib import Path from numpy import array import pygame import math from pygame.locals import * from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GL import glClear, GL_COLOR_BUFFER_BIT, glBegin, GL_QUADS, glEnd, glColor3f, glVertex2f, glFlush, glClearColor os.environ['SDL_VIDEO_CENTERED'] = '1' windowSize = (1500, 800) Screen = pygame.display.set_mode(windowSize, pygame.DOUBLEBUF | pygame.OPENGL) HOME = str(Path.home()) path = HOME + '\\Desktop\piston2.png' path2 = HOME + '\\Desktop\piston3.png' path3 = HOME + '\\Desktop\Piston Platformer2\Images\Flower1.png' def loadTexture(texture, flip): try: text = Image.open(texture) except IOError as ex: print("Failed to open texture file: ", texture) text = Image.open("0.png") textData = array(list(text.getdata())) textID = glGenTextures(1) glPixelStorei(GL_UNPACK_ALIGNMENT, 1) glBindTexture(GL_TEXTURE_2D, textID) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, text.size[0], text.size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, textData) text.close() return (text.size[0], text.size[1]), textID def make_opengl_rect(image_sizes, cur_ID, offsets, rotate): texts = ((1, 0), (1, 1), (0, 1), (0, 0)) x_ratio = image_sizes[0]/windowSize[0] y_ratio = image_sizes[1]/windowSize[1] offset_x = 2*(offsets[0]/windowSize[0]) offset_y = 2*(offsets[1]/windowSize[1]) verts = [(2*x_ratio, 2*y_ratio), (2*x_ratio, 0), (0, 0), (0, 2*y_ratio)] # upright, downright, downleft, upleft additional_offset_x, additional_offset_y = 0, 0 verts = [(x-1+offset_x+additional_offset_x, y+1-verts[0][1]-offset_y+additional_offset_y) for (x, y) in verts] print('verts', verts) if rotate != 0: glPushMatrix() glTranslatef(-verts[0][0], -verts[0][1], 0) glRotatef(rotate, 0, 0, 1) glTranslatef(verts[0][0], verts[0][1], 0) glEnable(GL_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D, cur_ID) glBegin(GL_QUADS) for i in range(4): glTexCoord2f(texts[i][0], texts[i][1]) glVertex2f(verts[i][0], verts[i][1]) glEnd() print('verts', verts) if rotate != 0: glPopMatrix() glDisable(GL_TEXTURE_2D) my_image1_sizes, my_image1_ID = loadTexture(path, False) my_image2_sizes, my_image2_ID = loadTexture(path2, False) my_image3_sizes, my_image3_ID = loadTexture(path3, True) glEnable(GL_BLEND) glBlendEquation(GL_FUNC_ADD) running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: raise SystemExit elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: raise SystemExit # glClear(GL_COLOR_BUFFER_BIT) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) #make_opengl_rect(my_image1_sizes, my_image1_ID, (100,100), 0) #make_opengl_rect(my_image2_sizes, my_image2_ID, (100,100), 0) make_opengl_rect(my_image3_sizes, my_image3_ID, (300,300), 340) glFlush() pygame.display.flip() print('') Am I missing something? I attached example images. Rotated: Not rotated:
Your images are distorted because of the aspect ratio of the viewport. You need to set up an Orthographic projection matrix that takes the aspect ratio into account with glOrtho. Set the projection matrix once before the application loop: w, h = Screen.get_size() aspect = w / h glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-aspect, aspect, -1, 1, -1, 1) glMatrixMode(GL_MODELVIEW) glLoadIdentity() running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: raise SystemExit elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: raise SystemExit glClear(GL_COLOR_BUFFER_BIT) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) #make_opengl_rect(my_image1_sizes, my_image1_ID, (100,100), 0) #make_opengl_rect(my_image2_sizes, my_image2_ID, (100,100), 0) make_opengl_rect(my_image3_sizes, my_image3_ID, (300,300), 340) glFlush() pygame.display.flip()
OpenGl incomplete formation of the 3d cuboid when i use Gl_lines
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.
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()
My pygame/pyopengl code seems to apply a texture to every surface
I'm throwing some code together to help me better understand python, pygame, pyopengl, and 3D rendering. I've used code from two different places and I'm integrating them by writing my own code as I go. I've textured cubes in one program and made camera movement work in another. But when I put them together, the colors are wrong and surfaces that I don't intend to texture are affected. I'm sure I'm missing something, but I can't figure it out. Here is what the two programs look like seperately. , But when I put them together, I get this. Here is my code, sorry I couldn't figure out how to attach it as a file! import pygame from pygame.locals import * from OpenGL.GL import * from OpenGL.GLU import * import math def tex_coord(x, y, n=4): """ Return the bounding vertices of the texture square. """ m = 1.0 / n dx = x * m dy = y * m return dx, dy, dx + m, dy, dx + m, dy + m, dx, dy + m def tex_coords(top, bottom, side): """ Return a list of the texture squares for the top, bottom and side. """ top = tex_coord(*top) bottom = tex_coord(*bottom) side = tex_coord(*side) result = [ (top), (bottom), (side), (side), (side), (side), ] """result = [] result.extend(top) result.extend(bottom) result.extend(side * 4)""" return result #block type names and location on template go here BLOCK1 = tex_coords((3, 0), (3, 0), (3, 0)) def verts(x, y, z, n): vertices = ( (1+(2*x), -1+(2*y), -1+(2*z)), (1+(2*x), 1+(2*y), -1+(2*z)), (-1+(2*x), 1+(2*y), -1+(2*z)), (-1+(2*x), -1+(2*y), -1+(2*z)), (1+(2*x), -1+(2*y), 1+(2*z)), (1+(2*x), 1+(2*y), 1+(2*z)), (-1+(2*x), -1+(2*y), 1+(2*z)), (-1+(2*x), 1+(2*y), 1+(2*z)) ) return(vertices) print(verts(0, 0, 0, 1)) edges = ( (0,1), (0,3), (0,4), (2,1), (2,3), (2,7), (6,3), (6,4), (6,7), (5,1), (5,4), (5,7) ) colors = ( (1,0,0), (0,1,0), (0,0,1), (0,1,0), (1,1,1), (0,1,1), (1,0,0), (0,1,0), (0,0,1), (1,0,0), (1,1,1), (0,1,1), ) surfaces = ( (0,1,2,3), (3,2,7,6), (6,7,5,4), (4,5,1,0), (1,5,7,2), (4,0,3,6) ) forced = False def Cube(vx,vy,vz,block): if not forced: glBegin(GL_QUADS) y = 0 for surface in surfaces: x = 0 y+=1 for vertex in surface: x+=1 #glColor3fv(colors[x]) glTexCoord2f(block[y-1][2*(x-1)], block[y-1][(2*x)-1]) #print(block[y-1][2*(x-1)], block[y-1][(2*x)-1]) glVertex3fv(verts(vx,vy,vz,1)[vertex]) glEnd() glBegin(GL_LINES) for edge in edges: for vertex in edge: glVertex3fv(verts(vx,vy,vz,1)[vertex]) glEnd() else: texX = 0.75 texY = 0.25 glBegin(GL_QUADS) glTexCoord2f(0.0+texX, 0.0) glVertex3f(-1.0, -1.0, 1.0) glTexCoord2f(0.25+texX, 0.0) glVertex3f(1.0, -1.0, 1.0) glTexCoord2f(0.25+texX, 0.25) glVertex3f(1.0, 1.0, 1.0) glTexCoord2f(0.0+texX, 0.25) glVertex3f(-1.0, 1.0, 1.0) glEnd() def loadTexture(): textureSurface = pygame.image.load('texture2.png') textureData = pygame.image.tostring(textureSurface, "RGBA", 1) width = textureSurface.get_width() height = textureSurface.get_height() glEnable(GL_TEXTURE_2D) texid = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, texid) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) return texid pygame.init() display = (800, 600) scree = pygame.display.set_mode(display, DOUBLEBUF | OPENGL) glEnable(GL_DEPTH_TEST) glEnable(GL_LIGHTING) glShadeModel(GL_SMOOTH) glEnable(GL_COLOR_MATERIAL) glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) glEnable(GL_LIGHT0) glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5, 1]) glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1]) """ glClearColor(0.0, 0.0, 0.0, 0.0) glClearDepth(1.0) glDepthMask(GL_TRUE) glDepthFunc(GL_LESS) glEnable(GL_DEPTH_TEST) #glEnable(GL_CULL_FACE) #glCullFace(GL_FRONT) ##glFrontFace(GL_CCW) ##glShadeModel(GL_SMOOTH) glDepthRange(0.0,1.0) """ sphere = gluNewQuadric() glMatrixMode(GL_PROJECTION) gluPerspective(45, (display[0]/display[1]), 0.1, 50.0) glMatrixMode(GL_MODELVIEW) gluLookAt(0, -8, 0, 0, 0, 0, 0, 0, 1) viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX) glLoadIdentity() # init mouse movement and center mouse on screen displayCenter = [scree.get_size()[i] // 2 for i in range(2)] mouseMove = [0, 0] pygame.mouse.set_pos(displayCenter) loadTexture() up_down_angle = 0.0 paused = False run = True while run: for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE or event.key == pygame.K_RETURN: run = False if event.key == pygame.K_PAUSE or event.key == pygame.K_p: paused = not paused pygame.mouse.set_pos(displayCenter) if not paused: if event.type == pygame.MOUSEMOTION: mouseMove = [event.pos[i] - displayCenter[i] for i in range(2)] pygame.mouse.set_pos(displayCenter) if not paused: # get keys keypress = pygame.key.get_pressed() #mouseMove = pygame.mouse.get_rel() # init model view matrix glLoadIdentity() # apply the look up and down up_down_angle += mouseMove[1]*0.1 glRotatef(up_down_angle, 1.0, 0.0, 0.0) # init the view matrix glPushMatrix() glLoadIdentity() # apply the movment if keypress[pygame.K_w]: glTranslatef(0,0,0.1) if keypress[pygame.K_s]: glTranslatef(0,0,-0.1) if keypress[pygame.K_d]: glTranslatef(-0.1,0,0) if keypress[pygame.K_a]: glTranslatef(0.1,0,0) if keypress[pygame.K_LSHIFT]: glTranslatef(0,0.5,0) if keypress[pygame.K_SPACE]: glTranslatef(0,-0.5,0) # apply the left and right rotation glRotatef(mouseMove[0]*0.1, 0.0, 1.0, 0.0) # multiply the current matrix by the get the new view matrix and store the final vie matrix glMultMatrixf(viewMatrix) viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX) # apply view matrix glPopMatrix() glMultMatrixf(viewMatrix) #glLightfv(GL_LIGHT0, GL_POSITION, [1, -1, 1, 0]) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) glPushMatrix() Cube(0,0,0,BLOCK1) Cube(1,0,0,BLOCK1) Cube(0,1,0,BLOCK1) Cube(0,0,1,BLOCK1) Cube(-2,0,0,BLOCK1) glColor4f(0.5, 0.5, 0.5, 1) glBegin(GL_QUADS) glVertex3f(-10, -10, -2) glVertex3f(10, -10, -2) glVertex3f(10, 10, -2) glVertex3f(-10, 10, -2) glEnd() glTranslatef(-1.5, 0, 0) glColor4f(0.5, 0.2, 0.2, 1) gluSphere(sphere, 1.0, 32, 16) glTranslatef(3, 0, 0) glColor4f(0.2, 0.2, 0.5, 1) gluSphere(sphere, 1.0, 32, 16) glPopMatrix() pygame.display.flip() pygame.time.wait(10) pygame.quit() I'd be very thankful if someone could explain this to me! Edit: Thank you Rabbid76!!! Here is a picture, and my working code. import pygame from pygame.locals import * from OpenGL.GL import * from OpenGL.GLU import * import math def tex_coord(x, y, n=4): """ Return the bounding vertices of the texture square. """ m = 1.0 / n dx = x * m dy = y * m return dx, dy, dx + m, dy, dx + m, dy + m, dx, dy + m def tex_coords(top, bottom, side): """ Return a list of the texture squares for the top, bottom and side. """ top = tex_coord(*top) bottom = tex_coord(*bottom) side = tex_coord(*side) result = [ (top), (bottom), (side), (side), (side), (side), ] """result = [] result.extend(top) result.extend(bottom) result.extend(side * 4)""" return result #block type names and location on template go here BLOCK1 = tex_coords((3, 0), (3, 0), (3, 0)) def verts(x, y, z, n): vertices = ( (1+(2*x), -1+(2*y), -1+(2*z)), (1+(2*x), 1+(2*y), -1+(2*z)), (-1+(2*x), 1+(2*y), -1+(2*z)), (-1+(2*x), -1+(2*y), -1+(2*z)), (1+(2*x), -1+(2*y), 1+(2*z)), (1+(2*x), 1+(2*y), 1+(2*z)), (-1+(2*x), -1+(2*y), 1+(2*z)), (-1+(2*x), 1+(2*y), 1+(2*z)) ) return(vertices) print(verts(0, 0, 0, 1)) edges = ( (0,1), (0,3), (0,4), (2,1), (2,3), (2,7), (6,3), (6,4), (6,7), (5,1), (5,4), (5,7) ) colors = ( (1,0,0), (0,1,0), (0,0,1), (0,1,0), (1,1,1), (0,1,1), (1,0,0), (0,1,0), (0,0,1), (1,0,0), (1,1,1), (0,1,1), ) surfaces = ( (0,1,2,3), (3,2,7,6), (6,7,5,4), (4,5,1,0), (1,5,7,2), (4,0,3,6) ) forced = False def Cube(vx,vy,vz,block): if not forced: glBegin(GL_QUADS) y = 0 for surface in surfaces: x = 0 y+=1 for vertex in surface: x+=1 #glColor3fv(colors[x]) glTexCoord2f(block[y-1][2*(x-1)], block[y-1][(2*x)-1]) #print(block[y-1][2*(x-1)], block[y-1][(2*x)-1]) glVertex3fv(verts(vx,vy,vz,1)[vertex]) glEnd() glBegin(GL_LINES) for edge in edges: for vertex in edge: glVertex3fv(verts(vx,vy,vz,1)[vertex]) glEnd() else: texX = 0.75 texY = 0.25 glBegin(GL_QUADS) glTexCoord2f(0.0+texX, 0.0) glVertex3f(-1.0, -1.0, 1.0) glTexCoord2f(0.25+texX, 0.0) glVertex3f(1.0, -1.0, 1.0) glTexCoord2f(0.25+texX, 0.25) glVertex3f(1.0, 1.0, 1.0) glTexCoord2f(0.0+texX, 0.25) glVertex3f(-1.0, 1.0, 1.0) glEnd() def loadTexture(): textureSurface = pygame.image.load('texture2.png') textureData = pygame.image.tostring(textureSurface, "RGBA", 1) width = textureSurface.get_width() height = textureSurface.get_height() glColor3f(0.5, 0.5, 0.5) glEnable(GL_TEXTURE_2D) texid = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, texid) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) return texid glDisable(GL_TEXTURE_2D) pygame.init() display = (800, 600) scree = pygame.display.set_mode(display, DOUBLEBUF | OPENGL) glEnable(GL_DEPTH_TEST) glEnable(GL_LIGHTING) glShadeModel(GL_SMOOTH) glEnable(GL_COLOR_MATERIAL) glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) glEnable(GL_LIGHT0) glLightfv(GL_LIGHT0, GL_AMBIENT, [0.5, 0.5, 0.5, 1]) glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1]) """ glClearColor(0.0, 0.0, 0.0, 0.0) glClearDepth(1.0) glDepthMask(GL_TRUE) glDepthFunc(GL_LESS) glEnable(GL_DEPTH_TEST) #glEnable(GL_CULL_FACE) #glCullFace(GL_FRONT) ##glFrontFace(GL_CCW) ##glShadeModel(GL_SMOOTH) glDepthRange(0.0,1.0) """ sphere = gluNewQuadric() glMatrixMode(GL_PROJECTION) gluPerspective(45, (display[0]/display[1]), 0.1, 50.0) glMatrixMode(GL_MODELVIEW) gluLookAt(0, -8, 0, 0, 0, 0, 0, 0, 1) viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX) glLoadIdentity() # init mouse movement and center mouse on screen displayCenter = [scree.get_size()[i] // 2 for i in range(2)] mouseMove = [0, 0] pygame.mouse.set_pos(displayCenter) loadTexture() up_down_angle = 0.0 paused = False run = True while run: for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE or event.key == pygame.K_RETURN: run = False if event.key == pygame.K_PAUSE or event.key == pygame.K_p: paused = not paused pygame.mouse.set_pos(displayCenter) if not paused: if event.type == pygame.MOUSEMOTION: mouseMove = [event.pos[i] - displayCenter[i] for i in range(2)] pygame.mouse.set_pos(displayCenter) if not paused: # get keys keypress = pygame.key.get_pressed() #mouseMove = pygame.mouse.get_rel() # init model view matrix glLoadIdentity() # apply the look up and down up_down_angle += mouseMove[1]*0.1 glRotatef(up_down_angle, 1.0, 0.0, 0.0) # init the view matrix glPushMatrix() glLoadIdentity() # apply the movment if keypress[pygame.K_w]: glTranslatef(0,0,0.1) if keypress[pygame.K_s]: glTranslatef(0,0,-0.1) if keypress[pygame.K_d]: glTranslatef(-0.1,0,0) if keypress[pygame.K_a]: glTranslatef(0.1,0,0) if keypress[pygame.K_LSHIFT]: glTranslatef(0,0.5,0) if keypress[pygame.K_SPACE]: glTranslatef(0,-0.5,0) # apply the left and right rotation glRotatef(mouseMove[0]*0.1, 0.0, 1.0, 0.0) # multiply the current matrix by the get the new view matrix and store the final vie matrix glMultMatrixf(viewMatrix) viewMatrix = glGetFloatv(GL_MODELVIEW_MATRIX) # apply view matrix glPopMatrix() glMultMatrixf(viewMatrix) #glLightfv(GL_LIGHT0, GL_POSITION, [1, -1, 1, 0]) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) glPushMatrix() glEnable(GL_TEXTURE_2D) Cube(0,0,0,BLOCK1) Cube(1,0,0,BLOCK1) Cube(0,1,0,BLOCK1) Cube(0,0,1,BLOCK1) Cube(-2,0,0,BLOCK1) glDisable(GL_TEXTURE_2D) glColor4f(0.5, 0.5, 0.5, 1) glBegin(GL_QUADS) glVertex3f(-10, -10, -2) glVertex3f(10, -10, -2) glVertex3f(10, 10, -2) glVertex3f(-10, 10, -2) glEnd() glTranslatef(-1.5, 0, 0) glColor4f(0.5, 0.2, 0.2, 1) gluSphere(sphere, 1.0, 32, 16) glTranslatef(3, 0, 0) glColor4f(0.2, 0.2, 0.5, 1) gluSphere(sphere, 1.0, 32, 16) glColor3f(1, 1, 1) glPopMatrix() pygame.display.flip() pygame.time.wait(10) pygame.quit()
OpenGL is a state engine. A state is kept until it is changed again. Two-dimensional texturing can be enabled and disabled, see glEnable. When texturing is activated, by default the color of the pixel is multiplied by the current color, because by default the texture environment mode (GL_TEXTURE_ENV_MODE) is GL_MODULATE. See glTexEnv. This causes that the color of the piles of the texture is "mixed" by the last color which you have set by glColor4f. Set a "white" color and enable texturing before you render an object with a texture. Disable texturing before you draw an object with colors: glColor3f(1.0f, 1.0f, 1.0f) glEnable(GL_TEXTURE_2D) # draw object with texture # [...] glDisable(GL_TEXTURE_2D) # draw object with color # [...] Changes in your code: forced = False def Cube(vx,vy,vz,block): glColor4f(1, 1, 1, 1) # <-- glEnable(GL_TEXTURE_2D) if not forced: glBegin(GL_QUADS) for y, surface in enumerate(surfaces): for x, vertex in enumerate(surface): glTexCoord2f(block[y-1][2*(x-1)], block[y-1][(2*x)-1]) glVertex3fv(verts(vx,vy,vz,1)[vertex]) glEnd() glDisable(GL_TEXTURE_2D) # <-- glColor4f(0, 0, 0, 1) glBegin(GL_LINES) for edge in edges: for vertex in edge: glVertex3fv(verts(vx,vy,vz,1)[vertex]) glEnd() # [...] run = True while run: # [...] Cube(0,0,0,BLOCK1) Cube(1,0,0,BLOCK1) Cube(0,1,0,BLOCK1) Cube(0,0,1,BLOCK1) Cube(-2,0,0,BLOCK1) glDisable(GL_TEXTURE_2D) # <-- glColor4f(0.5, 0.5, 0.5, 1) glBegin(GL_QUADS) glVertex3f(-10, -10, -2) glVertex3f(10, -10, -2) glVertex3f(10, 10, -2) glVertex3f(-10, 10, -2) glEnd() # [...]
PyOpengl: Changing gluPerspective variables makes cube flash
When using gluPerspective in glutReshapeFunc function, the square image flashes while resizing and is gone after a few moments. from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * width = 500 height = 500 def cube(): glBegin(GL_QUADS) glColor3f(0, 1, 0) glVertex3f(10, 0, 0) glVertex3f(10, 10, 0) glVertex3f(10, 0, 0) glVertex3f(0, 0, 0) glVertex3f(10, 0, 0) glVertex3f(10, 0, 10) glVertex3f(0, 10, 0) glVertex3f(10, 10, 0) glVertex3f(0, 10, 0) glVertex3f(0, 0, 0) glVertex3f(0, 10, 0) glVertex3f(0, 10, 10) glVertex3f(0, 0, 10) glVertex3f(0, 0, 0) glVertex3f(0, 0, 10) glVertex3f(10, 0, 10) glVertex3f(0, 0, 10) glVertex3f(0, 10, 10) glVertex3f(10, 10, 10) glVertex3f(10, 10, 0) glVertex3f(10, 10, 10) glVertex3f(10, 0, 10) glVertex3f(10, 10, 10) glVertex3f(0, 10, 10) glEnd() def showScreen(): global width, height glClearColor(0, 0, 0, 1) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) cube() glutSwapBuffers() def mouseTracker(mousex, mousey): print(f"Mouse pos: {mousex}, {mousey}") def reshapeWindow(x, y): global width, height width = x height = y print(x, y) gluPerspective(45, (width / height), 0.0001, 1000) glutInit() glutInitDisplayMode(GLUT_RGBA) glutInitWindowSize(500, 500) wind = glutCreateWindow("OpenGL") glutDisplayFunc(showScreen) glutIdleFunc(showScreen) glutMotionFunc(mouseTracker) glutPassiveMotionFunc(mouseTracker) glutReshapeFunc(reshapeWindow) gluPerspective(45, (width / height), 0.0001, 1000) glTranslatef(0, 0, -5) while True: glutMainLoopEvent() glutPostRedisplay() If I put the gluPerspective into the showScreen function like so: def showScreen(): global width, height glClearColor(0, 0, 0, 1) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) cube() gluPerspective(45, (width / height), 0.0001, 1000) glutSwapBuffers() The square flashes without resizing but it is gone after a few moments. If I remove the gluPerspective entirely, the image turns into a triangle. Is there any way to change gluPerspective variables without making the image flash?
You have to call gluPerspective before drawing the cube. The matrix operations not only set the current matrix, but define a new matrix and multiply the current matrix by the new matrix. Therefore you must load the Identity matrix with glLoadIdentity before modifying the matrix. The legacy OpenGL provides different current matrices for the model view matrix and the projection matrix. Before changing a matrix, select the matrix mode with glMatrixMode: Change the projection matrix in the reshape callback: def reshapeWindow(x, y): global width, height width = x height = y print(x, y) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45, (width / height), 0.0001, 1000) glMatrixMode(GL_MODELVIEW) Set the model view matrix before the application loop or in the application loop: glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(0, 0, -5) gluPerspective defines a Viewing frustum. The center of the view is (0, 0). Hence you need to change the vertex coordinates. I suggest enabling the Depth Test when drawing 3D meshes. Minimale example based on your code: from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * import time width = 500 height = 500 vertices = [(-1,-1,-1), ( 1,-1,-1), ( 1, 1,-1), (-1, 1,-1), (-1,-1, 1), ( 1,-1, 1), ( 1, 1, 1), (-1, 1, 1)] faces = [(4,0,3,7), (1,0,4,5), (0,1,2,3), (1,5,6,2), (3,2,6,7), (5,4,7,6)] colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1), (0, 1, 1)] def cube(): glRotatef(1, 3, 1, 1) glBegin(GL_QUADS) for i, face in enumerate(faces): glColor3fv(colors[i]) for vertex in face: glVertex3fv(vertices[vertex]) glEnd() def showScreen(): glClearColor(0, 0, 0, 1) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) cube() glutSwapBuffers() def mouseTracker(mousex, mousey): print(f"Mouse pos: {mousex}, {mousey}") def reshapeWindow(x, y): global width, height width = x height = y print(x, y) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45, (width / height), 0.0001, 1000) glMatrixMode(GL_MODELVIEW) glutInit() glutInitDisplayMode(GLUT_RGBA) glutInitWindowSize(500, 500) wind = glutCreateWindow("OpenGL") glutDisplayFunc(showScreen) glutIdleFunc(showScreen) glutMotionFunc(mouseTracker) glutPassiveMotionFunc(mouseTracker) glutReshapeFunc(reshapeWindow) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(0, 0, -5) glEnable(GL_DEPTH_TEST) while True: glutMainLoopEvent() glutPostRedisplay() time.sleep(0.01)
PyOpenGL not drawing anything after clearing
I used Glut for making window and wanted to draw triangle, then on click button redraw it, but after clearing window I can't draw again. Does something wrong with Buffer depth and buffer bit? If I cleared it do I need to setup both again in my draw function? def drawSomething(): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslatef(-2.5, 0.5, -6.0) glColor3f( 1.0, 1.5, 0.0 ) glPolygonMode(GL_FRONT, GL_FILL) glBegin(GL_TRIANGLES) glVertex3f(2.0,-1.2,0.0) glVertex3f(2.6,0.0,0.0) glVertex3f(2.9,-1.2,0.0) glEnd() glFlush() def funcForUpdate(): glClearColor(0.0, 0.0, 0.0, 0) glClear(GL_COLOR_BUFFER_BIT) glEnable(GL_TEXTURE_2D) glBegin(GL_QUADS) glTexCoord2f(0.0, 0.0) glVertex2f(0.0, 0.0) glTexCoord2f(0.0, 1.0) glVertex2f(0.0, width) glTexCoord2f(1.0, 1.0) glVertex2f(height, width) glTexCoord2f(1.0, 0.0) glVertex2f(height, 0.0) glEnd() glFlush() def resizeUpdateFunc(width, height): glMatrixMode(GL_MODELVIEW) glLoadIdentity() gluOrtho2D(0.0, width, 0.0, height) def handleKey(bkey,x,y): key = bkey.decode("utf-8") if key == "a": glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) drawSomething() glFlush() glutInit() glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB) glutInitWindowSize(width, height) glutInitWindowPosition(0, 0) glutCreateWindow("test") drawSomething() glutDisplayFunc(funcForUpdate) glutReshapeFunc(resizeUpdateFunc) glutKeyboardFunc(handleKey) glutMainLoop()
See glutDisplayFunc: [...] sets the display callback for the current window. [...] The redisplay state for a window can be either set explicitly by calling glutPostRedisplay or implicitly as the result of window damage reported by the window system. In fact, a triangle is drawn in drawSomething, but it is immediately overdrawn in funcForUpdate. Add a state drawTriangle and set the state in handleKey: drawTriangle = False def handleKey(bkey, x, y): global drawTriangle key = bkey.decode("utf-8") if key == "a": drawTriangle = not drawTriangle glutPostRedisplay() Draw depending on the variable drawTriangle in funcForUpdate: def funcForUpdate(): glClearColor(0, 0, 0, 0) glClear(GL_COLOR_BUFFER_BIT) # [...] if drawTriangle: # [...] glFlush() A complete example: from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * drawTriangle = False def funcForUpdate(): glClearColor(0, 0, 0, 0) glClear(GL_COLOR_BUFFER_BIT) glColor3f(1, 1, 0) glBegin(GL_QUADS) glVertex2f(0.0, 0.0) glVertex2f(0, height) glVertex2f(width, height) glVertex2f(width, 0) glEnd() if drawTriangle: glPushMatrix() glLoadIdentity() glTranslate(width/2, height/2, 0) glColor3f(1, 0, 0) glBegin(GL_TRIANGLES) glVertex3f(-width/4, -height/4, 0) glVertex3f(width/4, -height/4, 0) glVertex3f(width/4, height/4, 0) glEnd() glPopMatrix() glFlush() def resizeUpdateFunc(width, height): glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(0.0, width, 0.0, height) glMatrixMode(GL_MODELVIEW) glLoadIdentity() def handleKey(bkey, x, y): global drawTriangle key = bkey.decode("utf-8") if key == "a": drawTriangle = not drawTriangle glutPostRedisplay() width, height = 320, 200 glutInit() glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB) glutInitWindowSize(width, height) glutInitWindowPosition(0, 0) glutCreateWindow("test") glutDisplayFunc(funcForUpdate) glutReshapeFunc(resizeUpdateFunc) glutKeyboardFunc(handleKey) glutMainLoop()