OpenGL Texture Coordinates in Pixel Space

2019-01-01 11:43发布

问题:

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);

回答1:

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.



回答2:

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

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)


回答3:

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.