png image blurry when loaded onto texture - opengl

I have created a png image in photoshop with transparencies that I have loaded into and OpenGL program. I have binded it to a texture and in the program the picture looks blurry and I'm not sure why.
alt text http://img685.imageshack.us/img685/9130/upload2.png
alt text http://img695.imageshack.us/img695/2424/upload1e.png
Loading Code
// Texture loading object
nv::Image title;
// Return true on success
if(title.loadImageFromFile("test.png"))
{
glGenTextures(1, &titleTex);
glBindTexture(GL_TEXTURE_2D, titleTex);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, title.getInternalFormat(), title.getWidth(), title.getHeight(), 0, title.getFormat(), title.getType(), title.getLevel(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
}
else
MessageBox(NULL, "Failed to load texture", "End of the world", MB_OK | MB_ICONINFORMATION);
Display Code
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, titleTex);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTranslatef(-800, 0, 0.0);
glColor3f(1,1,1);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f(0,0);
glTexCoord2f(0.0, 1.0); glVertex2f(0,600);
glTexCoord2f(1.0, 1.0); glVertex2f(1600,600);
glTexCoord2f(1.0, 0.0); glVertex2f(1600,0);
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
EDIT: I don't think i'm stretching each pixel should be two in the co-ordinate system
int width=800, height=600;
int left = -400-(width-400);
int right = 400+(width-400);
int top = 400+(height-400);
int bottom = -400-(height-400);
gluOrtho2D(left,right,bottom,top);

OpenGL will (normally) require that the texture itself have a size that's a power of 2, so what's (probably) happening is that your texture is being scaled to a size where the dimensions are a power of 2, then it's being scaled back to the original size -- in the process of being scaled twice, you're losing some quality.
You apparently just want to display your bitmap without any scaling, without wrapping it to the surface of another object, or anything like that (i.e., any of the things textures are intended for). That being the case, I'd just display it as a bitmap, not a texture (e.g. see glRasterPos2i and glBitmap).

Why would you want to use mipmapping and anisotropic filtering for a static image on your start screen in the first place? It looks unlikely the image will be rotated (what anisotropic filtering is for) or has to be resized many times really fast (what mipmapping is for).
If the texture is being stretched: try using GL_NEAREST for your GL_MAG_FILTER, in this case it could give better results (GL_LINEAR is more accurate, but has a nature of blurring).
If the texture is minimized: same thing, try using GL_NEAREST_MIPMAP_NEAREST, or even better, try using no mipmaps and GL_NEAREST (or GL_LINEAR, whichever gives you the best result).

I'd suggest that you make the png have a resolution in a power of 2's. Ie 1024x512 and place the part you want to drawn in the upper left corner of it still in the resolution for the screen. Then rescale the texcoords to be 800.0/1024.0 and 600.0/512.0 to get the right part from the texture. I belive that what is going on is glTexImage2D can sometime handle width and height that are not a power of 2 but can then scale the input image thus filter it.
An example of handling this can be viewed here (a iPhone - OpenGLES - project that grabs a screen part non-power of 2 and draws that into a 512x512 texture and rescales the GL_TEXTURE matrix, line 123, instead of doing a manual rescale of the texcoords)
Here is another post mentioning this method.

Here is an hypothesis:
Your window is 800x600 (and maybe your framebuffer too), but your client area is not, because of the window decoration on the sides.
So your frame-buffer gets resized when being blitted to the client area of your window. Can you check your window creation code ?

Beware of exact size of the client area of your window. Double check it is what you expect it to be
Beware of pixel alignment rules. You might need to add 0.5 to your x/y coordinates to hit the pixel centers. Description for DirectX can be found here - OpenGL rules may be different, though.

Related

Qt OpenGL textures transparency issues

