rectangular texture in OpenGL with both width and height POT - opengl

I'm trying to use rectangular texture with OpenGL. When the height is equal to the width of the texture, everything looks fine, however, when the height is different than the width the texture looks distorted.
My display function is (h and w are globals storing the height and the width of the image):
Please note that the size of the drawn image doesn't matter. It is distorted regardless of the actual polygon size.
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, texName);
glTranslatef(-2.0f,-2.0f,0.0f);
glScalef(1.0f/128.0f,1.0f/128.0f,1.0f);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(0.0, w, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(h, w, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(h, 0.0, 0.0);
// Will be distorted also with the following:
/*glScalef(1.0f/128.0f,1.0f/128.0f,1.0f);
glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(0.0, h, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(w, h, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(w, 0.0, 0.0);*/
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
}
I'm loading the texture with:
void *data = LoadBMP("c:\\dev\\64x128_face.bmp");
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w,
h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
data);
When I'm loading a 64x64 square texture image, it looks fine. However when I'm loading a rectangular texture image, the image looks distorted.
How does OpenGL support rectangular POT texture? What's wrong with my code?

Your rect image is 64x128 but you render it with these commands:
glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(0.0, w, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(h, w, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(h, 0.0, 0.0);
where h is height (=128) and w (=64) is width.
But you placed height on x (which is width) and width on y (which is height).
Maybe try this instead:
glTexCoord2f(0.0, 0.0); glVertex3f(0.0, 0.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(0.0, h, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(w, h, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(w, 0.0, 0.0);

You should probably check the support of the GL_ARB_texture_non_power_of_two extension before you use non-power-of-two values for h and w in glTexImage2D(), because specifying arbitrary heights and widths is only valid with this extension.

Related

OpenGL texture mapping issue

I'm trying to do texture on my cube as the code below. However, the result that I got is that the image did not cover the entire cube surface while looks like it looped.
You can see the blue lining from the picture used:
I've checked the coordinates but doesn't seem to have any error. I check the image size (512x512), it's also the same as I declared when loading the texture. So, I had trouble figuring where is the problem.
void square(void) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[0]); //bind our texture to our shape
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
glTexCoord3d(0.0, 0.0, 0.0); glVertex3d(500, -500, -500); //behind
glTexCoord3d(1.0, 0.0, 0.0); glVertex3d(500, 500, -500);
glTexCoord3d(1.0, 1.0, 0.0); glVertex3d(-500, 500, -500);
glTexCoord3d(0.0, 1.0, 0.0); glVertex3d(-500, -500, -500);
glEnd();
glBegin(GL_POLYGON);
glTexCoord3d(0.0, 0.0, 0.0); glVertex3f(500, -500, 500); //front
glTexCoord3d(1.0, 0.0, 0.0); glVertex3f(500, 500, 500);
glTexCoord3d(1.0, 1.0, 0.0); glVertex3f(-500, 500, 500);
glTexCoord3d(0.0, 1.0, 0.0); glVertex3f(-500, -500, 500);
glEnd();
glBegin(GL_POLYGON);
glTexCoord3d(0.0, 0.0, 0.0); glVertex3f(500, -500, -500); //right
glTexCoord3d(1.0, 0.0, 0.0); glVertex3f(500, 500, -500);
glTexCoord3d(1.0, 1.0, 0.0); glVertex3f(500, 500, 500);
glTexCoord3d(0.0, 1.0, 0.0); glVertex3f(500, -500, 500);
glEnd();
glBegin(GL_POLYGON);
glTexCoord3d(0.0, 0.0, 0.0); glVertex3f(-500, -500, 500); //left
glTexCoord3d(1.0, 0.0, 0.0); glVertex3f(-500, 500, 500);
glTexCoord3d(1.0, 1.0, 0.0); glVertex3f(-500, 500, -500);
glTexCoord3d(0.0, 1.0, 0.0); glVertex3f(-500, -500, -500);
glEnd();
glBindTexture(GL_TEXTURE_2D, texture[1]);
glBegin(GL_POLYGON);
glTexCoord3d(0.0, 0.0, 0.0); glVertex3f(500, 500, 500); //top
glTexCoord3d(1.0, 0.0, 0.0); glVertex3f(500, 500, -500);
glTexCoord3d(1.0, 1.0, 0.0); glVertex3f(-500, 500, -500);
glTexCoord3d(0.0, 1.0, 0.0); glVertex3f(-500, 500, 500);
glEnd();
glBindTexture(GL_TEXTURE_2D, texture[2]);
glBegin(GL_POLYGON);
glTexCoord3d(0.0, 0.0, 0.0); glVertex3f(500, -500, -500); //bottom
glTexCoord3d(1.0, 0.0, 0.0); glVertex3f(500, -500, 500);
glTexCoord3d(1.0, 1.0, 0.0); glVertex3f(-500, -500, 500);
glTexCoord3d(0.0, 1.0, 0.0); glVertex3f(-500, -500, -500);
glEnd();
glDisable(GL_TEXTURE_2D);
}
function to load the RAW file:
GLuint LoadTexture(const char * filename, int width, intbheight)
{
GLuint texture;
unsigned char * data;
FILE * file;
//The following code will read in our RAW file
file = fopen(filename, "rb");
if (file == NULL) return 0;
data = (unsigned char *)malloc(width * height * 3);
fread(data, width * height * 3, 1, file);
fclose(file);
glGenTextures(1, &texture); //generate the texture with the loaded data
glBindTexture(GL_TEXTURE_2D, texture); //bind the textureto it’s array
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
GL_MODULATE); //set texture environment parameters
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_REPEAT);
//Generate the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, data);
free(data); //free the texture
return texture; //return whether it was successful
}

GL_QUADS state does not support multiple glBindTexture?

To be short, why couldn't I put two glBindTexture into one glBegin(GL_QUADS)...glEnd()?
I am following chapter 9 of OpenGL red book, http://www.glprogramming.com/red/chapter09.html
In example 9-5, program texbind.c produces two quads with different texture, like this:
The quad on the left has a white checker board texture while the quad on the right has a red one.
Here is the code which maps the textures to two quads:
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texName[0]);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0);
glEnd();
glBindTexture(GL_TEXTURE_2D, texName[1]);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421);
glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421);
glEnd();
glFlush();
}
We can see that even though the code uses GL_QUADS it draws one quad in each GL_QUADS state. However, if I comment out the glEnd() and glBegin(GL_QUADS) in the middle of this code, like this:
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, texName[0]);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0);
glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0);
// glEnd();
glBindTexture(GL_TEXTURE_2D, texName[1]);
// glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421);
glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421);
glEnd();
glFlush();
}
It turns out the second glBindTexture(GL_TEXTURE_2D, texName1) does not work anymore. And the result is:
Could anyone tell me why I cannot put two glBindTexture into one GL_QUADS state?
Because OpenGL doesn't support doing that.
The only calls you can make to OpenGL while inside glBegin/glEnd are vertex submission calls like glTexCoord*, glVertex*, etc. Anything else is an error.
As to "why", one reason is "because the specification says so". More likely, the GPU processes the entire data set (or significant chunks of it) in parallel, during which it cannot switch textures.
Also consider the newer way of drawing with OpenGL: uploading your data to a Vertex Buffer Object and calling one of the glDraw* commands. There's no way you can even call glBindTexture in between primitives using that.

