Este artigo foi traduzido por máquina.

Toque e ouça

Windows Phone movimento e vistas 3D

Charles Petzold

Baixe o código de exemplo

Charles PetzoldA nova classe de movimento introduzida com Windows Phone 7.1 é uma ferramenta maravilhosa para programadores que precisam saber como o telefone é orientado no espaço tridimensional. Classe Motion combina informações de sensores (acelerômetro, magnetômetro e giroscópio) e também suaviza os dados e torna-o disponível em formas convenientes.

Quando um programa de Windows Phone sabe a orientação do telefone no espaço 3D, o telefone pode fornecer um portal para um mundo 3D. Esta facilidade tem aplicações no mapeamento, realidade virtual, realidade aumentada e, claro, jogos, mas provavelmente também alguns aplicativos que ainda não foram concebidos. Esta é definitivamente uma área onde você vai querer exercer sua imaginação tanto quanto suas habilidades de codificação.

Dados de movimento

Quero me concentrar unicamente na obtenção da orientação do telefone ao invés de velocidade ou aceleração, que também estão disponíveis da classe Motion. O sensor fornece uma estrutura de MotionReading, e as informações de orientação estão disponíveis na propriedade de atitude. A palavra "atitude" vem da dinâmica de voo, onde ele indica a orientação de um plano no espaço 3D — distintas da altitude, que é a altura acima da terra. A palavra também é usada na geometria vetorial.

Esta propriedade de atitude é do tipo AttitudeReading, outra estrutura que define cinco propriedades que descrevem a orientação tridimensional:

  • Guinada do tipo float, um ângulo em radianos
  • Campo do tipo float, um ângulo em radianos
  • Rolo do tipo float, um ângulo em radianos
  • RotationMatrix do tipo Matrix, um tipo de matriz 4 × 4 definido no XNA
  • Quaternion do tipo Quaternion, um tipo definido em XNA

Yaw, Pitch e rolo também são termos utilizados na dinâmica de voo, e eles são muitas vezes referidos como ângulos de Euler. Guinada indica a direção da bússola que enfrenta o nariz do avião, assim como o avião vira à direita ou à esquerda, a guinada é alterado. Arremesso de mudanças como o nariz sobe para uma subida ou para baixo para um mergulho. Reverter alterações que os bancos do avião de esquerda e direita. Para visualizar estas em relação ao telefone, ele ajuda a imaginar a tela "voando" em seu telefone como um tapete mágico sentando ao telefone com a parte superior do telefone à sua frente e três botões padrão para o seu traseiro.

Um programinha chamado YawPitchRoll incluído com o código para download neste artigo também pode ajudar a visualizar esses ângulos. (Como todos os programas neste artigo, requer referências aos assemblies Microsoft.Devices.Sensors e Microsoft.Xna.Framework.) Conforme Figura 1, o programa exibe os valores desses três ângulos convertido em graus, e também simboliza graficamente seus valores.


Figura 1: A exibição de YawPitchRoll

Guinada é exibida com uma simples linha que aponta o norte como uma bússola, Considerando que o Pitch and Roll são exibidos como bolas sólidas que parecem rolar em direção à terra. Quando o telefone está sentado em uma mesa de nível com a tela de cima e a parte superior do telefone apontando para norte, todos os três ângulos têm valores iguais a zero.

Como você inclinar a parte superior do telefone acima e para baixo, você pode alterar a altura de 90 ° quando o telefone está na posição vertical a-90 °, quando a parte superior do telefone aponta para baixo. Da mesma forma, você pode alterar rolo de 90 ° a-90 ° inclinando o telefone direito e esquerdo.

Quando o visor do telefone está virado para baixo, o ângulo de guinada pontos de Sul. Campo assume valores que variam de 90 ° a 180 ° e de-90 °-180 °. No programa YawPitchRoll, esses valores são simbolizados por uma esfera oca, delineada em vermelho. Os valores do rolo de continuam a tomar valores variando de 90 °-90 °.

Perspectivas de rotação

Embora nós gastamos toda a nossa vida em um universo tridimensional, muitos de nós têm uma muito má compreensão intuitiva de rotação tridimensional. Por conseguinte, visualizando e trabalhando com rotações no espaço 3D podem ser um desafio. Yaw, Pitch e Roll parecem descrever adequadamente a rotação no espaço 3D, mas eles acabam por ser um pouco desajeitado na programação prática.

