Sprites render pixels from cell next to it

There appears to be a rendering bug with sprites. It appears as though the sprite renderer is sampling pixels from the cell next to it. This is exhibited in all of the following documentation samples:

  1. Sprites from different cells: https://playground.babylonjs.com/#YCY2IL#3
  2. Sprite animation: https://playground.babylonjs.com/#YCY2IL#4
  3. Slide show animation from JSON file: https://playground.babylonjs.com/#YCY2IL#13
  4. Pick And Rotate A Selected Sprite: https://playground.babylonjs.com/#YCY2IL#9
  5. Single Layer Sprite Map From A File: https://playground.babylonjs.com/#YCY2IL#14
  6. OutputSize Changes Size And Ratio Of Plane: https://playground.babylonjs.com/#YCY2IL#17
  7. Color Multipled By Red: https://playground.babylonjs.com/#YCY2IL#19
  8. Single Tile Animation: https://playground.babylonjs.com/#YCY2IL#26
  9. Far Distance Sprite Map: https://playground.babylonjs.com/#YCY2IL#25

Here is a screenshot the bug in action:
image

I was really hoping to use Babylon for a top-down pixel art survival-crafting-exploration game :slight_smile:

Hi and welcome to the Community,

This looks to me like just a poorly designed spritesheet. The line you are seeing and qualify asā€™ a bugā€™ is simply the feets from the sprite above. Say you would change the size to 65px instead of 64px (it would of course mess everything horizontally). But the line is gone. So this is really just when designing your spritesheet. Itā€™s important you create a grid and when working with pixels (obviously) remain consistent and precise (and leave at least 1px, possibly 2px to play it safe for resize/rescale, transparent on each cell). Else, I donā€™t see anything wrong with the sprite manager.

I hope this helps and reassures you towards your project andā€¦meanwhile, have a great day :sunglasses:

Edit: Since I donā€™t like answering by making just assumptions :wink: I quickly double-checked by opening the spritesheet in PSD. Turns out I was right (check out the rulers set at 64px in this SS below from PSD on the original spritesheet).

Hereā€™s a very rushed edited version.
You can see the line is ā€˜gone with the windā€™ :grin:

https://media-geneva.ch/demos/bjs/forum/spritesheet-debug.html

3 Likes

I created a repro PG that exhibits the bug I described earlier today.

Here is a screenshot showing the source image in Aseprite and the PG. The image is 224 x 96 pixels, and the tile size is 32 pixels. I drew lines one pixel outside the cell of each of the three colored circles. When rendered by the BJS sprite class, you can see these lines even though they should not be part of the sprite cell.

In case that sprite sheet goes missing, Iā€™m attaching it here.
sprite_224x96_px_7by3cells

My assumption is that only the pixels inside the tile cell should be rendered, not the pixels outside of it. Is that not correct?

1 Like

In essence, yes. Should be. In practiceā€¦ Honestly, I also have the same issue with i.e. svg (non-related to BJS). When I draw a circle at zero pixel on the canvas and then import my svg (even in photoshop) I eventually get a bit of it thatā€™s cropped. Reason why I always leave at least 1px transparent.

You can also see it flickering when zooming in or out. Eventually the line would disappear. I believe itā€™s because there must be some rounding operation made. Now, Iā€™m shit with maths. May be this can be improved, ensuring it will never round higher than the limit. But that might also mean that the last bit could be cropped 1px (at least from my understanding).

