Opengl:what Is The Best Way To Get Color Of One Pixel From A 2D Texture?

Started by
12 comments, last by nickme 7 years, 9 months ago

hi

When my program ran, it produced the following image. note how the red line at the bottom of the image, it is suppose to be something difference. the texture is a 16x16 pixel image as shown below. I guess the glTexcoord2i() did not work properly, I mean something need to take care of before it.

the relevant codes are:

void plotDot(GLint x, GLint y, int c)
{
glTexCoord2i(c%16, c/16);
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
}
void winReshapeFcn(GLint newWidth, GLint newHeight)
{ // doesnot allow window size change
glutReshapeWindow(sizeX, sizeY);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(l, r, b, t);
glMatrixMode(GL_MODELVIEW);
}
void render()
{
double ds = 4.0, x = 10.0;
if (once) {
once = false;
display_splash_screen(MenuID);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, palID);
glPointSize(ds); // for debug
for (int c = 0; c < ss; x += ds, c++) {
plotDot((int)x, 700, c);
}
glFlush();
}
}
void init()
{
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_TEXTURE_2D);
buttonsID = LoadTexture2D("buttonsandwait.png");
MenuID = LoadTexture2D("fractals_screen.png");
palID = LoadTexture2D("gradient1.png");
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowSize(sizeX, sizeY);
glutCreateWindow("Testing Program");
init();
glutIgnoreKeyRepeat(1);
glutReshapeFunc(winReshapeFcn);
glutDisplayFunc(render);
glutMainLoop();
cleanup();
return 0;
}
Advertisement

Can you show the code where you actually draw that line? Is it this:


void plotDot(GLint x, GLint y, int c)
{
     glBegin(GL_POINTS);
     glVertex2i(x, y);
     glEnd();
}

You are not providing any texture coordinates so that's why it only shows red. Do you have to draw it as dots? you'd be much better off drawing it as 2 triangles unless you need it as points for some reason. Ideally you would call glBegin, draw all the points, then do glEnd rather than doing begin/point/end however many times each.

I don't recommend sticking with this approach but you would need to do somehting along the lines of:


void plotDot(GLint x, GLint y, int c)
{
     glBegin(GL_POINTS); // You should have this outside of your loop
     glVertex2i(x, y);
     // notice it is 2f, not 2i. 2i only lets you have 0, 1, 2 etc so you will never see anything
     // other than the start and end pixels of your texture.
     glTexcoord2f(u, v); // u should be a value from 0 to 1, 0 when c==0 and 1 when c==ss-1 (done outside the call)
     glEnd(); // This should also be outside the loop
}

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

hi Nanoha:

I am sorry, I deleted it accidentally when i indented the codes copy from vs to this website. It is like:

glTexCoord2i(c%16, c/16);

it is either before the glBegin(GL_POINTS); or immediately after it.

i edited my original one in my first post.

let's be clear, my output is the same(red line), it was just a typo in copy and paste to this website problem.

thanks

hi Nanoha

void plotDot(GLint x, GLint y, int c)
{
glBegin(GL_POINTS); // You should have this outside of your loop
glVertex2i(x, y);
// notice it is 2f, not 2i. 2i only lets you have 0, 1, 2 etc so you will never see anything
// other than the start and end pixels of your texture.
glTexcoord2f(u, v); // u should be a value from 0 to 1, 0 when c==0 and 1 when c==ss-1 (done outside the call)
glEnd(); // This should also be outside the loop
}

what about v? in gradient1.png file, there are a lot of redundant colors (all row are in the same colors), but in the future, I will create a new gradient png file, it will be quite different.

with an integer, i can mod it (c % 16) and (c / 16) to access the 2d texture. How can i calculate the u and v with only c(integer or float)? SS = 16*16.

Are you suggesting that load the gradient1.png as a 1xss pixels texture? u will always be 0 and v is 0 to c/ss?

thanks

