मैं एक साधारण ऐप लिख रहा हूं जो एक छवि लोड करता है और इसे स्क्रीन पर प्रदर्शित करता है जैसे बाएं और दाएं आधे हिस्से को अलग-अलग प्रस्तुत किया जाता है।

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 है, तो इसे अन्य बनावट, और आप दाएँ आधे को दो बार दोहराते हुए देखेंगे।

example bug

मुझे यह बताना चाहिए कि यदि मेरे पास केवल एक बनावट होती, न कि दो, और उस बनावट का सूचकांक 31 होता, तो कोई समस्या नहीं होती। समस्या केवल तब उत्पन्न होती है जब एक बनावट 31 के साथ होती है और दूसरी बनावट जो 31 बनावट के बाद लोड होती है।

[संपादित करें: मुझे यह भी बताना चाहिए कि मुझे ३२ से अधिक बनावट लोड करने में कोई समस्या नहीं है। अगर मुझे अपनी छवि को ३२ टाइलों या अधिक (उपरोक्त उदाहरण में २ टाइलों के बजाय), और ६४ टाइलों या अधिक में अलग करना था, तो एकमात्र समस्या बनावट सूचकांक 31 के साथ होगी जिसे ओवरराइड किया जाएगा अंतिम बनावट भरी हुई है।]

मेरे पास एक अस्पष्ट अनुमान है कि जिस तरह से संख्या 31 को int के रूप में छेड़छाड़ की जाती है, उसके साथ इसका कुछ संबंध है? (जैसे यहां)

तो, अंत में, मेरा प्रश्न है - यहाँ क्या हो रहा है ?? क्या मुझे कुछ बड़ा याद आ रहा है जो हो रहा है, या यह सिर्फ जीवन का एक तथ्य है और मुझे बनावट सूचकांक 31 से बचना चाहिए और इसके बारे में भूल जाना चाहिए?

2
DalyaG 12 अक्टूबर 2020, 15:21

1 उत्तर

सबसे बढ़िया उत्तर

ऐसा लगता है कि यह समस्या Context.texture

जब एक बनावट को GPU पर लोड किया जाता है, तो एक बनावट वस्तु उत्पन्न होती है और एक लक्ष्य और बनावट इकाई (DSA को छोड़कर) के लिए बाध्य होती है। मॉडर्नजीएल इस कार्य के लिए आंतरिक रूप से बनावट इकाई 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)
2
Rabbid76 12 अक्टूबर 2020, 18:05