Anyway, the Team will likely have a look at it today and answer. For whatever answer there is, I think Iā€™m gonna stick with my way of leaving 1px transparent. As a designer, this sort of thing doesnā€™t really strike me :face_with_hand_over_mouth:. I just find a way to play it safe :grin: (but I do understand that it can strike a dev or eng sinceā€¦ as you say, this is just not entirely correct (at least in theory :sweat_smile:)

Here you can compare the sprite shader with a custom pixel perfect shader. The latter doesnā€™t flicker.

EDIT:
With pixelPerfect = true, same result, flickersā€¦

EDIT END

Original topic:

1 Like

The problem comes from the fact that the default blending for sprites is ā€œcombineā€. If your sprite is alpha-tested only and you donā€™t want to blend with the screen, you can disable alpha blending (see line 14):

You can check that turning alpha blending for the shader material makes the artifacts appear:

This has me confused. Not speaking about the shader, if I use pixelperfect and bilinear sampling with alpha disable, I still have the lines. Not to mention I lost the alpha of course.

Though, Iā€™m not even sure why I bother. As said, I always leave at least 1px transparent when working with the alpha. This way, thereā€™s absolutely zero issue, so I really donā€™t see the pointā€¦ I must be missing something?!

Good morning everyone. Thanks for chiming in on this issue.

The original point of my thread here is that I was expecting to have 3 separate sprites rendered on screen, but WITHOUT the lines surrounding them because they are NOT part of the sprite cell. I created the sprite sheet very specifically to show that the inner 3 cells only have filled circles, and the cells adjacent to them have content in them (lines in this case, and they very intentionally are butted up against the cells that I intended to render).

---------------------------------------------------------------------------------------------------
| empty cell | empty cell   | empty cell | empty cell    | empty cell | empty cell   | empty cell |
---------------------------------------------------------------------------------------------------
| empty cell | first sprite | empty cell | second sprite | empty cell | third sprite | empty cell |
---------------------------------------------------------------------------------------------------
| empty cell | empty cell   | empty cell | empty cell    | empty cell | empty cell   | empty cell |
---------------------------------------------------------------------------------------------------

It should not matter if the cells I marked as ā€œempty cellā€ actually have any content in them. The problem is if the they do have content that is directly adjacent to the sprite cells in the sprite sheet, they are getting incorrectly rendered. I should only see filled circles on the screen, no lines. Does that make things clearer?

Iā€™ve figured this one also, however ran into the issue as @mawa did:

I came to a solution by turning out sprite instancing and always applying the epsilon for the offsets:

EDIT:

Iā€™ve added inner borders to test the solution w/o sprite instancing:

Do you have a PG link for your final solution? It looks promising!

It requires changes to the core library so I have to create a draft pull request. It will trigger a creation of a snapshot build. Once itā€™s ready, Iā€™ll send you the link to the snapshot.

Wait a minuteā€¦ or 45 while it builds the snapshot :joy:

Thanks Roland. Iā€™m at work for the day so will have to wait till this evening to try it out. I very much appreciate your help. Also thanks to everyone else on this thread.

1 Like

You are welcome!

I had to introduce a new property called pixelPerfect to the cellSize options. I need to disable sprite instancing in the constructor of the SpriteManager. This is of of course subject to change. This is just a proposal so actually every change is subject to change :wink:

Modifying the pixelPerfect property after creating the SpriteManager does not turn on sprite instancing for now.

1 Like

You can disable sprite instancing by doing engine._features.supportSpriteInstancing = false;:

The offset (0.01 - default value if you donā€™t pass a parameter for the 6th parameter of SpriteManager constructor) seems to help, although I guess the right value to use will depend on the texture/sprite sizesā€¦

1 Like

Thanks, I traced back the source where it is read from, however it would be more convenient to turn it of just for a single SpriteManager instance.

Would you please have a look at the draft PR and express your thoughts? I must confess, I didnā€™t really think through the condition when to apply a positive or negative epsilon so that part might be not exactly correct.

Another thing is how are we gonna deal with the pixelPerfect setter.

Correct.

Thanks a lot!

Guys, @Evgeni_Popov came with a much more elegant solution which I have implemented. You can read about the details in the pull request comments

Test PG:

1 Like

Awesome! This is exactly what I was looking for! Hopefully the documentation samples work with this fix as well.

2 Likes

Yes, would be great to check on that. I can review them if neededā€¦

1 Like

Guys, there was another pro tip from @Evgeni_Popov. The final solution was pretty simple:

Thanks goes to @Evgeni_Popov for letting me to do the PR despite he literally wrote all the necessary code in the comments section of the PRs :pray:

4 Likes

Unfortunately, it looks like the bug is still in BJS v7.26.3. PG:

You can still see that the pixels outside the cell are still being rendered.

This earlier PG worked correctly:

Hmm, when you view them in different browser tabs and flip back and forth, you can also see that the pixels from the cell you do want to render is being possibly cropped (looks like its being shrunk).