I'm working on a viewer in Qt to show images with lines or text on top.
I have organized images, lines and text on several layers, each layer is a GL_QUADS.
If I stack images in z and then draw a layer on top with lines, it all works as expected.
But I want to draw more lines on several other layers at the same z as the first lines layer, and that's the result:
lines layers conflict.
I don't understand why each lines layer erase previous overlapped lines layer (but don't corrupt underlying images).
Moreover if I draw another layer at the same z as lines layer but with some text, this is the result:
text layer issue.
Text layer create a hole in all undelying layers and you can see the background.
Lines and text are painted with QPainter on a QImage this way:
m_img = new QImage(&m_buffer[0], width, height, QImage::Format_RGBA8888);
m_img->fill(Qt::transparent);
QPen pen(color);
pen.setWidth(2);
m_painter.begin(m_img);
m_painter.setRenderHints(QPainter::Antialiasing, true);
m_painter.setPen(pen);
m_painter.drawLines(lines);
m_painter.end();
QFont font;
int font_size = font.pointSize() * scale;
if (font_size > 0) { font.setPointSize(font_size); }
QPen pen(color);
m_painter.begin(m_img);
m_painter.setRenderHints(QPainter::Antialiasing, true);
m_painter.setFont(font);
m_painter.setPen(pen);
for(int index = 0; index < messages.size(); index++)
m_painter.drawText(positions.at(index), messages.at(index));
m_painter.end();
and textures:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, d->width(), d->height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, d->data());
This is my texture setup():
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST/*GL_LINEAR*/);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST/*GL_LINEAR*/);
opengl_error_check(__FILE__, __LINE__);
This is my initializeGL():
glClearColor(0.0, 0.25, 0.5, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_MULTISAMPLE);
glEnable(GL_DEPTH_TEST);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_FLAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Finally I have set QGLFormat(QGL::AlphaChannel) in my QGLWidget.
I know that there is a problem of z-fighting using overlapping planes at the same z, but as far as I know it should matter only if the overlapping textures are not transparent. In my case some artifacts may be expected where lines crosses, but I don't understand why lines disappear.
And since I use the same way to draw lines and text, I don't understand why text layer influence images while lines not.
Last note: I have printed pixel values in all textures right before glTexImage2D() and values are as expected.
I'm pretty sure there is some obvious mistake, can someone point me where I'm wrong?
OpenGL works by "painter" principle. Unless you use Z-ordering (aka depth test), what is drawn last is drawn on top. It works like splattering paint on the wall, hence the term. Nota bene: depth test is off by default, in general, it does slow rendering down.
If you use Z-ordering, OpenGL will "hide" fragments which fall into area of "window space" (color buffer), where "paint" with bigger Z value already exist. Thus , there is no depth-based "automatic" transparency in OpenGL: to emulate transparency you must paint things in proper order, with proper blending mode. That may prove to be problem, if objects intersect or self-intersect. Creating complex scenes with transparency and shadows requres technique called deferred rendering.
If you paint with same Z, result again depends on blending and if color is solid, you'll just overpaint what is already there, just like if depth test is off.
PS. There is not enough data about text issue, I don't see any text there but it looks like you do painting on top of OpenGL's output. Which widget is is, QGLWidget, or QOpenGLWindget? In fact, those two source write into separate passes, and font is draw by Qt using platform-depenadant means, so text might be overwritten? It's not recomended to use Qt's painter output with OpenGL, you may need to look into use of libraries to output text in OpenGL.

Framebuffer clipping anything drawn 'off screen'

