Reputation: 9863
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.
Upvotes: 0
Views: 766
Reputation: 45322
If i set
current_method=1
only one face will be textured properly, that's a wrong output.
No, this is not a wrong output. This is the perfectly correct output. You never set up your fixed function pipeline state to do any multitexturing (see @Dietrich Epp's answer for the details). What your render pipeline is configured to is just:
GL_DECAL
mode) So it is clear that you will never see anything from textures bound to the texture units > 0. So what do you see?
When current_method==0
, you see what you expect.
If current_method==1
, you see a single sample taken from the first texture - which is bound on unit 0 all the time. Since you do not set any tex coords for unit 0, the GL will just repeat the most recently set value, which is (0,1)
for the last vertex of your first face. This will of course be used for all vertices of the new faces, so the interpolation will yield a constant value, resulting in a constant texture sampling result, resulting in a constant color.
Now with current_method=2
you still have the first texture bound at texture 0 for all faces. But since you now supply proper per-vertex texcoords for texture unit 0 again, sampling it will actually sample the texture at different regions again, so you'll get a sane mapping of that texture to the primitives.
Upvotes: 1
Reputation: 213308
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.
Upvotes: 2