Curses, I wrote a long post, accidentally pasted over it and clicked submit and lost it :(. Will try again.

When you want to sample (take a color from) a texture you have to provide u,v coordinates to opengl to tell it where on that texture to take a color from. Typically people call the horizontal axis u and the vertical axis v. For the u axis, the left of the texture is 0, the right of the texture is 1 so if you wanted that cyan part of your gradient in the central area you would likely provide a value of 0.5 for u. V is then the vertical axis and in opengl the bottom of the texture is v=0 and the top is v=1. All areas inside are then within the range 0-1. If you provide values outside of that range then it will have a different effect depending on the texture wrap you have setup (search opengl texture wrapping for more info).

With the gradient texture you have, it is effectively 1D, no matter what v value you give it the color won't change so you can happily use a v value of 0 (the second parameter in glTexcoord2i). We are interested only in the horizontal value u. To get the left we give a value of 0, to get the right we give a value of 1 and to sample the texture in between we give a value between 0 and 1. The problem with glTexcoord2i is that it accepts only integers (0, 1, 2, 3 etc and negatives) so we can never actually give it a value in between so we can never show the whole of your gradient only the left and right pixels. To solve this we can switch to glTexcoord2f instead which takes floats so we can provide values such as 0.5 and thus get that cyan in the central area.

The other issue is you are passing in c%16 which will give integer values too which you don't want. From what I understand of your code that line should be a rainbow being repeated every 16 pixels. Hopefully this should help you out:


// It is horribly inefficient to call begin/end for every single primitive so do this 
// outside of the loop
glBegin(GL_POINTS);
for(int c = 0; c < ss; x+=ds, c++)
{
   // You want a value that goes 0-1 every 16c. To get it going every 16c:
   // c = c%16; Then to convert that to 0-1
   // u = c/(16-1); It's -1 since the largest value you can have is 15 which will then give 1
   glTexcoord2f((c%16)/15.0f, 0);
   glVertex2i((int)x, 700);
}
glEnd();
what about v? in gradient1.png file, there are a lot of redundant colors (all row are in the same colors), but in the future, I will create a new gradient png file, it will be quite different.

If you want the vertical aspect then you should stop using points and instead create a quad which will be much more efficient and easier to work with. You would simply define 4 points (the corners) and let opengl do the rest. If you wanted the texture to be repeated, say 10 times, then instead of putting the texture coord to u=1 on the right you'd just set it to 10 (and setup your texture wrapping to repeat). It will save you a lot of trouble. You can make textures procedurally which is sort of the same as drawing a whole bunch of points but a lot more efficient. Ask yourself if you really need to be using points, they are probably a bad choice for what you are trying to do.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

thanks for your reply

If you want the vertical aspect then you should stop using points and instead create a quad which will be much more efficient and easier to work with. You would simply define 4 points (the corners) and let opengl do the rest. If you wanted the texture to be repeated, say 10 times, then instead of putting the texture coord to u=1 on the right you'd just set it to 10 (and setup your texture wrapping to repeat). It will save you a lot of trouble. You can make textures procedurally which is sort of the same as drawing a whole bunch of points but a lot more efficient. Ask yourself if you really need to be using points, they are probably a bad choice for what you are trying to do.

I have to use points to draw a fractals. I can load it with 1d texture with raw formatted file like i did it before. I just decided to use 2d with png file.

It will take times to digest your post

thanks for your great efforts

I have to use points to draw a fractals.

Are you planning to render your fractal as a dense area of points? If so you will be much better off making a texture out of them instead. In effect a texture is just that, an area of points (pixels). It'll be much more efficient to draw each frame too.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Are you planning to render your fractal as a dense area of points?

yes, I would like to draw the whole screen dots by dots when user click one location and the program will then zoom in to the area and show the whole screen selected by the mouse click. what i would liked to do is to zoom in to the pos user clicked according to a small square window which i called cursor. the points is to zoom in to the fractals one level after the other until when the GLdouble variables' values of the windows X1 - X0 < 10e-12 because by then all the values will be zeros.

I did it successfully, in 2012, obviously with older opengl (as some in the forum rant that i use heavily deprecated API).

This is just a hobby. I do this out of boredom.

In the 2012 version, I used a *.raw file as gradient and i used gltexcoord1d(), and it rendered what i expected it to be. As you can see in the attached picture.

It really opened my eyes when you suggested that i put the for loop inside the glBegin(), glEnd(); as a procedural programming student back in the 90, i tried to used modulization as often as possible. your suggestions are obviously better.

regards

hi

the strangest thing happened. I load the gradient1d.raw, as a 1d texture, which is a 1x256 pixels file created in photoshop. but bind it in 2d before access it with glTexCoord2d(), it started to show something. though I don't know why it does not render the rest of the pixel.

here is the codes and the screen shot:

void render()
{
GLdouble ds = 4.0f, x = 10.0;
if (once) {
once = false;
display_splash_screen(MenuID);
clear();
glPointSize(ds);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, palID);
glBegin(GL_POINTS);
for (int c = 0; c < ss; x += ds, c += 1.0) {
glTexCoord2d((GLdouble)(c % ss) / (GLdouble) (ss - 1), 0.0);
glVertex2d(x, 600.0);
}
glEnd();
x = 10.0;
glEnable(GL_TEXTURE_1D);
glBindTexture(GL_TEXTURE_1D, palID); // bind to 2d
glBegin(GL_POINTS);
for (GLint c = 0.0; c < ss; x += ds, c++) {
glTexCoord1d((GLdouble) c/ (GLdouble) ss);
glVertex2d(x, 700.0);
}
glEnd();
glFlush();
}
}
void init()
{
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_TEXTURE_2D);
buttonsID = LoadTexture2D("buttonsandwait.png");
MenuID = LoadTexture2D("fractals_screen.png");
glEnable(GL_TEXTURE_1D);
palID = LoadTexture1D("Gradient.raw", ss); // vs only recognized this as 1d
printf("\n but %i Men %i pal %i\n\n", buttonsID, MenuID, palID);
initV();
}
Also note that the gradient.raw file contain one row of color similar to one row of color of gradient.png. the gradient.raw is basically one row of gradient expanded to 256 pixels wide.
from the screenshot, it show that the colors are repeated 16 times, maybe someone can explain to me.

