我一直在尝试纹理这个立方体,它与图像一起纹理但不是以正确的方式

Posted

技术标签:

【中文标题】我一直在尝试纹理这个立方体,它与图像一起纹理但不是以正确的方式【英文标题】:I've been trying to texture this cube, it is textured with the image but not in the right way 【发布时间】:2019-08-17 21:48:31 【问题描述】:

当我运行我的程序时,立方体上的纹理似乎方向不正确并重复出现。图像中的白色似乎也被绿色取代了。我曾尝试删除 glColor 标签,但这只会引发错误。如果有人也知道如何让它只显示原始图像,那就太好了,但如果没有人可以,这不是世界末日。

看起来像这样

纹理是这样的

这是我的代码:

import pygame
import sys
from OpenGL.GL import *
from OpenGL.GLU import *
from pygame.locals import *

verticies = (
    (1, 1, 1),      #0
    (1, 1, -1),     #1
    (1, -1, 1),     #2
    (1, -1, -1),    #3
    (-1, 1, 1),     #4
    (-1, 1, -1),    #5
    (-1, -1, 1),    #6
    (-1, -1, -1),   #7
    )

# (<node1>, <node2>)
edges = (
    (0, 1),         #0
    (0, 2),         #1
    (0, 4),         #2
    (1, 3),         #3
    (1, 5),         #4
    (2, 3),         #5
    (2, 6),         #6
    (3, 7),         #7
    (4, 5),         #8
    (4, 6),         #9
    (5, 7),         #10
    (6, 7),         #11
    )

# (<node1>, <node2>, <node3>, <node4>)
faces = (
    (0, 1, 3, 2),   #0
    (0, 1, 5, 4),   #1
    (0, 2, 6, 4),   #2
    (1, 3, 7, 5),   #3
    (2, 3, 7, 6),   #4
    (4, 5, 7, 6),   #5
    )

def cube():
    glBegin(GL_QUADS)
    for face in faces:
        for vertex in face:
            glColor3fv((0, 1, 0))
            glTexCoord2fv(edges[vertex])
            glVertex3fv(verticies[vertex])
    glEnd()

    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glColor3fv((0, 0, 0))
            glVertex3fv(verticies[vertex])
    glEnd()


def loadTexture():
    textureSurface = pygame.image.load('test_image.png')
    textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
    width = textureSurface.get_width()
    height = textureSurface.get_height()

    glEnable(GL_TEXTURE_2D)
    texid = glGenTextures(1)

    glBindTexture(GL_TEXTURE_2D, texid)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height,
                  0, GL_RGBA, GL_UNSIGNED_BYTE, textureData)

    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)

def main():
    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)

##    loadTexture()

    gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)

    glTranslatef(0.0, 0.0, -5)

    glRotatef(0, 0, 0, 0)

    shiftActive = 0
    ctrlActive = 0

    while 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                  glTranslatef(0.03, 0, 0)
            if event.key == pygame.K_RIGHT:
                  glTranslatef(-0.03, 0, 0)
            if event.key == pygame.K_UP:
                  glTranslatef(0, -0.03, 0)    
            if event.key == pygame.K_DOWN:
                  glTranslatef(0, 0.03, 0)
            if event.key == pygame.K_LSHIFT:
                shiftActive = 1
            if event.key == pygame.K_LCTRL:
                ctrlActive = 1

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LSHIFT:
                shiftActive = 0
            if event.key == pygame.K_LCTRL:
                ctrlActive = 0

        # scroll controls  !CURRENTLY IN CLIK MODE BECAUSE OF MOUSE ISSUES!
        if shiftActive:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    glTranslatef(-0.03, 0, 0)
                if event.button == 3:
                    glTranslatef(0.03, 0, 0)
        elif ctrlActive:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    glTranslatef(0, 0, 0.03)
                if event.button == 3:
                    glTranslatef(0, 0, -0.03)
        else:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    glTranslatef(0, -0.03, 0)
                if event.button == 3:
                    glTranslatef(0, 0.03, 0)

##        glRotatef(1, 1, 1, 1)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        cube()
        loadTexture()
        pygame.display.flip()
        pygame.time.wait(10)

