pyOpenGL how to draw 2d image? - python

I tried many things and found out how to get data using pillow and numpy. Even if I looked around, I could only see how to make vertex and fragments in 3d, and I couldn't find a way to actually draw a 2d image.
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
tex = Image.open("Resources/bg55.png")
mode = "".join(Image.Image.getbands(tex))
data = tex.tobytes("raw", "RGBA", 0, -1)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width, tex.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
glGenerateMipmap(GL_TEXTURE_2D)
Is this code correct? How can I continue? glfw and pyopengl is in use.

You need to draw a rectangle and wrap the texture on it. This is the usual way to proceed. OpenGL renders primitives and does not draw images. See the very basic example:
image
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
from PIL import Image
from numpy import array
def loadTexture(texture):
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 textID
def drawQuad(centerX, centerY, textureID):
verts = ((1, 1), (1,-1), (-1,-1), (-1,1))
texts = ((1, 0), (1, 1), (0, 1), (0, 0))
surf = (0, 1, 2, 3)
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, textureID)
glBegin(GL_QUADS)
for i in surf:
glTexCoord2f(texts[i][0], texts[i][1])
glVertex2f(centerX + verts[i][0], centerY + verts[i][1])
glEnd()
glDisable(GL_TEXTURE_2D)
def main():
pygame.init()
disp = (200, 200)
pygame.display.set_mode(disp, DOUBLEBUF|OPENGL)
gluPerspective(45, (disp[0] / disp[1]), 0.1, 50.0)
glTranslatef(0.0, 0.0, -5)
textID = loadTexture("0.png")
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
drawQuad(0, 0, textID)
pygame.display.flip()
pygame.time.wait(10)
main()

Related

PyopenGL Square Texture

I'm trying to load a minecraft texture in OpenGL, can someone help me?
texture:
My Code:
import sys
from OpenGL.GLUT import *
from OpenGL.GL import *
def color(r, g, b):
return (r/255, g/255, b/255)
def display():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glColor3f(*color(40, 101, 212))
glBegin(GL_QUADS)
glVertex3f(-0.5, -0.5, 0.0)
glVertex3f(0.5, -0.5, 0.0)
glVertex(0.5, 0.5, 0.0)
glVertex(-0.5, 0.5, 0.0)
glEnd()
glFlush()
glutInit(sys.argv)
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
glutInitWindowSize(400, 400)
glutCreateWindow("Square Test")
glutDisplayFunc(display)
glutMainLoop()
I would try to avoid using pygame
Use Pillow to load the image:
from PIL import Image
pil_image = Image.open('texture.jpg')
Create the texture object:
pil_image = Image.open('d:/temp/texture.jpg')
texture_id = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture_id)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
format = GL_RGBA if pil_image.mode == 'RGBA' else GL_RGB
glTexImage2D(GL_TEXTURE_2D, 0, format, *pil_image.size, 0, format, GL_UNSIGNED_BYTE, pil_image.tobytes())
Enable 2 dimensional texturing:
glEnable(GL_TEXTURE_2D)
Draw the geometry with the texture coordinates:
glColor3f(1, 1, 1)
glBegin(GL_QUADS)
glTexCoord2f(0, 0)
glVertex3f(-0.5, -0.5, 0.0)
glTexCoord2f(1, 0)
glVertex3f(0.5, -0.5, 0.0)
glTexCoord2f(1, 1)
glVertex(0.5, 0.5, 0.0)
glTexCoord2f(0, 1)
glVertex(-0.5, 0.5, 0.0)
glEnd()
Complete example:
import sys
from OpenGL.GLUT import *
from OpenGL.GL import *
from PIL import Image
def display():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glColor3f(1, 1, 1)
glBegin(GL_QUADS)
glTexCoord2f(0, 0)
glVertex3f(-0.5, -0.5, 0.0)
glTexCoord2f(1, 0)
glVertex3f(0.5, -0.5, 0.0)
glTexCoord2f(1, 1)
glVertex(0.5, 0.5, 0.0)
glTexCoord2f(0, 1)
glVertex(-0.5, 0.5, 0.0)
glEnd()
glFlush()
glutInit(sys.argv)
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB)
glutInitWindowSize(400, 400)
glutCreateWindow("Square Test")
pil_image = Image.open('texture.jpg')
texture_id = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture_id)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
format = GL_RGBA if pil_image.mode == 'RGBA' else GL_RGB
glTexImage2D(GL_TEXTURE_2D, 0, format, *pil_image.size, 0, format, GL_UNSIGNED_BYTE, pil_image.tobytes())
glEnable(GL_TEXTURE_2D)
glutDisplayFunc(display)
glutMainLoop()

Draw rectangle over texture OpenGL

