Shubham Aggarwal
Shubham Aggarwal

Reputation: 121

I have encountered strange behaviour with opengl shader in iOS

I am writing opengl shader in iOS to apply image effects. I need to use a map to lookup pixels from image. Here is the code for my shader:

precision lowp float;
uniform sampler2D u_Texture;
uniform sampler2D u_Map; //map

varying highp vec2 v_TexCoordinate;

void main()
{
     //get the pixel
     vec3 texel = texture2D(u_Map, v_TexCoordinate).rgb;
     gl_FragColor = vec4(texel, 1.0);
}

Above is a test shader which should show up the map that is being used.

Now, here is the behaviour of above shader with two maps

MAP_1 pixel size (256 x 1)

MAP_1 (256x1)

and here is the output using above shader:

Output with MAP_1

MAP_2 pixel size (256 x 3) MAP_2

and here is the output:

enter image description here

So, while using the map of 256 x 1 pixel it works as it should but on using the map of 256 x 3 pixel it shows up the black image. I have tested this well with other maps too and encountered that it is because of the pixel height of the map.

Here is the code on how I am loading the map:

+ (GLuint)loadImage:(UIImage *)image{
//Convert Image to Data
GLubyte* imageData = malloc(image.size.width * image.size.height * 4);
CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();

CGContextRef imageContext = CGBitmapContextCreate(imageData, image.size.width, image.size.height, 8, image.size.width * 4, genericRGBColorspace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, image.size.width, image.size.height), image.CGImage);

//Release Objects
CGContextRelease(imageContext);
CGColorSpaceRelease(genericRGBColorspace);

//load into texture
GLuint textureHandle;
glGenTextures(1, &textureHandle);
glBindTexture(GL_TEXTURE_2D, textureHandle);
[GLToolbox checkGLError:@"glTextureHandle"];
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.size.width, image.size.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
[GLToolbox checkGLError:@"glTexImage2D"];

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//Free Image Data
free(imageData);

return textureHandle;}

I am not sure why this is happening. May be, I am doing something wrong in loading the Map of size 256x3. Someone, please show me the way up to fix above issue.

Thanks in advance.

Upvotes: 1

Views: 48

Answers (1)

Columbo
Columbo

Reputation: 6766

In OpenGLES2, non-power-of-two textures are required to have no mipmaps (you're fine there) and use GL_CLAMP_TO_EDGE (I think this is your problem). From here:

Similarly, if the width or height of a texture image are not powers of two and either the GL_TEXTURE_MIN_FILTER is set to one of the functions that requires mipmaps or the GL_TEXTURE_WRAP_S or GL_TEXTURE_WRAP_T is not set to GL_CLAMP_TO_EDGE, then the texture image unit will return (R, G, B, A) = (0, 0, 0, 1).

You don't set the wrap mode, but from the same document:

Initially, GL_TEXTURE_WRAP_S is set to GL_REPEAT.

To fix, set the wrap mode to GL_CLAMP_TO_EDGE, or use a 256x4 texture instead of 256x3 (I'd lean toward the latter unless there's some obstacle to doing so, GPUs love powers of two!).

Upvotes: 2

Related Questions