Programadores prefiro muito mais trabalhar com formas alternativas para descrever a rotação 3D:

  • Um único ângulo, descrevendo a rotação em torno de um vetor 3D (rotação de eixo/ângulo)
  • Uma matriz de rotação (um subconjunto de uma matriz 3D de transformar)
  • Quaternion, um análogo 3D rotação 2D no plano complexo

Estas formas podem todos ser convertidas entre si, como demonstrarei nos capítulos 7 e 8 do meu livro "3D Programming for Windows" (Microsoft Press, 2008). Quaternion é particularmente útil para um movimento suave de uma orientação para outra, porque ela se presta a interpolação linear.

A classe de movimento fornece a rotação 3D com uma matriz de rotação e quaternion, mas vou focar exclusivamente a propriedade RotationMatrix da estrutura AttitudeReading. Este é um valor de matriz de XNA, que é uma matriz de transformação de 4 × 4 padrão, mas a matriz representa apenas de rotação. Tem sem escala e sem tradução. Os campos M14, M24, M34, M41, M42 e M43 são todos 0, e o campo de M44 é 1.

Ao trabalhar com esta matriz de rotação, uma mudança na perspectiva será útil. Na edição anterior desta coluna, descrevi como o vetor tridimensional disponível a partir de sensores acelerômetro e bússola é em relação a um sistema de coordenadas 3D, sobre a geografia do telefone. No entanto, ao trabalhar com a matriz de rotação, você realmente precisa Visualizar dois 3D coordenar sistemas diferentes, um para o telefone e outro para a terra:

  • No sistema de coordenadas 3D do telefone, Y positivo aponta para a parte superior do telefone (em modo retrato), positivos x pontos direito e positivos z sai da tela.
  • No sistema de coordenadas 3D da terra, positivo Y Norte, pontos positivos x pontos leste e z positivo sai da terra.

Quando o telefone se senta em uma superfície nivelada com a tela acima e o topo apontando para norte, o valor de RotationMatrix é a matriz identidade. Caso contrário, ele descreve como a terra é girada em relação ao telefone, que é o oposto da rotação descrita pelos ângulos de Euler.

Para ilustrar isso, escrevi um pequeno programa chamado MotionMatrix. Display (mostrado na Figura 2) consiste apenas em valores numéricos: os valores Yaw, Pitch and Roll, o subconjunto de matriz de rotação de 3 × 3 da matriz completa e expressos sob a forma de eixo/ângulo de rotação.

The MotionMatrix Display
Figura 2: A exibição de MotionMatrix

Quando você começa a jogar com este programa, seu instinto imediato é, provavelmente, para orientar o telefone para que todos os ângulos de Euler são zero. No entanto, o vetor de eixo para baixo na parte inferior fica louco, porque não há quase nenhuma rotação, então o valor do eixo pode ser quase qualquer coisa. Rotações simples acalmam a exibição. A captura de tela em Figura 2 mostra o topo do telefone apontando Norte mas elevado cerca de 45 °. Isso é o que informa o valor de densidade, e a rotação do eixo/ângulo mostra um valor muito próximo do 46 °.

Mas observe o eixo de rotação: É aproximadamente (– 1, 0, 0), que é o eixo de coordenadas que aponta para a esquerda do telefone. Rotações do eixo/ângulo XNA obedecer a regra da mão direita: Aponte o polegar da mão direita na direção do eixo (que é, neste caso para a esquerda do telefone). A curva dos dedos, em seguida, mostra a direção da rotação positiva. Isso significa que a rotação é oposto ao ângulo de inclinação. Ela nos diz que o telefone deve ser girado-45 ° para ser alinhado com a terra.

O MotionMatrix e o XNA

Parece razoável usar a matriz de rotação de classe Motion para a visualização de objetos 3D no telefone. Mas em vez da abordagem normal — onde um objeto 3D é girado em relação ao visor, talvez com um mouse ou o dedo — aqui a exibição poderia ser girada em relação ao objeto 3D (conceitualmente, enfim).