I'm using python 3 with pygame and OpenGL to try to accomplish what I thought it would be a simple task: Drawing a rectangle.
The idea is to have a white rectangle over (or bellow) a transparent texture, but whenever I add the texture to the screen the rectangle vanishes, whether I render it before or after the texture.
Bellow is a sample code displaying the problem (you can add any Player1.png image of your choice, the problem will remain the same - at least in my computer)
import pygame
import sys
from OpenGL.GL import *
from pygame.locals import *
# set pygame screen
pygame.display.set_mode((500, 500), OPENGL | DOUBLEBUF)
info = pygame.display.Info()
# basic opengl configuration
glViewport(0, 0, info.current_w, info.current_h)
glDepthRange(0, 1)
glMatrixMode(GL_PROJECTION)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glShadeModel(GL_SMOOTH)
glClearColor(0.0, 0.0, 0.0, 0.0)
glClearDepth(1.0)
glDisable(GL_DEPTH_TEST)
glDisable(GL_LIGHTING)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glEnable(GL_BLEND)
# load texture
surf = pygame.image.load('Player1.png')
s = pygame.image.tostring(surf, 'RGBA')
texID = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texID)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 142, 65, 0, GL_RGBA, GL_UNSIGNED_BYTE, s)
glGenerateMipmap(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, 0)
# create pygame clock
MAINCLOCK = pygame.time.Clock()
# init screen
pygame.display.init()
while True:
# get quit event
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# prepare to render screen
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glClearColor(0, 0, 0, 1.0)
# draw texture
glBindTexture(GL_TEXTURE_2D, texID)
glBegin(GL_QUADS)
glTexCoord2f(0, 0); glVertex2f(-1, -1)
glTexCoord2f(0, 1); glVertex2f(-1, 1)
glTexCoord2f(1, 1); glVertex2f(1, 1)
glTexCoord2f(1, 0); glVertex2f(1, -1)
glEnd()
# draw rectangle
glColor3fv((1, 1, 1))
glRectf(-1, 1, 0, 0.5)
pygame.display.flip()
MAINCLOCK.tick(60)
It most likely has to do something on how OpenGL treats Textures vs Rects, but I'm not sure what.
BTW: I know the image is upside down
Thanks in advance
You have to enable two-dimensional texturing before you draw the texture, as you do it (glEnable(GL_TEXTURE_2D)).
But you have to disable two-dimensional texturing again, before you draw the rectangle:
# draw rectangle
glDisable(GL_TEXTURE_2D)
glColor3fv((1, 1, 1))
glRectf(-1, 1, 0, 0.5)
Note, the texture is still bound, when you draw the rectangle. Since you do not provide texture coordinates, when you draw the rectangle. This causes that the current texture coordinate is applied to the rectangle and a single texel is drawn all over the rectangle.
e.g. The last texture coordinate set was glTexCoord2f(1, 0):
Further note, if you would change the color for the rectangle, then the entire texture get tint by this color. 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.
glDisable(GL_TEXTURE_2D)
glColor3fv((1, 0, 0)) # red
glRectf(-1, 1, 0, 0.5)
Set the "white" color before you draw the texture:
glEnable(GL_TEXTURE_2D)
glColor3fv((1, 1, 1))

Stencil test does not clip Texture

I'm trying to clip a texture using a Stencil Test.
The idea is to create a surface (in this example a simple rectangle) to select a region of the texture to be shown (as the image bellow)
I created a simple code to do so, where I first perform an ALWAYS stencil test to set all the bits on the stencil buffer to 2, and then change the test to KEEP, which I thought would output the desired result, but nothing happens
import pygame
import sys
from OpenGL.GL import *
from pygame.locals import *
# set pygame screen
pygame.display.set_mode((1000, 500), OPENGL | DOUBLEBUF)
info = pygame.display.Info()
# basic opengl configuration
glViewport(0, 0, info.current_w, info.current_h)
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# set up texturing
glEnable(GL_TEXTURE_2D)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
# load texture
surf = pygame.image.load('Player1.png')
s = pygame.image.tostring(surf, 'RGBA')
texID = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texID)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf.get_width(), surf.get_height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, s)
glGenerateMipmap(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, 0)
# create pygame clock
MAINCLOCK = pygame.time.Clock()
# init screen
pygame.display.init()
while True:
# get quit event
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# prepare to render screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
# Enable stencil test
glEnable(GL_STENCIL_TEST)
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
glStencilFunc(GL_ALWAYS, 2, ~0)
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE)
# draw rectangle
glDisable(GL_TEXTURE_2D)
glColor3fv((0, 0, 0))
glRectf(-1, 1, 0, 0.5)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
glStencilFunc(GL_EQUAL, 2, ~0)
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)
# draw texture
glEnable(GL_TEXTURE_2D)
glColor3fv((1, 1, 1))
glBindTexture(GL_TEXTURE_2D, texID)
glBegin(GL_QUADS)
glTexCoord2f(0, 0); glVertex2f(-1, -1)
glTexCoord2f(0, 1); glVertex2f(-1, 1)
glTexCoord2f(1, 1); glVertex2f(1, 1)
glTexCoord2f(1, 0); glVertex2f(1, -1)
glEnd()
# disable stencil test
glDisable(GL_STENCIL_TEST)
pygame.display.flip()
MAINCLOCK.tick(60)
What am I missing?
Thanks in advance
The stencil test is proper implemented, but you forgot to setup the size of the stencil buffer when you initialize the PyGame OpenGL window. In your case the stencil test does not work, because there is no stencil buffer.
The stecil buffer can be set up by setting the GL_STENCIL_SIZE attribute with the method pygame.display.gl_set_attribute
Add the following to your code:
pygame.display.init()
pygame.display.gl_set_attribute(GL_STENCIL_SIZE, 8)
pygame.display.set_mode((1000, 500), OPENGL | DOUBLEBUF)

