【问题标题】:Why does texture index 31 is overridden in moderngl?为什么纹理索引 31 在moderngl 中被覆盖?
【发布时间】:2020-10-13 18:11:40
【问题描述】:

我正在编写一个简单的应用程序,它加载图像并将其显示在屏幕上,以便分别呈现左半部分和右半部分。

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

但是在纹理索引 31 处发生了一些奇怪的事情:

如果您更改索引以使加载的纹理首先(在我们的例子中是左侧纹理,如render 方法中所述)具有索引31,它将被other 纹理,你会看到右半部分重复了两次。

我应该指出,如果我只有一个纹理,而不是两个,并且该纹理的索引为 31,则不会有问题。仅当一个纹理的索引为 31 且另一个纹理在 31 纹理之后加载时,才会出现此问题。

[编辑:我还应该指出,我加载 超过 32 个纹理没有问题。如果我要将图像分成 32 个或更多的图块(而不是上面示例中的 2 个图块),甚至 64 个或更多的图块,唯一的问题将是纹理索引 31 将被 最后一个纹理加载。]

我有一个模糊的猜测,这与数字 31 被操纵为 int 的方式有关吗? (如here

所以,最后,我的问题是 - 这里发生了什么?我是否错过了正在发生的更大的事情,或者它只是生活中的一个事实,我应该避免纹理索引31 并忘记它?

【问题讨论】:

    标签: python python-3.x opengl graphics python-moderngl


    【解决方案1】:

    问题似乎与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_IDXRIGHT_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)
    

    【讨论】:

    • 哇,这太奇怪了,但肯定能解决问题!通过将use 语句从__init__ 移动到渲染方法using,然后分别渲染每个纹理,我能够@workaround@ 错误。现在我明白为什么这个 hack 有效了!谢谢!
    猜你喜欢
    • 1970-01-01
    • 2010-10-17
    • 2014-06-05
    • 2021-04-07
    • 1970-01-01
    • 2010-10-11
    • 2020-09-01
    • 2011-09-22
    • 2017-05-08
    相关资源
    最近更新 更多