0

in initializeGL in QGLWidget:
I'm loading a .exr image (128mb) 4000x2000 with imageio.imread

from imageio import imread
img_array = imread("c:/sample.exr")
self.textureID = glGenTextures(1)

in paintGL in QGLWidget:
I draw my single quad with glBegin(GL_QUADS) and glEnd() then feed the texture into glTexImage2D and bind it to the quad I created earlier.

glBindTexture(GL_TEXTURE_2D, self.textureID)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1920, 1080, 0, GL_RGBA, GL_FLOAT, img_array)

I don't have any problem with loading the image or code itself, everything works perfectly, but I'm facing performance issue and navigating the scene starts to lag, I assume is because of the huge size of image.

Is there any way that I can reduce the size? or increase the performance of it?

Note: Even the image is numpy.float32 I only display it as GL_RGBA which means there is 0.4545 gamma multiplication, I don't know if that affects the performance but thought to point it out.

Thanks in advance.

Update:
here is the code:

import os
from PySide.QtGui import QColor
from PySide.QtOpenGL import QGLWidget

from imageio import imread

from OpenGL.GL import *
from OpenGL.GLU import *

from engine.nodes import (ImageNode, NodeType, CubeNode, Vector3)

class QImageProcessor(QGLWidget):
    def __init__(self, parent=None):
        super(QImageProcessor, self).__init__(parent)
        self.model = list()

        self.zoomVal = 1.2
        self.local_translate = (0.0, 0.0, 0.0)
        self.local_scale = (1.0, 1.0, 1.0)
        self.xRot = 0
        self.yRot = 0
        self.zRot = 0

    def initializeGL(self):
        self.qglClearColor(QColor.fromCmykF(0.0, 0.1, 0.0, 0.882))
        glViewport( 0, 0, self.width(), self.height())
        glEnable(GL_TEXTURE_2D)
        glEnable(GL_CULL_FACE)
        glEnable(GL_MULTISAMPLE)
        glEnable(GL_LINE_SMOOTH, GL_LINE_WIDTH, GL_ALIASED_LINE_WIDTH_RANGE)
        glShadeModel(GL_FLAT)
        glEnable(GL_DEPTH_TEST)
        glHint(GL_LINE_SMOOTH_HINT,  GL_NICEST)
        glDepthRange (0.1, 1.0)

        # adding images
        image1 = "c:/sample.exr"
        new_image1 = ImageNode(image1)
        new_image1.TextureID = glGenTextures(1)
        new_image1.Data = imread(image1, format='.exr')
        self.model.append(new_image1)
        image2 = "c:/sample2.jpg"
        new_image2 = ImageNode(image2)
        new_image2.TextureID = glGenTextures(1)
        new_image2.Data = imread(image2, format='.jpg')
        self.model.append(new_image2)

    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        gluOrtho2D(-self.zoomVal, +self.zoomVal, -self.zoomVal, +self.zoomVal)
        glLoadIdentity()
        glTranslated(*self.local_translate)
        glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0)
        glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0)
        glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0)
        glScalef(*self.local_scale)
        genList = glGenLists(1)
        glNewList(genList, GL_COMPILE)
        for node in self.model:
            vertices = node.Vertices # list of vertices
            edges = node.Edges # list of edges
            face = node.Face # list of faces
            texcoords = node.TextureCoordinates # list of texture coordinates

            glPushAttrib(GL_ALL_ATTRIB_BITS)
            glPolygonMode(GL_FRONT, GL_FILL)

            glPixelStorei(GL_UNPACK_ALIGNMENT,1)
            glBindTexture(GL_TEXTURE_2D, node.TextureID)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
            glTexImage2D(GL_TEXTURE_2D, 0, node.InternalFormat, node.Width, node.Height, 0, node.Format, node.Type, node.Data)
            # face and UV
            glBegin(GL_QUADS)
            self.qglColor(QColor(255,255,255))
            for vertex in face:
                glVertex3fv(vertices[vertex])
                glTexCoord2f(texcoords[vertex][0], texcoords[vertex][1])
            glEnd()
            glPopAttrib()
        glEndList()
        glCallList(genList)

I tried this:
I moved glTexCoord2f to initializeGL function, bind it once and then bind it to 0:

