Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 4 of 4

Thread: glGetTexImage yields slanted image with wrong content (no GL_(UN)PACK_ALIGNMENT!)

  1. #1
    Intern Contributor Brokenmind's Avatar
    Join Date
    Feb 2014
    Location
    Aachen / Germany
    Posts
    78

    Question glGetTexImage yields slanted image with wrong content (no GL_(UN)PACK_ALIGNMENT!)

    Hey guys,

    render to texture, awesome. Beautiful stuff can be made with some Perlin Noise. Imagine a metal cube with a procedural texture:


    So now I want to extract the texture, with glTexImage2D or, in my case (openTK) it's GL.TexImage2D. Result looks like this:


    I've read through tons of posts, most of which resulted in the usage of glPixelStorei(GL_UNPACK_ALIGNMENT, 1). It was also mentioned that this is a common problem for textures that are no power of 2, but in my case, I can't extract the data no matter how big the texture is.

    This is all the relevant code leading to the texture extraction:
    Code :
    int dimension = 100; // can be any number
     
    // create render target
    int screenRenderFBO = GL.GenFramebuffer();
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, screenRenderFBO);
    DrawBuffersEnum renderTarget = DrawBuffersEnum.ColorAttachment0;
     
    GL.ActiveTexture(TextureUnit.Texture0);
    int createdTextures[i] = GL.GenTexture();
    GL.BindTexture(TextureTarget.Texture2D, createdTexture);
     
    GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, dimension, dimension, 0, PixelFormat.Rgba, PixelType.Byte, IntPtr.Zero);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
    GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
     
    GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, createdTexture, 0);
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);

    Code :
    // bind render target
    // assuming viewport stays the same
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, screenRenderFBO);
    GL.DrawBuffers(1, renderTarget);
     
    // do drawing code, I assume it works because the displayed texture is perfectly fine
     
    // extract texture
    byte[] pixels = new byte[dimension * dimension * 4];
    IntPtr pixelAddress = Marshal.UnsafeAddrOfPinnedArrayElement(pixels, 0);
     
    GL.ActiveTexture(TextureUnit.Texture0);
    GL.BindTexture(TextureTarget.Texture2D, createdTexture);
     
    GL.GetTexImage(TextureTarget.Texture2D, 0, PixelFormat.Bgra, PixelType.UnsignedByte, pixelAddress);
     
    Bitmap bmp = new Bitmap(texture.Width, texture.Height, 8, PixelFormat.Format32bppRgb, pixelAddress);
    bmp.Save(...)

    I tried using every combination of glPixelStorei(GL_(UN)PACK_ALIGNMENT, 1|2|4|8) and it did not change a thing, but I have to say I don't really understand when exactly to use it. But with textures sized power of two, it should work without, right?
    I also tried drawing the texture and then reading it with glReadPixels, the result was the exact same. Also, the colors are not only distorted in the Bitmap, but already before in the pixels array, so that should not be the problem.

    Seeing the slanted image (the lines have a slope of exactly 0.5, in case that's important), I get the feeling that the mistake must be very obvious. I just hope the problem does not lie within openTK because in that case, good luck waiting for a fix...

    If you have any idea what's going on here, please help!

    Regards,
    Brokenmind
    Last edited by Brokenmind; 05-30-2017 at 11:19 AM.

  2. #2
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,463
    If you're retrieving RGBA data, an alignment of 4 (the default) is fine regardless of the texture width, as each pixel will be 4 bytes.

    Are you sure that you aren't skewing the image in the rendering process? How are you determining fragment location? Interpolated vertex coordinates or gl_FragCoord?

  3. #3
    Intern Contributor Brokenmind's Avatar
    Join Date
    Feb 2014
    Location
    Aachen / Germany
    Posts
    78
    I'm quite sure because the top screenshot was taken directly from the openGL window.. so I reckon it has to be right, right? Vertex shader looks like this
    Code :
    #version 330
     
    layout(location = 0) in vec2 pos;
    out vec2 coord;
     
    void main()
    {
    	coord = pos.xy;
    	gl_Position = vec4(pos, 0, 1);
    }
    with pos going from (-1,-1) around counterclockwise, and no other transformation is applied to out vec2 coord apart from going a bit left and right for that nice smoothing effect (in the noise algorithm only). Anything else I might have missed?

  4. #4
    Intern Contributor Brokenmind's Avatar
    Join Date
    Feb 2014
    Location
    Aachen / Germany
    Posts
    78

    Problem solved!

    Quote Originally Posted by Brokenmind View Post
    Also, the colors are not only distorted in the Bitmap, but already before in the pixels array, so that should not be the problem.
    Assumptions can be so wrong... looks like I didn't see the error before. The pixel retrieval worked all along
    Converting RGB data to a proper Bitmap (without SetPixel!) is a bit tricky, but if anyone ever has the same problem, here goes:
    Code :
    public static Image ExtractTexture(TextureWrapper texture)
    {	
    	byte[] pixels = new byte[texture.Width * texture.Height * 3];
     
    	texture.Bind();
     
    	// has to be BGR because weird color shift otherwise
    	GL.GetTexImage<byte>(TextureTarget.Texture2D, 0,
    		OpenTK.Graphics.OpenGL.PixelFormat.Bgr, PixelType.UnsignedByte, pixels);
     
    	Bitmap bmp = new Bitmap(texture.Width, texture.Height);
    	BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
    		System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
    	IntPtr ptr = data.Scan0;
     
    	// same as memcpy
    	Marshal.Copy(pixels, 0, ptr, texture.Width * texture.Height * 3);
     
    	bmp.UnlockBits(data);
    	// flip due to different alignment
    	bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
     
    	return bmp;
    }

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •