Pyglet draw text into texture - python

I'm trying to render an image with OpenGL using Pyglet. So far I've been able to setup the framebuffer and texture, render into it and save it as a PNG image. But I can't find out how to use Pyglets font rendering.
import numpy as np
import pyglet
from pyglet.gl import *
from ctypes import byref, sizeof, POINTER
width = 800
height = 600
cpp = 4
# Create the framebuffer (rendering target).
buf = gl.GLuint(0)
glGenFramebuffers(1, byref(buf))
glBindFramebuffer(GL_FRAMEBUFFER, buf)
# Create the texture (internal pixel data for the framebuffer).
tex = gl.GLuint(0)
glGenTextures(1, byref(tex))
glBindTexture(GL_TEXTURE_2D, tex)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, None)
# Bind the texture to the framebuffer.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0)
# Something may have gone wrong during the process, depending on the
# capabilities of the GPU.
res = glCheckFramebufferStatus(GL_FRAMEBUFFER)
if res != GL_FRAMEBUFFER_COMPLETE:
raise RuntimeError('Framebuffer not completed')
glViewport(0, 0, width, height)
# DRAW BEGIN
# =====================
glClearColor(0.1, 0.1, 0.1, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 0.5, 0.02)
glRectf(-0.75, -0.75, 0.75, 0.75)
glColor3f(1.0, 1.0, 1.0)
label = pyglet.text.Label(
"Hello, World", font_name='Times New Roman', font_size=36,
x=0, y=0, anchor_x='center', anchor_y='center')
label.draw()
# =====================
# DRAW END
# Read the buffer contents into a numpy array.
data = np.empty((height, width, cpp), dtype=np.float32)
glReadPixels(0, 0, width, height, GL_RGBA, GL_FLOAT, data.ctypes.data_as(POINTER(GLfloat)))
# Save the image.
import imageio
data = np.uint8(data * 255)
imageio.imwrite("foo.png", data)
The text does not appear on the framebuffer. How can I render the label on the framebuffer?

