Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (736)
Games in Android Showcase (223)
games submitted by our members
Games in WIP (813)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  [LWJGL] problem with alpha texture and GL_LINEAR rendering  (Read 2450 times)
0 Members and 1 Guest are viewing this topic.
Offline Egraynn

Senior Newbie


Exp: 15 years



« Posted 2014-05-07 12:03:23 »

Hello!

I'm using lwjgl to render a 2D scene. The map is based on blocks referencing textures.

here is the init code for orthographic view and alpha channel;
1  
2  
3  
4  
5  
6  
7  
8  
      GL11.glMatrixMode(GL11.GL_PROJECTION);
      GL11.glLoadIdentity();
      GL11.glOrtho(0, W, H, 0, 1, -1);
      GL11.glMatrixMode(GL11.GL_MODELVIEW);      

      GL11.glEnable(GL11.GL_TEXTURE_2D);
      GL11.glEnable(GL11.GL_BLEND);
      GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);


the textures are loaded (then all mipmap levels are generated), they have the following parameters:
1  
2  
3  
4  
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, id);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
    GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, w, h, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);


I tried the alternatives to LINEAR and LINEAR_MIPMAP_LINEAR modes with NEAREST but so far I see rendering artifacts when the textures are scaled (zoom in or out).

Here are some examples of what I get with linear interpolation:



These are some basic textures with a strong zoom. As you can see there are artifacts on the border of the bloc, a dark semi-transparent line which comes from a pixel mix with the opposite side of the texture (dark lines can also be seen at the transition between opaque and transparent zones but are less problematic). I checked that the original textures do not include those artifacts.

So the default linear pixel mixing openGL function really does not seem appropriate to just draw scaled alpha textures Huh Isn't that weird ? Is there a solution to remove those unwanted lines ? Does it require some GLSL code or is there a standard method ? (Would the result be the same if I used a 3D projection matrix instead of an orthogonal one ?)

Thanks for reading Smiley
Offline theagentd
« Reply #1 - Posted 2014-05-07 14:01:16 »

This is caused by linear interpolation of both RGB and alpha. The problem is that your transparent pixels have a different color. Consider two texels in your texture next to each other. One has the color (0, 0, 0, 0) which is transparent so the actual color <shouldn't> matter. The second one has the color (1, 1, 1, 1). Let's say that the pixel you're rendering is sampling the texture at exactly the point inbetween these two texels. With GL_LINEAR blending, you end up with an even mix between these two colors. The intuitive result you're expecting is (1, 1, 1, 0.5) which is the color of the opaque texel (white) but with 50% transparency, but what you're actually getting is
    ((0, 0, 0, 0) * 0.5 + (1, 1, 1, 1) * 0.5) = (0.5, 0.5, 0.5, 0.5)

The more transparent the color gets, the more you mix in the hidden color of the transparent texel, which is usually black. Let's say that we're blending this color with a white background, (1, 1, 1, 1). The result with your current blend function is then
    ((0.5, 0.5, 0.5, 0.5) * srcAlpha + (1, 1, 1, 1) * (1-srcAlpha))

