iPhone Opengl Es 2.0 - Pixel Perfect Textures

iPhone OpenGL ES 2.0 - Pixel Perfect Textures

See my answer here: OpenGL Texture Coordinates in Pixel Space


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.

OpenGL ES 2.0 Rendering with a Texture

There's a nice tutorial on this in the web site to go with the book OpenGL ES 2 The examples from the book are all at www.opengles-book.com.

Chapter 9, Simple_Texture2D does exactly what you want. It sets up a shader that samples a texture, initializes it, and shades the triangles using the texture.

The shader program is close to:

varying vec2 v_texCoord;
uniform sampler2D s_texture;
void main() {
gl_FragColor = texture2D(s_texture, v_texCoord);
}

and you set it up thusly:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, userData->textureId);
// Set the sampler texture unit to 0
glUniform1i(userData->samplerLoc, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);

But see the actual code, from the links I gave above, to really see the example.

OpenGL Texture Coordinates in Pixel Space

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.

Unable to load multiple textures in opengl es 2.0

The long of the short of it: make sure you assign textures to samplers -after- the shader is loaded. I was tricked into thinking uniforms[] is assigned correctly because I was only checking it after all loading had completed.

Distortion with 'pixel accurate' OpenGL rendering of sprites

[(EAGLView *)self.view setContentScaleFactor:2.0f];

By default, iPhone windows do scaling to reach their high resolution modes. Which was destroying my image quality ..

Thanks for all the help folks

Avoiding texture switching (openGL es 2.0)

Assuming you have evidence of a real performance issue (and you shouldn't bother with this unless you do), the solution is quite easy: use your depth buffer.

Use an orthographic projection so that sprites don't get bigger/smaller when they move forward. Give each sprite a depth value, and let the depth test remove unwanted parts of sprites.



Related Topics



Leave a reply



Submit