For rendering labels in Pyglet, first, an orthographic projection should be set up. In the given example, do it as follows:
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, width, 0, height, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glColor3f(1.0, 1.0, 1.0)
label = pyglet.text.Label(
"Hello, World", font_name='Times New Roman', font_size=36,
x=width/2, y=height/2, anchor_x='center', anchor_y='center')
label.draw()
Then, the label is rendered as expected. (Note: moved the label's offset to the image center, i.e. x=width/2, y=height/2,)
foo.png (output framebuffer image)

Related

Why are extra RGB colors appearing in PyOpenGL generated bitmap image?

Using Python and OpenGL, I'm creating a simple red triangle of RGBA = (1,0,0,1) and saving it as a bmp. I then load the image using CV2 and extract the RGBA colors that can be seen.
I want the red color and the background color to be the only colors in the image.
This code isn't pretty but successfully generates and save the triangle image as bmp:
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
from OpenGL.GL import shaders
import numpy as np
from PIL import Image
import cv2
VERTEX_SHADER = """
#version 330
in vec4 position;
void main() {
gl_Position = position;
}
"""
FRAGMENT_SHADER = """
#version 330
void main() {
gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
"""
shaderProgram = None
WIDTH, HEIGHT = 200,200
def initialize():
global VERTEX_SHADER
global FRAGMENT_SHADER
global shaderProgram
vertexshader = shaders.compileShader(VERTEX_SHADER, GL_VERTEX_SHADER)
fragmentshader = shaders.compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER)
shaderProgram = shaders.compileProgram(vertexshader, fragmentshader)
triangles = [-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0]
triangles = np.array(triangles, dtype=np.float32)
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, triangles.nbytes, triangles, GL_STATIC_DRAW)
position = glGetAttribLocation(shaderProgram, "position")
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, 0, None)
glEnableVertexAttribArray(position)
def render():
glClearColor(0,0,0,1)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glUseProgram(shaderProgram)
glDrawArrays(GL_TRIANGLES,0,3)
glUseProgram(0)
# Save a screenshot
screenshot_file_path = 'test.bmp'
data = glReadPixels(0,0,200,200, GL_RGBA,GL_UNSIGNED_BYTE)
image = Image.frombytes('RGBA',(200, 200), data)
image.save(screenshot_file_path, 'bmp')
print('Image saved to ' + screenshot_file_path)
glutSwapBuffers()
def main():
glutInit()
glutInitWindowSize(WIDTH, HEIGHT)
glutInitWindowPosition(200,200)
glutCreateWindow("Modern Opengl Triangle")
initialize()
glutDisplayFunc(render)
glutMainLoop()
if __name__ == "__main__":
main()
But when I parse the image's colors, I see 3 RGB triplets! rather than the expected 2.
Image parsing code:
import cv2
import numpy as np
imgfile = r"test.bmp"
npimg = cv2.imread(imgfile)
# cv2 reads the file into BGR, but we want to see the color as RGB
npimg = cv2.cvtColor(npimg, cv2.COLOR_BGR2RGB)
# Get unique RGB colors
uniqueRGB, uniqueRGBcounts = np.unique(npimg.reshape(-1, npimg.shape[2]), axis=0, return_counts=True)
print(uniqueRGB)
Result is:
[[ 0 0 0] <- Background
[188 0 0] <- ??? some other red
[255 0 0]] <- Desired red
What is going on? Can anyone explain where the extra triplet comes from? More importantly, how to make sure that ONLY the (255,0,0) and background (0,0,0) RGBs are saved to the bmp image?
Like #derhass had suggested, it was due to anti-aliasing. In my comment above I didn't completely turn off anti-aliasing and was still seeing weird results. After disabling it completely, I only have my desired red and background colors in my bitmap!
So, for any other noobs dabbling in image generation where you need to specify or read the exact colors in an image, make sure anti-aliasing is disabled!
EDIT: To the comment below suggesting I provide more detail on how to disable anti-aliasing:
I believe it's going to depend on whatever GPU or graphics drivers are in use. I have an NVIDIA GPU so I changed my settings using the NVIDIA Control Panel Application. Any feature referencing "Antialiasing" was changed to the off setting. Here's a screenshot of my NVIDIA control panel (3D settings tab) settings

pyOpenGL texture not rendering