srcAlpha is simply the alpha of the incoming color, 0.5, so the result is
    ((0.5, 0.5, 0.5, 0.5) * 0.5 + (1, 1, 1, 1) * (1-0.5)) = ((0.25, 0.25, 0.25, 0.25) + (0.5, 0.5, 0.5, 0.5) = (0.75, 0.75, 0.75, 0.75)

Boom, blending a "white" color onto a white background resulted in gray! Also note that we actually made the framebuffer transparent even though it was 100% opaque before we added a transparent color on top of it.



The solution is to use premultiplied alpha. The idea is to move the multiplication by srcAlpha to when the texture is loaded. When loading in your texture, simply multiply R, G and B by the alpha of the pixel and leave the alpha intact. Here's an example of a function which takes in an int pixel from a BufferedImage and converts it to premultiplied RGBA bytes.

1  
2  
3  
4  
5  
6  
7  
8  
9  
        public void handlePixel(ByteBuffer b, int pixel) {
            int rawAlpha = (pixel >> 24) & 0xFF; //0 - 255
            float a = rawAlpha / 255f; //0.0 - 1.0
           
            b.put((byte) Math.round(((pixel >> 16) & 0xFF) * a));
            b.put((byte) Math.round(((pixel >> 8) & 0xFF) * a));
            b.put((byte) Math.round((pixel & 0xFF) * a));
            b.put((byte) rawAlpha);
        }


Since we've already multiplied the colors in our textures by the alpha, we no longer need to do so after blending anymore. We therefore change our blend function to (GL_ONE, GL_ONE_MINUS_ALPHA). What happens if we go through the above steps again, mixing a transparent texel with an opaque texel? Our premultiplication didn't do much to our two texels. (0*0, 0*0, 0*0, 0) is still (0, 0, 0, 0) and (1*1, 1*1, 1*1, 1) is still just (1, 1, 1, 1). The premultiplication is necessary when using more interesting colors though, so don't skip it! Anyway, after interpolation, we get the same even mix between these two texels as before:
    ((0, 0, 0, 0) * 0.5 + (1, 1, 1, 1) * 0.5) = (0.5, 0.5, 0.5, 0.5)

Here comes the interesting part. What happens when we blend this together with the background using the new blend function, (GL_ONE, GL_ONE_MINUS_ALPHA)?

    ((0.5, 0.5, 0.5, 0.5) * 1 + (1, 1, 1, 1) * (1-0.5)) = ((0.5, 0.5, 0.5, 0.5) + (0.5, 0.5, 0.5, 0.5) = (1.0, 1.0, 1.0, 1.0)

Adding white to white resulted in white! And the surface is still opaque! Wooh!

Myomyomyo.
Offline Egraynn

Senior Newbie


Exp: 15 years



« Reply #2 - Posted 2014-05-07 15:07:24 »

Thanks a lot!

I just tested this solution and it's perfect to remove any artifact inside a bloc with abrupt alpha jumps !

However, I still have the problem with the blocs' borders.
It's obvious that when the texture of a bloc is scaled, its last line is interpolated with its first line, and its last column with its first one.
Is there anything I can do about this ?
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline theagentd
« Reply #3 - Posted 2014-05-07 15:18:14 »

Disable wrapping?

1  
2  
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


You may also want to try GL_CLAMP_TO_BORDER, which blends in (0, 0, 0, 0) at the edge. This may give a slight anti-aliasing effect, although this might be better handled by multisampling.

Myomyomyo.
Offline Egraynn

Senior Newbie


Exp: 15 years



« Reply #4 - Posted 2014-05-07 15:32:21 »

Yeah ! Excellent, now I know all that I needed to rule the gaming world, thanks !!! mouhahahahaha Grin
Offline theagentd
« Reply #5 - Posted 2014-05-07 19:12:20 »

Glad to help with your quest for world domination. =P

Myomyomyo.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 
cybrmynd (121 views)
2017-08-02 12:28:51

cybrmynd (145 views)
2017-08-02 12:19:43

cybrmynd (140 views)
2017-08-02 12:18:09

Sralse (155 views)
2017-07-25 17:13:48

Archive (625 views)
2017-04-27 17:45:51

buddyBro (734 views)
2017-04-05 03:38:00

CopyableCougar4 (1263 views)
2017-03-24 15:39:42

theagentd (1241 views)
2017-03-24 15:32:08

Rule (1217 views)
2017-03-19 12:43:22

Rule (1270 views)
2017-03-19 12:42:17
List of Learning Resources
by elect
2017-03-13 14:05:44

List of Learning Resources
by elect
2017-03-13 14:04:45

SF/X Libraries
by philfrei
2017-03-02 08:45:19

SF/X Libraries
by philfrei
2017-03-02 08:44:05

SF/X Libraries
by SkyAphid
2017-03-02 06:38:56

SF/X Libraries
by SkyAphid
2017-03-02 06:38:32

SF/X Libraries
by SkyAphid
2017-03-02 06:38:05

SF/X Libraries
by SkyAphid
2017-03-02 06:37:51
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!