代码之家  ›  专栏  ›  技术社区  ›  Andrei Krotkov

OpenGL纹理加载问题

  •  1
  • Andrei Krotkov  · 技术社区  · 16 年前

    这是一个非常模糊的问题,请随时澄清关于这个项目的任何事情。

    我正在开发一个非常大的应用程序,最近出现了一个非常令人困惑的关于纹理的错误。我们正在加载的一些纹理正在被加载-我已经完成了代码,它运行了-但是所有OpenGL为这些纹理渲染的都是一个奇怪的粉红色/白色条纹纹理。

    您建议如何开始调试这种情况?

    • 该项目是多线程的,但互斥体确保所有OpenGL调用不会被其他任何东西中断。
    • 有些纹理正在加载,有些没有加载。它们的装载方式完全相同。
    • 我已经确定了所有的纹理都存在
    • “粉色/白色”纹理肯定会加载到内存中——在我将任何其他纹理加载到OpenGL之后,它们很快就会显示出来。

    我很困惑,不知道还有什么问题。是否有一个OpenGL命令可以在glteximage之后调用,从而强制纹理变得可用?

    编辑: 这不是命令失败的问题,主要是时间问题。粉色/白色纹理会出现一段时间,直到加载更多纹理。这就好像纹理被排成了一列,而队列只是在某个时间暂停。

    下一次编辑:我让glintercept日志正常工作,这就是它输出的内容(在整个程序崩溃之前)

    http://freetexthost.com/1kdkksabdg

    下一次编辑:我知道有一个事实,纹理加载在OpenGL内存中,但出于某种原因,它们没有在程序中呈现。

    7 回复  |  直到 15 年前
        1
  •  1
  •   Mr. Berna    16 年前

    检查纹理坐标。如果设置错误,您可以看到仅一个或两个texel映射到整个原语。记住,OpenGL是一个状态机。检查是否在错误的时间更改纹理坐标状态。您可能在代码的稍后点设置纹理坐标,然后当您返回重新绘制这些元素时,状态对于将纹理映射到代码是可以接受的。

    如果这仅仅是一个时间问题,纹理加载OpenGL调用没有及时执行,并且线程代码是正确的,那么在加载纹理后尝试添加对glflush()的调用。glflush()导致执行所有挂起的opengl命令。

        2
  •  3
  •   Ron Warholic    16 年前

    如果纹理的颜色不正确,则很可能加载了错误的RGB顺序。确保在glteximage2d中,图像格式使用了正确的枚举。确保组件的数量是正确的,并且在格式参数中获得了RGB像素的顺序。

    尽管可能与显示错误的纹理无关,但OpenGL不支持多线程绘制,因此请确保您没有在拥有上下文的线程之外的其他线程上执行任何绘制工作。

    编辑:是否有一个引用渲染器,以便验证图像像素是否按预期加载?我强烈建议编写一个要加载的小程序,然后立即将像素保存到一个文件中,这样可以确保获得正确的纹理结果。

        3
  •  1
  •   James    16 年前

    当你说:

    该项目是多线程的,但互斥体确保所有OpenGL调用不会被其他任何东西中断。

    对我来说,这听起来不像是强大的保护:记住OpenGL是一个具有大量内部状态的状态机。您需要确保OpenGL状态是您在进行调用时所期望的状态,并且某些调用序列不会被其他线程的调用中断。

    我不是OpenGL线程安全专家,但在我看来,这可能是您的问题所在。

        4
  •  0
  •   jose    16 年前

    检查用作纹理的图像的大小和压缩。我认为OpenGL纹理大小必须是2的幂…

        5
  •  0
  •   jfcalvo    16 年前

    你不能在一条线中加载一个纹理并在其他不同的线中使用它,因为你会看到一个漂亮的白色纹理。要做到这一点,在使用任何OpenGL函数之前,必须在不同线程之间加载OpenGL上下文。

        6
  •  0
  •   Damian Trebilco    16 年前

    如果使用glintercept检查代码,请确保启用: 螺纹检查=真; 在gliconfig.ini文件中。

    查看日志,似乎有相当多的OpenGL调用是主上下文之外的主上下文。

        7
  •  0
  •   Alexander Müller    15 年前

    可以在另一个线程中加载纹理而不获得白色纹理。问题是,一旦初始化了OpenGL窗口,OpenGL上下文就会“绑定”到这个线程。在加载纹理时,必须停用主线程中的上下文,并且在开始加载纹理之前,必须激活该线程中的上下文。

    您可以使用以下类:

    语境:H:

    #ifndef CONTEXT_H
    #define CONTEXT_H
    
    #include <GL/glut.h>
    
    class Context
    {
    public:
        static Context* getInstance();
    
        void bind();
        void unbind();
    private:
        Context();
        Context(const Context&);
        ~Context();
    
        static Context *instance;
    
        HGLRC hglrc;
        HDC hdc;
    
        class Guard
        {
        public:
            ~Guard()
            {
                if (Context::instance != 0) {
                    delete Context::instance;
                }
            }
        };
        friend class Guard;
    };
    
    #endif
    

    Context.cpp:

    #include "Context.h"
    
    Context* Context::getInstance()
    {
        static Guard guard;
        if(Context::instance == 0) {
            Context::instance = new Context();
        }
        return Context::instance;
    }
    
    void Context::bind()
    {
        wglMakeCurrent(this->hdc, this->hglrc);
    }
    
    void Context::unbind()
    {
        wglMakeCurrent(NULL, NULL);
    }
    
    Context::Context()
    {
        this->hglrc = wglGetCurrentContext();
        this->hdc = wglGetCurrentDC();
    }
    
    Context::~Context()
    {
    }
    
    Context *Context::instance = 0;
    

    这就是你要做的:

    int state = 0;
    
    void main()
    {
        // Create the window.
        glutCreateWindow(TITLE);
    
        // Set your loop function.
        glutDisplayFunc(&loop);
    
        // Initialize the singleton for the 1st time.
        Context::getInstance()->bind();
    
        glutMainLoop();
    }
    
    void loop()
    {
        if (state == 0) {
            Context::getInstance()->unbind();
            startThread(&run);
        } else if (state == 1) {
            // Rebind the context to the main thread (just once).
            Context::getInstance()->bind();
            state = 2;
        } else if (state == 2) {
            // Draw your textures, lines, etc.
        } else {
            // Draw something (but no textures).
        }
    }
    
    void run()
    {
        Context::getInstance()->bind();
    
        // Load textures...
    
        Context::getInstance()->unbind();
        state = 1;
    }