PyOpenGL numpy texture appears as solid color

I'm trying to set numpy arrays as OpenGl textures in pygame. The problem is that only the first pixel is taken as texture data and instead of a random pattern (for example) I only get a random color every time.
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
import numpy as np
#Settings
width = 200
height = 300
resolution = (800,600)
texture_data = np.random.randint(256,size=(height, width, 3))
#pygame init
pygame.init()
gameDisplay = pygame.display.set_mode(resolution,OPENGL)
#OpenGL init
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0,resolution[0],0,resolution[1],-1,1)
glMatrixMode(GL_MODELVIEW)
glDisable(GL_DEPTH_TEST)
glClearColor(0.0,0.0,0.0,0.0)
glEnable(GL_TEXTURE_2D)
#Set texture
texture = glGenTextures(1)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data)
glGenerateMipmap(GL_TEXTURE_2D)
glActiveTexture(GL_TEXTURE0)
#Clean start
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
#draw rectangle
glTranslatef(300,200,0)
glBegin(GL_QUADS)
glVertex2f(0,0)
glVertex2f(0,height)
glVertex2f(width,height)
glVertex2f(width,0)
glEnd()
glFlush()
#game loop until exit
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
#throttle
pygame.time.wait(100)
As pointed out by genpfault I was missing texture coordinates. I needed to add them to the rectangle drawing part.
#draw rectangle
glTranslatef(300,200,0)
glBegin(GL_QUADS)
glTexCoord(0,0)
glVertex2f(0,0)
glTexCoord(0,1)
glVertex2f(0,height)
glTexCoord(1,1)
glVertex2f(width,height)
glTexCoord(1,0)
glVertex2f(width,0)
glEnd()
glFlush()
Read this if you are lost on how texture mapping works:
OpenGL Programming Guide - Chapter 9 Texture Mapping

Showing a dynamic plane

I have written a Python program that continuously returns 4 changing Cartesian coordinates that align to form a square plane that can be at any given orientation; yaw, pitch, or roll. What is the best way to go about displaying the constantly updating plane in 3D space?
Note: This is being done on a Linux machine if that changes anything, however I cannot see how it would.
You can use PyOpenGL for that.
http://pyopengl.sourceforge.net/
It can be installed with pip.
Easiest is to use the "legacy" API and draw a quad.
To change yaw, pitch and roll, use a transformation matrix and glRotate.
You can also use shaders with it and draw up the transformation matrix yourself.
https://en.wikipedia.org/wiki/Rotation_matrix
Example of drawing a textured plane with the OpenGL legacy API:
import sys
import math
from OpenGL.GLUT import *
from OpenGL.GL import *
from OpenGL.GLU import *
def init():
global image, texName
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH)
glShadeModel(GL_FLAT)
glEnable(GL_DEPTH_TEST)
import Image, numpy
img = Image.open('flagEn.bmp') # .jpg, .bmp, etc. also work
img_data = numpy.array(list(img.getdata()), numpy.int8)
global texture
texture = glGenTextures(1)
glPixelStorei(GL_UNPACK_ALIGNMENT,1)
glBindTexture(GL_TEXTURE_2D, texture)
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_LINEAR)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.size[0], img.size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, img_data)
def display():
#global texName
global texture
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glEnable(GL_TEXTURE_2D)
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
glBindTexture(GL_TEXTURE_2D, texture)
glBegin(GL_QUADS)
glTexCoord2f(0, 0)
glVertex3f(-2, -1, 0)
glTexCoord2f(0, 10)
glVertex3f(-2, 1, 0)
glTexCoord2f(10, 10)
glVertex3f(0, 1, 0)
glTexCoord2f(10, 0)
glVertex3f(0, -1, 0)
glTexCoord2f(0, 0)
glVertex3f(1, -1, 0)
glTexCoord2f(0, 10)
glVertex3f(1, 1, 0)
glTexCoord2f(10, 10)
glVertex3f(1+math.sqrt(2), 1, -math.sqrt(2))
glTexCoord2f(10, 0)
glVertex3f(1+math.sqrt(2), -1, -math.sqrt(2))
glEnd()
glFlush()
glDisable(GL_TEXTURE_2D)
def reshape(w, h):
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, w/h, 1.0, 30.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -3.6);
def keyboard(key, x, y):
pass
glutInit(sys.argv)
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH | GLUT_MULTISAMPLE)
glutInitWindowSize (500, 500)
glutInitWindowPosition (100, 100)
glutCreateWindow ('texture')
init ()
glutDisplayFunc(display)
glutReshapeFunc(reshape)
glutKeyboardFunc(keyboard)
glutMainLoop()

Categories