image2 = "c:/sample2.jpg"
new_image2 = ImageNode(image2)
new_image2.TextureID = glGenTextures(1)
new_image2.Data = imread(image2, format='.jpg')
glTexImage2D(GL_TEXTURE_2D, 0, new_image2.InternalFormat, new_image2.Width, new_image2.Height, 0, new_image2.Format, new_image2.Type, new_image2.Data)
glBindTexture(GL_TEXTURE_2D, new_image2.TextureID)
glBindTexture(GL_TEXTURE_2D, 0)
self.model.append(new_image2)

and then in paintGL bind it again,

def paintGL(self):
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    gluOrtho2D(-self.zoomVal, +self.zoomVal, -self.zoomVal, +self.zoomVal)
    glLoadIdentity()
    glTranslated(*self.local_translate)
    glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0)
    glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0)
    glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0)
    glScalef(*self.local_scale)
    genList = glGenLists(1)
    glNewList(genList, GL_COMPILE)
    for node in self.model:
        vertices = node.Vertices # list of vertices
        edges = node.Edges # list of edges
        face = node.Face # list of faces
        texcoords = node.TextureCoordinates # list of texture coordinates

        glPushAttrib(GL_ALL_ATTRIB_BITS)
        glPolygonMode(GL_FRONT, GL_FILL)

        glPixelStorei(GL_UNPACK_ALIGNMENT,1)
        glBindTexture(GL_TEXTURE_2D, node.TextureID)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        # face and UV
        glBegin(GL_QUADS)
        self.qglColor(QColor(255,255,255))
        for vertex in face:
            glVertex3fv(vertices[vertex])
            glTexCoord2f(texcoords[vertex][0], texcoords[vertex][1])
        glEnd()
        glPopAttrib()
    glEndList()
    glCallList(genList)

but it didn't show the texture, not sure if I'm missing something.

Bear
  • 550
  • 9
  • 25
  • Just making sure, you are not calling `glTexImage2D` every frame, correct? The texture data only needs to be uploaded to the GPU once. Also, it looks like this is a NPOT (non-power-of-two) sized texture. Not sure is that is too important nowadays, but that could have a performance hit, as suggested in [this answer](https://gamedev.stackexchange.com/a/7949/78005). – CodeSurgeon Apr 19 '18 at 00:06
  • @CodeSurgeon but I thought I have to use `glTexImage2D` in `paintGL` function and the image is only loaded once in `initializeGL` function, also regarding the NPOT, I'm using this method for viewing images, and users could load any resolution. – Bear Apr 19 '18 at 02:59
  • There should be no need to put `glTexImage2D` within `paintGL` as that would be called on every redraw. Have you tried moving the `glTexImage2D` call to your `initializeGL` function? You can ignore the NPOT thing for now; it is far less likely to be a bottleneck than reloading the texture every redraw, and it would not support user textures well anyways like you mention. – CodeSurgeon Apr 19 '18 at 03:11
  • @CodeSurgeon I tried moving it to `initializeGL` and it's just plain white, looking at `glTexImage2D` documentation it doesn't connect to the textureID, it just simply loads the texture and when I `glBindTexture` it it's just bound whatever is currently loaded right? – Bear Apr 19 '18 at 04:05
  • Could you show exactly what is in your `initializeGL` and `paintGL` functions? In your `initializeGL` function, you need to bind your texture before you set its pixel data with `glTexImage2D` and then can unbind it afterwards. You then just need to bind it again in your `paintGL` function as needed when you want to draw with that texture. – CodeSurgeon Apr 19 '18 at 04:10
  • @CodeSurgeon I updated my question, please have a look. – Bear Apr 19 '18 at 07:52
  • 1
    In your "I tried this" code, you put the `glTexImage2D` call before you bound the texture. Put it on the next line, after you bind the texture. Otherwise, how is OpenGL supposed to know which texture id is associated with the pixel data you are uploading? Will work on getting PySide installed on my laptop to test further. – CodeSurgeon Apr 20 '18 at 02:39
  • 1
    @CodeSurgeon oh, I tried `glBindTexture` after `glGenTextures` and then loading the texture with `glTexImage2D` and then `glBindTexture` to `0` id, and it works perfectly!! no lag what so ever! Thanks! – Bear Apr 20 '18 at 02:48

0 Answers0