So I've been racking my brain with nonstop trial and error. I feel like I keep coming back with questions about the same thing and it is frustrating.
I am following the tutorials and looking at the C++ code and following along with Python trying to replicate the result. I've noticed there are subtle differences through trial and error and I've searched high and low on the internet to see if someone else has experienced my issue. 9/10 times it is because the texture was not bound, however, it my case it is.
https://learnopengl.com/code_viewer_gh.php?code=src/1.getting_started/4.1.textures/textures.cpp
So I am wondering what I am doing wrong... any help?
import os # For mac... I am using a mac
import glfw # We're using this instead of GLUT as we have more flexibility
import numpy as np # We will use numpy for our arrays
# Using the API wrapper instead of something mugh higher. Keep in mind that the API is a state machine
from OpenGL.GL import *
from OpenGL.arrays import *
from ctypes import c_void_p
from PIL import Image
class HelloWindow():
width = 800
height = 640
title = 'Hello Window'
window = None
shader_program = None
vao = None
vbo = None
texture = None
vertex_gsl = """
#version 410 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 3) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main() {
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = vec2(aTexCoord);
}
"""
fragment_gsl = """
#version 410 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D texture1;
void main() {
FragColor = texture(texture1, TexCoord);
}
"""
def __init__(self):
if not glfw.init():
raise TypeError('Unable to initalize glfw')
self.main()
def main(self):
# Set window hints
self.set_window_hints()
# Create the window
self.create_window()
max_vertex_attributes = glGetIntegerv(GL_MAX_VERTEX_ATTRIBS)
print('Maximum number of vertex attributes in a vertex shader is: ' + str(max_vertex_attributes))
# Keep the window open in a loop
self.loop()
def set_window_hints(self):
glfw.window_hint(glfw.SAMPLES, 4)
# Using the core version in Mac OS but can be set to something else
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 1)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True)
def create_window(self):
self.window = glfw.create_window(self.width, self.height, self.title, None, None)
if not self.window:
raise TypeError('Unable to create the window')
glfw.terminate()
glfw.make_context_current(self.window)
glfw.set_framebuffer_size_callback(self.window, self.frame_buffer_size)
### Let's setup our data
verts = np.array([
# positions # colors # texture coords
[-0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
[-0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0],
[0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0],
[0.5, 0.5, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]
], dtype=np.float32) # OpenGL expects 32 bit data. Not 64 bit if you're on a 64 bit machine
indicies = np.array([
[0, 1, 3],
[1, 2, 3]
], dtype=np.uint32)
self.vao = glGenVertexArrays(1)
self.vbo = glGenBuffers(1)
self.ebo = glGenBuffers(1)
glBindVertexArray(self.vao)
glBindBuffer(GL_ARRAY_BUFFER, self.vbo) # Bind the buffer as an array buffer and not an element buffer
glBufferData(GL_ARRAY_BUFFER, verts, GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.ebo)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, False, 8 * verts.itemsize, None)
glEnableVertexAttribArray(0)
glVertexAttribPointer(1, 3, GL_FLOAT, False, 8 * verts.itemsize, c_void_p(3 * verts.itemsize))
glEnableVertexAttribArray(1)
glVertexAttribPointer(2, 2, GL_FLOAT, False, 8 * verts.itemsize, c_void_p(6 * verts.itemsize))
glEnableVertexAttribArray(2)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
self.setup_shader()
self.texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.texture)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
# Set the wrapping texture parameters for x,y equivalents
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
# Set the texture filtering parameters from min to max
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
# Load our image
img = Image.open('../res/container.jpg')
img.transpose(Image.FLIP_TOP_BOTTOM)
img.convert('RGB')
data = np.array(list(img.getdata()), np.uint8)
# Set the texture data
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.width, img.height, 0, GL_RGB, GL_UNSIGNED_BYTE, data)
glGenerateMipmap(GL_TEXTURE_2D)
#img.close()
def loop(self):
while not glfw.window_should_close(self.window):
glClearColor(0.2, 0.3, 0.3, 1.0)
glClear(GL_COLOR_BUFFER_BIT) # We always use this after we clear the color
# Maintain aspect ratio (optional)
glfw.set_window_aspect_ratio(self.window, self.width, self.height)
# Handle input
self.capture_input()
# Bind the texture
glBindTexture(GL_TEXTURE_2D, self.texture)
# Do some rendering
glUseProgram(self.shader_program)
glBindVertexArray(self.vao)
#glEnableVertexAttribArray(0)
#glDrawArrays(GL_TRIANGLES, 0, 3)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, None)
glfw.swap_interval(1)
glfw.swap_buffers(self.window)
glfw.poll_events()
glfw.destroy_window(self.window)
# Add the vao and vbo to an array so they're deleted. We can use this when creating several vaos and vbos
vao_list = np.array([self.vao], dtype=np.uint32)
vbo_list = np.array([self.vbo], dtype=np.uint32)
glDeleteVertexArrays(1, vao_list)
glDeleteBuffers(1, vbo_list)
glfw.terminate()
def capture_input(self):
if glfw.get_key(self.window, glfw.KEY_ESCAPE) == glfw.PRESS: # Get the key pressed and check if it is escape key
glfw.set_window_should_close(self.window, True)
def frame_buffer_size(self, window, width, height):
glViewport(0, 0, width, height)
def setup_shader(self):
vertex_shader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertex_shader, self.vertex_gsl)
glCompileShader(vertex_shader)
if not glGetShaderiv(vertex_shader, GL_COMPILE_STATUS):
glGetShaderInfoLog(vertex_shader, 512, None)
raise TypeError('vertex_shader did not compile correctly. Check the GSL')
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragment_shader, self.fragment_gsl)
glCompileShader(fragment_shader)
if not glGetShaderiv(fragment_shader, GL_COMPILE_STATUS):
glGetShaderInfoLog(fragment_shader, 512, None)
raise TypeError('fragment_shader did not compile correctly. Check the GSL')
self.shader_program = glCreateProgram()
glAttachShader(self.shader_program, vertex_shader)
glAttachShader(self.shader_program, fragment_shader)
glLinkProgram(self.shader_program)
if not glGetProgramiv(self.shader_program, GL_LINK_STATUS):
glGetProgramInfoLog(self.shader_program, 512, None)
glDeleteShader(vertex_shader)
glDeleteShader(fragment_shader)
if __name__ == '__main__':
hello_window = HelloWindow()
In the program the attribute index specified for the array of texture coordinates is 2:
glVertexAttribPointer(2, 2, GL_FLOAT, False, 8 * verts.itemsize, c_void_p(6 * verts.itemsize))
glEnableVertexAttribArray(2)
But in the vertex shader the attribute index specified for the texture coordinates is 3, by Layout Qualifier:
layout (location = 3) in vec2 aTexCoord;
Use the same attribute index in both cases and your texture will show up.