main()

有人知道我做错了什么吗?

再次,堆栈溢出不喜欢我的代码与描述的比率,所以我必须在问题的末尾添加随机句子让我发布它。我希望这被删除或只是一个可选的警告。我不认为深入讨论图像的角度以及图像的百分比大小应该与每个面的当前大小进行比较并给出覆盖纹理中白色的绿色的确切十六进制值将帮助任何人回答这个问题。 FFS 堆栈溢出。

【问题讨论】:

【参考方案1】:

有一些问题。一是贴图颜色不对。

如果启用纹理,则默认情况下纹理元素的颜色乘以当前颜色,因为默认情况下纹理环境模式 (GL_TEXTURE_ENV_MODE) 为GL_MODULATE。见glTexEnv

这会导致纹理纹素的颜色与您在glColor3f 设置的最后一种颜色“混合”。

在渲染纹理之前设置“白色”颜色,以解决您的问题:

glColor3f(1, 1, 1)

同样,您可以将环境模式更改为GL_REPLACE,而不是:

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)

此外,纹理未按预期包裹到几何体。这是因为纹理坐标错误。阅读How do opengl texture coordinates work?。

如果您想将整个纹理放在立方体的每一侧,那么您必须为四边形的每个角定义一个纹理坐标,从而形成立方体的一侧。最小纹理坐标为 (0, 0),最大值为 (1, 1)。例如:

(0, 1)        (1, 1)
      +------+
      |      |
      |      |
      +------+
(0, 0)        (1, 0)

修改代码如下绘制一个合适的立方体:

uv = ((1, 1), (1, 0), (0, 0), (0, 1))

def cube():
    glColor3f(1, 1, 1)
    glBegin(GL_QUADS)
    for face in faces:
        for i, vertex in enumerate(face):
            glTexCoord2fv(uv[i])
            glVertex3fv(verticies[vertex])
    glEnd()

如果您希望立方体靠近相机的侧面覆盖它们后面的侧面,那么您必须通过glEnable(GL_DEPTH_TEST) 启用Depth Test。

在每一帧中重新加载纹理是浪费时间。在主循环之前加载一次纹理就足够了。:

# load texture
loadTexture()

# enable  the depth test
glEnable(GL_DEPTH_TEST)

while 1:

    # [...]

    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    cube()
    pygame.display.flip()
    pygame.time.wait(10)

请注意,在绘制几何体(立方体)之前,您必须确保绑定了正确的纹理 (glBindTexture(GL_TEXTURE_2D, texid)) 并启用了二维纹理 (glEnable(GL_TEXTURE_2D))。 OpenGL 是一个状态引擎。设置的状态会被保留,直到您再次更改它们,甚至超出框架。


有不同的电流矩阵,可以通过glMatrixMode切换。顶点坐标通过投影矩阵和模型视图矩阵进行变换:

pos = projectionMatrix * modelviewMatrix * vertex

因此应该将投影矩阵设置为当前投影矩阵,并将视图模型矩阵分别设置为模式视图矩阵:

glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)

glMatrixMode(GL_MODELVIEW)
glTranslatef(0.0, 0.0, -5)
glRotatef(0, 0, 0, 0)

当前的矩阵被组织在一个堆栈上,可以被glPushMatrix()/glPopMatrix保存和恢复

请参阅以下main() 的示例代码:

def main():
    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)

    glMatrixMode(GL_PROJECTION)
    gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)

    glMatrixMode(GL_MODELVIEW)
    glTranslatef(0.0, 0.0, -5)

    loadTexture()
    glEnable(GL_DEPTH_TEST)

    shiftActive, ctrlActive = 0, 0
    anglex, angley = 0, 0
    while 1:
        for event in pygame.event.get():
            # [...]
        # [...]

        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

        glPushMatrix()
        glRotate(anglex, 1, 0, 0)
        glRotate(angley, 0, 1, 0)
        anglex += 2
        angley += 1

        cube()

        glPopMatrix()

        pygame.display.flip()
        pygame.time.wait(10)

【讨论】:

【参考方案2】:

试试这个(注意 glColor3fv((1, 1, 1)) 和“textcoords”):

