Pregunta

Bien, esto es algo que debería ser una simple pregunta de matriz, pero mi comprensión de las matrices es algo limitada. Aquí está el escenario: tengo un sprite de 1 px por 1 px que quiero escalar en cierta cantidad x e y (diferentes cantidades en cada lado), y luego quiero rotar ese sprite en algún ángulo, y luego quiero poder posicionar todo con precisión (desde la parte superior izquierda o el centro, no me importa).

Hasta ahora, mi código está vagamente cerca, pero tiende a estar desactivado en una cantidad aleatoria dependiendo del ángulo que paso.

Creo que esto lo haría:

        Point center = new Point( 50, 50 );
        float width = 60;
        float height = 100;
        float angle = 0.5;
        Vector3 axis = new Vector3( center.X, center.Y, 0 );
        axis.Normalize();
        Matrix m = Matrix.Scaling( width, height, 0 ) *
            Matrix.RotationAxis( axis, angle ) *
            Matrix.Translation( center.X, center.Y, 0 );

Pero tiende a reducir la escala de la línea girada hacia abajo, a pesar de que creo que está posicionándola más o menos a la derecha.

También he intentado esto:

  Matrix m = Matrix.Transformation2D( new Vector2( center.X, center.Y ), 0f,
      new Vector2( width, height ), new Vector2( center.X, center.Y ),
      angle, Vector2.Zero );

La línea se ve exactamente correcta, con el tamaño y la forma correctos, pero no puedo posicionarla correctamente. Si uso el vector de traducción al final de la llamada anterior, o si establezco una posición usando Sprite.Draw, ninguno funciona bien.

Todo esto está en SlimDX. ¿Qué estoy haciendo mal?

¿Fue útil?

Solución

Acabo de pasar por el dolor de aprender la transformación de la matriz, pero usando XNA.

Encontré estos artículos a be muy útil para comprender lo que sucede. Las llamadas al método son muy similares en XNA y la teoría detrás de todo esto debería aplicarse a usted, incluso con SlimDX.

Al mirar su código, creo que debería traducir al principio, al origen, y luego volver a traducir al final, a la posición final, aunque todavía soy un poco novato en esto como bien.

El orden en el que lo haría es:

  • Traducir al origen
  • Escala
  • Rotar
  • Traducir a la ubicación deseada

La razón para traducir primero al origen es que las rotaciones se basan en el origen . Por lo tanto, para rotar algo sobre cierto punto, colóquelo en el origen antes de rotarlo.

Otros consejos

Bien, esto ahora está funcionando. Aquí está mi código de trabajo para esto, en caso de que alguien más lo necesite:

    Point sourceLoc = new Point ( 50, 50 );
    float length = 60;
    float thickness = 2;
    float angle = 0.5;
    Matrix m = Matrix.Scaling( length, thickness, 0 ) *
            Matrix.RotationZ( angle ) *
            Matrix.Translation( sourceLoc.X, sourceLoc.Y, 0 );
    sprite.Transform = m;

    sprite.Draw( this.tx, Vector3.Zero, Vector3.Zero, Color.Red );

Esto dibujará una línea en ángulo de la longitud elegida, con un grosor igual al grosor elegido (suponiendo que su textura sea una imagen blanca de 1x1 píxeles). La ubicación de origen es desde donde emitirá la línea, con cualquier ángulo que especifique (en radianes). Entonces, si comienza en cero e incrementa en algo como 0.1 hasta llegar a 2PI, y luego se restablece a 0, tendrá una línea que gira alrededor de un centro como una manecilla de reloj o barrido de radar. Esto es lo que estaba buscando, ¡gracias a todos los que contribuyeron!

¿Estás girando alrededor del eje correcto? Soy un novato en materia de matrices, pero me parece que dado que el sprite existe en el espacio x, y, el eje de rotación debería ser el eje Z, es decir (0,0,1).

Lo que debe hacer es hacer cada transformación paso a paso. Haz la escala primero dibujala. ¿Es donde lo esperas? Luego arroje la rotación y luego la traslación. Esto ayudará a descubrir suposiciones incorrectas.

También puede dibujar líneas temporales para ayudar a calcular dónde están las coordenadas. Por ejemplo, si haces tu estiramiento y rotación y esperas que tu punto final esté en 0,0. Dibujar otra línea con un punto final en 0,0 servirá como una doble verificación para ver si ese es realmente el caso.

Para su problema específico, el problema puede estar relacionado con la rotación. Después de haber escalado y rotado, la línea ya no está en el centro y le causa problemas cuando está traduciendo.

La solución general es mover la línea de regreso al origen y realizar cualquier operación que implique cambiar su forma u orientación. Después, porque está en una buena ubicación conocida, puede traducir a su destino final.

RESPUESTA A LOS COMENTARIOS

Si la traducción es un problema y está transformando el sistema de coordenadas, entonces deberá escribir una función de conversión para convertir entre el sistema antiguo y el nuevo.

Por ejemplo, si está girando 45 grados. Antes de la rotación, podría traducir 0,1 para moverse 1 pulgada hacia arriba. Después de la rotación, tendrá que traducir aproximadamente -.70707, .070707 para subir 1 pulgada en relación con el sistema de coordenadas original.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top