Given the below snippet:
import os
import textwrap
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from PIL import Image
from OpenGL.GL.ARB.multitexture import *
from OpenGL.extensions import alternate
def get_opengl_info():
return textwrap.dedent("""\
Vendor: {0}
Renderer: {1}
OpenGL Version: {2}
Shader Version: {3}
{4:*^80}
Num Extensions: {5}
{6}
""").format(
glGetString(GL_VENDOR).decode("utf-8"),
glGetString(GL_RENDERER).decode("utf-8"),
glGetString(GL_VERSION).decode("utf-8"),
glGetString(GL_SHADING_LANGUAGE_VERSION).decode("utf-8"),
"OPENGL EXTENSIONS",
glGetIntegerv(GL_NUM_EXTENSIONS),
"\n".join(glGetString(GL_EXTENSIONS).decode("utf-8").split())
)
def create_gl_texture(use_active_texture, channel, width, height, pbits):
id_texture = glGenTextures(1)
if use_active_texture:
glActiveTexture(GL_TEXTURE0 + channel)
glBindTexture(GL_TEXTURE_2D, id_texture)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, pbits)
glTexParameter(
GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameter(
GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
glTexParameter(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
glGenerateMipmap(GL_TEXTURE_2D)
return id_texture
def load_texture(use_active_texture, filename, i):
image = Image.open(filename)
ix = image.size[0]
iy = image.size[1]
pbits = image.convert("RGBA").tobytes("raw", "RGBA")
id_texture = create_gl_texture(use_active_texture, i, ix, iy, pbits)
print("Loaded", id_texture)
return id_texture
X_AXIS = 0.0
Y_AXIS = 0.0
Z_AXIS = 0.0
DIRECTION = 1
id_textures = []
def init_gl(Width, Height):
global glMultiTexCoord2f, glActiveTexture
print(get_opengl_info())
print("Choosing between: ", glMultiTexCoord2f.__name__,
glMultiTexCoord2fARB.__name__)
print("Choosing between: ", glActiveTexture.__name__,
glActiveTextureARB.__name__)
glMultiTexCoord2f = alternate(
glMultiTexCoord2f,
glMultiTexCoord2fARB
)
glActiveTexture = alternate(
glActiveTexture,
glActiveTextureARB,
)
print("Selected: ", glMultiTexCoord2f.__name__)
print("Selected: ", glActiveTexture.__name__)
if not glMultiTexCoord2f:
print('Multitexture not supported!')
sys.exit(1)
glClearColor(0.0, 0.0, 0.0, 0.0)
glClearDepth(1.0)
glDepthFunc(GL_LESS)
glEnable(GL_DEPTH_TEST)
glShadeModel(GL_SMOOTH)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0, float(Width) / float(Height), 0.1, 100.0)
glMatrixMode(GL_MODELVIEW)
glEnable(GL_TEXTURE_2D)
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)
def keyPressed(*args):
if args[0] == "\033":
sys.exit()
# Method0: Using glBindTexture + glTexCoord2f per face
def draw_method_0():
global X_AXIS, Y_AXIS, Z_AXIS
global DIRECTION
global id_textures
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0.0, 0.0, -6.0)
glRotatef(X_AXIS, 1.0, 0.0, 0.0)
glRotatef(Y_AXIS, 0.0, 1.0, 0.0)
glRotatef(Z_AXIS, 0.0, 0.0, 1.0)
glBindTexture(GL_TEXTURE_2D, id_textures[0])
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()
glBindTexture(GL_TEXTURE_2D, id_textures[1])
glBegin(GL_QUADS)
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)
glTexCoord2f(0.0, 0.0)
glVertex3f(1.0, -1.0, -1.0)
glEnd()
glBindTexture(GL_TEXTURE_2D, id_textures[2])
glBegin(GL_QUADS)
glTexCoord2f(0.0, 1.0)
glVertex3f(-1.0, 1.0, -1.0)
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)
glEnd()
glBindTexture(GL_TEXTURE_2D, id_textures[3])
glBegin(GL_QUADS)
glTexCoord2f(1.0, 1.0)
glVertex3f(-1.0, -1.0, -1.0)
glTexCoord2f(0.0, 1.0)
glVertex3f(1.0, -1.0, -1.0)
glTexCoord2f(0.0, 0.0)
glVertex3f(1.0, -1.0, 1.0)
glTexCoord2f(1.0, 0.0)
glVertex3f(-1.0, -1.0, 1.0)
glEnd()
glBindTexture(GL_TEXTURE_2D, id_textures[4])
glBegin(GL_QUADS)
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)
glTexCoord2f(0.0, 0.0)
glVertex3f(1.0, -1.0, 1.0)
glEnd()
glBindTexture(GL_TEXTURE_2D, id_textures[5])
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()
X_AXIS = X_AXIS - 0.030
Z_AXIS = Z_AXIS - 0.030
glutSwapBuffers()
# Method1: Using glActiveTexture+glBindTexture+glMultiTexCoord2f per face
def draw_method_1():
global X_AXIS, Y_AXIS, Z_AXIS
global DIRECTION
global id_textures
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0.0, 0.0, -6.0)
glRotatef(X_AXIS, 1.0, 0.0, 0.0)
glRotatef(Y_AXIS, 0.0, 1.0, 0.0)
glRotatef(Z_AXIS, 0.0, 0.0, 1.0)
glActiveTexture(GL_TEXTURE0 + 0)
glBindTexture(GL_TEXTURE_2D, id_textures[0])
glBegin(GL_QUADS)
glMultiTexCoord2f(GL_TEXTURE0 + 0, 0.0, 0.0)
glVertex3f(-1.0, -1.0, 1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 0, 1.0, 0.0)
glVertex3f(1.0, -1.0, 1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 0, 1.0, 1.0)
glVertex3f(1.0, 1.0, 1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 0, 0.0, 1.0)
glVertex3f(-1.0, 1.0, 1.0)
glEnd()
glActiveTexture(GL_TEXTURE0 + 1)
glBindTexture(GL_TEXTURE_2D, id_textures[1])
glBegin(GL_QUADS)
glMultiTexCoord2f(GL_TEXTURE0 + 1, 1.0, 0.0)
glVertex3f(-1.0, -1.0, -1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 1, 1.0, 1.0)
glVertex3f(-1.0, 1.0, -1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 1, 0.0, 1.0)
glVertex3f(1.0, 1.0, -1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 1, 0.0, 0.0)
glVertex3f(1.0, -1.0, -1.0)
glEnd()
glActiveTexture(GL_TEXTURE0 + 2)
glBindTexture(GL_TEXTURE_2D, id_textures[2])
glBegin(GL_QUADS)
glMultiTexCoord2f(GL_TEXTURE0 + 2, 0.0, 1.0)
glVertex3f(-1.0, 1.0, -1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 2, 0.0, 0.0)
glVertex3f(-1.0, 1.0, 1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 2, 1.0, 0.0)
glVertex3f(1.0, 1.0, 1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 2, 1.0, 1.0)
glVertex3f(1.0, 1.0, -1.0)
glEnd()
glActiveTexture(GL_TEXTURE0 + 3)
glBindTexture(GL_TEXTURE_2D, id_textures[3])
glBegin(GL_QUADS)
glMultiTexCoord2f(GL_TEXTURE0 + 3, 1.0, 1.0)
glVertex3f(-1.0, -1.0, -1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 3, 0.0, 1.0)
glVertex3f(1.0, -1.0, -1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 3, 0.0, 0.0)
glVertex3f(1.0, -1.0, 1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 3, 1.0, 0.0)
glVertex3f(-1.0, -1.0, 1.0)
glEnd()
glActiveTexture(GL_TEXTURE0 + 4)
glBindTexture(GL_TEXTURE_2D, id_textures[4])
glBegin(GL_QUADS)
glMultiTexCoord2f(GL_TEXTURE0 + 4, 1.0, 0.0)
glVertex3f(1.0, -1.0, -1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 4, 1.0, 1.0)
glVertex3f(1.0, 1.0, -1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 4, 0.0, 1.0)
glVertex3f(1.0, 1.0, 1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 4, 0.0, 0.0)
glVertex3f(1.0, -1.0, 1.0)
glEnd()
glActiveTexture(GL_TEXTURE0 + 5)
glBindTexture(GL_TEXTURE_2D, id_textures[5])
glBegin(GL_QUADS)
glMultiTexCoord2f(GL_TEXTURE0 + 5, 0.0, 0.0)
glVertex3f(-1.0, -1.0, -1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 5, 1.0, 0.0)
glVertex3f(-1.0, -1.0, 1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 5, 1.0, 1.0)
glVertex3f(-1.0, 1.0, 1.0)
glMultiTexCoord2f(GL_TEXTURE0 + 5, 0.0, 1.0)
glVertex3f(-1.0, 1.0, -1.0)
glEnd()
X_AXIS = X_AXIS - 0.030
Z_AXIS = Z_AXIS - 0.030
glutSwapBuffers()
# Method2: Using glActiveTexture+glBindTexture+glTexCoord2f per face
def draw_method_2():
global X_AXIS, Y_AXIS, Z_AXIS
global DIRECTION
global id_textures
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0.0, 0.0, -6.0)
glRotatef(X_AXIS, 1.0, 0.0, 0.0)
glRotatef(Y_AXIS, 0.0, 1.0, 0.0)
glRotatef(Z_AXIS, 0.0, 0.0, 1.0)
glActiveTexture(GL_TEXTURE0 + 0)
glBindTexture(GL_TEXTURE_2D, id_textures[0])
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()
glActiveTexture(GL_TEXTURE0 + 1)
glBindTexture(GL_TEXTURE_2D, id_textures[1])
glBegin(GL_QUADS)
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)
glTexCoord2f(0.0, 0.0)
glVertex3f(1.0, -1.0, -1.0)
glEnd()
glActiveTexture(GL_TEXTURE0 + 2)
glBindTexture(GL_TEXTURE_2D, id_textures[2])
glBegin(GL_QUADS)
glTexCoord2f(0.0, 1.0)
glVertex3f(-1.0, 1.0, -1.0)
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)
glEnd()
glActiveTexture(GL_TEXTURE0 + 3)
glBindTexture(GL_TEXTURE_2D, id_textures[3])
glBegin(GL_QUADS)
glTexCoord2f(1.0, 1.0)
glVertex3f(-1.0, -1.0, -1.0)
glTexCoord2f(0.0, 1.0)
glVertex3f(1.0, -1.0, -1.0)
glTexCoord2f(0.0, 0.0)
glVertex3f(1.0, -1.0, 1.0)
glTexCoord2f(1.0, 0.0)
glVertex3f(-1.0, -1.0, 1.0)
glEnd()
glActiveTexture(GL_TEXTURE0 + 4)
glBindTexture(GL_TEXTURE_2D, id_textures[4])
glBegin(GL_QUADS)
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)
glTexCoord2f(0.0, 0.0)
glVertex3f(1.0, -1.0, 1.0)
glEnd()
glActiveTexture(GL_TEXTURE0 + 5)
glBindTexture(GL_TEXTURE_2D, id_textures[5])
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()
X_AXIS = X_AXIS - 0.030
Z_AXIS = Z_AXIS - 0.030
glutSwapBuffers()
def load_textures(use_active_texture):
global id_textures
id_textures.append(load_texture(use_active_texture, "tex00.jpg", 0))
id_textures.append(load_texture(use_active_texture, "tex01.jpg", 1))
id_textures.append(load_texture(use_active_texture, "tex02.jpg", 2))
id_textures.append(load_texture(use_active_texture, "tex03.jpg", 3))
id_textures.append(load_texture(use_active_texture, "tex04.jpg", 4))
id_textures.append(load_texture(use_active_texture, "tex05.jpg", 5))
def main():
glutInit(sys.argv)
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH)
glutInitWindowSize(640, 480)
glutInitWindowPosition(200, 200)
glutCreateWindow(b'OpenGL Python Textured Cube')
init_gl(640, 480)
current_method = 2
draw_methods = {
0: {"f": draw_method_0, "use_active_texture": False},
1: {"f": draw_method_1, "use_active_texture": True},
2: {"f": draw_method_2, "use_active_texture": True}
}
draw = draw_methods[current_method]["f"]
load_textures(draw_methods[current_method]["use_active_texture"])
glutDisplayFunc(draw)
glutIdleFunc(draw)
glutKeyboardFunc(keyPressed)
glutMainLoop()
if __name__ == "__main__":
main()
If i set current_method=0
I'll get the output I expect, all cube faces will use a different texture (as intended):
If i set current_method=1
only one face will be textured properly, that's a wrong output:
If i set current_method=2
all faces will be textured with the same texture[0], which is also a wrong output:
I'd like to understand why methods 1 & 2 are not giving the same output as method 0. I know when using shaders using glActiveTexture properly becomes trivial but I'd like to understand what's wrong when using these methods on the old fixed pipeline.
I think the core issue here is a misunderstanding of how multitexturing works.
Multitexturing applies multiple textures at the same time to the same primitives. You want to apply different textures, one texture at a time, to different primitives. It should be clear from this that multitexturing does not do what you want, so there is no point in using it.
With multitexturing, multiple texture units combine their results using blending blending functions.
texture unit 0 --> +---------+
| blend | --\
texture unit 1 --> +---------+ \--> +---------+
| blend | --> etc.
texture unit 2 ----------------------> +---------+
The blending function for each stage is set by glTexEnv
and can be something like GL_MODULATE
, GL_DECAL
, or GL_ADD
. This is how lightmaps were combined with textures back in the day: one texture would have the diffuse texture, and one texture would have the lightmap texture.
Again, this is completely different from the effect which you want to achieve, so multitexturing has no point in your application.
glActiveTexture
doesn't change which texture unit is drawn to the screen. By default, only texture unit #0 will draw to the screen.
glActiveTexture
just allows you to bind textures to other texture units. However, since texture unit #1 isn't being used, it doesn't matter what texture is bound to unit #1 or what the coordinates are. So you should always be using glActiveTexture(GL_TEXTURE0)
, since you always want to change texture unit #0.
So, you have working code that doesn't use multitexturing. Great! You're done. You don't get bonus points for using more OpenGL features.
Alternatively, you could draw the entire cube in a single draw call if you use a 2D array texture. You simply load your existing textures as planes in a 2D array texture and use 3D texture coordinates instead of 2D texture coordinates. Again, no multitexturing required.