【问题标题】:OpenGL - draw pixels to screen?OpenGL - 将像素绘制到屏幕上?
【发布时间】:2023-04-11 07:32:01
【问题描述】:

我想使用 OpenGL 尽可能快地在屏幕上绘制像素数据(RGB/灰度值)的二维数组。像素数据变化频繁。

我曾希望我能找到一个简单的函数,让我可以将指针推入表示像素数据的数组,因为这可能是最快的方法。不幸的是,我没有找到这样的功能。

完成这项任务的最佳方法是什么?

【问题讨论】:

标签: opengl


【解决方案1】:

也许glDrawPixels 是您正在寻找的功能?虽然如果数据是静态的,最好用它创建一个纹理,然后在每一帧中绘制它。

【讨论】:

    【解决方案2】:

    我最近遇到了类似的问题,因为我正在尝试将视频渲染到屏幕上(即反复将像素数据上传到 VRAM),我的方法是:

    • 使用 glTexImage2D 和 glTexSubImage2D 将数据上传到纹理(即在调用之前绑定纹理(和纹理单元,如果适用))

    • 在我的情况下,由于视频帧速率(通常约为 24 fps)低于我的应用程序的帧速率(目标为 60 fps),为了避免再次上传相同的数据,我使用帧缓冲区对象 (查看 glGenFramebuffers/glBindFramebuffer/glDeleteFramebuffers) 并将我的纹理与帧缓冲区 (glFramebufferTexture2D) 链接。然后我上传该纹理一次,并多次绘制同一帧(只是使用 glBindTexture 进行普通纹理访问)

    • 我不知道您使用的是哪个平台,但由于我针对的是 Mac,我使用了一些 Apple 扩展来确保通过 DMA 将数据传输到 VRAM(即让 glTexSubImage2D 立即返回以让 CPU 执行其他工作)- 如果您也在使用 Mac,请随时向我询问更多信息

    • 1234563纹理数据,我正在流式传输高清 1920x1080 视频,所以我需要确保将其保持在低电平)
    • 还要注意您的硬件使用的格式以避免不必要的数据转换(即通常使用 BGRA 数据似乎比仅使用 RGB 数据更好)

    • 最后,在我的代码中,我用着色器替换了所有固定的管道功能(特别是将数据从灰度或 YUV 格式转换为 RGB),但这又取决于数据的大小,并且CPU 或 GPU 的工作负载

    希望对您有所帮助,如果您需要更多信息,请随时给我发消息

    【讨论】:

      【解决方案3】:

      我认为最快的方法是使用正交投影绘制一个屏幕大小的四边形,并使用像素着色器和Texture Buffer Object 直接绘制到像素着色器中的纹理。由于与 TBO 之间的传输延迟,您可能想看看双缓冲是否有帮助。

      如果速度不是问题(您只需要相当交互式的帧速率)glDrawPixels 很容易使用并且可以很好地用于多种用途。

      【讨论】:

        【解决方案4】:

        我在 OpenGL 中获取动态变化的图像数据到屏幕的解决方案,

        #define WIN32_LEAN_AND_MEAN
        
        #include "wx/wx.h"
        #include "wx/sizer.h"
        #include "wx/glcanvas.h"
        #include "BasicGLPane.h"
        
        // include OpenGL
        #ifdef __WXMAC__
        #include "OpenGL/glu.h"
        #include "OpenGL/gl.h"
        #else
        #include <GL/glu.h>
        #include <GL/gl.h>
        #endif
        #include "ORIScanMainFrame.h"
        
        BEGIN_EVENT_TABLE(BasicGLPane, wxGLCanvas)
        EVT_MOTION(BasicGLPane::mouseMoved)
        EVT_LEFT_DOWN(BasicGLPane::mouseDown)
        EVT_LEFT_UP(BasicGLPane::mouseReleased)
        EVT_RIGHT_DOWN(BasicGLPane::rightClick)
        EVT_LEAVE_WINDOW(BasicGLPane::mouseLeftWindow)
        EVT_SIZE(BasicGLPane::resized)
        EVT_KEY_DOWN(BasicGLPane::keyPressed)
        EVT_KEY_UP(BasicGLPane::keyReleased)
        EVT_MOUSEWHEEL(BasicGLPane::mouseWheelMoved)
        EVT_PAINT(BasicGLPane::render)
        END_EVENT_TABLE()
        
        // Test data for image generation.  floats range 0.0 to 1.0, in RGBRGBRGB... order.
        // Array is 1024 * 3 long. Note that 32 * 32 is 1024 and is the largest image we can randomly generate.
        float* randomFloatRGB;
        float* randomFloatRGBGrey;
        
        BasicGLPane::BasicGLPane(wxFrame* parent, int* args) :
            wxGLCanvas(parent, wxID_ANY, args, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
        {
            m_context = new wxGLContext(this);
        
            randomFloatRGB = new float[1024 * 3];
            randomFloatRGBGrey = new float[1024 * 3];
            // In GL images 0,0 is in the lower left corner so the draw routine does a vertical flip to get 'regular' images right side up.
            for (int i = 0; i < 1024; i++) {
                // Red
                randomFloatRGB[i * 3] = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
                // Green
                randomFloatRGB[i * 3 + 1] = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
                // Blue
                randomFloatRGB[i * 3 + 2] = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
                // Telltale 2 white pixels in 0,0 corner.
                if (i < 2) {
                    randomFloatRGB[i * 3] = randomFloatRGB[i * 3 + 1] = randomFloatRGB[i * 3 + 2] = 1.0f;
                }
        
                randomFloatRGBGrey[i * 3] = randomFloatRGB[i * 3];
                randomFloatRGBGrey[i * 3 + 1] = randomFloatRGB[i * 3];
                randomFloatRGBGrey[i * 3 + 2] = randomFloatRGB[i * 3];
            }
        
            // To avoid flashing on MSW
            SetBackgroundStyle(wxBG_STYLE_CUSTOM);
        }
        
        BasicGLPane::~BasicGLPane()
        {
            delete m_context;
        }
        
        void BasicGLPane::resized(wxSizeEvent& evt)
        {
            //  wxGLCanvas::OnSize(evt);
            Refresh();
        }
        
        int BasicGLPane::getWidth()
        {
            return GetSize().x;
        }
        
        int BasicGLPane::getHeight()
        {
            return GetSize().y;
        }
        
        void BasicGLPane::render(wxPaintEvent& evt)
        {
            assert(GetParent());
            assert(GetParent()->GetParent());
            ORIScanMainFrame* mf = dynamic_cast<ORIScanMainFrame*>(GetParent()->GetParent());
            assert(mf);
        
            switch (mf->currentMainView) {
            case ORIViewSelection::ViewCamera:
                renderCamera(evt);
                break;
            case ORIViewSelection::ViewDepth:
                renderDepth(evt);
                break;
            case ORIViewSelection::ViewPointCloud:
                renderPointCloud(evt);
                break;
            case ORIViewSelection::View3DModel:
                render3DModel(evt);
                break;
            default:
                renderNone(evt);
            }
        }
        
        void BasicGLPane::renderNone(wxPaintEvent& evt) {
            if (!IsShown())
                return;
            SetCurrent(*(m_context));
            glPushAttrib(GL_ALL_ATTRIB_BITS);
            glClearColor(0.08f, 0.11f, 0.15f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glFlush();
            SwapBuffers();
            glPopAttrib();
        }
        
        GLuint makeOpenGlTextureFromDataLuninanceFloats(int width, int height, float* f) {
            GLuint textureID;
        
            glEnable(GL_TEXTURE_2D);
            glGenTextures(1, &textureID);
        
            // "Bind" the newly created texture : all future texture functions will modify this texture
            glBindTexture(GL_TEXTURE_2D, textureID);
        
            // Give the image to OpenGL
            glTexImage2D(GL_TEXTURE_2D, 0, GL_FLOAT, width, height, 0, GL_FLOAT, GL_LUMINANCE, f);
        
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        
            return textureID;
        }
        
        GLuint makeOpenGlTextureFromRGBInts(int width, int height, unsigned int* f) {
            GLuint textureID;
        
        
            glEnable(GL_TEXTURE_2D);
            glGenTextures(1, &textureID);
        
            // "Bind" the newly created texture : all future texture functions will modify this texture
            glBindTexture(GL_TEXTURE_2D, textureID);
        
            // Give the image to OpenGL
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_INT, f);
        
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        
            return textureID;
        }
        
        /// <summary>
        /// Range of each float is 0.0f to 1.0f
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="floatRGB"></param>
        /// <returns></returns>
        GLuint makeOpenGlTextureFromRGBFloats(int width, int height, float* floatRGB) {
            GLuint textureID;
        
            // 4.6.0 NVIDIA 457.30  (R Keene machine, 11/25/2020)
            // auto sss = glGetString(GL_VERSION);
        
            glGenTextures(1, &textureID);
        
            // "Bind" the newly created texture : all future texture functions will modify this texture
            glBindTexture(GL_TEXTURE_2D, textureID);
        
            // Give the image to OpenGL
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, floatRGB);
        
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        
            return textureID;
        }
        
        void BasicGLPane::DrawTextureToScreenFloat(int w, int h, float* floatDataPtr, GLuint (*textureFactory)(int width, int height, float* floatRGB)) {
            if (w <= 0 || h <= 0 || floatDataPtr == NULL || w > 5000 || h > 5000) {
                assert(false);
                return;
            }
        
            SetCurrent(*(m_context));
        
            glPushAttrib(GL_ALL_ATTRIB_BITS);
            glPushMatrix();
            glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
        
            glClearColor(0.15f, 0.11f, 0.02f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
            glEnable(GL_TEXTURE_2D);
        
            glLoadIdentity();
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
        
            // 4.6.0 NVIDIA 457.30  (R Keene machine, 11/25/2020)
            // auto sss = glGetString(GL_VERSION);
        
            float onePixelW = (float)getWidth() / (float)w;
            float onePixelH = (float)getHeight() / (float)h;
            float orthoW = w;
            float orthoH = h;
            if (onePixelH > onePixelW) {
                orthoH = h * onePixelH / onePixelW;
            }
            else {
                orthoW = w * onePixelW / onePixelH;
            }
            // We want the image at the top of the window, not the bottom if the window is too tall.
            int topOfScreen = (float)getHeight() / onePixelH;
        
            // If the winjdow resizes after creation you need to change the viewport.
            glViewport(0, 0, getWidth(), getHeight());
            gluOrtho2D(0.0, orthoW, (double)topOfScreen - (double)orthoH, topOfScreen);
        
            GLuint myTextureName = textureFactory(w, h, floatDataPtr);
        
            glBegin(GL_QUADS);
            {
                // This order of UV coords and verticies will do the vertical flip of the image to get the 'regular' image 0,0
                // in the top left corner.
                glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 0.0f, 0.0f);
                glTexCoord2f(1.0f, 1.0f); glVertex3f(0.0f + w, 0.0f, 0.0f);
                glTexCoord2f(1.0f, 0.0f); glVertex3f(0.0f + w, 0.0f + h, 0.0f);
                glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 0.0f + h, 0.0f);
            }
            glEnd();
        
            glDeleteTextures(1, &myTextureName);
        
            glFlush();
            SwapBuffers();
        
        
            glPopClientAttrib();
            glPopMatrix();
            glPopAttrib();
        }
        
        void BasicGLPane::DrawTextureToScreenMat(wxPaintEvent& evt, cv::Mat m, float brightness) {
            m.type();
            if (m.empty()) {
                renderNone(evt);
                return;
            }
        
            if (m.type() == CV_32FC1) { // Grey scale.
                DrawTextureToScreenFloat(m.cols, m.rows, (float*)m.data, makeOpenGlTextureFromDataLuninanceFloats);
            }
            if (m.type() == CV_32FC3) { // Color.
                DrawTextureToScreenFloat(m.cols, m.rows, (float*)m.data, makeOpenGlTextureFromRGBFloats);
            }
            else {
                renderNone(evt);
            }
        }
        
        void BasicGLPane::renderCamera(wxPaintEvent& evt) {
            if (!IsShown())
                return;
            DrawTextureToScreenMat(evt, ORITopControl::Instance->im_white);
        }
        
        void BasicGLPane::renderDepth(wxPaintEvent& evt) {
            if (!IsShown())
                return;
            DrawTextureToScreenMat(evt, ORITopControl::Instance->depth_map);
        }
        
        void BasicGLPane::render3DModel(wxPaintEvent& evt) {
            if (!IsShown())
                return;
            SetCurrent(*(m_context));
            glPushAttrib(GL_ALL_ATTRIB_BITS);
            glPushMatrix();
        
            glClearColor(0.08f, 0.11f, 0.15f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        
        
            glFlush();
            SwapBuffers();
        
            glPopMatrix();
            glPopAttrib();
        }
        
        void BasicGLPane::renderPointCloud(wxPaintEvent& evt) {
            if (!IsShown())
                return;
            boost::unique_lock<boost::mutex> lk(ORITopControl::Instance->pointCloudCacheMutex);
        
            SetCurrent(*(m_context));
            glPushAttrib(GL_ALL_ATTRIB_BITS);
            glPushMatrix();
        
            glLoadIdentity();
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
        
            glViewport(0, 0, getWidth(), getHeight());
        
            glClearColor(0.08f, 0.11f, 0.15f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
            if (ORITopControl::Instance->pointCloudCache.size() > 0) {
                glMatrixMode(GL_PROJECTION);
                gluPerspective( /* field of view in degree */ 40.0,
                    /* aspect ratio */ 1.0,
                    /* Z near */ 1.0, /* Z far */ 500.0);
                glMatrixMode(GL_MODELVIEW);
                gluLookAt(100, 70, 200, // Eye
                    25, 25, 25, // Look at pt
                    0, 0, 1); // Up Vector
        
                glPointSize(2.0);
                glBegin(GL_POINTS);
                // Use explicit for loop because pointCloudFragments can grow asynchronously.
                for (int i = 0; i < ORITopControl::Instance->pointCloudCache.size(); i++) {
                    auto frag = ORITopControl::Instance->pointCloudCache[i];
                    auto current_point_cloud_ptr = frag->cloud;
                    glPushMatrix();
                    // glMultMatrixf(frag->xform.data());
                    for (size_t n = 0; n < current_point_cloud_ptr->size(); n++) {
                        glColor3ub(255, 255, 255);
                        glVertex3d(current_point_cloud_ptr->points[n].x, current_point_cloud_ptr->points[n].y, current_point_cloud_ptr->points[n].z);
                    }
                    glPopMatrix();
                }
                glEnd();
            }
        
            glFlush();
            SwapBuffers();
        
            glPopMatrix();
            glPopAttrib();
        }
        

        【讨论】:

          猜你喜欢
          • 2011-10-02
          • 1970-01-01
          • 2011-06-27
          • 1970-01-01
          • 1970-01-01
          • 2020-06-18
          • 1970-01-01
          • 1970-01-01
          • 2023-02-16
          相关资源
          最近更新 更多