OpenGL Texture doesn't show

I'm trying to show a texture in Qt with opengl but it just doesn't show the texture when i run.
I did some research and found out I needed to make the height and width of the texture as a power of 2. my texture is now (1024x1024).
I also added a lot of glTexParameterf's that could resolve my problem, but still no luck.
void WorldView::paintGL ()
{
this->dayOfYear = (this->dayOfYear+1);
this->hourOfDay = (this->hourOfDay+1) % 24;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// store current matrix
glMatrixMode( GL_MODELVIEW );
glPushMatrix( );
gluLookAt(camPosx ,camPosy ,camPosz,
camViewx,camViewy,camViewz,
camUpx, camUpy, camUpz );
//Draw Axes
glDisable( GL_LIGHTING );
glBegin(GL_LINES);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(10.0, 0.0, 0.0);
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 10.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 10.0);
glEnd();
//load texture
QImage img;
if(!img.load(":/files/FloorsCheckerboardSmall.bmp"))
printf("could not open image");
//try showing texture
glEnable( GL_LIGHTING );
glEnable( GL_COLOR_MATERIAL );
glEnable(GL_TEXTURE_2D);
unsigned int m_textureID;
glGenTextures(1, &m_textureID);
glBindTexture(GL_TEXTURE_2D,m_textureID);
glTexImage2D(GL_TEXTURE_2D,0,(GLint)img.depth(),(GLsizei)img.width(),(GLsizei)img.height(),0,GL_RGB,GL_UNSIGNED_BYTE,img.bits());
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
glColor3d(1.0,0.0,0.0);
glBegin(GL_POLYGON);
glTexCoord2d(0.0,5.0);
glVertex2d(0.0,3.0);
glTexCoord2d(0.0,0.0);
glVertex2d(0.0,0.0);
glTexCoord2d(5.0,0.0);
glVertex2d(3.0,0.0);
glTexCoord2d(5.0,5.0);
glVertex2d(3.0,3.0);
glEnd();
}
EDIT1: Could it be my texture is too big?
EDIT2: glBindTexture(GL_TEXTURE_2D,m_textureID); placed before glBindTexture instead of before glColor3d
SOLVED: My img.depth() returned an invalid internalFormat value. I replaced this GLint with the valid interalFormat value GL_RGBA. I also changed the format from GL_RGB to GL_RGBA (see genpfaults answer)
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,(GLsizei)img.width(),(GLsizei)img.height(),0,GL_RGBA,GL_UNSIGNED_BYTE,img.bits());
You have to call
glBindTexture(GL_TEXTURE_2D,m_textureID);
before calling glTexImage2D(...). Or OpenGL won't know where the data you send it belongs.
vvvvvvvvvvvvvvvvvv
glTexImage2D(GL_TEXTURE_2D,0,(GLint)img.depth(),(GLsizei)img.width(),(GLsizei)img.height(),0,GL_RGB,GL_UNSIGNED_BYTE,img.bits());
img.depth() returns 32
Then you need to pass in a valid internalFormat value, not img.depth(). Try GL_RGBA.
You should also set format to GL_RGBA since img.bits() is actually four-component.