hi

It just happened that either binding the png texture as 1d or 2d, it still worked. here are the codes that it generate a very interesting result after apply Nanoha's suggestions.

here is the codes:

void render()

{
GLdouble ds = 4.0f, x = 10.0;
if (once) {
once = false;
clear();
display_splash_screen(MenuID); glFlush();
Sleep(000);
clear();
glPointSize(ds);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, palID);
glBegin(GL_POINTS);
for (int c = 0; c < ss; x += ds, c++) {
glTexCoord2d((GLdouble)(c%ss) / (GLdouble)(ss-1), 0.0);
glVertex2d(x, 600.0);
}
glEnd();
glFlush();
x = 10.0;
glEnable(GL_TEXTURE_1D);
glBindTexture(GL_TEXTURE_1D, palID); // bind to 2d
glBegin(GL_POINTS);
for (GLint c = 0.0; c < ss; x += ds, c++) {
glTexCoord1d((GLdouble) (c%ss)/ (GLdouble) (ss-1));
glVertex2d(x, 700.0);
}
glEnd();
glFlush();
}
}
void init()
{
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_TEXTURE_2D);
buttonsID = LoadTexture2D("buttonsandwait.png");
MenuID = LoadTexture2D("fractals_screen.png");
glEnable(GL_TEXTURE_1D);
palID = LoadTexture2D("gradient1.png");
}

and here is the output:

This topic is closed to new replies.

Advertisement