I recently implemented a zoom-in/zoom-out function in my simple 2D engine and experienced some terrible seams between adjacent textures, as shown here:
http://oi59.tinypic.com/anmxyf.jpg
It doesn't look that bad but it was definitely annoying when it was constantly blinking at you when moving around.
I decided to change it so a very large portion of the game (as much as the player is allowed to zoom out) is instead drawn on a framebuffer, then I print the framebuffer and when zooming in or out it instead increases/decreases the framebuffer texture size, as to avoid the seams.
At first I decided to draw 5 times as much as is visible to the player at default zoom, so I made a framebuffer object with a texture 5 times as big, then draw to it.
Here is the initialization of the framebuffer object:
glGenFramebuffers(1, &main_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, main_framebuffer);
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glGenTextures(1, &main_ColorBuffer);
glBindTexture(GL_TEXTURE_2D, main_ColorBuffer);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, SCREEN_BUFFER_WIDTH, SCREEN_BUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, main_ColorBuffer, 0
);
Where SCREEN_BUFFER_WIDTH and SCREEN_BUFFER_HEIGHT is set as five times as big as the default screen size. I then draw my world as I would normally do (where I could zoom out as much as I wanted and everything was fine, except the seams).
The issue is that only 1024 x 768 (being the default screen size) is drawn to the framebuffer. This is how I activate, draw to the framebuffer, then draw the framebuffer:
glBindFramebuffer(GL_FRAMEBUFFER, main_framebuffer);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw_blocks(); //draws all the blocks in the correct screen y and x position
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, main_ColorBuffer);
draw_quad(shift_y*ratio, shift_x*ratio, SCREEN_BUFFER_WIDTH*ratio, SCREEN_BUFFER_HEIGHT*ratio);
glBindTexture(GL_TEXTURE_2D, 0);
Where ratio is a float I use for zooming in and out and shift_y and shift_x I use to shift the framebuffer texture around to get a better feel for how things are going.
By zooming out and shifting the framebuffer a bit I get this:
http://oi61.tinypic.com/34zlpip.jpg
it only draws a small portion of the screen (which exactly fits the screen if I don't zoom out).
In contrast, this is what it looks like if I zoom all the way out (and then some) before using a framebuffer and instead drawing straight to the screen:
http://oi61.tinypic.com/21akbit.jpg (the empty parts are just chunks that haven't been loaded as the player isn't supposed to be able to zoom out this much).
I'm truly stumped here, I've tried changing the viewport before drawing but this does just about nothing.
I'd also like to note that I'm pretty confident the actual framebuffer texture object actually is five times as large as what's being drawn to it, because if I don't stretch it in my draw_quad function by instead giving it the same width and height as the screen, I get this:
http://oi62.tinypic.com/4triiu.jpg
The width and height of the framebuffer is now the same as the width and height of the screen, yet there's only graphics in a fraction of it, which is the small portion that's actually being drawn to.
Anyone have any clue? If more portions of code are needed I'm happy to oblige but the entire thing is far too much.

Textures Stopped Working Correctly

Recently my textures went crazy. Last 2 textures that I tried to map appeared as in the picture below. I want it to appear as in the first picture but no matter what I did, it insists on appearing like in the latter one. Ignore the text please, it has nothing to do with texture.
I am using GLUT for my openGL windowing, and GLM obj loader's tga reader. I used the reader many times before and there was no problem. It just stopped working for my last two attempts to load texture. The related code is below:
Texture onScreenTexture;
if (LoadTGA(&onScreenTexture, "back.tga"))
{
glGenTextures(1, &onScreenTexture.texID);
glBindTexture(GL_TEXTURE_2D, onScreenTexture.texID);
glTexImage2D(GL_TEXTURE_2D, 0, onScreenTexture.bpp / 8, onScreenTexture.width, onScreenTexture.height, 0, onScreenTexture.type, GL_UNSIGNED_BYTE, onScreenTexture.imageData);
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);
if (onScreenTexture.imageData)
{
free(onScreenTexture.imageData);
}
}
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, onScreenTexture.texID);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex2f(10.0, 10.0);
glTexCoord2f(0,1); glVertex2f(260, 10.0);
glTexCoord2f(1,1); glVertex2f(260, 110);
glTexCoord2f(1,0); glVertex2f(10.0, 110);
glEnd();
glDisable(GL_TEXTURE_2D);
This is nothing to do with the ratio of width/height (though you do seem to be rendering it 90 degrees rotated, causing some additional stretching), but with the packing of rows of pixels. This is apparent from the diagonal pattern, indicating an progressive alignment issue, and also the coloured stripes, showing that the RGB data is unaligned differently on each line.
In your case, you're loading a TGA, which has no row-padding, but passing it to GL which by default expects rows of pixels to be padded to a multiple of 4 bytes.
Your working textures probably are either 32-bit rather than 24-bit or are a multiple of 4 pixels wide, either of which gives a natural alignment.
Possible fixes for this are:
Change the dimensions of your texture, such that there will be no padding.
Change the loading of your texture, such that the padding is consistent with what GL expects
Tell GL how your texture is packed, using (for example) glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

OpenGL CubeMap Texture Dimensions

