Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (516)
Games in Android Showcase (122)
games submitted by our members
Games in WIP (577)
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  
  [SOLVED] Gaps between tiles in motion?  (Read 2710 times)
0 Members and 1 Guest are viewing this topic.
Offline Mac70
« Posted 2013-01-08 21:13:13 »

Like in topic. I have problem with gaps between tiles in motion. When you move camera you can see white gaps between tiles. You can sometimes see them when camera is staying in one place, too. I can't find any solution for this problem, I hav found only one way to make it less visible (replacing GL_NICEST with GL_NEAREST in texture creating texParameters, increasing rendering coordinates by 0,1f - after this changes you can see this bug only when camera is moving).

EDIT: Problem is solved. Thanks for all help!

Check out my Devblog! Smiley
Offline davedes
« Reply #1 - Posted 2013-01-08 22:12:32 »

What are you using GL_NICEST for?!

Most of the time "bleeding" has to do with which pixels GL samples from when rendering. See here:
http://www.java-gaming.org/topics/bleeding/26823/msg/237162/view.html#msg237162

Offline Mac70
« Reply #2 - Posted 2013-01-08 22:27:05 »

Now my texture creating code and displaying textures looks like this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
    public static int create(TextureHolder tex) {
        int uniqueId = glGenTextures();
        glBindTexture(GL_TEXTURE_2D, uniqueId);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width, tex.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        return uniqueId;
    }

    public static void draw(Tex tex, float x, float y, float angle) {
        glBindTexture(GL_TEXTURE_2D, tex.ID);
        glPushMatrix();
            glTranslatef(x, y, 0);
            glRotated(angle/(Math.PI/180), 0, 0, 1);
            glBegin(GL_QUADS);
                glColor4f(1,1,1,1);
                glTexCoord2f(tex.minBindX,tex.maxBindY); glVertex2f(-tex.width/2-0.1f, -tex.height/2-0.1f);
                glTexCoord2f(tex.minBindX,tex.minBindY); glVertex2f(-tex.width/2-0.1f, tex.height/2+0.1f);
                glTexCoord2f(tex.maxBindX,tex.minBindY); glVertex2f(tex.width/2+0.1f, tex.height/2+0.1f);
                glTexCoord2f(tex.maxBindX,tex.maxBindY); glVertex2f(tex.width/2+0.1f, -tex.height/2-0.1f);
            glEnd();
        glPopMatrix();
    }


This leads to white lines "blinking" when scrolling and sometimes when camera is not moving anyway, like in screen below:


Check out my Devblog! Smiley
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline theagentd
« Reply #3 - Posted 2013-01-08 23:44:31 »

Seems like floating point rounding errors in your vertex positions. Try to make each tile slightly larger than they are.

Myomyomyo.
Offline Mac70
« Reply #4 - Posted 2013-01-08 23:51:18 »

Seems like floating point rounding errors in your vertex positions. Try to make each tile slightly larger than they are.

Already tried it, this makes nothing but more problems with another things and doesn't fix main problem.

Check out my Devblog! Smiley
Offline theagentd
« Reply #5 - Posted 2013-01-09 00:50:49 »

Try to feed the coordinates directly into glVertex() instead of moving the matrix. That should also be faster.

Myomyomyo.
Offline Mac70
« Reply #6 - Posted 2013-01-09 23:58:16 »

Try to feed the coordinates directly into glVertex() instead of moving the matrix. That should also be faster.

Could you explain this?

Check out my Devblog! Smiley
Offline theagentd
« Reply #7 - Posted 2013-01-10 00:28:47 »

You need to calculate mathematically identical vertices the exact same way, or floating point errors will make them slightly different. For example, x*2 might not exactly equal x+x. It's all a lot more complicated since you translate a matrix inbetween and all.

