Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

9 years ago by EnMod

Hello all,

I've started making a test TwoPointFive game using the included Super Blob Blaster as a base. However, I've noticed seams like these popping up, moreso when my tilesize was 16px. It's currently 64px: http://imgur.com/a/MGf46

The seams (or whatever they are) are the blue lines in each screenshot. Any ideas?

9 years ago by stahlmanDesign

Does it happen in all browsers? Try these different CSS styles on the canvas element. I apply all of them to get the pixel look (no anti-aliasing).

image-rendering: optimizeSpeed;              /* Older versions of FF */
image-rendering: -moz-crisp-edges;           /* FF 6.0+ */
image-rendering: -webkit-optimize-contrast;  /* Webkit (non standard naming) */
image-rendering: -o-crisp-edges;             /* OS X & Windows Opera (12.02+) */
image-rendering: crisp-edges;                /* Possible future browsers. */
-ms-interpolation-mode: nearest-neighbor;    /* IE (non standard naming) */
image-rendering: pixelated;					/* Chrome 41 */

9 years ago by EnMod

It happens in Chrome and Firefox, yes. Strangely it doesn't happen in IE, but that has its own share of issues that I'm not as concerned about. After applying these styles the issue persists unchanged, unfortunately.

9 years ago by Joncom

Is your project tracked in Git? If so, since the issue (probably) does not occur in the official project, you could try to isolate the commit where the issue begins, and then see what code triggers the issue.

9 years ago by EnMod

Unfortunately I haven't made enough smaller commits for that to be helpful, I think. consequence of my workflow I guess lol. what I did notice was that the color of each "seam" was actually the color of the rightmost single pixels of the tile located directly to the left of the tiles used for the walls/ceiling.

This leads me to believe that Impact is somehow reading the tileset 1 pixel to the left, when in fact everything should be good. I'm going to look at my tileset dimensions, since I've noticed similar problems with tilesets being misread when dimensions aren't perfect multiples

Edit: Welp those seem to be fine so...idk. Maybe it's the renderer...my tileset is rather big.

9 years ago by Joncom

Quote from EnMod
Unfortunately I haven't made enough smaller commits for that to be helpful, I think. consequence of my workflow I guess lol.
It's not too late. You could create a new branch and start working your way back toward the vanilla example project. Just remove big or small chunks of code, and then commit. Continue repeating this until the issue goes away.

It's one possible method anyway...

9 years ago by EnMod

That's a good option, I am still new to the intricacies of Git and hadn't thought of that. Thanks!

EDIT: I've compared my current master and the branch for the example...I made no changes to visuals from what I could see. I'm going to try something in the Blob Blaster demo default tileset to produce the lines, which I think are caused by strange pixel offsetting. If I'm correct, I will see a straight line across the left edge of the ceiling. Will post results in a new post.

9 years ago by EnMod

I have found that this visual anomaly exists in the code of the demo itself, but appears less noticeable due to the color scheme in the demo's tileset. I added a 1px line of contrasting color to the left of ceiling tiles in the Blob demo to test my theory, which produced the anomaly:

/><br />
<br />
It can be mitigated for the default tileset by changing line 101 of TwoPointFive's renderer.js to have NEAREST filtering, as per this thread: <a href=http://impactjs.com/forums/impact-engine/twopointfive-mip-mapping-problem

However, when I pop in my tileset and use it instead for walls/ceilings the anomaly is much more noticeable due to the contrasting colors I have in it. The same area as seen above, using my tileset, with LINEAR filtering:

/><br />
<br />
When I change the filtering to NEAREST, it makes the anomaly more noticeable when it appears, but only at certain positions. while walking there are flickering lines everywhere because of the color bleed popping in and out of existence.  I had to move around to get a sizeable sample for this shot:<br />
<br />
<img src=http://apps.noelquiles.com/tpfproblem

It's using everything from the demo except the environment tileset, which I replaced with mine for showing the anomaly better.

9 years ago by EnMod

Just a bump, and sorry for triple post (not sure of the ettiquette for calling attention to a post other than bumps), but if @dominic or anyone else with TPF knowledge could help me on how to rid myself of this issue I would be ecstatic.

9 years ago by Joncom

That does look unsightly. If you have Twitter, you could tweet @phoboslab (Dominic) directly? He seems to be more active there than here.

9 years ago by EnMod

Good call, just sent him a tweet. Here's hoping it's a simple fix

9 years ago by dominic

Yeah, that's color bleed from neighboring tiles. It's most noticeable if you have tiles with very different colors next to each other in the tileset image. Unfortunately, I was never able to completely fix this.

The gist of the problem is that OpenGL (and WebGL for that matter) sample textures with "sub pixel" accuracy, exactly where you tell it to. I.e. consider this 8x8px tileset:

/><br />
<br />
If you want to draw the 2nd tile, you&<code>039;d tell WebGL to take the part of the texture that starts at #(8,0)</code> to <code>(16, 8)</code>. Notice however, that in the image above, that the coordinates <code>(8,0)</code> are right <em>between</em> the two tiles. The rectangle that you actually want to draw starts at <code>(8.00001, 0)</code> to <code>(15.99999, 7.99999)</code>. For <code>bilinear</code> texture filtering, taking the point right between the two tiles is actually much more noticeable, because it will sample the neighboring pixels in all directions. With <code>nearest</code> filtering and perfect accuracy, this shouldn't be visible at all - in theory.<br />
<br />
However, in WebGL texture coordinates are normalized and represented as floating point, meaning the top left corner of the texture is at <code>(0.0, 0.0)</code> while the bottom right corner is always at <code>(1.0, 1.0)</code>, regardless of the texture&<code>039;s size. In the example the texture coordinates for the 2nd tile are #(0.0, 0.5)</code> to <code>(0.5, 1.0)</code>. Under some circumstances, this introduces rounding errors.<br />
<br />
Curiously, this doesn't happen in IE, because IE uses Direct3D to draw WebGL stuff, instead of OpenGL like Firefox and Chrome does. Also, for OpenGL it may be more or less noticeable on different hardware. Intel GPUs are usually the worst offenders here.<br />
<br />
Sooo, there are a couple of ways to work around this:<br />
<br />
1) Avoid having tiles with very different colors next to each other in the tileset<br />
<br />
2) Use a size for the whole tileset that is a power of two. I.e. 64, 128, 256, 512 etc. The tileset doesn't have to be quadratic, e.g. 512x64 is fine. This circumvents most floating point rounding errors.<br />
<br />
As an example, imagine 8x8 pixel tiles and a tileset that is 48px wide. If you want to draw the 2nd tile, starting at <code>(8, 0)</code>, this would be represented as floating point <code>(0.1666666, 0.0)</code> - i.e. it can&<code>039;t be represented _exactly_. If your tileset was 64px wide instead, it would be floating point #(0.125, 0.0)</code>, which can be represented exactly.<br />
<br />
3) Nudge the texture coordinates for each tile inwards a bit. Maybe by half a pixel. This can be done in <a href= plugins/twopointfive/world/tile.js for setTile() and setTileInBuffer().

Untested:
var nudge = 0.5;
var tx = (Math.floor(t * this.tileWidth + nudge) % this.image.width) / this.image.width,
	ty = (Math.floor(t * this.tileWidth / this.image.width) * this.tileHeight + nudge) / this.image.height,
	wx = (this.tileWidth - nudge*2) / this.image.width,
	wy = (this.tileHeight - nudge*2) / this.image.height;

However, this may introduce some other visual artifacts - i.e. the very edge of your tiles not being drawn, or being noticeably thinner than they should. This is more noticable the smaller your tilesize is.


If anyone finds a solution that works universally, please let me know!

Related google search. In particular, this article explains the problem pretty well, but none of the proposed solutions actually fixed the problem completely :/

9 years ago by EnMod

Wow, thanks for this very thorough response!

Fascinating to know these obscure quirks of WebGL, very important info. Unfortunate that there isn't a surefire fix for it...

I do have some status reports now that I've tried your last two recommendations.

After refactoring my tileset to fit 512x1024 as per the second recommendation, it turns out that the error remains. Here it is with jumbled tile coordinates, since I didn't use the right level when saving my tile coordinate changes for the new set lol. It's for the best though since the error is more clearly shown, I think. You can see it on the floor and on the walls.

I then tried the third recommendation, and it seemed to work but then I noticed the error persisted on the walls and on the ceiling somewhat while walking. You can go here for the build. The floor seems to be fixed though, likely a result of the tile thinning done by the nudge.

I saved the first recommendation for last as I'm tired of refactoring my tileset lol. I've been a perfectionist with it during this project and have done so more than a few times for organization purposes. I feel like it would flow better if I did indeed reorganize to remove contrast. I'll try that after I get any feedback on these by those reading this topic, and I feel that the first recommendation is the only way to avoid the problem entirely.

Thanks again for putting together that explanation!

9 years ago by dominic

Try a higher nudge value. Since your tileset seems to be scaled up 4x anyway (why?), you should be fine with 1 or 2, instead of 0.5.

var nudge = 1;
var tx = (Math.floor(t * this.tileWidth + nudge) % this.image.width) / this.image.width,
    ty = (Math.floor(t * this.tileWidth / this.image.width) * this.tileHeight + nudge) / this.image.height,
    wx = (this.tileWidth - nudge*2) / this.image.width,
    wy = (this.tileHeight - nudge*2) / this.image.height;

9 years ago by EnMod

Oh I had scaled it up thinking the tilesize was the issue with regard to the visual error, this was a long time ago lol. I think I'll scale it back down to reduce bloat in that case since I now know what the error is, thanks to your explanation. I'll try the nudge again after that.

9 years ago by dominic

Sooooo, I thought a bit more about this problem and came up with a solution. It's not very elegant, but it seems to work!

Before using the tileset, TwoPointFive now draws a 1px border around each tile. This border is copy of the neighboring row/column of this tile. WebGL can now safely sample the texture close or outside the tile borders and still get a visual consistent result, as if each tile was a separate, clamped texture.

This all happens during load time. So while it may use a bit more memory to juggle the tilesets around, it wont have any effect on drawing performance.

New version on Github (also see the updated readme.md):
https://github.com/phoboslab/twopointfive ( changes)

9 years ago by EnMod

Very cool, can confirm it's certainly working for me! Hopefully in the future there's a low-level way around it on the OpenGL end at some point in the future.

Thanks as always for your work, Dominic, and thanks again to everyone in this thread!
Page 1 of 1
« first « previous next › last »