Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL Texture Coordinates in Pixel Space

I'm working on an iPhone app that uses OpenGL ES 2 for its drawing. I know that typically texture coordinates are defined in the 0-1 range, but ideally I'd like to map them from 0-1023 (the size of my TextureAtlas) for readability's sake. I've seen sample code that defines coordinates in this manner, but haven't been able to suss out what previous calls were made that allowed for this. glMatrixMode(GL_TEXTURE) seems like it might be involved, but I'm not quite sure how to implement it.

My end goal would be to accomplish something like this, where the texture I'd be using within the atlas is in the upper left 48px square:

GLshort texcoords[]={
  48,48,
  0,48,
  48,0,
  0,0,
};
glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GL_SHORT, 0, 0, texcoords);
glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON);
like image 351
Sam Avatar asked May 04 '11 06:05

Sam


People also ask

What are texture coordinates used for in OpenGL?

Texture coordinates specify the point in the texture image that will correspond to the vertex you are specifying them for. Think of a rectangular rubber sheet with your texture image printed on it, where the length of each side is normalized to the range 0-1.

How do you show textures in OpenGL?

in display() function : GLuint texture; texture = LoadTexture("bubble. png"); glBindTexture(GL_TEXTURE_2D, texture);

Which texture filtering option allows you to clearly see the pixels of a texture?

GL_NEAREST (also known as nearest neighbor or point filtering) is the default texture filtering method of OpenGL. When set to GL_NEAREST , OpenGL selects the texel that center is closest to the texture coordinate. Below you can see 4 pixels where the cross represents the exact texture coordinate.


3 Answers

This has been asked a few times, but I don't have the links at hand, so a quick and rough explanation. Let's say the texture is 8 pixels wide:

 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
 ^   ^   ^   ^   ^   ^   ^   ^   ^
0.0  |   |   |   |   |   |   |  1.0
 |   |   |   |   |   |   |   |   |
0/8 1/8 2/8 3/8 4/8 5/8 6/8 7/8 8/8

The digits denote the texture's pixels, the bars the edges of the texture and in case of nearest filtering the border between pixels. You however want to hit the pixels' centers. So you're interested in the texture coordinates

(0/8 + 1/8)/2 = 1 / (2 * 8)

(1/8 + 2/8)/2 = 3 / (2 * 8)

...

(7/8 + 8/8)/2 = 15 / (2 * 8)

Or more generally for pixel i in a N wide texture the proper texture coordinate is

(2i + 1)/(2N)

However if you want to perfectly align your texture with the screen pixels, remember that what you specify as coordinates are not a quad's pixels, but edges, which, depending on projection may align with screen pixel edges, not centers, thus may require other texture coordinates.

like image 124
datenwolf Avatar answered Oct 17 '22 04:10

datenwolf


I waste 1 hour to find intuitive figure, but surprisingly nobody painted. So I did.

Given 4 pixel texture, normalized texture coordinate [0,1], unnormalized texture coordinate [0, width), gl_FragCoord [0, width] are as follows

enter image description here

Reference

  1. p270 in https://www.khronos.org/registry/gles/specs/3.1/es_spec_3.1.pdf
  2. https://www.opengl.org/sdk/docs/man/html/gl_FragCoord.xhtml
  3. https://www.opengl.org/wiki/Sampler_(GLSL)
like image 14
Huang Dongsung Avatar answered Oct 17 '22 02:10

Huang Dongsung


Turns out this is possible in OpenGl ES 2. Here's how I accomplished it:

Fragment Shader:

precision mediump float; 
varying vec2 v_texCoord;
uniform sampler2D textureSample;
uniform float texScale;
void main()
{
    vec2 mult=(2.0*v_texCoord - 1.0)/(2.0*texScale);
    gl_FragColor = texture2D(textureSample,mult);
}

Obj-C:

GLshort texCoords[]={
    512,512,
    0,512,
    512,0,
    0,0,
};
GLfloat textureWidth = 512.0; //texture size, assumed square, power of 2
texCoordLoc = glGetAttribLocation ( program, "a_texCoord");
GLuint textureScale = glGetUniformLocation ( program, "texScale");
glUniform1f(textureScale, textureWidth);
glVertexAttribPointer ( texCoordLoc, 2, GL_SHORT, GL_FALSE, 0, texCoords);

If anyone has comments on how this might work performance-wise, I would be interested.

like image 4
Sam Avatar answered Oct 17 '22 03:10

Sam