OpenCV Python OpenGL Texture

I want to overlay 3d objects on OpenCV feed. I found an example here That uses webcam video as texture in OpenGL. I changed some part so that it works with cv2. Now the output is something strange
CODE
import cv2
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import numpy as np
import sys
#window dimensions
width = 1280
height = 720
nRange = 1.0
global capture
capture = None
def cv2array(im):
h,w,c=im.shape
a = np.fromstring(
im.tostring(),
dtype=im.dtype,
count=w*h*c)
a.shape = (h,w,c)
return a
def init():
#glclearcolor (r, g, b, alpha)
glClearColor(0.0, 0.0, 0.0, 1.0)
glutDisplayFunc(display)
glutReshapeFunc(reshape)
glutKeyboardFunc(keyboard)
glutIdleFunc(idle)
def idle():
#capture next frame
global capture
_,image = capture.read()
cv2.cvtColor(image,cv2.COLOR_BGR2RGB)
#you must convert the image to array for glTexImage2D to work
#maybe there is a faster way that I don't know about yet...
#print image_arr
# Create Texture
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
720,1280,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
image)
cv2.imshow('frame',image)
glutPostRedisplay()
def display():
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glEnable(GL_TEXTURE_2D)
#glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
#glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
#glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
#this one is necessary with texture2d for some reason
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
# Set Projection Matrix
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluOrtho2D(0, width, 0, height)
# Switch to Model View Matrix
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
# Draw textured Quads
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0)
glVertex2f(0.0, 0.0)
glTexCoord2f(1.0, 0.0)
glVertex2f(width, 0.0)
glTexCoord2f(1.0, 1.0)
glVertex2f(width, height)
glTexCoord2f(0.0, 1.0)
glVertex2f(0.0, height)
glEnd()
glFlush()
glutSwapBuffers()
def reshape(w, h):
if h == 0:
h = 1
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# allows for reshaping the window without distoring shape
if w <= h:
glOrtho(-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange)
else:
glOrtho(-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def keyboard(key, x, y):
global anim
if key == chr(27):
sys.exit()
def main():
global capture
#start openCV capturefromCAM
capture = cv2.VideoCapture(0)
print capture
capture.set(3,1280)
capture.set(4,720)
glutInit(sys.argv)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowSize(width, height)
glutInitWindowPosition(100, 100)
glutCreateWindow("OpenGL + OpenCV")
init()
glutMainLoop()
main()
I find it very unlikely that your camera is providing a 720 pixel wide and 1280 pixel high image as you tell to OpenGL here:
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
720,1280, // <---- HERE
0,
GL_RGB,
GL_UNSIGNED_BYTE,
image)
It seems you just mixed up those two parametes, so the data is reinterpreted as such, resulting in the output you got.

PyOpenGL multitexture error - invalid operation