After struggling all weekend, I finally have a sphere reflecting its environment in OpenGL. It almost looks good. Problem is, certain features don't line up. I can't find much information on the topic of OpenGL sphere mapping, outside of a two page section in the Red Book and a few scattered, and mostly unfinished forum topics. Not sure it's necessary, but I included my code where I load the textures. After trial and error, I found that having symmetrical dimensions freom 0 to 512 gets the best results, but they still aren't perfect (and the dimensions have to be powers of two, or it crashes). Does any one know of any strategies to get textures that line up more correctly?
void loadCubemapTextures(){
glGenTextures(1, &cubemap);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
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_WRAP_R, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glDrawBuffer(GL_AUX1);
glReadBuffer(GL_AUX1);
glMatrixMode(GL_MODELVIEW);
//Generate cube map textures
for(int i = 0; i < 6; i++){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//Viewing Transformation
gluLookAt(pos[0], pos[1], pos[2],
view_pos[i][0], view_pos[i][1], view_pos[i][2],
top[i][0], top[i][1], top[i][2]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0, 1.0, cubemapRadius + 1, 200.0);
glMatrixMode(GL_MODELVIEW);
render();
glCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, 0, 0, 256, 256, 0);
}
Your walls lack enough features to make their orientation and location clear, but I would bet those are the issue.
The values you have in view_pos and top are what define those. Among the things that look suspicious:
the black at the bottom of the shere comes from the face that captured the front view. It should be at the top (ie it's either flipped, or rotated 180).
likewise, the black that comes from the back of the view (in the center of the sphere) looks turned by a quarter of a circle (as black goes on the left rather than being on the top).
the reflection of the map sphere looks weird. It lacks resolution to figure out exactly what this is.
Anyways, to fix it, you can either make sure your values are what is expected from a proper cube-map definition (as in check all the specification), or just do a bunch of trial and error, after adding enough geometry to figure out what the orientation of each face is.
The problem had nothing to do with coordinates, thanks for the input though. I had forgotten to set the view matrix... a simple call to gluViewport inside the for-loop fixed it for me.

Simple OpenGL texture map not working?

I'm trying to figure out texture mapping in OpenGL and I can't get a simple example to work.
The polygon is being drawn, though it's not textured but just a solid color. Also the bitmap is being loaded correctly into sprite1[] as I was successfully using glDrawPixels up til now.
I use glGenTextures to get my tex name, but I notice it doesn't change texName1; this GLuint is whatever I initialize it to, even after the call to glGenTextures...
I have enabled GL_TEXTURE_2D.
Heres the code:
GLuint texName1 = 0;
glGenTextures(1, &texName1);
glBindTexture(GL_TEXTURE_2D, texName1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
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);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, sprite1[18], sprite1[22], 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &sprite1[54]);
glColor3f(1, 1, 0);
glBindTexture(GL_TEXTURE_2D, texName1);
glBegin(GL_QUADS);
glTexCoord2f (0.0, 0.0);
glVertex3f (0.0, 0.0, -5.0f);
glTexCoord2f (1.0, 0.0);
glVertex3f (.5, 0.0, -5.0f);
glTexCoord2f (1.0, 1.0);
glVertex3f (.5, .5, -5.0f);
glTexCoord2f (0.0, 1.0);
glVertex3f (0.0, .5, -5.0f);
glEnd();
UPDATE:
I'm at a loss. Here's everything I've tried:
Turns out I was initializing my texture before OGL was initialized. The texture is initialized (glGenTextures->glTexImage2D) in a class constructor and drawn (glBegin->glEnd) in a member function that is called every frame. genTextures appears to be working correctly now and I'm getting a name of 1.
Every possible combination of GL_RGBA8, GL_BGRA_EXT (GL_BGRA doesn't work on my system; I need the _EXT), and I even removed the alpha channel from the bitmap and tried all combinations of GL_RGB, GL_BGR_EXT, etc etc. No luck.
Tried procedurally creating a bitmap and using that
Made sure GL_COLOR_MATERIAL isn't enabled.
Changed bitmap size to 32x32.
Tried glTexEnvi instead of glTexEnvf.
In addition to mentat's note that you might have a problem with non-power-of-two texture dimensions, you mention the texture name generation not changing the name.
That sounds as if you're calling glGenTextures() too early, i.e. before initializing OpenGL. If you're not, then I suggest adding code just after the call to glGenTextures() that check the OpenGL error state, by calling glGetError().
In your comments, you say your bitmap is 29x20 pixels. Afaik to generate a valid texture, OpenGL requires that the image size (on each dimension) be a power of 2. It doesn't need to be a square, it can be a rectangle though. You can overcome this by using some OpenGL extensions like GL_ARB_texture_rectangle.
I'll put this here as I had the same issue and found another post explaining the issue.
The iPhone does support GL_BGRA(GL_EXT_BGRA) but seemingly only as an input format and not as an internal format. So, if you change the glTexImage2D call to have an internal format of GL_RGBA then it works.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, &sprite1[54]);
I hope this helps someone else that stumbles upon this post.
Some random ideas:
GL_COLOR_MATERIAL might be enabled
change "glTexEnvf" to "glTexEnvi" and see if that helps
if texName1 is 0 after glGenTextures you might not have an active OpenGL context
For error checking I recommend writing a small function that prints readable output for the most common results from glGetErrors and use that to find the line that creates the error. Another possibility would be to use something like GLIntercept, BuGLe or gDEBugger.
My OpenGL is rusty, but I remember having same problems with with glTexImage2D
. Finally I managed to make it work, but I always had more luck with gluBuild2DMipmaps
so i ended up with
gluBuild2DMipmaps (
GL_TEXTURE_2D, type, i.width, i.height, type, GL_UNSIGNED_BYTE, i.data
);
which replaced
glTexImage2D (
GL_TEXTURE_2D, 0, type, i.width, i.height, 0, type, GL_UNSIGNED_BYTE, i.data
);
I found the problem. My call to glEnable was glEnable(GL_BLEND | GL_TEXTURE_2D). Using glGetError I saw I was getting a GL_INVALID_ENUM for this call, so I moved GL_TEXTURE_2D to its own enable function and bingo. I guess logical OR isn't allowed for glEnable?
First thing I'd check is the colour material setting, as mentioned by ShadowIce, then check your texture file to ensure it's a reasonable size (i.e. something like 256x256) and an RGB bitmap. If the file has even a slight problem it WILL NOT render correctly, no matter how you try.
Then, I'd stop trying to just debug that code and instead see what you have different to the tutorial on the NeHe website.
NeHe is always a good place to check if you're trying to do stuff in OpenGL. Textures are probably the hardest thing to get right, and they only get more difficult as the rest of your GL skills increase.