import pygame
import sys
from OpenGL.GL import *
from OpenGL.GLU import *
from pygame.locals import *

verticies = (
    (1, 1, 1),      #0
    (1, 1, -1),     #1
    (1, -1, 1),     #2
    (1, -1, -1),    #3
    (-1, 1, 1),     #4
    (-1, 1, -1),    #5
    (-1, -1, 1),    #6
    (-1, -1, -1),   #7
    )

# (<node1>, <node2>)
edges = (
    (0, 1),         #0
    (0, 2),         #1
    (0, 4),         #2
    (1, 3),         #3
    (1, 5),         #4
    (2, 3),         #5
    (2, 6),         #6
    (3, 7),         #7
    (4, 5),         #8
    (4, 6),         #9
    (5, 7),         #10
    (6, 7),         #11
    )

textcoords = (
    (1, 1),
    (1, 0),
    (0, 0),
    (0, 1)
    )

# (<node1>, <node2>, <node3>, <node4>)
faces = (
    (0, 1, 3, 2),   #0
    (0, 1, 5, 4),   #1
    (0, 2, 6, 4),   #2
    (1, 3, 7, 5),   #3
    (2, 3, 7, 6),   #4
    (4, 5, 7, 6),   #5
    )

def cube():
    glBegin(GL_QUADS)
    for face in faces:
        for vertex, id in zip(face, range(0, 4)):
            glColor3fv((1, 1, 1))
            glTexCoord2fv(textcoords[id])
            glVertex3fv(verticies[vertex])
    glEnd()

    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glColor3fv((0, 0, 0))
            glVertex3fv(verticies[vertex])
    glEnd()


def loadTexture():
    textureSurface = pygame.image.load('BkHwp.png')
    textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
    width = textureSurface.get_width()
    height = textureSurface.get_height()

    glEnable(GL_TEXTURE_2D)
    texid = glGenTextures(1)

    glBindTexture(GL_TEXTURE_2D, texid)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height,
                 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData)

    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)
    #glGenerateMipmap(GL_TEXTURE_2D)

def main():
    pygame.init()
    display = (800, 600)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)

    gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)

    glTranslatef(0.0, 0.0, -5)

    glRotatef(0, 0, 0, 0)

    shiftActive = 0
    ctrlActive = 0

    while 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                  glTranslatef(0.03, 0, 0)
            if event.key == pygame.K_RIGHT:
                  glTranslatef(-0.03, 0, 0)
            if event.key == pygame.K_UP:
                  glTranslatef(0, -0.03, 0)
            if event.key == pygame.K_DOWN:
                  glTranslatef(0, 0.03, 0)
            if event.key == pygame.K_LSHIFT:
                shiftActive = 1
            if event.key == pygame.K_LCTRL:
                ctrlActive = 1

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LSHIFT:
                shiftActive = 0
            if event.key == pygame.K_LCTRL:
                ctrlActive = 0

        # scroll controls  !CURRENTLY IN CLIK MODE BECAUSE OF MOUSE ISSUES!
        if shiftActive:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    glTranslatef(-0.03, 0, 0)
                if event.button == 3:
                    glTranslatef(0.03, 0, 0)
        elif ctrlActive:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    glTranslatef(0, 0, 0.03)
                if event.button == 3:
                    glTranslatef(0, 0, -0.03)
        else:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    glTranslatef(0, -0.03, 0)
                if event.button == 3:
                    glTranslatef(0, 0.03, 0)

##        glRotatef(1, 1, 1, 1)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        cube()
        loadTexture()
        pygame.display.flip()
        pygame.time.wait(10)

main()

【讨论】:

> “试试这个 [...]”

以上是关于我一直在尝试纹理这个立方体,它与图像一起纹理但不是以正确的方式的主要内容,如果未能解决你的问题,请参考以下文章

Three.js 运行时纹理/图像更新

如何在 OpenGL ES 2.0 中使用 png 图像纹理立方体?

SDL 3d OpenGL:立方体上的纹理产生空白屏幕

Three.js 立方体,每个面都有不同的纹理

使用 GLUT 在立方体上的 OpenGL 多纹理映射

CUDA 立方体贴图纹理