多纹理不能按预期工作

时间:2017-04-10 15:13:22

标签: python opengl multitexturing

鉴于以下代码段:

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()

如果我设置current_method=0我将获得我期望的输出,所有立方体面将使用不同的纹理(按预期):

enter image description here

如果我设置current_method=1,只有一张脸会被正确纹理化,那输出错误:

enter image description here

如果我设置current_method=2所有面都将使用相同的纹理[0]进行纹理处理,这也是错误的输出:

enter image description here

我想了解为什么方法1& 2没有提供与方法0相同的输出。我知道使用glActiveTexture时使用着色器正确变得微不足道但是我想了解在旧的固定管道上使用这些方法时出了什么问题。

2 个答案:

答案 0 :(得分:2)

我认为这里的核心问题是误解多重纹理的工作原理。

多纹理将多个纹理同时应用于相同的基元。您希望将不同的纹理,一次一个纹理应用于不同的基元。由此可以清楚地看出,多重纹理并不能达到你想要的效果,因此使用它是没有意义的。

多纹理的工作原理

使用多重纹理,多个纹理单元使用混合混合函数组合它们的结果。

texture unit 0 --> +---------+
                   |  blend  | --\
texture unit 1 --> +---------+    \--> +---------+
                                       |  blend  | --> etc.
texture unit 2 ----------------------> +---------+

每个阶段的混合功能由glTexEnv设置,可以是GL_MODULATEGL_DECALGL_ADD。这就是光照贴图在白天与纹理结合的方式:一个纹理具有漫反射纹理,一个纹理具有光照贴图纹理。

同样,这与您想要实现的效果完全不同,因此多重纹理在您的应用程序中没有任何意义。

glActiveTexture的工作原理

glActiveTexture不会更改绘制到屏幕的纹理单位。默认情况下,只有纹理单元#0将绘制到屏幕上。

glActiveTexture只允许您将纹理绑定到其他纹理单元。但是,由于纹理单元#1没有被使用,因此绑定到单元#1的纹理或坐标是什么并不重要。所以你应该总是使用glActiveTexture(GL_TEXTURE0),因为你总是想要改变纹理单元#0。

解决方案

因此,您拥有不使用多重纹理的工作代码。大!你完成了。使用更多OpenGL功能不会获得奖励积分。

或者,如果使用2D数组纹理,则可以在单个绘制调用中绘制整个多维数据集。您只需将现有纹理加载为2D阵列纹理中的平面,并使用3D纹理坐标而不是2D纹理坐标。同样,不需要多重纹理。

答案 1 :(得分:1)

  

如果我设置current_method=1,只有一张脸会被正确纹理化,那就是错误的输出。

不,这不是错误的输出。这是完全正确的输出。您从未设置固定功能管道状态以进行任何多重纹理(有关详细信息,请参阅@Dietrich Epp的答案)。您的渲染管道配置的只是:

  • 获取每片段插值顶点颜色的颜色值(您从未设置,iirc默认为白色)
  • 使用纹理坐标集0的每片段插值纹理坐标对当前绑定到纹理单元0的纹理进行采样
  • 使用纹理的alpha通道(GL_DECAL模式)
  • 将结果混合在一起
  • 将其用作最终的片段颜色。

很明显,你永远不会看到任何纹理单元绑定的纹理>所以你看到了什么?

current_method==0时,您会看到您的期望。

如果current_method==1,您会看到从第一个纹理中取出的单个样本 - 它始终绑定在单位0上。由于您没有为单位0设置任何tex坐标,GL将仅重复最近设置的值,即(0,1)表示第一个面的最后一个顶点。这当然将用于新面的所有顶点,因此插值将产生一个常量值,从而产生恒定的纹理采样结果,从而产生恒定的颜色。

现在使用current_method=2,您仍然可以在纹理0处为所有面部绑定第一个纹理。但是,由于您现在再次为纹理单元0提供适当的每顶点texcoords,对其进行采样实际上会再次在不同区域对纹理进行采样,因此您将获得该纹理到基元的合理映射。