Po dodaniu prędkości do mojej gry, czuję, że moje tekstury drżą. Myślałem, że to tylko moje oczy, aż w końcu uchwyciłem to na zrzucie ekranu:
Ten po lewej jest tym, co renderuje się w mojej grze; ten po prawej to oryginalny duszek, wklejony. (To jest zrzut ekranu z Photoshopa, powiększony 6x.)
Zauważ, że krawędzie są aliasingowe - wygląda prawie jak renderowanie subpikseli. W rzeczywistości, gdybym nie zmusił moich duszków (które mają pozycję i prędkość jako liczby całkowite) do rysowania przy użyciu wartości całkowitych, przysięgałbym, że MonoGame rysuje z wartościami zmiennoprzecinkowymi. Ale tak nie jest.
Co może być przyczyną rozmycia tych rzeczy? Nie dzieje się to bez zastosowania prędkości.
Mówiąc ściślej, moja SpriteComponent
klasa ma Vector2 Position
pole. Kiedy dzwonię Draw
, zasadniczo używam new Vector2((int)Math.Round(this.Position.X), (int)Math.Round(this.Position.Y))
stanowiska.
Miałem wcześniej błąd, w którym drgałyby nawet obiekty stacjonarne - to dlatego, że użyłem prostego Position
wektora i nie zaokrąglałem wartości ints
. Jeśli użyję Floor
/ Ceiling
zamiast okrągłej, duszek tonie / unosi się (różnica o jeden piksel w jedną stronę), ale nadal rysuje się rozmazany.
Odpowiedzi:
Cóż, to jest zawstydzające.
Okazuje się, że nie rysowałem przy użyciu pozycji liczb całkowitych, ale pozycji zmiennoprzecinkowych. Archy wskazał mi właściwą drogę swoim komentarzem
@ashes999 did you debug this call and checked this.X, this.Y and this.origin?
Gdy tylko dodałem instrukcję śledzenia, zauważyłem, że nic nie wytropiło. Okazuje się, że moja
SpriteComponent
klasa poprawnie używała wartości całkowitych, ale mojeSpriteSheetComponent
nadal używały wartości zmiennoprzecinkowych z surowegoVector2 Position
.Chociaż nie próbowałem filtrować i blokować tekstur, podejrzewałem, że to nie jest poprawna zmiana, ponieważ rysowałem obraz 2D o tej samej szerokości i wysokości co obraz źródłowy (bez skalowania).
źródło
XNA używa DirectX9, który wykorzystuje środek piksela jako swoją lokalizację. Jest to zauważalne przy użyciu przeciążeń opartych na Vector2 w klasie rysowania. Uważam, że odjęcie (.5, .5) powinno rozwiązać twój problem.
Więcej informacji tutaj.
źródło
int, int
jako argumenty. Poza tym wszystko wygląda idealnie, gdy nie mam żadnych obiektów w ruchu.SpriteComponent
maVector2
pozycję, która zwiększa się jako liczba zmienna w zależności od prędkości; kiedy rysuję, tworzę noweVector2
wersjeposition
X i Y z liczbami całkowitymi (zaokrąglonymi). Nie o to chodzi, ponieważ obiekty nieruchome bez prędkości wyglądają dobrze.p += v
podczasUpdate
i renderuję za pomocąnew Vector2((int)Math.Round(p.X), (int)Math.Round(p.Y)))
.Renderowanie nic nie wie o twojej prędkości, więc ani pozycja, rozmiar, ani nic innego, co przechodzisz do SpriteBatch.Draw jest inny lub błąd występował przed dodaniem prędkości. Jak dokładnie wywołać SpriteBatch.Draw?
Czy debugowałeś to połączenie i sprawdziłeś to X, this.Y i this.origin? Co to jest ustawiony this.origin? Zasadniczo nie ma możliwości, aby wynik renderowania z prędkością był inny, gdy to wywołanie Draw jest takie samo.
źródło
Problem prawdopodobnie polega na włączeniu filtrowania tekstur. Jeśli nie masz pewności, co to oznacza, rozważ sytuację, w której masz obraz o szerokości 2 pikseli: pierwszy piksel jest czarny, drugi piksel jest biały. Jeśli powiększysz tę teksturę, jeśli włączone jest filtrowanie tekstury, zobaczysz, że rozmazuje się i że obszar między pikselem czarnym i białym ma gradientowy szary kolor.
Klasycznym przykładem gier z lub bez filtrowania są Super Mario 64, które miały filtrowanie, podczas gdy Doom nie.
Kiedy nie używasz prędkości, Twój Sprite jest prawdopodobnie ustawiony w taki sposób, że środek tekstury znajduje się w punkcie próbki, w którym XNA (lub jakikolwiek bazowy API jest używany) chwyta kolor. Kiedy poruszasz się z prędkością zmiennoprzecinkową, wówczas zmienia się pozycja twojego duszka, dlatego punkt próbkowania może nie pokrywać się bezpośrednio ze środkiem piksela, więc końcowym wynikiem jest kolor będący średnią najbliższych pikseli używane do renderowania.
Możesz sprawdzić, czy filtrowanie jest włączone, po prostu renderując swojego Duszka naprawdę duży na ekranie. Jeśli jest rozmazany, to jest problem.
Jeśli musisz mieć idealną dokładność renderowania w pikselach, będziesz chciał mieć gdzieś zapisaną wartość zmiennoprzecinkową pozycji, ale użyj wartości całkowitych dla pozycji renderowanego obiektu ... lub oczywiście możesz po prostu wyłączyć filtrowanie jeśli twoja gra tego nie potrzebuje.
Możesz także przeczytać to .
źródło
Draw
. Nie jestem więc pewien, jak to możliwe - spróbuję renderować na dużą skalę i sprawdzać, czy wyłączenie filtrowania tekstur pomoże.Spróbuj ustawić SamplerState na SamplerState.PointClamp w wywołaniu SpriteBatch.Begin.
źródło