Como girar, escala, e traduzir uma matriz de uma só vez em C #?
-
10-07-2019 - |
Pergunta
Ok, isso é algo que deve ser uma pergunta simples matriz, mas o meu entendimento de matrizes é um pouco limitado. Aqui está o cenário: Eu tenho um 1 x 1 pixel sprite que eu quero escala por alguns montante xey (quantidades diferentes de cada lado), e depois quero rodar que Sprite por algum ângulo, e então eu quero ser capaz de posicionar precisamente a coisa toda (do topo para a esquerda ou ao centro, não faz diferença para mim).
Até agora o meu código é vagamente perto, mas ela tende a estar fora por alguma quantidade aleatória, dependendo do ângulo que eu passar em.
Gostaria de pensar que isso iria fazê-lo:
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 );
Mas ele tende a diminuir a escala da linha de caminho rodada, mesmo que eu acho que está posicionando-tipo de direito.
Eu também tentei isso:
Matrix m = Matrix.Transformation2D( new Vector2( center.X, center.Y ), 0f,
new Vector2( width, height ), new Vector2( center.X, center.Y ),
angle, Vector2.Zero );
Os olhares linha exatamente certo, com o tamanho ea forma exata certo, mas eu não pode posicioná-lo corretamente em tudo. Se eu usar o vetor de translação no final da chamada acima, ou se eu definir uma posição usando Sprite.Draw, nem funciona direito.
Esta é tudo em SlimDX. O que estou fazendo de errado?
Solução
Eu só fui com a dor de aprender transformação de matriz, mas usando XNA.
estes artigos para ser muito útil para compreender o que acontece. As chamadas de método são muito semelhantes em XNA e a teoria por trás de tudo deve se aplicar a você, mesmo com SlimDX.
A partir de olhar para o seu código, eu acho que você deve ser a tradução no início, a origem, e depois traduzir novamente no final, para a posição final, embora eu ainda sou um pouco de um novato para isso como bem.
A ordem que eu iria fazê-lo em é:
- Traduzir para origem
- Escala
- Girar
- Traduzir para o local desejado
A razão para traduzir a origem primeira é que rotações são baseadas a partir da origem . Portanto, para algo girar sobre um determinado ponto, lugar que ponto sobre a origem antes de girar.
Outras dicas
A aprovação, esta está agora a trabalhar. Aqui está o meu código trabalhando para isso, nas necessidades de outra pessoa caso de alguém que:
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 );
Isto irá desenhar uma linha angular do seu comprimento escolhido, com uma espessura igual à sua espessura escolhida (presumindo a sua textura é um pixel 1x1 imagem branca). O local de origem é onde a linha irá emitir a partir de, com qualquer ângulo que você especifique (em radianos). Então, se você começar a zero e incremento por algo como 0,1 até chegar 2PI, e depois repor a 0, você vai ter uma linha que gira em torno de um centro como uma mão relógio ou varredura radar. Isto é o que eu estava procurando - graças a todos os que contribuíram
Você está girando em torno do eixo correto? Eu sou um novato no material de matriz, mas parece-me que desde que existe o sprite na x, y espaço, o eixo de rotação deve ser o Z-Axis - ou seja, (0,0,1).
O que você precisa fazer é fazer cada transformação um passo de cada vez. Faça o escalonamento primeira desenhá-lo. É onde você espera. Em seguida, jogar à girar, e então a traduzir. Isso ajudará suposições uncover incorretas.
Você também pode desenhar em linhas temporárias para ajuda figura, onde as coordenadas são. Por exemplo, se você faz o seu alongamento e rotação e esperar que o seu ponto final para ser em 0,0. Desenhando uma outra linha com um ponto final em 0,0 servirá como uma segunda verificação para ver se isso realmente o caso.
Para o seu problema específico o problema pode estar com a rotação. Depois de ter escalado e girar a linha está agora fora do centro causando-lhe problemas quando você está traduzindo.
A solução geral é para mover a linha de volta à origem fazer quaisquer operações que envolvem mudando-lhe forma ou orientação. Depois porque você está em um local conhecido bom você pode traduzir para o seu destino final.
resposta aos comentários
Se a tradução é um problema e você estão transformando o sistema de coordenadas, então você terá que escrever uma função de conversão para converter entre o sistema antigo eo novo.
Por exemplo, se você está girando 45 graus. Antes da rotação você poderia traduzir por 0,1 para subir de 1 polegada. Depois de rotação você terá que traduzir em cerca de -.70707, 0,070707 para subir de 1 polegada em relação ao original sistema de coordenadas.