Comments (17)
I'm having to put a hack in my game right now where if I find that the position is >= 0.5 and < 0.51, I add 0.01f to it just to get it to round up.
You are overthinking this. If you want pixel art drawn at precise pixel locations without any filtering, there's no need to check for specific numeric ranges, just round all your coordinates to the nearest integer.
If you specify point sampling plus draw exactly halfway between pixels, results will depend on the vagaries of numeric precision, which differ across GPUs as well as across a triangle on a single GPU. So don't do that! This isn't specific to Direct3D or SpriteBatch, it's just an inherent characteristic of how GPUs work.
from directxtk.
Position = 36.51f:
Position = 36.50f;
from directxtk.
I think you're just seeing the nature of how texture filtering works on GPUs, rather than anything specific to DirectXTK. From these images it looks like you are using point sampling, which tells the GPU to round each sample location to the nearest integer. If you are drawing exactly halfway between integer positions, which way the hardware rounds will be determined by the low bits of interpolator positions, which may not round in the same direction for every pixel.
Solution: use bilinear sampling in place of point if you want the GPU to filter your images, or don't draw them at fractional locations if you want clearly defined pixel snapping.
from directxtk.
I think you're just seeing the nature of how texture filtering works on GPUs, rather than anything specific to DirectXTK. From these images it looks like you are using point sampling, which tells the GPU to round each sample location to the nearest integer. If you are drawing exactly halfway between integer positions, which way the hardware rounds will be determined by the low bits of interpolator positions, which may not round in the same direction for every pixel.
Solution: use bilinear sampling in place of point if you want the GPU to filter your images, or don't draw them at fractional locations if you want clearly defined pixel snapping.
If that's the case, why does it look like only the bottom right triangle the sprite's made of distorted?
And the behavior seems inconsistent to me. Why isn't 1.51f broken?
from directxtk.
I'm having to put a hack in my game right now where if I find that the position is >= 0.5 and < 0.51, I add 0.01f to it just to get it to round up. Really sucks and doesn't feel like the correct default behavior to me. It's weird for fractional positions to magically work themselves out other than this range.
from directxtk.
Maybe it's because Direct3D 11 considers '0.5' to be the pixel center per Microsoft Docs?
from directxtk.
@shawnhar and FYI linear filtering on the sprite batch doesn't fix it. It just blurs the distorted graphics. This is a bug.
from directxtk.
from directxtk.
I get that Direct3D wasn't designed for this, but it is "SpriteBatch," and this is a basic scenario. Spritebatch should never draw distorted sprites.
from directxtk.
I'm having to put a hack in my game right now where if I find that the position is >= 0.5 and < 0.51, I add 0.01f to it just to get it to round up.
You are overthinking this. If you want pixel art drawn at precise pixel locations without any filtering, there's no need to check for specific numeric ranges, just round all your coordinates to the nearest integer.
If you specify point sampling plus draw exactly halfway between pixels, results will depend on the vagaries of numeric precision, which differ across GPUs as well as across a triangle on a single GPU. So don't do that! This isn't specific to Direct3D or SpriteBatch, it's just an inherent characteristic of how GPUs work.
You can't just round positions in a native resolution pixel art game BECAUSE of the fact that internally it already rounds SOME numbers but not others, and because every computer convention in the world treats >= .5 as rounding up OTHER than this one, you have rounding conflicts that make sprites subtly jitter and not move as smoothly as the convoluted workaround I described. It BLOWS.
I'm not overthinking it, because the game has more complicated scenarios than I've gone into here and there's a reason it is the way it is, but if you're not going to do anything about this obvious bug, go ahead and close it I guess.
from directxtk.
For posterity's sake, this animated GIF shows just how blatant this bug is.
https://imgur.com/a4Xm08m
from directxtk.
What is happening in your code that results in the animation you provided?
I'm trying to understand where you believe the rounding should occur here, but have you tried modifying the SpriteBatch yourself to add rounding to see if it resolves the issue?
from directxtk.
What is happening in your code that results in the animation you provided?
I'm trying to understand where you believe the rounding should occur here, but have you tried modifying the SpriteBatch yourself to add rounding to see if it resolves the issue?
For that example I just manually set the sprite position to 36.5f, but you'll get sprite distortion on any value from around x.499f to x.51f. If I have a 1:1 framebuffer and set a position, I would expect the rounding to happen like any normal computer function where >= .5 gets rounded up. It already rounds up a value of 35.6f and rounds down a value of 35.4f. The behavior is inconsistent.
from directxtk.
Can you check which version of DirectXMath you are using? It's in the DirectXMath.h header as #define DIRECTX_MATH_VERSION
?
from directxtk.
There's no extra logic at all in the SpriteBatch implementation for pixel centers. It simply renders the exact positions you provide it transformed by the viewport matrix. As such, Direct3D 11 and Direct3D 12 consider the "0.5, 0.5" location to be the "pixel center" for 'nearest pixel' sampling, so it does not move the sampled pixel until the location is PAST the center to something like "0.6".
from directxtk.
You could do something like:
XMVECTOR pos = XMLoadFloat2(&m_position);
static const XMVECTORF32 s_half = { { { 0.5f, 0.5f, 0.f, 0.f } } };
pos = XMVectorAdd(XMVectorRound(pos), s_half);
m_spriteBatch->( ..., pos, ...)
XMVectorRound
is equivalent to SSE4 round and ARM-NEON vector round which does "Rounding half to even" or "Banker's rounding". There really isn't "any normal computer function" as you state it for rounding. Instead, you specifically expected "Rounding half away from zero" which is actually quite hard to achieve with SIMD math due to the dependance on the hardware rounding mode (which again is normally set to "Banker's rounding").
See Wikipedia
You would probably be happier with:
XMVECTOR pos = XMLoadFloat2(&m_position);
static const XMVECTORF32 s_half = { { { 0.5f, 0.5f, 0.f, 0.f } } };
pos = XMVectorAdd(XMVectorTruncate(pos), s_half);
m_spriteBatch->( ..., pos, ...)
Which at least make sures that ".0" values land exactly on the pixel center, and then it moves when you hit the next whole number.
from directxtk.
Updated the doc pages in the wiki to note this for future reference:
https://github.com/microsoft/DirectXTK/wiki/SpriteBatch#pixel-centers
https://github.com/microsoft/DirectXTK12/wiki/SpriteBatch#pixel-centers
from directxtk.
Related Issues (20)
- Jittery mouse movement with higher mouse sensitivities HOT 5
- [ddsview] Incorrect brightness found in ddsview HOT 1
- Windows not sending 'KSCATEGORY_AUDIO' notification for audio devices HOT 6
- Error on the mouse input HOT 1
- Retire legacy Xbox One XDK support
- NonPremultiplied has to be used in the Begin() function. HOT 1
- App.cpp and App.h for UWP DeviceResources HOT 1
- xaudio2 XAUDIO2_E_DEVICE_INVALIDATED HRESULT not handled HOT 16
- Make use of C++/WinRT when building for C++17
- ARM64 version of xwbtool HOT 3
- `MapGuard` undefined behavior after move HOT 3
- DirectX Tool Kit for DX9
- DrawLine line thickness HOT 1
- Mesh Outline Effect HOT 2
- Point Light Shader HOT 2
- Clarify required WinSDK version HOT 2
- Hard fps lock to refresh rate value in fullscreen games - Win11 22H2 (DX11) HOT 2
- XWBtool makes all wav files the same name after repackaging HOT 5
- Audio: how to set distance attenuation/fall-off? HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from directxtk.