Basically, change your tiles so that they're drawn like this:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
//mapWidth and mapHeight are the size of the tile map in tiles, not pixels.
glBegin(GL_QUADS);
for(int y = 0; y < mapHeight; y++){
    for(int x = 0; x < mapWidth; x++){
        glTexCoord2f(...); glVertex2f(x * tileWidth, y * tileHeight);
        glTexCoord2f(...); glVertex2f((x + 1) * tileWidth, y * tileHeight);
        glTexCoord2f(...); glVertex2f((x + 1) * tileWidth, (y + 1) * tileHeight);
        glTexCoord2f(...); glVertex2f(x * tileWidth, (y + 1) * tileHeight);
    }
}
glEnd();


Note how the vertex positions are calculated. It's important that you write it the same way as I did here. Do NOT write
x * tileWidth + tileWidth
since that is exactly what you need to avoid.

Myomyomyo.
Offline Mac70
« Reply #8 - Posted 2013-01-10 15:17:13 »

Despite the changes I don't see any difference. Maybe is this related to camera? (game must be zoomable or at least scrollable)

Check out my Devblog! Smiley
Offline theagentd
« Reply #9 - Posted 2013-01-10 15:28:02 »

Despite the changes I don't see any difference. Maybe is this related to camera? (game must be zoomable or at least scrollable)
If that still gives you seams, then you're not doing it correctly. 3D games never have seams in their models, right? Could you post your tile rendering code again?

Myomyomyo.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Mac70
« Reply #10 - Posted 2013-01-10 15:51:41 »

All codes taking part in rendering:

Texture creation and rendering

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
public static int create(TextureHolder tex) {
        int uniqueId = glGenTextures();
        glBindTexture(GL_TEXTURE_2D, uniqueId);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width, tex.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        return uniqueId;
    }
   
    public static void draw(Tex tex, float x, float y, float angle) {
        glBindTexture(GL_TEXTURE_2D, tex.ID);
        glPushMatrix();
            glTranslatef(x, y, 0);
            glRotated(angle/(Math.PI/180), 0, 0, 1);
            glBegin(GL_QUADS);
                glColor4f(1,1,1,1);
                glTexCoord2f(tex.minBindX,tex.maxBindY); glVertex2f(-tex.width/2-0.1f, -tex.height/2-0.1f);
                glTexCoord2f(tex.minBindX,tex.minBindY); glVertex2f(-tex.width/2-0.1f, tex.height/2+0.1f);
                glTexCoord2f(tex.maxBindX,tex.minBindY); glVertex2f(tex.width/2+0.1f, tex.height/2+0.1f);
                glTexCoord2f(tex.maxBindX,tex.maxBindY); glVertex2f(tex.width/2+0.1f, -tex.height/2-0.1f);
            glEnd();
        glPopMatrix();
    }
   
    public static void drawTiles(Tex tex, float x, float y, int rect) {
        glBindTexture(GL_TEXTURE_2D, tex.ID);
        glBegin(GL_QUADS);
            glColor4f(1,1,1,1);
            glTexCoord2f(tex.minBindX,tex.maxBindY); glVertex2f(x*rect, y*rect);
            glTexCoord2f(tex.minBindX,tex.minBindY); glVertex2f(x*rect, (y+1)*rect);
            glTexCoord2f(tex.maxBindX,tex.minBindY); glVertex2f((x+1)*rect, (y+1)*rect);
            glTexCoord2f(tex.maxBindX,tex.maxBindY); glVertex2f((x+1)*rect, y*rect);
        glEnd();
    }


Whole camera class

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
package Core.Camera;

import Core.Logic.Logic;
import org.lwjgl.opengl.Display;
import static org.lwjgl.opengl.GL11.*;

public class Camera {
   
    public static float cameraX = 0;
    public static float cameraY = 0;
    protected static float cameraThrustX = 0;
    protected static float cameraThrustY = 0;
    protected static int cameraThrustXMax = 5;
    protected static int cameraThrustYMax = 5;
   