I'm trying to make a game that uses pygame and OpenGL in python 3, but i keep getting the same error:
OpenGL.error.GLError: GLError(
err = 1282,
description = b'invalid operation',
baseOperation = glClear,
cArguments = (16640,)
)
Here is my code:
PART A - Create and Configure
Surface = pygame.display.set_mode((WIDTH, HEIGHT), pygame.OPENGL)
glViewport(0, 0, WIDTH, HEIGHT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluOrtho2D(-8.0, 8.0, -6.0, 6.0)
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)
PART B - Creating Texture
class Texture():
# simple texture class
# designed for 32 bit png images (with alpha channel)
def __init__(self,fileName):
self.texID=0
self.LoadTexture(fileName)
def LoadTexture(self,fileName):
try:
textureSurface = pygame.image.load(fileName).convert_alpha()
textureData = pygame.image.tostring(textureSurface, "RGBA", True)
self.w, self.h = textureSurface.get_size()
self.texID=glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.texID)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, textureSurface.get_width(),
textureSurface.get_height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
textureData )
except Exception as E:
print(E)
print ("can't open the texture: %s"%(fileName))
def __del__(self):
glDeleteTextures(self.texID)
def get_width(self):
return self.w
def get_height(self):
return self.h
PART C - Prepering the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
PART D - Adding Texture
def blit(texture, x, y):
glPushMatrix()
glTranslatef(x, y, 0.0)
glBindTexture(GL_TEXTURE_2D, texture.texID)
I looked it up, and apparently PyOpenGL 3 has this unfixed bug when try to render more than one texture. I use python 3.3, and dont wanna downgrade to 2.x, and i cant find a OpenGL 2 for python 3. Is there an away around this bug? Am i doing something wrong?
The OpenGL Context is thread local. If you try to invoke an OpenGL statement from another thread without making current the OpenGL context current, you will get an INVALID_OPERATION error.
Unfortunately, PyGame does not offer a function to make the OpenGL context explicitly current.
Another possibility is that you missed closing a glBegin/glEndsequence withglEnd` somewhere.

Multi-texturing in PyOpenGL using a GLSL shader

I would like to be able to combine two textures in a GLSL fragment shader. I am currently using PyOpenGL and everything i've done up to this point using shaders has worked fine.
I am running into difficulty when I try to access multiple textures from the fragment shader, for instance, the following shader displays the correct texture minus the blue pixels:
uniform sampler2D my_texture1;
uniform sampler2D my_texture2;
void main()
{
vec4 color1 = texture2D(my_texture1, gl_TexCoord[1].st);
vec4 color2 = texture2D(my_texture2, gl_TexCoord[2].st);
if (color1.b > 0.8)
discard;
gl_FragColor = color1;
}
but
uniform sampler2D my_texture1;
uniform sampler2D my_texture2;
void main()
{
vec4 color1 = texture2D(my_texture1, gl_TexCoord[1].st);
vec4 color2 = texture2D(my_texture2, gl_TexCoord[2].st);
if (color2.b > 0.8)
discard;
gl_FragColor = color2;
}
results in a blank screen.
I have a feeling that the problem might lie in how i am passing the texture uniforms to the shader but cant for the life of me work out why the first texture works but the second doesn't. Below is the full program.
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from Image import *
from OpenGL.GL.shaders import *
ESCAPE = '\033'
global size
size = 512
def drawQuad(B,T,L,R):
glBegin(GL_QUADS)
glMultiTexCoord2f(GL_TEXTURE1, 0.0, 0.0); glMultiTexCoord2f(GL_TEXTURE2, 0.0, 0.0); glVertex3f(B, L, 1.0); ## Bottom Left Of The Texture and Quad
glMultiTexCoord2f(GL_TEXTURE1, 1.0, 0.0); glMultiTexCoord2f(GL_TEXTURE2, 1.0, 0.0); glVertex3f( T, L, 1.0); ## Bottom Right Of The Texture and Quad
glMultiTexCoord2f(GL_TEXTURE1, 1.0, 1.0); glMultiTexCoord2f(GL_TEXTURE2, 1.0, 1.0); glVertex3f( T, R, 1.0); ## Top Right Of The Texture and Quad
glMultiTexCoord2f(GL_TEXTURE1, 0.0, 1.0); glMultiTexCoord2f(GL_TEXTURE2, 0.0, 1.0); glVertex3f(B, R, 1.0); ## Top Left Of The Texture and Quad
glEnd()
def InitGL(Width, Height):
print "Vendor: " + glGetString(GL_VENDOR)
print "Renderer: " + glGetString(GL_RENDERER)
print "OpenGL Version: " + glGetString(GL_VERSION)
print "Shader Version: " + glGetString(GL_SHADING_LANGUAGE_VERSION)
if not glUseProgram:
print 'Missing Shader Objects!'
sys.exit(1)
global program
program = compileProgram(
compileShader('''
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[1] = gl_MultiTexCoord1;
gl_TexCoord[2] = gl_MultiTexCoord2;
}
''',GL_VERTEX_SHADER),
compileShader('''
uniform sampler2D my_texture1;
uniform sampler2D my_texture2;
void main()
{
vec4 color1 = texture2D(my_texture1, gl_TexCoord[1].st);
vec4 color2 = texture2D(my_texture2, gl_TexCoord[2].st);
if (color1.b > 0.8)
discard;
gl_FragColor = color1;
}
''',GL_FRAGMENT_SHADER),
)
#bmp texture 1
image = open("rgb.bmp")
ix = image.size[0]
iy = image.size[1]
image = image.tostring("raw", "RGBX", 0, -1)
glActiveTexture(GL_TEXTURE1)
global my_texture1
my_texture1 = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, my_texture1)
glPixelStorei(GL_UNPACK_ALIGNMENT,1)
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)
glGenerateMipmap(GL_TEXTURE_2D)
#bmp texture 2
image = open("rgb2.bmp")
ix = image.size[0]
iy = image.size[1]
image = image.tostring("raw", "RGBX", 0, -1)
glActiveTexture(GL_TEXTURE2)
global my_texture2
my_texture2 = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, my_texture2)
glPixelStorei(GL_UNPACK_ALIGNMENT,1)
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)
glGenerateMipmap(GL_TEXTURE_2D)
def DrawGLScene():
global frame, testvar, my_texture1,my_texture2
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, 0)
glUseProgram(program)
myUniformLocation1 = glGetUniformLocation(program, "my_texture1")
glUniform1i(myUniformLocation1, 1)
myUniformLocation2 = glGetUniformLocation(program, "my_texture2")
glUniform1i(myUniformLocation2, 2)
glViewport(0, 0, size,size)
glClearDepth(1.0)
glClearColor (0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(-1, 1, -1, 1, -30.0, 30.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glEnable(GL_DEPTH_TEST)
drawQuad(-1.0,1.0,-1.0,1.0)
glutSwapBuffers()
def keyPressed(*args):
global texturenumber, shadernumber, frame
# If escape is pressed, kill everything.
if args[0] == ESCAPE:
sys.exit()
def main():
global window
glutInit(sys.argv)
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
glutInitWindowSize(size,size)
glutInitWindowPosition(0, 0)
window = glutCreateWindow("Multitexturing")
glutDisplayFunc(DrawGLScene)
glutIdleFunc(DrawGLScene)
glutKeyboardFunc(keyPressed)
InitGL(size,size)
glutMainLoop()
if __name__ == "__main__":
print "Press 'ESC' key to quit."
main()
You actually unbind the second texture before using it:
def DrawGLScene():
global frame, testvar, my_texture1,my_texture2
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, 0)
[...]
After your initialization, texture unit 1 has my_texture1 assigned and texture unit 2 my_texture2. The active texture is still texture 2. So by calling glBindTexture(GL_TEXTURE_2D, 0) you unbind the texture from the active texture unit 2.
What you shoud do is this:
def DrawGLScene():
global frame, testvar, my_texture1,my_texture2
glActiveTexture(GL_TEXTURE1)
glBindTexture(GL_TEXTURE_2D, my_texture1)
glActiveTexture(GL_TEXTURE2)
glBindTexture(GL_TEXTURE_2D, my_texture2)
[...]
You could also simply remove the last four lines (after global frame, testvar, my_texture1,my_texture2) since your init routine takes care of this. However, if you bind and unbind any other textures in your code you have to do the texture unit activation and texture binding as above.

Categories

Resources