为什么我的纹理没有显示 PyOpenGL

Why my texture is not showing PyOpenGL

我尝试了所有方法,但仍然没有收到错误。我正在尝试在我的球体对象上放置纹理。

"""
Minimal texture on sphere demo
This is demo for showing how to put image
on sphere as texture in PyOpenGL.
"""
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
from PIL import Image
import numpy


def run_scene():
    glutInit()
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
    glutCreateWindow("Minimal sphere OpenGL")
    lightning()
    glutDisplayFunc(draw_sphere)
    glMatrixMode(GL_PROJECTION)
    gluPerspective(40, 1, 1, 40)
    glMatrixMode(GL_MODELVIEW)
    gluLookAt(0, 0, 10,
              0, 0, 0,
              0, 1, 0)
    glPushMatrix()
    glutMainLoop()
    return


def lightning():
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_LIGHTING)
    glEnable(GL_BLEND)
    glLightfv(GL_LIGHT0, GL_POSITION, [10, 4, 10, 1])
    glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8, 1, 0.8, 1])
    glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1)
    glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05)
    glEnable(GL_LIGHT0)
    return


def draw_sphere():
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glPushMatrix()
    texture_id = read_texture('mars.png')
    glEnable(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, texture_id)
    glEnable(GL_TEXTURE_GEN_S)
    glEnable(GL_TEXTURE_GEN_T)
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP)
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP)
    glutSolidSphere(1, 50, 50)
    glDisable(GL_TEXTURE_2D)
    glPopMatrix()
    glutSwapBuffers()
    return


def read_texture(filename):
    img = Image.open(filename)
    img_data = numpy.array(list(img.getdata()), numpy.int8)
    texture_id = glGenTextures(1)
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
    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_WRAP_S, GL_REPEAT)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
    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)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.size[0], img.size[1], 0,
                 GL_RGB, GL_UNSIGNED_BYTE, img_data)
    return texture_id


if __name__ == '__main__':
    run_scene()

这是这段代码的结果,简单的绿色球体如下:

但这不是我期望的结果。我只想在球体表面显示此纹理 mars.png

帮我解决这个问题,我自己似乎解决不了。

read_texture() 中,生成纹理名称后不绑定它。因此后续的纹理相关调用将转到默认纹理,而不是您新创建的纹理。

texture_id = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture_id) # This is what's missing

此外,由于您的图片是 PNG 图片。然后 list(img.getdata()) 将是包含 (R, G, B, A) 的元组列表。因此,在调用 glTexImage2D 时,您需要告知您的数据是 GL_RGBA 而不是 GL_RGB.

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.size[0], img.size[1], 0,
             GL_RGBA, GL_UNSIGNED_BYTE, img_data)

您也可以将其自动化。

format = GL_RGB if img.mode == "RGB" else GL_RGBA
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img.size[0], img.size[1], 0,
             format, GL_UNSIGNED_BYTE, img_data)

您也可以将其转换为没有 alpha 通道。

img = img.convert("RGB")

这当然需要在调用 img.getdata() 之前完成。

现在您应该看到以下内容:

也是一个重要的注意事项。您正在 draw_sphere() 中呼叫 read_texture()。这意味着每次调用 draw_sphere() 时,都会加载图像并创建新纹理。你真的不想那样做。而不是在调用 glutMainLoop() 之前调用 read_texture() 并将结果存储为全局名称。