Sprites que se vuelven borrosos con la velocidad

9

Después de agregar velocidad a mi juego, siento que mis texturas se contraen. Pensé que solo eran mis ojos, hasta que finalmente lo capturé en una captura de pantalla:

ingrese la descripción de la imagen aquí

El de la izquierda es lo que aparece en mi juego; el de la derecha es el sprite original, pegado. (Esta es una captura de pantalla de Photoshop, ampliada 6x).

Observe que los bordes tienen un alias: parece casi una representación de subpíxeles. De hecho, si no hubiera forzado a mis sprites (que tienen posición y velocidad como ints) a dibujar usando valores enteros, juraría que MonoGame está dibujando con valores de punto flotante. Pero no lo es.

¿Cuál podría ser la causa de que estas cosas parezcan borrosas? No sucede sin la velocidad aplicada.

Para ser precisos, mi SpriteComponentclase tiene un Vector2 Positioncampo. Cuando llamo Draw, esencialmente uso new Vector2((int)Math.Round(this.Position.X), (int)Math.Round(this.Position.Y))para el puesto.

Tuve un error antes de que incluso los objetos estacionarios temblaran, eso se debió a que usé el Positionvector recto y no redondeé los valores ints. Si uso Floor/ en Ceilinglugar de redondo, el sprite se hunde / se desplaza (una diferencia de píxel en ambos sentidos) pero aún se dibuja borroso.

cenizas999
fuente
1
¿Podría esto estar relacionado con el filtrado de textura que se aplica?
OriginalDaemon
¿Tienes el código para tu sombreador? Algunas personas agregan medio píxel en ambos ejes para centrar los píxeles. Sin embargo, no estoy seguro, creo que eso es solo una cosa de DirectX.
William Mariager
3
Desactivar el filtrado es una solución alternativa, no una solución.
Archy
1
El renderizado no sabe nada sobre su velocidad, por lo que la posición, el tamaño o cualquier otra cosa que pase a SpriteBatch.Draw es diferente o el error estaba presente antes de agregar velocidad. ¿Cómo se llama a SpriteBatch.Draw exactamente?
Archy
1
@ ashes999 ¿depuró esta llamada y comprobó this.X, this.Y y this.origin? ¿En qué está configurado this.origin? Básicamente no hay forma de que el resultado del renderizado sea diferente cuando esta llamada de Draw es la misma.
Archy

Respuestas:

3

Bueno, esto es vergonzoso.

Resulta que no estaba dibujando usando posiciones enteras, sino posiciones flotantes. Archy me señaló el camino correcto con su comentario@ashes999 did you debug this call and checked this.X, this.Y and this.origin?

Tan pronto como agregué una declaración de seguimiento, noté que no se trazó nada. Resulta que mi SpriteComponentclase usaba correctamente valores enteros, pero SpriteSheetComponenttodavía usaba valores flotantes sin procesar Vector2 Position.

Aunque no probé el filtrado y la sujeción de texturas, sospechaba que no se trataba del cambio correcto, porque estaba dibujando una imagen 2D con el mismo ancho y alto que la imagen de origen (sin escala).

cenizas999
fuente
1
Hecho, me alegro de que lo hayas encontrado!
Archy
2

XNA usa DirectX9 que usa el centro del píxel como su ubicación. Esto es notable cuando se usan las sobrecargas basadas en Vector2 de la clase de dibujo. Creo que restar (.5, .5) debería solucionar su problema.

Más información aquí.

Trueno clásico
fuente
Técnicamente no puedo hacer esto, porque estoy pasando un Vector2 con int, intlos argumentos. Además de eso, las cosas se ven perfectamente bien cuando no tengo ningún objeto en movimiento.
cenizas999
¿Qué quieres decir con que el objeto está en movimiento? XNA no tiene noción de movimiento, dibuja cosas donde tú también lo dices. Es una serie de instantáneas estacionarias. También intente usar las sobrecargas Rectángulo, ya que de todos modos está redondeando a un rectángulo.
ClassicThunder
Tengo mi propia implementación de velocidad. SpriteComponenttiene una Vector2posición, que se incrementa como flotadores dependiendo de la velocidad; cuando dibujo, creo un nuevo Vector2con versiones enteras (redondeadas) de mi positionX e Y. Este no es el problema, ya que los objetos estacionarios sin velocidad parecen estar bien.
cenizas999
Entonces, dice que tiene un vector de posición p y un vector de velocidad v, agréguelos como p + = v, luego cree una copia de p usando valores redondeados. ¿Y que esto arroja valores diferentes que tienen una posición que es la misma que la p + = v anterior a pesar de que las llamadas de extracción son idénticas? Porque eso no tiene sentido.
ClassicThunder
Sí, eso es lo que @Archy también está diciendo. Déjame depurar y verificar de nuevo. Agrego p += vdurante Updatey renderizo con new Vector2((int)Math.Round(p.X), (int)Math.Round(p.Y))).
cenizas999
2

El renderizado no sabe nada sobre su velocidad, por lo tanto, la posición, el tamaño o cualquier otra cosa que pase a SpriteBatch.Draw es diferente o el error estaba presente antes de agregar velocidad. ¿Cómo se llama a SpriteBatch.Draw exactamente?

¿Depuró esta llamada y comprobó this.X, this.Y y this.origin? ¿En qué está configurado this.origin? Básicamente no hay forma de que el resultado del renderizado con velocidad sea diferente cuando esta llamada de Draw es la misma.

Archy
fuente
1

El problema es probable que el filtrado de textura esté activado. Si no está seguro de lo que eso significa, considere una situación en la que tiene una imagen que tiene 2 píxeles de ancho: el primer píxel es negro, el segundo píxel es blanco. Si amplía esta textura, si el filtro de textura está activado, verá que se vuelve borroso y que el área entre el píxel blanco y negro usa un color gris degradado.

Un ejemplo clásico de juegos con y sin filtro son Super Mario 64 que tenía un filtro mientras que Doom no.

Cuando no usa la velocidad, es probable que su Sprite esté posicionado de manera que el centro de la textura esté en el punto de muestra en el que XNA (o cualquier api subyacente que se esté usando) tome el color. Cuando te mueves con una velocidad de flotación, entonces la posición de tu Sprite cambia, por lo que el punto de muestra puede no alinearse directamente con el centro de un píxel, por lo que el resultado final es que se está obteniendo un color que es un promedio de los píxeles más cercanos solía renderizar.

Puede verificar que el filtrado esté activado simplemente haciendo que su Sprite sea realmente grande en la pantalla. Si está borroso, entonces ese es el problema.

Si debe tener una precisión de píxel perfecta en el renderizado, querrá tener un valor flotante para la posición almacenada en algún lugar, pero use valores enteros para la posición del objeto que está renderizando ... o, por supuesto, simplemente puede desactivar el filtrado si tu juego no lo necesita.

Quizás también quieras leer esto .

Victor Chelaru
fuente
Como mencioné en mi pregunta, cuando llamo ya estoy usando enteros para mi ubicación y el tamaño de la imagen original Draw. Así que no estoy seguro de cómo podría ser el caso, pero intentaré renderizar a gran escala y ver si ayudar a desactivar el filtrado de textura.
cenizas999
1

Intente configurar su SamplerState en SamplerState.PointClamp en la llamada SpriteBatch.Begin.

juegos de manualidades
fuente