optimize the 128mb EXR image - python-2.7

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.

Related

PNG loaded with SDL_image with glTexImage2D segfaults

I don't think this is a problem with the image I'm loading. The image resolution is 256x256 so it's not the power of 2 issue. I've looked at other segfaults people got with glTexImage2D and the segfault still can't seem to go away. Sorry that the code isn't in C/C++ (i don't think this is the problem either) but it should still be easy to understand.
let surface = sdlimage.load("image.png") # equivalent to IMG_Load call in C
if surface.isNil:
echo "Image couldn't be loaded: ", sdl2.getError()
quit 1
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_BLEND)
var tex: cuint
glGenTextures(1, addr tex)
glBindTexture(GL_TEXTURE_2D, tex)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glPixelStorei(GL_UNPACK_ROW_LENGTH, surface.pitch)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA.GLint, surface.w.GLsizei, surface.h.GLsizei, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface.pixels) # segfault
UPDATE:
I managed to get it to not segfault thanks to user1118321's answer (I checked the pixel format and saw that SDL used a "indexed" format, which I saw another user said was the problem when they fixed this issue for theirselves. Seems like creating a new surface is the right solution), but now it shows nothing on the screen. It's black when I set glClearColor to black, and it's white when i set glClearColor to white.
Updated image loading code:
let surface = sdlimage.load("image.png")
if surface.isNil:
echo "Image couldn't be loaded: ", sdl2.getError()
quit 1
var w = surface.w # may need to make this the next power of two
var h = surface.h # and this
var bpp: cint
var Rmask, Gmask, Bmask, Amask: uint32
if not pixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, bpp,
Rmask, Gmask, Bmask, Amask):
quit "pixel format enum to masks " & $sdl2.getError()
let newSurface = createRGBSurface(0, w, h, bpp,
Rmask, Gmask, Bmask, Amask)
discard surface.setSurfaceAlphaMod(0xFF)
discard surface.setSurfaceBlendMode(BlendMode_None)
blitSurface(surface, nil, newSurface, nil)
var tex: cuint
glGenTextures(1, addr tex)
glBindTexture(GL_TEXTURE_2D, tex)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexImage2D(GL_TEXTURE_2D, 0, 4, w.GLsizei, h.GLsizei, 0, GL_RGBA, GL_UNSIGNED_BYTE, newSurface.pixels)
Image rendering code:
glUseProgram(shaderProgram)
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0.0, 0.0, -7.0)
glColor3f(1.0, 1.0, 1.0)
glBegin(GL_QUADS)
glTexCoord2i(0, 0)
glVertex3f(-0.5, -1.9, 0.0)
glTexCoord2i(1, 0)
glVertex3f(0.5, -1.9, 0.0)
glTexCoord2i(0, 1)
glVertex3f(-0.5, -1.4, 0.0)
glTexCoord2i(1, 1)
glVertex3f(0.5, -1.4, 0.0)
glEnd()
If shaders have something to do with it, here's my vertex shader:
#version 330 core
in vec4 data;
out vec3 ourColor;
void main() {
gl_Position = vec4(data.x, data.y, data.z, 1.0);
ourColor = vec3(data.w, data.w, data.w);
}
And the fragment shader:
#version 330 core
precision highp float;
in vec3 ourColor;
out vec4 color;
void main() {
color = vec4(ourColor, 1.0);
}
You should check glGetError() to see if there are any OpenGL errors occurring. You should also check the surface.pixelFormat to see whether you actually have 4 bytes per pixel in your image. If it's just RGB data and not RGBA, then glTexImage2D() will read past the end of the image data and likely crash with a segmentation fault.

OpenGL 3D model texture mapping

