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()
Related
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()
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)
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()
I found somewhere on StackOverflow this cross-platform way to draw text:
def drawText(x, y, text):
position = (x, y, 0)
font = pygame.font.Font(None, 64)
textSurface = font.render(text, True, (255,255,255,255),
(0,0,0,255))
textData = pygame.image.tostring(textSurface, "RGBA", True)
GL.glRasterPos3d(*position)
GL.glDrawPixels(textSurface.get_width(), textSurface.get_height(),
GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, textData)
The problem is that I cannot call drawText after I called glBegin(GL_QUADS). How can I create a rectangle and texture it with the text's contents, then display it so that this drawText could be called even after glBegin?
I found that I can't change the current texture inside of glBegin, so I had to redesign parts of my code. Here's an example of using pygame to create the texture, based on Python version of Nehe's tutorial, lesson 6:
#!/usr/bin/env python
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import pygame
ESCAPE = '\033'
window = 0
texture = 0
A_TEX_NUMBER = None
B_TEX_NUMBER = None
def GenTextureForText(text):
font = pygame.font.Font(None, 64)
textSurface = font.render(text, True, (255,255,255,255),
(0,0,0,255))
ix, iy = textSurface.get_width(), textSurface.get_height()
image = pygame.image.tostring(textSurface, "RGBX", True)
glPixelStorei(GL_UNPACK_ALIGNMENT,1)
i = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, i)
glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
return i
def InitGL(Width, Height):
global A_TEX_NUMBER, B_TEX_NUMBER
pygame.init()
A_TEX_NUMBER = GenTextureForText("a")
B_TEX_NUMBER = GenTextureForText("b")
glEnable(GL_TEXTURE_2D)
glClearColor(0.0, 0.0, 0.0, 0.0)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0, float(Width)/float(Height), 0.1, 100.0)
glMatrixMode(GL_MODELVIEW)
done = 1
def DrawGLScene():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0.0,0.0,-10.0)
glBindTexture(GL_TEXTURE_2D, B_TEX_NUMBER)
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, 1.0)
glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, 1.0)
glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, 1.0)
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, 1.0)
glEnd()
glutSwapBuffers()
def keyPressed(*args):
if args[0] == ESCAPE:
glutDestroyWindow(window)
sys.exit()
def main():
global window
glutInit("")
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH)
glutInitWindowSize(640, 480)
glutInitWindowPosition(0, 0)
window = glutCreateWindow("Jeff Molofee's GL Code Tutorial ... NeHe '99")
glutDisplayFunc(DrawGLScene)
glutIdleFunc(DrawGLScene)
glutKeyboardFunc(keyPressed)
InitGL(640, 480)
glutMainLoop()
print "Hit ESC key to quit."
main()
Im trying to display a simple immediate mode sets of textured polygons with pyOpenGL with no luck. I have lashed together some code that loads a some geometry data and that all works fine and as far as I can tell I have all the code to add a texture to it but just getting white polys.
Here's the important bits of the code:
self.img = PIL.Image.open('/projects/openGL_robot_face/facemap.png')
self.image_data = numpy.array(list(self.img.getdata()), numpy.uint8)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
texture = glGenTextures( 1)
glPixelStorei(GL_UNPACK_ALIGNMENT,1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
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, self.img.size[0], self.img.size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, self.image_data)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslate(0.0, 0.0, -50.0)
glScale(20.0, 20.0, 20.0)
glRotate(self.yRotDeg, 0.2, 1.0, 0.3)
glTranslate(-0.5, -0.5, -0.5)
glBegin(GL_TRIANGLES)
for vert in self.poly_verts:
glTexCoord2f(vert[6], vert[7])
glVertex3f(vert[0], vert[1], vert[2])
glEnd()
Have you enabled textures in OpenGL, using :
glEnable(GL_TEXTURE_2D)
Also, you should not create the texture on each Paint call, you should create it once and for all (with glGenTextures, and glTex*), then store the texture ID, and do the strict minimum during Paint, which is binding with the texture.
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, texture)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslate(0.0, 0.0, -50.0)
glScale(20.0, 20.0, 20.0)
glRotate(self.yRotDeg, 0.2, 1.0, 0.3)
glTranslate(-0.5, -0.5, -0.5)
glBegin(GL_TRIANGLES)
for vert in self.poly_verts:
glTexCoord2f (vert[6], vert[7]);
glVertex3f(vert[0], vert[1], vert[2])
glEnd()
glDisable(GL_TEXTURE_2D)
Unfortunately I cannot try the answer right now so this is purely from the top of my head.
You could probably benefit from this previous post :
Render a textured rectangle with PyOpenGL