通过 glBindTexture 获取错误的纹理
Getting wrong texture by glBindTexture
我有两个 .png 格式的纹理(地板和墙壁),我在初始化期间加载它们,并在 glBindTexture
渲染之前选择,但我得到了这个:
screen_shot_1
而不是这个:
screen_shot_2
初始化:
def __init__(self, screen_info, wall_number):
self.screen = screen_info
self.inscription = font.Font(get_path([RES_PATH[0], 'font', 'main.ttf']), 12)
self.path = get_path([RES_PATH[0], RES_PATH[1], ''])
self.sprite_list = {}
self.tex_list = {}
self.generate_list()
self.wall_coordinates = []
self.wall_number = wall_number
self.wall_counter = 0
glClearColor(*BACKGROUND_COLOR)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(FOV, self.screen.current_w / self.screen.current_h, DISTANCE_NEAR, DISTANCE_FAR)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glEnable(GL_DEPTH_TEST)
glEnable(GL_TEXTURE_2D)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
主循环:
gi = interaction.GI(screen_info, 11)
while True:
timer.tick(60)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
camera.update_view()
camera.update_move(forward, backward, left, right, gi.get_wall_coordinates())
gi.draw_ground(0, 0)
gi.draw_square(-2, 1.5, -4)
gi.draw_square(0, 1.5, -4)
gi.draw_square(2, 1.5, -4)
gi.draw_square(4, 1.5, -4, rot=True)
gi.draw_square(4, 1.5, -2, rot=True)
gi.draw_square(4, 1.5, 0, rot=True)
gi.draw_square(2, 1.5, 2)
gi.draw_square(0, 1.5, 2)
gi.draw_square(-2, 1.5, 2)
gi.draw_square(-2, 1.5, 0, rot=True)
gi.draw_square(-2, 1.5, -4, rot=True)
pygame.display.flip()
纹理加载器:
def load_tex(self, filename, rotate=False, text_render=False, text=''):
if not text_render:
surface = image.load(filename)
if rotate:
surface = transform.rotate(surface, 180)
else:
surface = self.inscription.render(str(text), 1, (255, 255, 255), (0, 0, 0))
surface = transform.scale(surface, (64, 64))
surface = transform.rotate(surface, 180)
size = surface.get_size()
surface = image.tostring(surface, 'RGB', True)
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
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, 3, size[0], size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, surface)
return texture
在初始化期间加载纹理:
def generate_list(self):
for filename in listdir(self.path):
self.tex_list[filename] = self.load_tex(get_path([RES_PATH[0], RES_PATH[1], filename]))
绘图地:
def draw_ground(self, x, z, length=50):
glBindTexture(GL_TEXTURE_2D, self.tex_list['floor.png'])
# glBindTexture(GL_TEXTURE_2D, self.load_tex(get_path([RES_PATH[0], RES_PATH[1], 'floor.png'])))
glBegin(GL_QUADS)
glTexCoord2f(0, length)
glVertex3f(x - length, -0.5, z + length)
glTexCoord2f(length, length)
glVertex3f(x + length, -0.5, z + length)
glTexCoord2f(length, 0)
glVertex3f(x + length, -0.5, z - length)
glTexCoord2f(0, 0)
glVertex3f(x - length, -0.5, z - length)
glEnd()
画墙:
def draw_square(self, x, y, z, length=2, rot=False):
glBindTexture(GL_TEXTURE_2D, self.tex_list['wall.png'])
# glBindTexture(GL_TEXTURE_2D, self.load_tex(get_path([RES_PATH[0], RES_PATH[1], 'wall.png'])))
glBegin(GL_QUADS)
glTexCoord2f(0, 1)
glVertex3f(x, y, z)
glTexCoord2f(1, 1)
if not rot:
glVertex3f(x + length, y, z)
glTexCoord2f(1, 0)
glVertex3f(x + length, y - length, z)
else:
glVertex3f(x, y, z + length)
glTexCoord2f(1, 0)
glVertex3f(x, y - length, z + length)
glTexCoord2f(0, 0)
glVertex3f(x, y - length, z)
glEnd()
那么问题是什么?
这些是我在您的代码中注意到的一些事情,它们可能与您的纹理问题有关,也可能无关:
- 对于您的 glTexParameterf 调用,我看到您使用了 GL_NEAREST。这将导致像素化纹理。如果您不使用像素艺术,您可能需要考虑将 GL_LINEAR 作为最终参数,因为这会执行双线性插值,从而消除明显的像素化。
- 我认为您不需要 glTexEnvf 或 glPixelStorei 调用。
- 作为一个好习惯,一旦你使用完一个纹理,你应该通过调用 glBindTexture(GL_TEXTURE_0, 0) 来解除它的绑定。 OpenGL 完全是关于状态的,所以在你完成之后 return 事情是个好主意,这样你以后就不会对奇怪的行为感到惊讶。我的猜测是您没有正确绑定第二个纹理(检查纹理 ID),导致第一个纹理被用于所有调用。尝试重新排序绘制调用并查看纹理是否发生变化。这是推测,因为我无法 运行 您的示例代码。
- glTexImage2D 的参数看起来很奇怪。您可能想看看 opengl docs as well as their python 等价物。我个人喜欢使用像 GL_RGBA 这样的枚举格式来使代码更清晰。
这是我使用 pyopengl 和 pygame 制作的一个简单演示。它渲染两个 2d 正方形,每个都具有不同的纹理。主要的 while 循环和 load_texture 函数是重要的部分:
import pygame
from pygame.locals import *
from OpenGL.GL import *
import sys
def init_gl():
window_size = width, height = (550, 400)
pygame.init()
pygame.display.set_mode(window_size, OPENGL | DOUBLEBUF)
glEnable(GL_TEXTURE_2D)
glMatrixMode(GL_PROJECTION)
glOrtho(0, width, height, 0, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def load_texture(texture_url):
tex_id = glGenTextures(1)
tex = pygame.image.load(texture_url)
tex_surface = pygame.image.tostring(tex, 'RGBA')
tex_width, tex_height = tex.get_size()
glBindTexture(GL_TEXTURE_2D, tex_id)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_surface)
glBindTexture(GL_TEXTURE_2D, 0)
return tex_id
if __name__ == "__main__":
init_gl()
texture1 = load_texture("texture1.png")
texture2 = load_texture("texture2.png")
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
glClear(GL_COLOR_BUFFER_BIT)
glBindTexture(GL_TEXTURE_2D, texture1)
glBegin(GL_QUADS)
glTexCoord(0, 0)
glVertex(50, 50, 0)
glTexCoord(0, 1)
glVertex(50, 100, 0)
glTexCoord(1, 1)
glVertex(100, 100, 0)
glTexCoord(1, 0)
glVertex(100, 50, 0)
glEnd()
glBindTexture(GL_TEXTURE_2D, 0)
glBindTexture(GL_TEXTURE_2D, texture2)
glBegin(GL_QUADS)
glTexCoord(0, 0)
glVertex(450, 300, 0)
glTexCoord(0, 1)
glVertex(450, 350, 0)
glTexCoord(1, 1)
glVertex(500, 350, 0)
glTexCoord(1, 0)
glVertex(500, 300, 0)
glEnd()
glBindTexture(GL_TEXTURE_2D, 0)
pygame.display.flip()
附带说明一下,您的大部分代码和我发布的演示代码在现代 OpenGL 中已被弃用,它不支持像 glBegin 和 glEnd 这样的慢速即时模式调用。如果您以后 运行 遇到性能问题,可能需要考虑重构以使用更现代的技术,例如 VBO(顶点缓冲区对象)。但是对于简单的应用程序,这应该不是什么大问题。让我知道这是否有帮助!
我有两个 .png 格式的纹理(地板和墙壁),我在初始化期间加载它们,并在 glBindTexture
渲染之前选择,但我得到了这个:
screen_shot_1
而不是这个:
screen_shot_2
初始化:
def __init__(self, screen_info, wall_number):
self.screen = screen_info
self.inscription = font.Font(get_path([RES_PATH[0], 'font', 'main.ttf']), 12)
self.path = get_path([RES_PATH[0], RES_PATH[1], ''])
self.sprite_list = {}
self.tex_list = {}
self.generate_list()
self.wall_coordinates = []
self.wall_number = wall_number
self.wall_counter = 0
glClearColor(*BACKGROUND_COLOR)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(FOV, self.screen.current_w / self.screen.current_h, DISTANCE_NEAR, DISTANCE_FAR)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glEnable(GL_DEPTH_TEST)
glEnable(GL_TEXTURE_2D)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
主循环:
gi = interaction.GI(screen_info, 11)
while True:
timer.tick(60)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
camera.update_view()
camera.update_move(forward, backward, left, right, gi.get_wall_coordinates())
gi.draw_ground(0, 0)
gi.draw_square(-2, 1.5, -4)
gi.draw_square(0, 1.5, -4)
gi.draw_square(2, 1.5, -4)
gi.draw_square(4, 1.5, -4, rot=True)
gi.draw_square(4, 1.5, -2, rot=True)
gi.draw_square(4, 1.5, 0, rot=True)
gi.draw_square(2, 1.5, 2)
gi.draw_square(0, 1.5, 2)
gi.draw_square(-2, 1.5, 2)
gi.draw_square(-2, 1.5, 0, rot=True)
gi.draw_square(-2, 1.5, -4, rot=True)
pygame.display.flip()
纹理加载器:
def load_tex(self, filename, rotate=False, text_render=False, text=''):
if not text_render:
surface = image.load(filename)
if rotate:
surface = transform.rotate(surface, 180)
else:
surface = self.inscription.render(str(text), 1, (255, 255, 255), (0, 0, 0))
surface = transform.scale(surface, (64, 64))
surface = transform.rotate(surface, 180)
size = surface.get_size()
surface = image.tostring(surface, 'RGB', True)
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
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, 3, size[0], size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, surface)
return texture
在初始化期间加载纹理:
def generate_list(self):
for filename in listdir(self.path):
self.tex_list[filename] = self.load_tex(get_path([RES_PATH[0], RES_PATH[1], filename]))
绘图地:
def draw_ground(self, x, z, length=50):
glBindTexture(GL_TEXTURE_2D, self.tex_list['floor.png'])
# glBindTexture(GL_TEXTURE_2D, self.load_tex(get_path([RES_PATH[0], RES_PATH[1], 'floor.png'])))
glBegin(GL_QUADS)
glTexCoord2f(0, length)
glVertex3f(x - length, -0.5, z + length)
glTexCoord2f(length, length)
glVertex3f(x + length, -0.5, z + length)
glTexCoord2f(length, 0)
glVertex3f(x + length, -0.5, z - length)
glTexCoord2f(0, 0)
glVertex3f(x - length, -0.5, z - length)
glEnd()
画墙:
def draw_square(self, x, y, z, length=2, rot=False):
glBindTexture(GL_TEXTURE_2D, self.tex_list['wall.png'])
# glBindTexture(GL_TEXTURE_2D, self.load_tex(get_path([RES_PATH[0], RES_PATH[1], 'wall.png'])))
glBegin(GL_QUADS)
glTexCoord2f(0, 1)
glVertex3f(x, y, z)
glTexCoord2f(1, 1)
if not rot:
glVertex3f(x + length, y, z)
glTexCoord2f(1, 0)
glVertex3f(x + length, y - length, z)
else:
glVertex3f(x, y, z + length)
glTexCoord2f(1, 0)
glVertex3f(x, y - length, z + length)
glTexCoord2f(0, 0)
glVertex3f(x, y - length, z)
glEnd()
那么问题是什么?
这些是我在您的代码中注意到的一些事情,它们可能与您的纹理问题有关,也可能无关:
- 对于您的 glTexParameterf 调用,我看到您使用了 GL_NEAREST。这将导致像素化纹理。如果您不使用像素艺术,您可能需要考虑将 GL_LINEAR 作为最终参数,因为这会执行双线性插值,从而消除明显的像素化。
- 我认为您不需要 glTexEnvf 或 glPixelStorei 调用。
- 作为一个好习惯,一旦你使用完一个纹理,你应该通过调用 glBindTexture(GL_TEXTURE_0, 0) 来解除它的绑定。 OpenGL 完全是关于状态的,所以在你完成之后 return 事情是个好主意,这样你以后就不会对奇怪的行为感到惊讶。我的猜测是您没有正确绑定第二个纹理(检查纹理 ID),导致第一个纹理被用于所有调用。尝试重新排序绘制调用并查看纹理是否发生变化。这是推测,因为我无法 运行 您的示例代码。
- glTexImage2D 的参数看起来很奇怪。您可能想看看 opengl docs as well as their python 等价物。我个人喜欢使用像 GL_RGBA 这样的枚举格式来使代码更清晰。
这是我使用 pyopengl 和 pygame 制作的一个简单演示。它渲染两个 2d 正方形,每个都具有不同的纹理。主要的 while 循环和 load_texture 函数是重要的部分:
import pygame
from pygame.locals import *
from OpenGL.GL import *
import sys
def init_gl():
window_size = width, height = (550, 400)
pygame.init()
pygame.display.set_mode(window_size, OPENGL | DOUBLEBUF)
glEnable(GL_TEXTURE_2D)
glMatrixMode(GL_PROJECTION)
glOrtho(0, width, height, 0, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def load_texture(texture_url):
tex_id = glGenTextures(1)
tex = pygame.image.load(texture_url)
tex_surface = pygame.image.tostring(tex, 'RGBA')
tex_width, tex_height = tex.get_size()
glBindTexture(GL_TEXTURE_2D, tex_id)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_surface)
glBindTexture(GL_TEXTURE_2D, 0)
return tex_id
if __name__ == "__main__":
init_gl()
texture1 = load_texture("texture1.png")
texture2 = load_texture("texture2.png")
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
glClear(GL_COLOR_BUFFER_BIT)
glBindTexture(GL_TEXTURE_2D, texture1)
glBegin(GL_QUADS)
glTexCoord(0, 0)
glVertex(50, 50, 0)
glTexCoord(0, 1)
glVertex(50, 100, 0)
glTexCoord(1, 1)
glVertex(100, 100, 0)
glTexCoord(1, 0)
glVertex(100, 50, 0)
glEnd()
glBindTexture(GL_TEXTURE_2D, 0)
glBindTexture(GL_TEXTURE_2D, texture2)
glBegin(GL_QUADS)
glTexCoord(0, 0)
glVertex(450, 300, 0)
glTexCoord(0, 1)
glVertex(450, 350, 0)
glTexCoord(1, 1)
glVertex(500, 350, 0)
glTexCoord(1, 0)
glVertex(500, 300, 0)
glEnd()
glBindTexture(GL_TEXTURE_2D, 0)
pygame.display.flip()
附带说明一下,您的大部分代码和我发布的演示代码在现代 OpenGL 中已被弃用,它不支持像 glBegin 和 glEnd 这样的慢速即时模式调用。如果您以后 运行 遇到性能问题,可能需要考虑重构以使用更现代的技术,例如 VBO(顶点缓冲区对象)。但是对于简单的应用程序,这应该不是什么大问题。让我知道这是否有帮助!