I am trying to render an obj model with texture. Here is what I do:
Get the 3d model model and the corresponding view matrix view_mat and projection matrix proj_mat from the image.
Project the 3d model to the image using proj_mat * view_mat * model, in this way I can get uv coordinates in the image for every vertex in 3d model.
Use the uv coordinates to render the 3d model.
Here is what I get (on the left is the render result), I think I should get the main steps done right, as the overall texture looks in the right position. But it looks like that triangles are not in the rotation mode.
Here is the part of the code I consider that is related to the texture mapping.
int main() {
Tracker tracker;
tracker.set_image("clooney.jpg");
Viewer viewer(tracker.get_width(), tracker.get_height());
while (tracker.track()) {
Model* model = tracker.get_model();
glm::mat4x4 proj_mat = tracker.get_proj_mat();
proj_mat = glm::transpose(proj_mat);
glm::mat4x4 view_mat = tracker.get_view_mat();
view_mat = glm::transpose(view_mat);
// render 3d shape
viewer.set_model(model);
viewer.draw(view_mat, proj_mat);
waitKey(0);
}
return 0;
}
// initialization of the render part
Viewer::Viewer(int width, int height) {
glfwInit();
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
m_window = glfwCreateWindow(width, height, "demo", NULL, NULL);
if (!m_window)
{
fprintf(stderr, "Failed to open GLFW window\n");
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(m_window);
glfwGetWindowSize(m_window, &m_width, &m_height);
glfwSetFramebufferSizeCallback(m_window, reshape_callback);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
glfwSwapInterval(1);
config();
}
void Viewer::config() {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDisable(GL_CULL_FACE);
glShadeModel(GL_FLAT);
}
// entry of the drawing function
void Viewer::draw(glm::mat4x4 view_mat, glm::mat4x4 proj_mat) {
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
proj_mat = glm::transpose(proj_mat);
glLoadMatrixf(&proj_mat[0][0]);
glMatrixMode(GL_MODELVIEW);
view_mat = glm::transpose(view_mat);
glLoadMatrixf(&view_mat[0][0]);
// m_pmodel is an instance of Model Class
// set texture
m_pmodel->set_texture(m_image);
// set model uvs
m_pmodel->set_uvs(view_mat, proj_mat);
m_pmodel->draw();
glfwSwapBuffers(m_window);
glfwPollEvents();
}
// set the texture for the model from the image
void Model::set_texture(cv::Mat img) {
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexImage2D(GL_TEXTURE_2D, 0, 3, img.cols, img.rows, 0, GL_BGR, GL_UNSIGNED_BYTE, img.data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_2D);
}
// specify correspondence between image and the model
void Model::set_uvs(glm::mat4x4 view_mat, glm::mat4x4 proj_mat) {
for (int i = 0; i < m_uvs.size(); i++) {
glm::vec4 clip_coord = proj_mat * view_mat * glm::vec4(m_vertices[i], 1);
float w = clip_coord.w;
glm::vec3 normal_coord = glm::vec3(clip_coord.x, clip_coord.y, clip_coord.z) / w;
m_uvs[i] = glm::vec2(normal_coord.x * 0.5f + 0.5f, normal_coord.y * 0.5f + 0.5f);
}
}
// render the 3d model
void Model::draw() const {
glBindTexture(GL_TEXTURE_2D, m_texture);
for (unsigned long i = 0; i < m_faces.size(); ++i) {
glm::ivec3 face = this->m_faces[i];
glBegin(GL_TRIANGLES);
for (int j = 0; j < 3; j++) {
glm::vec3 v = this->m_vertices[face[j]];
glm::vec2 uv = this->m_uvs[face[j]];
glVertex3f(v.x, v.y, v.z);
glTexCoord2f(1 - uv.x,1 - uv.y);
}
glEnd();
}
}
You have to set the current texture coordinate (glTexCoord) before you specify a vertex (glVertex), because the current color, normal, texture coordinates, and fog coordinate are associated with the vertex when glVertex is called.
This means you have to swap glVertex3f and glTexCoord2f:
glTexCoord2f(1 - uv.x,1 - uv.y);
glVertex3f(v.x, v.y, v.z);
Otherwise you would set the texture coordinate which is associated to the next vertex position.
See OpenGL 2.0 API Specification, 2.6 Begin/End Paradigm, page 13:
Each vertex is specified with two, three, or four coordinates. In addition, a current normal, multiple current texture coordinate sets, multiple current generic vertex attributes, current color, current secondary color, and current fog coordinate may be used in processing each vertex.

Point drawed over texture doesn't get the desired colour

Important: I have to work with the fixed pipeline (I have no voice in this matter).
I have to modify some existing OpenGL code (a panoramic picture viewer, where the panorama is split into the six faces of a cube) so we're able to draw lines/points on top of the loaded textures, where the points are the mouse coordinates unprojected to object coordinates.
I wrote a test program with a coloured cube just to try the line painting on top of it:
I got this with the code pushing the GL_DEPTH_BUFFER_BIT attribute to the stack, disabling it before painting the points and poping the stack attribute after I have done with the painting.
I tried to use that same approach in the existing application, but I got these results (here, I'm trying only to paint a point):
I specified red as the color for the point but, as you can see, it doesn't have the desired one. I thought it might be due to blending and that it might be mixing its color with the underlying texture, so I pushed the GL_BLEND attribute to the stack as well and disabled it before painting, but the point isn't getting the desired color anyway.
What is happening here? Is there a way to "force" the pipeline to paint the point red?
initCube() : this is call before updating the GL scene.
void panoViewer::initCube() {
makeCurrent();
if(texture){
glDisable( texture );
textName = 0;
texture = 0;
}
glDisable( GL_TEXTURE_GEN_S );
glDisable( GL_TEXTURE_GEN_T );
glDisable( GL_TEXTURE_GEN_R );
glFrontFace( GL_CCW );
glEnableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
texture = GL_TEXTURE_CUBE_MAP;
textName = texnms[1];
glEnableClientState(GL_NORMAL_ARRAY);
glTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP );
glTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP );
glTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP );
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_GEN_T );
glEnable( GL_TEXTURE_GEN_R );
// Add the textures to the cube faces.
// ...
}
initializeGL() :
void panoViewer::initializeGL() {
qglClearColor(Qt::black);
glShadeModel(GL_SMOOTH);
glEnable(GL_CULL_FACE);
glEnable( GL_DEPTH_TEST );
// create texture objects
glGenTextures( 1, textName );
glBindTexture( GL_TEXTURE_CUBE_MAP, textName );
// find the largest feasible textures
maxTex2Dsqr = maxTexSize( GL_PROXY_TEXTURE_2D, max2d, max2d );
maxTex2Drec = maxTexSize( GL_PROXY_TEXTURE_2D, max2d, max2d / 2 );
maxTexCube = maxTexSize( GL_PROXY_TEXTURE_CUBE_MAP, maxcube, maxcube );
// constant texture mapping parameters...
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
// for cube maps...
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// enable alpha blending for overlay
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glDisable(GL_LIGHTING);
// Create display list: dispList
// ...
}
paintGL() :
void panoViewer::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if(texture) {
glBindTexture(texture, textName);
glEnable( texture );
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glRotated( 180, 0, 1, 0 ); // camera looks at the front of the van
glRotated( 180, 0, 0, 1 ); // van's roof points to the sky
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// double hFOV, vFOV; // angular size at sphere center (deg)
// double minFOV, maxFOV; // limits on vFOV
// double wFOV; // vert angle at eye (deg) sets magnification
double hhnear = Znear * tan( 0.5 * RAD(wFOV) ),
hwnear = hhnear * aspectRatio,
dxnear = 2 * hwnear * fcompx,
dynear = 2 * hhnear * fcompy;
glFrustum( -(hwnear + dxnear), hwnear - dxnear,
-(hhnear + dynear), hhnear - dynear,
Znear, Zfar
);
glRotated( 180, 0, 1, 0 );
glTranslated( eyex, eyey, eyez );
glRotated( tiltAngle, 1, 0, 0 );
glRotated( panAngle, 0, 1, 0 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glCallList(dispList);
glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
// Paint the point in red
// ...
glPopAttrib();
}
UPDATE: I forgot to mention that the code is based in Qt. It uses the QtOpenGL module extensively.
UPDATE #2: I've added some code.
In the fixed function pipeline, there are many states which could lead to the vertex color beeing completely ignored.
As Reto Koradi pointed out in the comments, when lighting is enabled, the colors have no effect (unless GL_COLOR_MATERIAL is enabled, in which case the color value is used to update the material parameters used for the lighting equation.)
As I pointed out in the comments, another case is texturing. Depending on the GL_TEX_ENV_MODE selected, the fragment's color (as determined by lighting, or directly interpolated from the vertex colors) is modulated by the texture color, or completely replaced. In that case, disabling texturing for every texture unit in use can solve the issue.

PyOpenGL Transformation Blur

I would like to know how to make openGL to not "blur" an upscaled texture, as it seems that the bluring is set to default for transformations. The texure is a POT png file. The code used to define a texture and put it on the screen is this:
class Texture():
# simple texture class
# designed for 32 bit png images (with alpha channel)
def __init__(self,fileName):
self.texID=0
self.LoadTexture(fileName)
def LoadTexture(self,fileName):
try:
textureSurface = pygame.image.load(fileName).convert_alpha()
textureData = pygame.image.tostring(textureSurface, "RGBA", True)
self.w, self.h = textureSurface.get_size()
self.texID=glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, self.texID)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, textureSurface.get_width(),
textureSurface.get_height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
textureData )
except Exception as E:
print(E)
print ("can't open the texture: %s"%(fileName))
def __del__(self):
glDeleteTextures(self.texID)
def get_width(self):
return self.w
def get_height(self):
return self.h
def blit(texture, x, y):
"""
Function that blits a given texture on the screen
"""
#We put the texture onto the screen
glBindTexture(GL_TEXTURE_2D, texture.texID)
#Now we must position the image
glBegin(GL_QUADS)
#We calculate each of the points relative to the center of the screen
top = -y/(HEIGHT//2) + 1.0
left = x/(WIDTH//2) - 1.0
right = left + texture.w/(WIDTH//2)
down = top - texture.h/(HEIGHT//2)
#We position each point of the image
glTexCoord2f(0.0, 1.0)
glVertex2f(left, top)
glTexCoord2f(1.0,1.0)
glVertex2f(right, top)
glTexCoord2f(1.0,0.0)
glVertex2f(right, down)
glTexCoord2f(0.0,0.0)
glVertex2f(left, down)
glEnd()
I configured openGL as follows:
def ConfigureOpenGL(w, h):
#glShadeModel(GL_SMOOTH)
#glClearColor(0.0, 0.0, 0.0, 1.0)
#glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
#glLoadIdentity()
#gluOrtho2D(-8.0, 8.0, -6.0, 6.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glShadeModel(GL_SMOOTH)
glClearColor(0.0, 0.0, 0.0, 0.0)
glClearDepth(1.0)
glDisable(GL_DEPTH_TEST)
glDisable(GL_LIGHTING)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glEnable(GL_BLEND)
Surface = pygame.display.set_mode((WIDTH, HEIGHT), OPENGL|DOUBLEBUF)#|FULLSCREEN)
ConfigureOpenGL(WIDTH, HEIGHT)
Before putting anything in the screen i also call this method:
def OpenGLRender(self):
"""
Used to prepare the screen to render
"""
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glDisable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glClearColor(1.0, 1.0, 1.0, 1.0)
I'm using PyOpenGL 3.0.2
Use GL_NEAREST in your glTexParameteri() calls:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST)

Convert Coin3D SoOffscreenRenderer to QImage and render with OpenGL

I'm trying to display a Coin3D/Open Inventor scene with QT in a QGLWidget, by using the SoOffscreenRenderer and I need help converting it to a QImage
What I tried so far, is render the scene into SoOffscreenRenderer and get the buffer like this:
unsigned char * getCoinCubeImgBuffer(){
// [...] create the scene, add lightning and camera
SoOffscreenRenderer offscreenRenderer(vpRegion);
offscreenRenderer.setComponents(
SoOffscreenRenderer::Components::RGB_TRANSPARENCY
);
SbBool ok = offscreenRenderer.render(root);
// to be sure that something is actually rendered
// save the buffer content to a file
SbBool ok = offscreenRenderer.render(root);
qDebug() << "SbBool ok?" << ok;
qDebug() << "wasFileWrittenRGB" <<
offscreenRenderer.writeToRGB("C:/test-gl.rgb");
qDebug() << "wasFileWrittenPS" <<
offscreenRenderer.writeToPostScript("C:/test-gl.ps");
unsigned char * imgbuffer = offscreenRenderer.getBuffer();
return imgbuffer;
}
and then create a QImage from the buffer data:
QImage convertImgBuffer(){
unsigned char *const imgBuffer = getCoinCubeImgBuffer();
QImage img(imgBuffer, windowWidth, windowHeight, QImage::Format_ARGB32);
// Important!
img = img.rgbSwapped();
QImage imgGL = convertToGLFormat(img);
return imgGL;
}
Would this be the correct way to do it?
As described in this question about drawing a QImage, I'm able to draw it if the source is a picture.
e: To make sure that my buffer actually contains a scene, I write the buffer content to two files. You can view .rgb and .ps files for example with IrfanView plus its plugins.
e2: Just figured out, that I have to use img.rgbSwapped(). Now it's showing the scene black&white and without lightning. I will investigate further.
e3: With the code like this, you need to adapt the OpenGL call in this way to render in color
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex.width(),
tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
First format is GL_RGB, second GL_RGBA. The cube is still completely black though.
e4: It was an error in my scene, you have to add a light before you add the rest and especially before you add the camera.
So now I can either use `QGLWidget`s functions like `bindTexture()` or use direct OpenGL calls, but I'm not sure how exactly. It would be great if someone could push me in the right direction.
Can't I just use OpenGL like this?
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &offscreenBufferTexture);
glBindTexture(GL_TEXTURE_2D, offscreenBufferTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imgGL.width(),
imgGL.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
imgGL.bits());
Or maybe `glDrawPixels()`?
glDrawPixels(imgGL.width(), imgGL.height(), GL_RGBA,
GL_UNSIGNED_BYTE, imgGL.bits());
I figured out how to draw a QImage with OpenGL, see this thread. So there seems to be a problem with the buffer or the conversion of it.
Here's the resulting code which renders the scene correctly.
First create a valid scene
void loadCoinScene(){
// Init Coin
SoDB::init();
// The root node
root = new SoSeparator;
root->ref();
// Add the light _before_ you add the camera
SoDirectionalLight * light = new SoDirectionalLight;
root->addChild(light);
vpRegion.setViewportPixels(0, 0, coinSceneWidth, coinSceneHeight);
SoPerspectiveCamera *perscam = new SoPerspectiveCamera();
root->addChild(perscam);
SbRotation cameraRotation = SbRotation::identity();
cameraRotation *= SbRotation(SbVec3f(0, 1, 0), 0.4f);
perscam->orientation = cameraRotation;
SoCube * cube = new SoCube;
root->addChild(cube);
// make sure that the cube is visible
perscam->viewAll(root, vpRegion);
}
Then render the scene into the Offscreen Buffer and convert it to a QImage:
QImage getCoinCubeImgBuffer(){
SoOffscreenRenderer offscreenRenderer(vpRegion);
offscreenRenderer.setComponents(
SoOffscreenRenderer::Components::RGB_TRANSPARENCY
);
offscreenRenderer.render(root);
QImage img(offscreenRenderer.getBuffer(), coinSceneWidth,
coinSceneHeight, QImage::Format_ARGB32);
// Important!
return img.rgbSwapped();
}
If you now want to render the QImage with OpenGL, use my solution from my Render QImage with OpenGL question and change the loadTexture2() method to this:
QImage loadTexture2(GLuint &textureID){
glEnable(GL_TEXTURE_2D); // Enable texturing
glGenTextures(1, &textureID); // Obtain an id for the texture
glBindTexture(GL_TEXTURE_2D, textureID); // Set as the current texture
QImage im = getCoinCubeImgBuffer();
// Convert to OpenGLs unnamed format
// The resulting GL format is GL_RGBA
QImage tex = QGLWidget::convertToGLFormat(im);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex.width(), tex.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glDisable(GL_TEXTURE_2D);
return tex;
}
I don't think there is a need to feed the texture through QImage. The following is a working example:
#include <QApplication>
#include <QGLWidget>
#include <Inventor/SoInput.h>
#include <Inventor/SoOffscreenRenderer.h>
#include <Inventor/nodes/SoSeparator.h>
static GLuint textureID(0);
class GLWidget : public QGLWidget
{
public:
explicit GLWidget() : QGLWidget() {}
~GLWidget() {}
protected:
void initializeGL() {
glShadeModel(GL_FLAT);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
static GLfloat lightAmbient[4] = { 1.0, 1.0, 1.0, 1.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
}
void paintGL() {
if (!textureID)
return;
glClearColor(0.4f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID);
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex3f(-1, -1, -1);
glTexCoord2f(1,0); glVertex3f( 1, -1, -1);
glTexCoord2f(1,1); glVertex3f( 1, 1, -1);
glTexCoord2f(0,1); glVertex3f(-1, 1, -1);
glEnd();
glDisable(GL_TEXTURE_2D);
}
void resizeGL(int width, int height) {
int side = qMin(width, height);
glViewport((width - side) / 2, (height - side) / 2, side, side);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, 0.0, 1000.0);
glMatrixMode(GL_MODELVIEW);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
GLWidget glWidget;
glWidget.show();
static const char * inlineSceneGraph[] = {
"#Inventor V2.1 ascii\n",
"\n",
"Separator {\n",
" PerspectiveCamera { position 0 0 5 }\n",
" DirectionalLight {}\n",
" Rotation { rotation 1 0 0 0.3 }\n",
" Cone { }\n",
" BaseColor { rgb 1 0 0 }\n",
" Scale { scaleFactor .7 .7 .7 }\n",
" Cube { }\n",
"\n",
" DrawStyle { style LINES }\n",
" ShapeHints { vertexOrdering COUNTERCLOCKWISE }\n",
" Coordinate3 {\n",
" point [\n",
" -2 -2 1.1, -2 -1 1.1, -2 1 1.1, -2 2 1.1,\n",
" -1 -2 1.1, -1 -1 1.1, -1 1 1.1, -1 2 1.1\n",
" 1 -2 1.1, 1 -1 1.1, 1 1 1.1, 1 2 1.1\n",
" 2 -2 1.1, 2 -1 1.1, 2 1 1.1, 2 2 1.1\n",
" ]\n",
" }\n",
"\n",
" Complexity { value 0.7 }\n",
" NurbsSurface {\n",
" numUControlPoints 4\n",
" numVControlPoints 4\n",
" uKnotVector [ 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 ]\n",
" vKnotVector [ 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 ]\n",
" }\n",
"}\n",
NULL
};
SoInput in;
in.setStringArray(inlineSceneGraph);
glWidget.resize(600, 600);
SoOffscreenRenderer renderer(SbViewportRegion(glWidget.width(),
glWidget.height()));
renderer.setComponents(SoOffscreenRenderer::RGB_TRANSPARENCY);
renderer.setBackgroundColor(SbColor(.0f, .0f, .8f));
SoSeparator *rootScene = SoDB::readAll(&in);
rootScene->ref();
renderer.render(rootScene);
rootScene->unref();
glEnable(GL_TEXTURE_2D); // Enable texturing
glGenTextures(1, &textureID); // Obtain an id for the texture
glBindTexture(GL_TEXTURE_2D, textureID); // Set as the current texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
renderer.getViewportRegion().getViewportSizePixels()[0],
renderer.getViewportRegion().getViewportSizePixels()[1],
0, GL_BGRA, GL_UNSIGNED_BYTE, renderer.getBuffer());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glDisable(GL_TEXTURE_2D);
return app.exec();
}
A simple example of rendering a local scene with SoWin, Coin3D ( download SoWin from here )
SoSeparator * CreateScene(SoSeparator* root)
{
root->ref();
root->setName("root_node");
SoPerspectiveCamera * camera = new SoPerspectiveCamera;
camera->setName("simple_camera");
SbRotation cameraRotation = SbRotation::identity();
cameraRotation *= SbRotation(SbVec3f(1, 0, 0), -0.4f);
cameraRotation *= SbRotation(SbVec3f(0, 1, 0), 0.4f);
camera->orientation = cameraRotation;
SoCone* cone1= new SoCone();
cone1->setName("Cone1");
SoBaseColor * color = new SoBaseColor;
color->setName("myColor");
root->addChild(camera);
root->addChild(cone1);
root->addChild(color);
return root;
}
Render scene created above
void RenderLocal()
{
HWND window = SoWin::init("IvExample");
if (window==NULL) exit(1);
SoWinExaminerViewer * viewer = new SoWinExaminerViewer(window);
SoSeparator * root = new SoSeparator;
auto* data = CreateScene(root);
data->getNumChildren();
viewer->setSceneGraph(root);
viewer->show();
SoWin::show(window);
SoWin::mainLoop();
delete viewer;
root->unref();
}
Render scene from iv file
int RenderFile()
{
HWND window = SoWin::init("Iv");
if (window==NULL) exit(1);
SoWinExaminerViewer * viewer = new SoWinExaminerViewer(window);
SoInput sceneInput;
if ( !sceneInput.openFile( "example.iv" ) )
return -1;
if ( !sceneInput.openFile(cPath) )
return -1;
SoSeparator *root =SoDB::readAll( &sceneInput );
root->ref();
viewer->setSceneGraph(root);
viewer->show();
SoWin::show(window);
SoWin::mainLoop();
delete viewer;
}