    public static void interfaceCamera() {
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, Display.getWidth(), 0, Display.getHeight(), 1, -1);
        glMatrixMode(GL_MODELVIEW);
    }
   
    public static void gameCamera(int width, int height) {
        if (Logic.mouse.x<15 || Logic.keyboard.LeftArrow) {
            cameraThrustX-=0.1;
            if (cameraThrustX<-cameraThrustXMax) {cameraThrustX=-cameraThrustXMax;}
        }
        else if (Logic.mouse.x>Display.getWidth()-15 || Logic.keyboard.rightArrow) {
            cameraThrustX+=0.1;
            if (cameraThrustX>cameraThrustXMax) {cameraThrustX=cameraThrustXMax;}
        }
        else {
            if (cameraThrustX>0.1) {cameraThrustX-=0.1;}
            else if (cameraThrustX<-0.1) {cameraThrustX+=0.1;}
            else {cameraThrustX=0;}
        }
        if (Logic.mouse.y<15 || Logic.keyboard.downArrow) {
            cameraThrustY-=0.1;
            if (cameraThrustY<-cameraThrustYMax) {cameraThrustY=-cameraThrustYMax;}
        }
        else if (Logic.mouse.y>Display.getHeight()-15 || Logic.keyboard.upArrow) {
            cameraThrustY+=0.1;
            if (cameraThrustY>cameraThrustYMax) {cameraThrustY=cameraThrustYMax;}
        }
        else {
            if (cameraThrustY>0.1) {cameraThrustY-=0.1;}
            else if (cameraThrustY<-0.1) {cameraThrustY+=0.1;}
            else {cameraThrustY=0;}
        }
        cameraX+=cameraThrustX;
        cameraY+=cameraThrustY;
       
        if (cameraX<-10) {cameraX=-10;}
        else if (cameraX>width*20-10-Display.getWidth()) {cameraX=width*20-10-Display.getWidth();}
       
        if (cameraY<-10) {cameraY=-10;}
        else if (cameraY>height*20-10-Display.getHeight()) {cameraY=height*20-10-Display.getHeight();}
       
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(cameraX, Display.getWidth()+cameraX, cameraY, Display.getHeight()+cameraY, 1, -1);
        glMatrixMode(GL_MODELVIEW);
    }
   
    public static void gameCameraStop(int width, int height) {
        if ((Logic.mouse.x<15 && Logic.mouse.y<15) || Logic.keyboard.LeftArrow) {
            cameraThrustX-=0.1;
            if (cameraThrustX<-cameraThrustXMax) {cameraThrustX=-cameraThrustXMax;}
        }
        else if ((Logic.mouse.x>Display.getWidth()-15 && Logic.mouse.y<15) || Logic.keyboard.rightArrow) {
            cameraThrustX+=0.1;
            if (cameraThrustX>cameraThrustXMax) {cameraThrustX=cameraThrustXMax;}
        }
        else {
            if (cameraThrustX>0.1) {cameraThrustX-=0.1;}
            else if (cameraThrustX<-0.1) {cameraThrustX+=0.1;}
            else {cameraThrustX=0;}
        }
        if ((Logic.mouse.x<15 && Logic.mouse.y<15) || (Logic.mouse.x>Display.getWidth()-15 && Logic.mouse.y<15) || Logic.keyboard.downArrow) {
            cameraThrustY-=0.1;
            if (cameraThrustY<-cameraThrustYMax) {cameraThrustY=-cameraThrustYMax;}
        }
        else if (Logic.keyboard.upArrow) {
            cameraThrustY+=0.1;
            if (cameraThrustY>cameraThrustYMax) {cameraThrustY=cameraThrustYMax;}
        }
        else {
            if (cameraThrustY>0.1) {cameraThrustY-=0.1;}
            else if (cameraThrustY<-0.1) {cameraThrustY+=0.1;}
            else {cameraThrustY=0;}
        }
       
        cameraX+=cameraThrustX;
        cameraY+=cameraThrustY;
       
        if (cameraX<-10) {cameraX=-10;}
        else if (cameraX>width*20-10-Display.getWidth()) {cameraX=width*20-10-Display.getWidth();}
       
        if (cameraY<-10) {cameraY=-10;}
        else if (cameraY>height*20-10-Display.getHeight()) {cameraY=height*20-10-Display.getHeight();}
       
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(cameraX, Display.getWidth()+cameraX, cameraY, Display.getHeight()+cameraY, 1, -1);
        glMatrixMode(GL_MODELVIEW);
    }
   
}