Para experimentar isso, baixei um modelo 3D de um telefone antigo do archive3d. NET Web site (especificamente bit.ly/GSNTi3) e depois convertido do formato 3DS para o formato FBX XNA-amigável usando uma conversor ferramenta da Autodesk. Criei quatro projetos de Visual Studio que mostram progressivamente melhores maneiras de exibir este objeto. (Na verdade, eu afundava em torno de um pouco e só mais tarde criou estes quatro projectos para disfarçar esse fato!) Para reduzir o seu código fonte, baixar o tempo, todos os quatro projetos referenciam o mesmo arquivo de modelo 3D.

O primeiro dos quatro projetos é chamado View3DPhonePlain, que é apenas uma visão estática do objeto; Figura 3 mostra o código relevante. Este programa carrega no modelo, define uma transformação do mundo que dimensiona o modelo para baixo de um monte e define uma câmera simple. (A aparente superfluidade das variáveis de campo fará sentido em breve.)

Figura 3 O programa de View3DPhonePlain

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    Model model;
    Matrix scaleMatrix, worldMatrix, lookatMatrix,
           viewMatrix, projectionMatrix;
    ...
protected override void LoadContent()
    {
        model = this.Content.Load<Model>(“Phone Retro Caesar N170910”);
        foreach (ModelMesh mesh in model.Meshes)
            foreach (BasicEffect effect in mesh.Effects)
                effect.EnableDefaultLighting();
        // World matrix
        scaleMatrix = Matrix.CreateScale(0.0001f);
        worldMatrix = scaleMatrix;
        // View matrix
        lookatMatrix = Matrix.CreateLookAt(new Vector3(0, 0, 10f),
                                                       Vector3.Zero,
                                                       Vector3.Up);
        viewMatrix = lookatMatrix;
        // Projection matrix
        float aspectRatio = 
            graphics.GraphicsDevice.Viewport.AspectRatio;
        projectionMatrix =
            Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
                                                aspectRatio,
                                                1f, 100.0f);
    }
    ...
protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        model.Draw(worldMatrix, viewMatrix, projectionMatrix);
        base.Draw(gameTime);
    }
}

Em um sistema gráfico 3D como o XNA, modelos estão sujeitos a uma série de transformações de matrix em seu caminho para a exibição. A transformação do mundo é aplicada primeiro, e isso se o modelo no espaço 3D. A câmera é uma combinação das duas transformações aplicadas sucessivamente: A visão transformar contas para a localização e a orientação da câmera, enquanto a transformação de projeção trata de efeitos de perspectiva e também normaliza todas as coordenadas para recorte.

Figura 4 mostra como o modelo aparece no XNA padrão, modo de paisagem, e é muito mais que poderíamos esperar.

The View3DPhonePlain Display
Figura 4: A exibição de View3DPhonePlain

O próximo passo é o projeto chamado View3DPhoneReoriented. Eu queria mudar para o modo retrato para que as coordenadas 3D usadas dentro XNA eram o mesmo que o sistema de coordenadas 3D usado pelos sensores. Esta é uma simples questão de adicionar algumas instruções para o construtor do jogo derivado:

graphics.IsFullScreen = true;
   graphics.PreferredBackBufferWidth = 480;
   graphics.PreferredBackBufferHeight = 800;

Eu também queria reorientar o próprio telefone. Como mencionei, a matriz de rotação 3D de classe Motion é a matriz identidade, quando o telefone está sentado em uma mesa com a tela de cima e a parte superior apontando para norte. Como eu quero o telefone 3D para aparecer quando o telefone estava nessa posição? Eu queria estar olhando na parte superior do telefone como se visto de cima, então eu simplesmente adicionei uma rotação em torno do eixo x para a transformação do mundo:

worldMatrix *= Matrix.CreateRotationX(MathHelper.PiOver2);

O resultado é mostrado na Figura 5.

The View3DPhone­Reoriented Display
Figura 5 O View3DPhone­reorientou Display

A câmera parece um pouco demasiado perto do objeto neste momento, mas isso não me incomoda, porque sabia que quando eu incorporei a matriz de rotação, eu seria capaz de girar o telefone um pouco para conseguir tudo isso em vista. (Um visualizador aguçado de luz 3D e sombreamento pode notar uma falha conceitual na abordagem eu estou usando, mas deixe-me ingenuamente regressarão este caminho primeiro e depois eu vou arrumar coisas.)

