-
Notifications
You must be signed in to change notification settings - Fork 364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Batcher: Removed half pixel offset calculation. #846
base: master
Are you sure you want to change the base?
Batcher: Removed half pixel offset calculation. #846
Conversation
… also not needed for Monogame (expect for legacy XNA games which still use DirectX9...)
2e6f2a6
to
329dbae
Compare
I've found some kind of rendering issue introduced by this change. I will provide more info soon. |
Hey @optimo, thank you for your feedback.
Imo it's the same as in the FNA SpriteBatch.
I always use even-numbered sprites, so I didn't run into this issue. I did a test anyway with a 9x9 texture. To my understanding, if you really need to use an odd-numbered sprite, you should adjust the position accordingly so it will end up with an integer raster position. Here's an example to show what I mean: public class SampleScene : Scene {
private Entity _spriteEntity;
public override void Initialize() {
SetDesignResolution(640, 360, SceneResolutionPolicy.ShowAllPixelPerfect);
var texture = Content.LoadTexture("Content/sprite9x9.png");
var sourceRectangle = texture.Bounds;
var centerOrigin = sourceRectangle.GetHalfSize();
var sprite = new Sprite(texture, sourceRectangle, centerOrigin);
_spriteEntity = CreateEntity("sprite");
var spriteRenderer = _spriteEntity.AddComponent(new SpriteRenderer(sprite));
spriteRenderer.SetLocalOffset(new Vector2(0.5f, 0.5f));
_spriteEntity.Position = new Vector2(100, 100);
}
public override void Update() {
base.Update();
if (Input.IsKeyDown(Keys.Down)) {
_spriteEntity.Position = new Vector2(_spriteEntity.Position.X, _spriteEntity.Position.Y + 1);
}
else if (Input.IsKeyDown(Keys.Up)) {
_spriteEntity.Position = new Vector2(_spriteEntity.Position.X, _spriteEntity.Position.Y - 1);
}
}
} The default origin when using a Sprite is center. Position: (100, 100) If we do not compensate the 'odd numbered texture' by updating the position with e.g. Instead it will have this position: (95.5, 95,5) As can be seen here: https://github.com/prime31/Nez/blob/master/Nez.Portable/Graphics/Batcher/Batcher.cs#L901-L914 And this will result in the sprite not being rendered correctly. This could normally be fixed by updating the position. But there is a flag which prevents that: 'ShouldRoundDestinations' I don't know why this flag exists, but it prevents the user from manually adjusting the position: https://github.com/prime31/Nez/blob/master/Nez.Portable/Graphics/Batcher/Batcher.cs#L855-L859 So this flag needs to be set to false. I really do wonder why this flag is set to true by default? (Looks like it was introduced with #367) Here's the result of the calculation: The sprite is now being displayed correctly. Alternatively it would also be possible to just set the origin to Vector2.Zero. Here's the texture I used in case you also want to experiment a bit: |
Very good research. Understood and all good. Setting the sprite origin to Vector2.Zero actually best matches my expectations for how sprites should work. So that's how I will plan to use them in the future also. This was a good think-about and reinforces my suspicions about default sprite origins being kind of annoying for my use-case. Since this problem starts in the atlas being generated for me by the Aseprite class, I'm going to introduce a PR adding a method there to allow setting a custom origin for the created sprites. This seems like the best remedy. The aseprite methods have only been in nez framework for a short while. Others using manually-created sequences or atlases have otherwise full agency over the origin settings if need be. The rounding of destinations you uncovered holds some intrigue but we can put that aside for now. It's another can of worms. :) |
Hello,
when switching from Monogame to FNA, I experienced some kind of texture bleeding:

FNA
I compared the NEZ Batcher with the FNA Batcher.
(Kinda hard to read because of pointer arithmetic)
https://github.com/FNA-XNA/FNA/blob/master/src/Graphics/SpriteBatch.cs#L1436-L1457
Key takeaway:
M11 = (float)(2.0 / (double)viewport.Width)
M22 = (float)(-2.0 / (double)viewport.Height)
M41 = -1
M42 = 1
So no half pixel offset is calculated in the SpriteBatcher of FNA.
This is also mentioned here: https://fna-xna.github.io/docs/2a%3A-Building-XNA-Games-with-FNA/#2a-about-effect-support
(I initially got confused because of https://github.com/FNA-XNA/FNA/blob/master/src/Graphics/Effect/StockEffects/SpriteEffect.cs#L71-L74
But SpriteEffect is not used anywhere and is an internal class. So the offset calculation is never applied anywhere.)
Monogame
I also checked the SpriteBatcher of Monogame.
It also does not apply an offset by default:
But it does if 'UseHalfPixelOffset' is set to true. So they still support this feature (for OpenGL):
https://docs.monogame.net/articles/migration/migrate_xna.html
For DirectX the flag will be set to false: https://github.com/MonoGame/MonoGame/blob/develop/MonoGame.Framework/Graphics/GraphicsDevice.cs#L317-L320
Key takeaways from the article:
Changes
Completely removed the half pixel offset calculation in the Batcher.
This benefits FNA and Monogame. For both frameworks this calculation should not be used.
The problems are more visible when using FNA but M41/M42 is also a little bit off for Monogame.
Set the Monogame-specific 'UseHalfPixelOffset'-Flag in Core to false. I do not think many users will need this feature. And having it set to true by default will do more harm than good. That's also the reason why this flag is set to false by default in monogame.
I am aware that legacy XNA games in Monogame will now have the half pixel offset problem. But to fix this, it would be necessary to check for more conditions aside from 'UseHalfPixelOffset'.
And I don't think adding this legacy feature is worth the time.
I did test this change with FNA and Monogame (OpenGL only) and in both cases I didn't see any texture bleeding.
Best regards,
stallratte