Get pixels from a CUDA graphics resource

How can I obtain a pixel buffer object and get the RGB pixels into an array, given a CUDA graphics resource? Could somebody provide an example or confirm if my own attempt is correct? The existing code looks like this:
cutilSafeCall(cudaGraphicsMapResources(1, &render_cuda_pbo_resource, stream));
uchar4 *d_output;
size_t num_bytes;
cutilSafeCall(cudaGraphicsResourceGetMappedPointer((void **)&d_output, &num_bytes, render_cuda_pbo_resource));
I have added the following code:
glBindTexture (GL_TEXTURE_2D, renderTex);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
glBegin(GL_QUADS);
glTexCoord2f (0.0, 0.0);
glVertex3f (-1.0, -1.0, 0.0);
glTexCoord2f (1.0, 0.0);
glVertex3f (1.0, -1.0, 0.0);
glTexCoord2f (1.0, 1.0);
glVertex3f (1.0, 1.0, 0.0);
glTexCoord2f (0.0, 1.0);
glVertex3f (-1.0, 1.0, 0.0);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glReadPixels(10, 10, width, height, GL_BGRA, GL_UNSIGNED_BYTE, data);
You don't.
OpenGL objects are OpenGL objects; CUDA objects are CUDA objects. If you want CUDA to put stuff into OpenGL objects, you must give CUDA OpenGL objects and have it put the stuff into them. This is generally done with cudaGraphicsGLRegisterBuffer.

How do I make textures transparent in OpenGL?

I've tried to research this on Google but there doesn't appear to me to be any coherent simple answers. Is this because it's not simple, or because I'm not using the correct keywords?
Nevertheless, this is the progress I've made so far.
Created 8 vertices to form 2 squares.
Created a texture with a 200 bit alpha value (so, about 80% transparent).
Assigned the same texture to each square, which shows correctly.
Noticed that when I use a texture with 255 alpha, it appears brighter.
The init is something like the following:
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, textureIds);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
int i, j;
GLubyte pixel;
for (i = 0; i < TEXTURE_HEIGHT; i++)
{
for (j = 0; j < TEXTURE_WIDTH; j++)
{
pixel = ((((i & 0x8) == 0) ^ ((j & 0x8) == 0)) * 255);
texture[i][j][0] = pixel;
texture[i][j][1] = pixel;
texture[i][j][2] = pixel;
texture[i][j][3] = 200;
}
}
glBindTexture(GL_TEXTURE_2D, textureIds[0]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
TEXTURE_WIDTH, TEXTURE_HEIGHT,
0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
This is somewhat similar to the code snippet from page 417 in the book, OpenGL Programming Guide, and creates a check pattern.
And then, the display function contains...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
// Use model view so that rotation value is literal, not added.
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// ... translation, etc ...
glBindTexture(GL_TEXTURE_2D, textureIds[0]);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, +1.0, 0.0); // top left
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, -1.0, 0.0); // bottom left
glTexCoord2f(1.0, 1.0); glVertex3f(+1.0, -1.0, 0.0); // bottom right
glTexCoord2f(1.0, 0.0); glVertex3f(+1.0, +1.0, 0.0); // top right
glEnd();
// not neccecary to repeat, just good practice
glBindTexture(GL_TEXTURE_2D, textureIds[0]);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(-0.5, +1.0, -1.0); // top left
glTexCoord2f(0.0, 1.0); glVertex3f(-0.5, -1.0, -1.0); // bottom left
glTexCoord2f(1.0, 1.0); glVertex3f(+1.5, -1.0, -1.0); // bottom right
glTexCoord2f(1.0, 0.0); glVertex3f(+1.5, +1.0, -1.0); // top right
glEnd();
glFlush();
glDisable(GL_TEXTURE_2D);
glPopMatrix();
SwapBuffers();
So, this renders a 2nd square in the background; I can see this but it looks like they're being blended with the background (I assume this because they are darker with 200 bit alpha than 255 bit) instead of the texture behind...
As you can see, no transparency... How can I fix this?
So the other answer which was here but was deleted mentioned this - Generally, for alpha blending to work correctly you need to sort the objects from far to near in the coordinate system of the camera.
This is why your polygons are blended with the background. You can confirm that this is indeed the problem by disabling the depth test. Without depth test all the fragments are displayed and you'll be able to see the alpha blending.
More on this in this page.