Fragments of GameTerrain and Tile (I am using draw there because drawTiles gives the same results):

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
public void draw() {
        toX = (int) ((Camera.cameraX+Display.getWidth())/20+1);
        if (toX<width) {toX=width;}
        toY = (int) ((Camera.cameraY+Display.getHeight())/20+1);
        if (toY<height) {toY=height;}
        for (int i=(int) Camera.cameraX/20; i<toX; i++) {
            for (int i2=(int) (Camera.cameraY/20); i2<toY; i2++) {
                if (tiles[i][i2]!=null) {
                    tiles[i][i2].draw();
                }
            }
        }


1  
2  
3  
public void draw() {
        Lib.Graphics.Texture.draw(tex, locWidth, locHeight, 0);
    }

Check out my Devblog! Smiley
Offline theagentd
« Reply #11 - Posted 2013-01-10 15:58:33 »

How did the rendering look like when you used drawTiles()?

Myomyomyo.
Offline Mac70
« Reply #12 - Posted 2013-01-10 16:07:54 »

There is 10 pixels "shift" in everything (but it can be easily fixed), at max acceleration there are gaps all the time, blinking gaps while moving and sometimes when nothing is moving, too (you must stop camera in right position, I made this in few approaches).

Check out my Devblog! Smiley
Offline theagentd
« Reply #13 - Posted 2013-01-10 16:24:06 »

Yes, but how does the CODE look?

Also, are you using a power-of-two texture?

Myomyomyo.
Offline Mac70
« Reply #14 - Posted 2013-01-10 16:30:22 »

Power-of-two-texture? No, every part of sprite sheet have size 20X20.

Code with drawTiles - it is the same for GameTerrain, but we can see differences in Tile:

1  
2  
3  
public void draw() {
        Lib.Graphics.Texture.drawTiles(tex, locWidth, locHeight, 20);
    }


Where tex contains ID of texture, locWidth - x coordinate in grid, locHeight - y coordinate, 20 - size of single grid tile.

Check out my Devblog! Smiley
Offline theagentd
« Reply #15 - Posted 2013-01-10 16:41:50 »

Are you sure the problem is that there are seems between the tiles? It could be a problem with the texture reading the tile next to it. You can test that by changing the color of the background/clear color. If the seems have that color too, they're because of the vertex coordinates. Otherwise they're because of the texture coordinates.

Exactly how is locWidth and locHeight calculated? drawTiles() should take in local tile coordinates in INTS! If you want to offset all tiles by a specific value (cameraX, cameraY I suppose), you can use glTranslatef() to do that in one call before you start rendering tiles the tiles. Just don't call glTranslatef() once for each tile.

Myomyomyo.
Offline Mac70
« Reply #16 - Posted 2013-01-10 17:45:09 »

Red background and gaps between tiles are still white. It seems that there is something wrong with texture coordinates.

This is my texture preloading from sprite sheet code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
private Tex preloadSymSprite(SpriteSheet source, float regX, float regY, float rect) {
        regX--;
        regY--;
        bind=new Tex();
        bind.ID = source.ID;
        bind.width = (int) rect;
        bind.height = (int) rect;
        float height = source.height;
        float width = source.width;
        bind.minBindX=(regX*rect)/width;
        bind.minBindY=(regY*rect)/height;
        bind.maxBindX=((regX*rect)+rect)/width;
        bind.maxBindY=((regY*rect)+rect)/height;
        return bind;
    }


Example execution:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
private void roads() {
        LT.road.upDown = preloadSymSprite(LT.road.roads, 1, 1, 20);
        LT.road.leftRight = preloadSymSprite(LT.road.roads, 2, 1, 20);
        LT.road.none = preloadSymSprite(LT.road.roads, 3, 1, 20);
        LT.road.all = preloadSymSprite(LT.road.roads, 4, 1, 20);
        LT.road.downRight = preloadSymSprite(LT.road.roads, 1, 2, 20);
        LT.road.downLeft = preloadSymSprite(LT.road.roads, 2, 2, 20);
        LT.road.upRight = preloadSymSprite(LT.road.roads, 1, 3, 20);
        LT.road.upLeft = preloadSymSprite(LT.road.roads, 2, 3, 20);
        LT.road.up = preloadSymSprite(LT.road.roads, 1, 4, 20);
        LT.road.right = preloadSymSprite(LT.road.roads, 2, 4, 20);
        LT.road.down = preloadSymSprite(LT.road.roads, 3, 4, 20);
        LT.road.left = preloadSymSprite(LT.road.roads, 4, 4, 20);
        LT.road.upDownLeft = preloadSymSprite(LT.road.roads, 4, 2, 20);
        LT.road.downLeftRight = preloadSymSprite(LT.road.roads, 3, 2, 20);
        LT.road.upDownRight = preloadSymSprite(LT.road.roads, 3, 3, 20);
        LT.road.upLeftRight = preloadSymSprite(LT.road.roads, 4, 3, 20);
    }


Can be something wrong in there? I checked sprite sheet .png, it seems that there is nothing wrong with it (everything is pixel perfect).

EDIT: It MUST be problem with texture coordinates. Debug drawing code below is perfect. Now question what is the cause of the problem...

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
public static void draw(Tex tex, float x, float y, float angle) {
        glBindTexture(GL_TEXTURE_2D, tex.ID);
        glPushMatrix();
            glTranslatef(x, y, 0);
            glRotated(angle/(Math.PI/180), 0, 0, 1);
            glBegin(GL_QUADS);
                glColor4f(1,1,1,1);
                glTexCoord2f(tex.minBindX+0.0001f,tex.maxBindY-0.0001f); glVertex2f(-tex.width/2, -tex.height/2);
                glTexCoord2f(tex.minBindX+0.0001f,tex.minBindY+0.0001f); glVertex2f(-tex.width/2, tex.height/2);
                glTexCoord2f(tex.maxBindX-0.0001f,tex.minBindY+0.0001f); glVertex2f(tex.width/2, tex.height/2);
                glTexCoord2f(tex.maxBindX-0.0001f,tex.maxBindY-0.0001f); glVertex2f(tex.width/2, -tex.height/2);
            glEnd();
        glPopMatrix();
    }

Check out my Devblog! Smiley
Offline theagentd
« Reply #17 - Posted 2013-01-10 18:33:15 »

Then it's probably because you're using a non-power-of-two texture. If you think about how floating point values work, you realize that they can only hold exact coordinates for X/(power of two) values. If you have a non-power-of-two texture, for some pixels the values might be rounded over a tile border and end up on the wrong tile. With power-of-two textures that should be impossible since the rounding follows conventions when sampling pixels on exact texel edges.

EDIT: In other words, try to pad the texture to make it a power-of-two sized.
EDIT2: Or use a texture rectangle instead, which takes unnormalized texture coordinates.

Myomyomyo.
Offline davedes
« Reply #18 - Posted 2013-01-10 18:51:37 »

Just a note... if you are using Slick's texture loader, it will pad non-power-of-two textures for you with black transparent pixels. This may lead to bleeding in some cases, along the edge of the image's texture region.

For seamless tiles you can also pre-process your sprite sheets and mirror the texture edges, as described in the post I linked earlier. LibGDX's TexturePacker-GUI can do this for you, or you could write your own tool fairly easily with Java2D.

Of course the ideal solution would be to use texture arrays and GL_CLAMP_TO_EDGE, but that requires GL3+.

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

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

TehJavaDev (31 views)
2014-10-27 03:28:38

TehJavaDev (26 views)
2014-10-27 03:27:51

DarkCart (40 views)
2014-10-26 19:37:11

Luminem (21 views)
2014-10-26 10:17:50

Luminem (26 views)
2014-10-26 10:14:04

theagentd (32 views)
2014-10-25 15:46:29

Longarmx (61 views)
2014-10-17 03:59:02

Norakomi (57 views)
2014-10-16 15:22:06

Norakomi (46 views)
2014-10-16 15:20:20

lcass (43 views)
2014-10-15 16:18:58
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
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!