为什么纹理索引 31 在 moderngl 中被覆盖?
Why does texture index 31 is overridden in moderngl?
我正在编写一个简单的应用程序,它加载图像并将其显示在屏幕上,以便分别呈现左半部分和右半部分。
import glm
import moderngl_window
import numpy as np
from PIL import Image
class BugExample(moderngl_window.WindowConfig):
LEFT_TEXTURE_IDX = 0
RIGHT_TEXTURE_IDX = 1
def __init__(self, **kwargs):
super().__init__(**kwargs)
image = Image.open("test.jpg").transpose(Image.FLIP_TOP_BOTTOM)
w, h = image.size
w_even = 2 * (w // 2)
left = image.crop((0, 0, w_even // 2, h))
right = image.crop((w_even // 2, 0, w_even, h))
self.texture_left = self.ctx.texture(left.size, 3, left.tobytes())
self.texture_left.use(self.LEFT_TEXTURE_IDX)
self.texture_right = self.ctx.texture(right.size, 3, right.tobytes())
self.texture_right.use(self.RIGHT_TEXTURE_IDX)
self.program = self.ctx.program(
vertex_shader="""
#version 330
in vec2 in_position;
uniform mat4 model;
out vec2 uv0;
void main() {
gl_Position = model * vec4(in_position, 0.0, 1.0);
uv0 = (0.5 * in_position) + vec2(0.5);
}
""",
fragment_shader="""
#version 330
out vec4 fragColor;
uniform sampler2D texture_idx;
in vec2 uv0;
void main() {
fragColor = texture(texture_idx, uv0);
}
""")
self.left_scale_mat = glm.scale(glm.mat4(), glm.vec3(0.5, 1.0, 1.0))
self.left_translate_mat = glm.translate(glm.mat4(), glm.vec3(-0.5, 0.0, 0.0))
self.left_model_mat = self.left_translate_mat * self.left_scale_mat
self.right_scale_mat = glm.scale(glm.mat4(), glm.vec3(0.5, 1.0, 1.0))
self.right_translate_mat = glm.translate(glm.mat4(), glm.vec3(0.5, 0.0, 0.0))
self.right_model_mat = self.right_translate_mat * self.right_scale_mat
vertices = np.array([-1.0, 1.0, -1.0, -1.0, 1.0, -1.0,
-1.0, 1.0, 1.0, -1.0, 1.0, 1.0], dtype='f4')
self.vbo = self.ctx.buffer(vertices)
self.vao = self.ctx.simple_vertex_array(self.program, self.vbo, 'in_position')
def render(self, time, frame_time):
self.ctx.clear(1.0, 1.0, 1.0)
self.program["model"].write(bytes(self.left_model_mat))
self.program["texture_idx"].value = self.LEFT_TEXTURE_IDX
self.vao.render()
self.program["model"].write(bytes(self.right_model_mat))
self.program["texture_idx"].value = self.RIGHT_TEXTURE_IDX
self.vao.render()
if __name__ == '__main__':
moderngl_window.run_window_config(BugExample, args=('--window', 'glfw'))
运行 此程序将使用您的图像 test.jpg
打开一个 window。
但是 纹理索引 31 处发生了一些奇怪的事情:
如果您更改索引,使 first 加载的纹理(在我们的例子中是左侧纹理,如 render
方法中所述)具有索引 31,它将被 other 纹理覆盖,您会看到右半部分重复两次。
我应该指出,如果我只有一个纹理,而不是两个,并且该纹理的索引为 31
,就不会有问题。仅当存在索引为 31
的纹理和在 31
纹理 之后 加载另一纹理时才会出现问题。
[编辑:我还应该指出,加载 超过 32 个纹理没有问题。如果我要将我的图像分成 32 个或更多的图块(而不是上面示例中的 2 个图块),甚至 64 个图块或更多,唯一的问题是纹理索引 31
将被覆盖上次 纹理加载。]
我有一个模糊的猜测,这与数字 31
作为 int 进行操作的方式有关? (喜欢 here)
所以,最后,我的问题是 - 这里发生了什么??我是否错过了正在发生的更大的事情,或者这只是生活中的一个事实,我应该避免纹理索引 31
而忘记它?
这个问题似乎与 Context.texture
的内部实现有关。
当纹理加载到 GPU 时,会生成纹理对象并将其绑定到目标和纹理单元(DSA 除外)。 ModernGL 似乎在内部使用纹理单元 31 来完成此任务。
我对此非常确定,因为当我在 self.ctx.texture(left.size, 3, left.tobytes())
、
之后打印活动纹理单元时
from OpenGL.GL import *
print(glGetInteger(GL_ACTIVE_TEXTURE) - GL_TEXTURE0)
输出为 31,与 LEFT_TEXTURE_IDX
和 RIGHT_TEXTURE_IDX
的值无关。
解释:
当您使用纹理单元 31 和 32 时:
LEFT_TEXTURE_IDX = 0
RIGHT_TEXTURE_IDX = 1
textur_left
使用纹理单元 31:
在内部加载
self.texture_left = self.ctx.texture(left.size, 3, left.tobytes())
textue_left
显式绑定到纹理单元 31:
self.texture_left.use(self.LEFT_TEXTURE_IDX)
texture_right
使用纹理单元 31 在内部加载。这打破了 textue_left
到纹理单元 31 的绑定:
self.texture_right = self.ctx.texture(right.size, 3, right.tobytes())
texture_right
显式绑定到纹理单元 32:
self.texture_right.use(self.RIGHT_TEXTURE_IDX)
最终texture_right
绑定到纹理单元31和32。
更改说明的顺序以解决问题。首先加载两个纹理,然后将它们分配给纹理单元:
self.texture_left = self.ctx.texture(left.size, 3, left.tobytes())
self.texture_right = self.ctx.texture(right.size, 3, right.tobytes())
self.texture_left.use(self.LEFT_TEXTURE_IDX)
self.texture_right.use(self.RIGHT_TEXTURE_IDX)
我正在编写一个简单的应用程序,它加载图像并将其显示在屏幕上,以便分别呈现左半部分和右半部分。
import glm
import moderngl_window
import numpy as np
from PIL import Image
class BugExample(moderngl_window.WindowConfig):
LEFT_TEXTURE_IDX = 0
RIGHT_TEXTURE_IDX = 1
def __init__(self, **kwargs):
super().__init__(**kwargs)
image = Image.open("test.jpg").transpose(Image.FLIP_TOP_BOTTOM)
w, h = image.size
w_even = 2 * (w // 2)
left = image.crop((0, 0, w_even // 2, h))
right = image.crop((w_even // 2, 0, w_even, h))
self.texture_left = self.ctx.texture(left.size, 3, left.tobytes())
self.texture_left.use(self.LEFT_TEXTURE_IDX)
self.texture_right = self.ctx.texture(right.size, 3, right.tobytes())
self.texture_right.use(self.RIGHT_TEXTURE_IDX)
self.program = self.ctx.program(
vertex_shader="""
#version 330
in vec2 in_position;
uniform mat4 model;
out vec2 uv0;
void main() {
gl_Position = model * vec4(in_position, 0.0, 1.0);
uv0 = (0.5 * in_position) + vec2(0.5);
}
""",
fragment_shader="""
#version 330
out vec4 fragColor;
uniform sampler2D texture_idx;
in vec2 uv0;
void main() {
fragColor = texture(texture_idx, uv0);
}
""")
self.left_scale_mat = glm.scale(glm.mat4(), glm.vec3(0.5, 1.0, 1.0))
self.left_translate_mat = glm.translate(glm.mat4(), glm.vec3(-0.5, 0.0, 0.0))
self.left_model_mat = self.left_translate_mat * self.left_scale_mat
self.right_scale_mat = glm.scale(glm.mat4(), glm.vec3(0.5, 1.0, 1.0))
self.right_translate_mat = glm.translate(glm.mat4(), glm.vec3(0.5, 0.0, 0.0))
self.right_model_mat = self.right_translate_mat * self.right_scale_mat
vertices = np.array([-1.0, 1.0, -1.0, -1.0, 1.0, -1.0,
-1.0, 1.0, 1.0, -1.0, 1.0, 1.0], dtype='f4')
self.vbo = self.ctx.buffer(vertices)
self.vao = self.ctx.simple_vertex_array(self.program, self.vbo, 'in_position')
def render(self, time, frame_time):
self.ctx.clear(1.0, 1.0, 1.0)
self.program["model"].write(bytes(self.left_model_mat))
self.program["texture_idx"].value = self.LEFT_TEXTURE_IDX
self.vao.render()
self.program["model"].write(bytes(self.right_model_mat))
self.program["texture_idx"].value = self.RIGHT_TEXTURE_IDX
self.vao.render()
if __name__ == '__main__':
moderngl_window.run_window_config(BugExample, args=('--window', 'glfw'))
运行 此程序将使用您的图像 test.jpg
打开一个 window。
但是 纹理索引 31 处发生了一些奇怪的事情:
如果您更改索引,使 first 加载的纹理(在我们的例子中是左侧纹理,如 render
方法中所述)具有索引 31,它将被 other 纹理覆盖,您会看到右半部分重复两次。
我应该指出,如果我只有一个纹理,而不是两个,并且该纹理的索引为 31
,就不会有问题。仅当存在索引为 31
的纹理和在 31
纹理 之后 加载另一纹理时才会出现问题。
[编辑:我还应该指出,加载 超过 32 个纹理没有问题。如果我要将我的图像分成 32 个或更多的图块(而不是上面示例中的 2 个图块),甚至 64 个图块或更多,唯一的问题是纹理索引 31
将被覆盖上次 纹理加载。]
我有一个模糊的猜测,这与数字 31
作为 int 进行操作的方式有关? (喜欢 here)
所以,最后,我的问题是 - 这里发生了什么??我是否错过了正在发生的更大的事情,或者这只是生活中的一个事实,我应该避免纹理索引 31
而忘记它?
这个问题似乎与 Context.texture
的内部实现有关。
当纹理加载到 GPU 时,会生成纹理对象并将其绑定到目标和纹理单元(DSA 除外)。 ModernGL 似乎在内部使用纹理单元 31 来完成此任务。
我对此非常确定,因为当我在 self.ctx.texture(left.size, 3, left.tobytes())
、
from OpenGL.GL import *
print(glGetInteger(GL_ACTIVE_TEXTURE) - GL_TEXTURE0)
输出为 31,与 LEFT_TEXTURE_IDX
和 RIGHT_TEXTURE_IDX
的值无关。
解释:
当您使用纹理单元 31 和 32 时:
LEFT_TEXTURE_IDX = 0 RIGHT_TEXTURE_IDX = 1
textur_left
使用纹理单元 31:
self.texture_left = self.ctx.texture(left.size, 3, left.tobytes())
textue_left
显式绑定到纹理单元 31:
self.texture_left.use(self.LEFT_TEXTURE_IDX)
texture_right
使用纹理单元 31 在内部加载。这打破了 textue_left
到纹理单元 31 的绑定:
self.texture_right = self.ctx.texture(right.size, 3, right.tobytes())
texture_right
显式绑定到纹理单元 32:
self.texture_right.use(self.RIGHT_TEXTURE_IDX)
最终texture_right
绑定到纹理单元31和32。
更改说明的顺序以解决问题。首先加载两个纹理,然后将它们分配给纹理单元:
self.texture_left = self.ctx.texture(left.size, 3, left.tobytes())
self.texture_right = self.ctx.texture(right.size, 3, right.tobytes())
self.texture_left.use(self.LEFT_TEXTURE_IDX)
self.texture_right.use(self.RIGHT_TEXTURE_IDX)