Agora vamos incorporar a matriz de rotação de classe Motion.

Conceitualmente, o objeto 3D deve parecem permanecer fixa no espaço, e mover o telefone deve permitir que você exibir o objeto a partir de diferentes direções. Naturalmente, a experiência não é como na "vida real", porque você já não pode mover o telefone para olhar longe do objeto. O objeto está sempre lá no visor, mas a orientação da tela no espaço 3D dá-lhe diferentes pontos de vista dele.

Para conseguir este efeito, precisamos aplicar uma matriz para o objeto que atinge a rotação do sistema de coordenada do telefone para o sistema de coordenadas da terra, onde este objeto conceitualmente existe.

Seremos capazes de conseguir este efeito simplesmente, incluindo o objeto de RotationMatrix da classe Motion no cálculo de transformar o mundo. O projeto de View3DPhoneWorldMotion faz isso. Ele inclui código para criar um sensor de movimento em seu construtor, iniciá-lo a substituir OnActivated e pará-lo a substituir OnDeactivated. Mudei então o cálculo de transformar o mundo para a substituição de atualização, como mostrado na Figura 6.

Figura 6 A substituição de atualização em View3DPhoneWorldMotion

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == 
      ButtonState.Pressed)
        this.Exit();
    worldMatrix = scaleMatrix * 
      Matrix.CreateRotationX(MathHelper.PiOver2);
    if (motion != null && motion.IsDataValid)
        worldMatrix *= motion.CurrentValue.Attitude.RotationMatrix;
    base.Update(gameTime);
}

Neste programa, como você se move a orientação do telefone no espaço 3D, você exibir o objeto 3D a partir de todas as direções diferentes. O efeito é muito bom e — devo admitir — muito legal.

Mudando a rotação

E ainda, mais eu brinquei com esta versão do programa, mais eu senti que algo estava errado.

Aplicando a matriz de rotação para a transformação do mundo, o objeto 3D é efetivamente rodado não só em relação a câmera, mas também em relação a fonte de luz. Em alguns cenários, isso seria correto. Por exemplo, se você implementar uma interface de toque, assim você pode virar a imagem em 3D com os dedos, aplicando a matriz de rotação para a transformação do mundo seria apropriado.

Mas para este programa, o paradigma é bem diferente. Eu queria que o visor do telefone a ser como uma câmera móvel, que se move em relação ao objeto 3D, e isso significa que esse objeto deve permanecer fixo em relação a fonte de luz. A matriz de rotação de sensor de movimentos deve ser aplicada para transformar a exibição, em vez de transformar o mundo.

A versão final do programa — chamado View3DPhone­CameraMotion — eu restaurei o cálculo de transformar o mundo para a versão original:

worldMatrix = scaleMatrix;

Mesmo aplicando a rotação inicial foi um erro, porque isso implicava que a luz estava vindo por trás do telefone, em vez de acima. O novo método de atualização é mostrado em Figura 7.

Figura 7 A substituição de atualização em View3DPhoneCameraMotion

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == 
      ButtonState.Pressed)
        this.Exit();
    if (motion != null && motion.IsDataValid)
        viewMatrix = Matrix.CreateRotationX(MathHelper.PiOver2) *
                        motion.CurrentValue.Attitude.RotationMatrix *
                        lookatMatrix;
    else
        viewMatrix = Matrix.CreateRotationX(MathHelper.PiOver2) *
                        lookatMatrix;
    base.Update(gameTime);
}

Você precisa realmente de experimentar este programa em um telefone para obter o efeito completo, mas a imagem em Figura 8 mostra uma visão possível.

One View in View3DPhoneCameraMotion
Figura 8 um vista em View3DPhoneCameraMotion

Charles Petzold é um colaborador de longa data para MSDN Magazine e atualmente está atualizando seu clássico livro "Programming Windows" (Microsoft Press, 1998) para o Windows 8. Seu site é charlespetzold.com.

Graças ao especialista técnico seguir para revisar este artigo: Donn Morse